1
0
Fork 0
mirror of https://github.com/LemmyNet/lemmy.git synced 2025-03-13 23:12:40 +00:00

Changes to community visibility ()

* Move community.hidden to visibility (fixes )

* fix up migration by dropping index

* also add enum variant `LocalOnlyPublic`, rename `LocalOnly` to `LocalOnlyPrivate`

fixes 

* fix column order in down.sql

* wip

* more wip

* fixes

* migration for modlog

* fix migration

* wip

* db_schema compiling

* make the code compile

* lint

* fix down migration

* fix test

* make hidden status federate

* ts attr

* fix

* fix api test

* update api client

* review

* Extracting filter_not_hidden_or_is_subscribed ()

* Extracting filter_not_hidden_or_is_subscribed

* Cleanup.

* Cleanup 2.

* rename hidden to unlisted

---------

Co-authored-by: Dessalines <dessalines@users.noreply.github.com>
This commit is contained in:
Nutomic 2025-03-12 13:45:02 +00:00 committed by GitHub
parent d93bfdd2fa
commit 8ffeeca52d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
39 changed files with 583 additions and 293 deletions
api_tests
crates
api/src/community
api_common/src
api_crud/src/community
apub/src
activities
http
objects
protocol/objects
db_schema
db_views/src
routes/src
utils/src
migrations/2025-03-11-124442_community-hidden-visibility
src

View file

@ -29,7 +29,7 @@
"eslint": "^9.20.0", "eslint": "^9.20.0",
"eslint-plugin-prettier": "^5.2.3", "eslint-plugin-prettier": "^5.2.3",
"jest": "^29.5.0", "jest": "^29.5.0",
"lemmy-js-client": "0.20.0-remove-aggregate-tables.5", "lemmy-js-client": "0.20.0-move-community-hidden.3",
"prettier": "^3.5.0", "prettier": "^3.5.0",
"ts-jest": "^29.1.0", "ts-jest": "^29.1.0",
"tsoa": "^6.6.0", "tsoa": "^6.6.0",

View file

@ -33,8 +33,8 @@ importers:
specifier: ^29.5.0 specifier: ^29.5.0
version: 29.7.0(@types/node@22.13.1) version: 29.7.0(@types/node@22.13.1)
lemmy-js-client: lemmy-js-client:
specifier: 0.20.0-remove-aggregate-tables.5 specifier: 0.20.0-move-community-hidden.3
version: 0.20.0-remove-aggregate-tables.5 version: 0.20.0-move-community-hidden.3
prettier: prettier:
specifier: ^3.5.0 specifier: ^3.5.0
version: 3.5.0 version: 3.5.0
@ -1528,8 +1528,8 @@ packages:
resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
engines: {node: '>=6'} engines: {node: '>=6'}
lemmy-js-client@0.20.0-remove-aggregate-tables.5: lemmy-js-client@0.20.0-move-community-hidden.3:
resolution: {integrity: sha512-A/p4LLWNiVp7fsQOctbFm/biBAunk0FIl5X79WJ/hRu/UiD1M+tCLGYPGdy308R+zscZsDNqECe1LYBenOFzOA==} resolution: {integrity: sha512-X7bbSrnGGgupr//Qk2M1Z9nvFawNU4T116X+4/j912GO6KbQdWN7+10obbQJuoEYr15oCXwSaK8DLusofLxIig==}
leven@3.1.0: leven@3.1.0:
resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==}
@ -4169,7 +4169,7 @@ snapshots:
kleur@3.0.3: {} kleur@3.0.3: {}
lemmy-js-client@0.20.0-remove-aggregate-tables.5: {} lemmy-js-client@0.20.0-move-community-hidden.3: {}
leven@3.1.0: {} leven@3.1.0: {}

View file

@ -521,7 +521,7 @@ test("Content in local-only community doesn't federate", async () => {
let communityRes = (await createCommunity(alpha)).community_view.community; let communityRes = (await createCommunity(alpha)).community_view.community;
let form: EditCommunity = { let form: EditCommunity = {
community_id: communityRes.id, community_id: communityRes.id,
visibility: "LocalOnly", visibility: "LocalOnlyPublic",
}; };
await editCommunity(alpha, form); await editCommunity(alpha, form);

View file

@ -1,53 +0,0 @@
use activitypub_federation::config::Data;
use actix_web::web::Json;
use lemmy_api_common::{
community::HideCommunity,
context::LemmyContext,
send_activity::{ActivityChannel, SendActivityData},
utils::is_admin,
SuccessResponse,
};
use lemmy_db_schema::{
source::{
community::{Community, CommunityUpdateForm},
mod_log::moderator::{ModHideCommunity, ModHideCommunityForm},
},
traits::Crud,
};
use lemmy_db_views::structs::LocalUserView;
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult};
pub async fn hide_community(
data: Json<HideCommunity>,
context: Data<LemmyContext>,
local_user_view: LocalUserView,
) -> LemmyResult<Json<SuccessResponse>> {
// Verify its a admin (only admin can hide or unhide it)
is_admin(&local_user_view)?;
let community_form = CommunityUpdateForm {
hidden: Some(data.hidden),
..Default::default()
};
let mod_hide_community_form = ModHideCommunityForm {
community_id: data.community_id,
mod_person_id: local_user_view.person.id,
reason: data.reason.clone(),
hidden: Some(data.hidden),
};
let community_id = data.community_id;
let community = Community::update(&mut context.pool(), community_id, &community_form)
.await
.with_lemmy_type(LemmyErrorType::CouldntUpdateCommunityHiddenStatus)?;
ModHideCommunity::create(&mut context.pool(), &mod_hide_community_form).await?;
ActivityChannel::submit_activity(
SendActivityData::UpdateCommunity(local_user_view.person.clone(), community),
&context,
)?;
Ok(Json(SuccessResponse::default()))
}

View file

@ -2,7 +2,6 @@ pub mod add_mod;
pub mod ban; pub mod ban;
pub mod block; pub mod block;
pub mod follow; pub mod follow;
pub mod hide;
pub mod pending_follows; pub mod pending_follows;
pub mod random; pub mod random;
pub mod transfer; pub mod transfer;

View file

@ -44,7 +44,6 @@ use lemmy_db_schema::{
}, },
traits::{Crud, Likeable}, traits::{Crud, Likeable},
utils::DbPool, utils::DbPool,
CommunityVisibility,
FederationMode, FederationMode,
RegistrationMode, RegistrationMode,
}; };
@ -1190,7 +1189,7 @@ pub fn read_auth_token(req: &HttpRequest) -> LemmyResult<Option<String>> {
pub fn send_webmention(post: Post, community: Community) { pub fn send_webmention(post: Post, community: Community) {
if let Some(url) = post.url.clone() { if let Some(url) = post.url.clone() {
if community.visibility == CommunityVisibility::Public { if community.visibility.can_view_without_login() {
spawn_try_task(async move { spawn_try_task(async move {
let mut webmention = Webmention::new::<Url>(post.ap_id.clone().into(), url.clone().into())?; let mut webmention = Webmention::new::<Url>(post.ap_id.clone().into(), url.clone().into())?;
webmention.set_checked(true); webmention.set_checked(true);

View file

@ -9,13 +9,15 @@ pub mod list;
pub mod remove; pub mod remove;
pub mod update; pub mod update;
/// For now only admins can make communities private, in order to prevent abuse. /// For now only admins can make communities private or hidden, in order to
/// Need to implement admin approval for new communities to get rid of this. /// prevent abuse. Need to implement admin approval for new communities to
/// get rid of this.
fn check_community_visibility_allowed( fn check_community_visibility_allowed(
visibility: Option<CommunityVisibility>, visibility: Option<CommunityVisibility>,
local_user_view: &LocalUserView, local_user_view: &LocalUserView,
) -> LemmyResult<()> { ) -> LemmyResult<()> {
if visibility == Some(lemmy_db_schema::CommunityVisibility::Private) { use CommunityVisibility::*;
if visibility == Some(Private) || visibility == Some(Unlisted) {
is_admin(local_user_view)?; is_admin(local_user_view)?;
} }
Ok(()) Ok(())

View file

@ -23,10 +23,7 @@ use activitypub_federation::{
traits::{ActivityHandler, Actor}, traits::{ActivityHandler, Actor},
}; };
use lemmy_api_common::context::LemmyContext; use lemmy_api_common::context::LemmyContext;
use lemmy_db_schema::{ use lemmy_db_schema::source::{activity::ActivitySendTargets, community::CommunityFollower};
source::{activity::ActivitySendTargets, community::CommunityFollower},
CommunityVisibility,
};
use lemmy_utils::error::{FederationError, LemmyError, LemmyErrorType, LemmyResult}; use lemmy_utils::error::{FederationError, LemmyError, LemmyErrorType, LemmyResult};
use serde_json::Value; use serde_json::Value;
use url::Url; use url::Url;
@ -211,7 +208,7 @@ async fn can_accept_activity_in_community(
) -> LemmyResult<()> { ) -> LemmyResult<()> {
if let Some(community) = community { if let Some(community) = community {
// Local only community can't federate // Local only community can't federate
if community.visibility == CommunityVisibility::LocalOnly { if !community.visibility.can_federate() {
return Err(LemmyErrorType::NotFound.into()); return Err(LemmyErrorType::NotFound.into());
} }
if !community.local { if !community.local {

View file

@ -14,7 +14,6 @@ use lemmy_db_schema::{
site::Site, site::Site,
}, },
traits::Crud, traits::Crud,
CommunityVisibility,
}; };
use lemmy_db_views::structs::CommunityModeratorView; use lemmy_db_views::structs::CommunityModeratorView;
use lemmy_utils::error::LemmyResult; use lemmy_utils::error::LemmyResult;
@ -50,7 +49,7 @@ pub(crate) async fn send_activity_in_community(
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
) -> LemmyResult<()> { ) -> LemmyResult<()> {
// If community is local only, don't send anything out // If community is local only, don't send anything out
if community.visibility == CommunityVisibility::LocalOnly { if !community.visibility.can_federate() {
return Ok(()); return Ok(());
} }

View file

@ -89,6 +89,7 @@ impl ActivityHandler for Follow {
} }
async fn receive(self, context: &Data<LemmyContext>) -> LemmyResult<()> { async fn receive(self, context: &Data<LemmyContext>) -> LemmyResult<()> {
use CommunityVisibility::*;
insert_received_activity(&self.id, context).await?; insert_received_activity(&self.id, context).await?;
let actor = self.actor.dereference(context).await?; let actor = self.actor.dereference(context).await?;
let object = self.object.dereference(context).await?; let object = self.object.dereference(context).await?;
@ -111,10 +112,10 @@ impl ActivityHandler for Follow {
} }
} }
let state = Some(match c.visibility { let state = Some(match c.visibility {
CommunityVisibility::Public => CommunityFollowerState::Accepted, Public | Unlisted => CommunityFollowerState::Accepted,
CommunityVisibility::Private => CommunityFollowerState::ApprovalRequired, Private => CommunityFollowerState::ApprovalRequired,
// Dont allow following local-only community via federation. // Dont allow following local-only community via federation.
CommunityVisibility::LocalOnly => return Err(LemmyErrorType::NotFound.into()), LocalOnlyPrivate | LocalOnlyPublic => return Err(LemmyErrorType::NotFound.into()),
}); });
let form = CommunityFollowerForm { let form = CommunityFollowerForm {
state, state,

View file

@ -125,9 +125,8 @@ pub(crate) fn verify_visibility(to: &[Url], cc: &[Url], community: &Community) -
use CommunityVisibility::*; use CommunityVisibility::*;
let object_is_public = [to, cc].iter().any(|set| set.contains(&public())); let object_is_public = [to, cc].iter().any(|set| set.contains(&public()));
match community.visibility { match community.visibility {
Public if !object_is_public => Err(FederationError::ObjectIsNotPublic)?, Public | Unlisted if !object_is_public => Err(FederationError::ObjectIsNotPublic)?,
Private if object_is_public => Err(FederationError::ObjectIsNotPrivate)?, Private if object_is_public => Err(FederationError::ObjectIsNotPrivate)?,
LocalOnly => Err(LemmyErrorType::NotFound.into()),
_ => Ok(()), _ => Ok(()),
} }
} }

View file

@ -280,7 +280,7 @@ pub(crate) mod tests {
#[serial] #[serial]
async fn test_get_deleted_community() -> LemmyResult<()> { async fn test_get_deleted_community() -> LemmyResult<()> {
let context = LemmyContext::init_test_context().await; let context = LemmyContext::init_test_context().await;
let (instance, _, path) = init(true, CommunityVisibility::LocalOnly, &context).await?; let (instance, _, path) = init(true, CommunityVisibility::Public, &context).await?;
let request = TestRequest::default().to_http_request(); let request = TestRequest::default().to_http_request();
// should return tombstone // should return tombstone
@ -320,7 +320,7 @@ pub(crate) mod tests {
#[serial] #[serial]
async fn test_get_local_only_community() -> LemmyResult<()> { async fn test_get_local_only_community() -> LemmyResult<()> {
let context = LemmyContext::init_test_context().await; let context = LemmyContext::init_test_context().await;
let (instance, _, path) = init(false, CommunityVisibility::LocalOnly, &context).await?; let (instance, _, path) = init(false, CommunityVisibility::LocalOnlyPrivate, &context).await?;
let request = TestRequest::default().to_http_request(); let request = TestRequest::default().to_http_request();
let res = get_apub_community_http(path.clone().into(), context.reset_request_count()).await; let res = get_apub_community_http(path.clone().into(), context.reset_request_count()).await;

View file

@ -122,7 +122,7 @@ pub(crate) async fn get_activity(
/// Ensure that the community is public and not removed/deleted. /// Ensure that the community is public and not removed/deleted.
fn check_community_fetchable(community: &Community) -> LemmyResult<()> { fn check_community_fetchable(community: &Community) -> LemmyResult<()> {
check_community_removed_or_deleted(community)?; check_community_removed_or_deleted(community)?;
if community.visibility == CommunityVisibility::LocalOnly { if !community.visibility.can_federate() {
return Err(LemmyErrorType::NotFound.into()); return Err(LemmyErrorType::NotFound.into());
} }
Ok(()) Ok(())
@ -137,12 +137,7 @@ async fn check_community_content_fetchable(
use CommunityVisibility::*; use CommunityVisibility::*;
check_community_removed_or_deleted(community)?; check_community_removed_or_deleted(community)?;
match community.visibility { match community.visibility {
// content in public community can always be fetched Public | Unlisted => Ok(()),
Public => Ok(()),
// no federation for local only community
LocalOnly => Err(LemmyErrorType::NotFound.into()),
// for private community check http signature of request, if there is any approved follower
// from the fetching instance then fetching is allowed
Private => { Private => {
let signing_actor = signing_actor::<SiteOrCommunityOrUser>(request, None, context).await?; let signing_actor = signing_actor::<SiteOrCommunityOrUser>(request, None, context).await?;
if community.local { if community.local {
@ -167,6 +162,7 @@ async fn check_community_content_fetchable(
Err(LemmyErrorType::NotFound.into()) Err(LemmyErrorType::NotFound.into())
} }
} }
LocalOnlyPublic | LocalOnlyPrivate => Err(LemmyErrorType::NotFound.into()),
} }
} }

View file

@ -122,6 +122,7 @@ impl Object for ApubCommunity {
posting_restricted_to_mods: Some(self.posting_restricted_to_mods), posting_restricted_to_mods: Some(self.posting_restricted_to_mods),
attributed_to: Some(generate_moderators_url(&self.ap_id)?.into()), attributed_to: Some(generate_moderators_url(&self.ap_id)?.into()),
manually_approves_followers: Some(self.visibility == CommunityVisibility::Private), manually_approves_followers: Some(self.visibility == CommunityVisibility::Private),
discoverable: Some(self.visibility != CommunityVisibility::Unlisted),
}; };
Ok(group) Ok(group)
} }
@ -148,6 +149,8 @@ impl Object for ApubCommunity {
let banner = proxy_image_link_opt_apub(group.image.map(|i| i.url), context).await?; let banner = proxy_image_link_opt_apub(group.image.map(|i| i.url), context).await?;
let visibility = Some(if group.manually_approves_followers.unwrap_or_default() { let visibility = Some(if group.manually_approves_followers.unwrap_or_default() {
CommunityVisibility::Private CommunityVisibility::Private
} else if !group.discoverable.unwrap_or(true) {
CommunityVisibility::Unlisted
} else { } else {
CommunityVisibility::Public CommunityVisibility::Public
}); });

View file

@ -77,6 +77,8 @@ pub struct Group {
pub(crate) manually_approves_followers: Option<bool>, pub(crate) manually_approves_followers: Option<bool>,
pub(crate) published: Option<DateTime<Utc>>, pub(crate) published: Option<DateTime<Utc>>,
pub(crate) updated: Option<DateTime<Utc>>, pub(crate) updated: Option<DateTime<Utc>>,
/// https://docs.joinmastodon.org/spec/activitypub/#discoverable
pub(crate) discoverable: Option<bool>,
} }
impl Group { impl Group {

View file

@ -595,7 +595,7 @@ CALL r.create_person_saved_combined_trigger ('comment');
-- mod_ban -- mod_ban
-- mod_ban_from_community -- mod_ban_from_community
-- mod_feature_post -- mod_feature_post
-- mod_hide_community -- mod_change_community_visibility
-- mod_lock_post -- mod_lock_post
-- mod_remove_comment -- mod_remove_comment
-- mod_remove_community -- mod_remove_community
@ -646,7 +646,7 @@ CALL r.create_modlog_combined_trigger ('mod_ban_from_community');
CALL r.create_modlog_combined_trigger ('mod_feature_post'); CALL r.create_modlog_combined_trigger ('mod_feature_post');
CALL r.create_modlog_combined_trigger ('mod_hide_community'); CALL r.create_modlog_combined_trigger ('mod_change_community_visibility');
CALL r.create_modlog_combined_trigger ('mod_lock_post'); CALL r.create_modlog_combined_trigger ('mod_lock_post');

View file

@ -634,7 +634,6 @@ mod tests {
inbox_url: inserted_community.inbox_url.clone(), inbox_url: inserted_community.inbox_url.clone(),
moderators_url: None, moderators_url: None,
featured_url: None, featured_url: None,
hidden: false,
posting_restricted_to_mods: false, posting_restricted_to_mods: false,
instance_id: inserted_instance.id, instance_id: inserted_instance.id,
visibility: CommunityVisibility::Public, visibility: CommunityVisibility::Public,

View file

@ -4,8 +4,8 @@ use crate::{
ModAddId, ModAddId,
ModBanFromCommunityId, ModBanFromCommunityId,
ModBanId, ModBanId,
ModChangeCommunityVisibilityId,
ModFeaturePostId, ModFeaturePostId,
ModHideCommunityId,
ModLockPostId, ModLockPostId,
ModRemoveCommentId, ModRemoveCommentId,
ModRemoveCommunityId, ModRemoveCommunityId,
@ -17,8 +17,8 @@ use crate::{
mod_add_community, mod_add_community,
mod_ban, mod_ban,
mod_ban_from_community, mod_ban_from_community,
mod_change_community_visibility,
mod_feature_post, mod_feature_post,
mod_hide_community,
mod_lock_post, mod_lock_post,
mod_remove_comment, mod_remove_comment,
mod_remove_community, mod_remove_community,
@ -34,10 +34,10 @@ use crate::{
ModBanForm, ModBanForm,
ModBanFromCommunity, ModBanFromCommunity,
ModBanFromCommunityForm, ModBanFromCommunityForm,
ModChangeCommunityVisibility,
ModChangeCommunityVisibilityForm,
ModFeaturePost, ModFeaturePost,
ModFeaturePostForm, ModFeaturePostForm,
ModHideCommunity,
ModHideCommunityForm,
ModLockPost, ModLockPost,
ModLockPostForm, ModLockPostForm,
ModRemoveComment, ModRemoveComment,
@ -263,14 +263,14 @@ impl Crud for ModBan {
} }
} }
impl Crud for ModHideCommunity { impl Crud for ModChangeCommunityVisibility {
type InsertForm = ModHideCommunityForm; type InsertForm = ModChangeCommunityVisibilityForm;
type UpdateForm = ModHideCommunityForm; type UpdateForm = ModChangeCommunityVisibilityForm;
type IdType = ModHideCommunityId; type IdType = ModChangeCommunityVisibilityId;
async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result<Self, Error> { async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result<Self, Error> {
let conn = &mut get_conn(pool).await?; let conn = &mut get_conn(pool).await?;
insert_into(mod_hide_community::table) insert_into(mod_change_community_visibility::table)
.values(form) .values(form)
.get_result::<Self>(conn) .get_result::<Self>(conn)
.await .await
@ -282,7 +282,7 @@ impl Crud for ModHideCommunity {
form: &Self::UpdateForm, form: &Self::UpdateForm,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let conn = &mut get_conn(pool).await?; let conn = &mut get_conn(pool).await?;
diesel::update(mod_hide_community::table.find(from_id)) diesel::update(mod_change_community_visibility::table.find(from_id))
.set(form) .set(form)
.get_result::<Self>(conn) .get_result::<Self>(conn)
.await .await

View file

@ -205,7 +205,7 @@ pub enum ModlogActionType {
ModTransferCommunity, ModTransferCommunity,
ModAdd, ModAdd,
ModBan, ModBan,
ModHideCommunity, ModChangeCommunityVisibility,
AdminPurgePerson, AdminPurgePerson,
AdminPurgeCommunity, AdminPurgeCommunity,
AdminPurgePost, AdminPurgePost,
@ -277,12 +277,28 @@ pub enum CommunityVisibility {
/// Public community, any local or federated user can interact. /// Public community, any local or federated user can interact.
#[default] #[default]
Public, Public,
/// Unfederated community, only local users can interact. /// Community is hidden and doesn't appear in community list. Post from the community
LocalOnly, /// are not shown in Local and All feeds, except for subscribed users.
Unlisted,
/// Unfederated community, only local users can interact (with or without login).
LocalOnlyPublic,
/// Unfederated community, only logged-in local users can interact.
LocalOnlyPrivate,
/// Users need to be approved by mods before they are able to browse or post. /// Users need to be approved by mods before they are able to browse or post.
Private, Private,
} }
impl CommunityVisibility {
pub fn can_federate(&self) -> bool {
use CommunityVisibility::*;
self != &LocalOnlyPublic && self != &LocalOnlyPrivate
}
pub fn can_view_without_login(&self) -> bool {
use CommunityVisibility::*;
self == &Public || self == &LocalOnlyPublic
}
}
#[derive( #[derive(
EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Default, Hash, EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Default, Hash,
)] )]

View file

@ -295,7 +295,7 @@ pub struct ModBanId(pub i32);
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)] #[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "full", derive(DieselNewType, TS))] #[cfg_attr(feature = "full", derive(DieselNewType, TS))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
pub struct ModHideCommunityId(pub i32); pub struct ModChangeCommunityVisibilityId(pub i32);
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)] #[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "full", derive(DieselNewType, TS))] #[cfg_attr(feature = "full", derive(DieselNewType, TS))]

View file

@ -204,7 +204,6 @@ diesel::table! {
followers_url -> Nullable<Varchar>, followers_url -> Nullable<Varchar>,
#[max_length = 255] #[max_length = 255]
inbox_url -> Varchar, inbox_url -> Varchar,
hidden -> Bool,
posting_restricted_to_mods -> Bool, posting_restricted_to_mods -> Bool,
instance_id -> Int4, instance_id -> Int4,
#[max_length = 255] #[max_length = 255]
@ -435,6 +434,7 @@ diesel::table! {
comment_downvotes -> FederationModeEnum, comment_downvotes -> FederationModeEnum,
disable_donation_dialog -> Bool, disable_donation_dialog -> Bool,
default_post_time_range_seconds -> Nullable<Int4>, default_post_time_range_seconds -> Nullable<Int4>,
disallow_nsfw_content -> Bool,
users -> Int8, users -> Int8,
posts -> Int8, posts -> Int8,
comments -> Int8, comments -> Int8,
@ -443,7 +443,6 @@ diesel::table! {
users_active_week -> Int8, users_active_week -> Int8,
users_active_month -> Int8, users_active_month -> Int8,
users_active_half_year -> Int8, users_active_half_year -> Int8,
disallow_nsfw_content -> Bool,
} }
} }
@ -588,6 +587,20 @@ diesel::table! {
} }
} }
diesel::table! {
use diesel::sql_types::*;
use super::sql_types::CommunityVisibility;
mod_change_community_visibility (id) {
id -> Int4,
community_id -> Int4,
mod_person_id -> Int4,
published -> Timestamptz,
reason -> Nullable<Text>,
visibility -> CommunityVisibility,
}
}
diesel::table! { diesel::table! {
mod_feature_post (id) { mod_feature_post (id) {
id -> Int4, id -> Int4,
@ -599,17 +612,6 @@ diesel::table! {
} }
} }
diesel::table! {
mod_hide_community (id) {
id -> Int4,
community_id -> Int4,
mod_person_id -> Int4,
published -> Timestamptz,
reason -> Nullable<Text>,
hidden -> Bool,
}
}
diesel::table! { diesel::table! {
mod_lock_post (id) { mod_lock_post (id) {
id -> Int4, id -> Int4,
@ -678,12 +680,12 @@ diesel::table! {
mod_ban_id -> Nullable<Int4>, mod_ban_id -> Nullable<Int4>,
mod_ban_from_community_id -> Nullable<Int4>, mod_ban_from_community_id -> Nullable<Int4>,
mod_feature_post_id -> Nullable<Int4>, mod_feature_post_id -> Nullable<Int4>,
mod_hide_community_id -> Nullable<Int4>,
mod_lock_post_id -> Nullable<Int4>, mod_lock_post_id -> Nullable<Int4>,
mod_remove_comment_id -> Nullable<Int4>, mod_remove_comment_id -> Nullable<Int4>,
mod_remove_community_id -> Nullable<Int4>, mod_remove_community_id -> Nullable<Int4>,
mod_remove_post_id -> Nullable<Int4>, mod_remove_post_id -> Nullable<Int4>,
mod_transfer_community_id -> Nullable<Int4>, mod_transfer_community_id -> Nullable<Int4>,
mod_change_community_visibility_id -> Nullable<Int4>,
} }
} }
@ -1107,10 +1109,10 @@ diesel::joinable!(local_user_language -> local_user (local_user_id));
diesel::joinable!(login_token -> local_user (user_id)); diesel::joinable!(login_token -> local_user (user_id));
diesel::joinable!(mod_add_community -> community (community_id)); diesel::joinable!(mod_add_community -> community (community_id));
diesel::joinable!(mod_ban_from_community -> community (community_id)); diesel::joinable!(mod_ban_from_community -> community (community_id));
diesel::joinable!(mod_change_community_visibility -> community (community_id));
diesel::joinable!(mod_change_community_visibility -> person (mod_person_id));
diesel::joinable!(mod_feature_post -> person (mod_person_id)); diesel::joinable!(mod_feature_post -> person (mod_person_id));
diesel::joinable!(mod_feature_post -> post (post_id)); diesel::joinable!(mod_feature_post -> post (post_id));
diesel::joinable!(mod_hide_community -> community (community_id));
diesel::joinable!(mod_hide_community -> person (mod_person_id));
diesel::joinable!(mod_lock_post -> person (mod_person_id)); diesel::joinable!(mod_lock_post -> person (mod_person_id));
diesel::joinable!(mod_lock_post -> post (post_id)); diesel::joinable!(mod_lock_post -> post (post_id));
diesel::joinable!(mod_remove_comment -> comment (comment_id)); diesel::joinable!(mod_remove_comment -> comment (comment_id));
@ -1130,8 +1132,8 @@ diesel::joinable!(modlog_combined -> mod_add (mod_add_id));
diesel::joinable!(modlog_combined -> mod_add_community (mod_add_community_id)); diesel::joinable!(modlog_combined -> mod_add_community (mod_add_community_id));
diesel::joinable!(modlog_combined -> mod_ban (mod_ban_id)); diesel::joinable!(modlog_combined -> mod_ban (mod_ban_id));
diesel::joinable!(modlog_combined -> mod_ban_from_community (mod_ban_from_community_id)); diesel::joinable!(modlog_combined -> mod_ban_from_community (mod_ban_from_community_id));
diesel::joinable!(modlog_combined -> mod_change_community_visibility (mod_change_community_visibility_id));
diesel::joinable!(modlog_combined -> mod_feature_post (mod_feature_post_id)); diesel::joinable!(modlog_combined -> mod_feature_post (mod_feature_post_id));
diesel::joinable!(modlog_combined -> mod_hide_community (mod_hide_community_id));
diesel::joinable!(modlog_combined -> mod_lock_post (mod_lock_post_id)); diesel::joinable!(modlog_combined -> mod_lock_post (mod_lock_post_id));
diesel::joinable!(modlog_combined -> mod_remove_comment (mod_remove_comment_id)); diesel::joinable!(modlog_combined -> mod_remove_comment (mod_remove_comment_id));
diesel::joinable!(modlog_combined -> mod_remove_community (mod_remove_community_id)); diesel::joinable!(modlog_combined -> mod_remove_community (mod_remove_community_id));
@ -1214,8 +1216,8 @@ diesel::allow_tables_to_appear_in_same_query!(
mod_add_community, mod_add_community,
mod_ban, mod_ban,
mod_ban_from_community, mod_ban_from_community,
mod_change_community_visibility,
mod_feature_post, mod_feature_post,
mod_hide_community,
mod_lock_post, mod_lock_post,
mod_remove_comment, mod_remove_comment,
mod_remove_community, mod_remove_community,

View file

@ -9,8 +9,8 @@ use crate::newtypes::{
ModAddId, ModAddId,
ModBanFromCommunityId, ModBanFromCommunityId,
ModBanId, ModBanId,
ModChangeCommunityVisibilityId,
ModFeaturePostId, ModFeaturePostId,
ModHideCommunityId,
ModLockPostId, ModLockPostId,
ModRemoveCommentId, ModRemoveCommentId,
ModRemoveCommunityId, ModRemoveCommunityId,
@ -48,7 +48,7 @@ pub struct ModlogCombined {
pub mod_ban_id: Option<ModBanId>, pub mod_ban_id: Option<ModBanId>,
pub mod_ban_from_community_id: Option<ModBanFromCommunityId>, pub mod_ban_from_community_id: Option<ModBanFromCommunityId>,
pub mod_feature_post_id: Option<ModFeaturePostId>, pub mod_feature_post_id: Option<ModFeaturePostId>,
pub mod_hide_community_id: Option<ModHideCommunityId>, pub mod_change_community_visibility_id: Option<ModChangeCommunityVisibilityId>,
pub mod_lock_post_id: Option<ModLockPostId>, pub mod_lock_post_id: Option<ModLockPostId>,
pub mod_remove_comment_id: Option<ModRemoveCommentId>, pub mod_remove_comment_id: Option<ModRemoveCommentId>,
pub mod_remove_community_id: Option<ModRemoveCommunityId>, pub mod_remove_community_id: Option<ModRemoveCommunityId>,

View file

@ -61,8 +61,6 @@ pub struct Community {
#[cfg_attr(feature = "full", ts(skip))] #[cfg_attr(feature = "full", ts(skip))]
#[serde(skip, default = "placeholder_apub_url")] #[serde(skip, default = "placeholder_apub_url")]
pub inbox_url: DbUrl, pub inbox_url: DbUrl,
/// Whether the community is hidden.
pub hidden: bool,
/// Whether posting is restricted to mods only. /// Whether posting is restricted to mods only.
pub posting_restricted_to_mods: bool, pub posting_restricted_to_mods: bool,
pub instance_id: InstanceId, pub instance_id: InstanceId,
@ -140,8 +138,6 @@ pub struct CommunityInsertForm {
#[new(default)] #[new(default)]
pub featured_url: Option<DbUrl>, pub featured_url: Option<DbUrl>,
#[new(default)] #[new(default)]
pub hidden: Option<bool>,
#[new(default)]
pub posting_restricted_to_mods: Option<bool>, pub posting_restricted_to_mods: Option<bool>,
#[new(default)] #[new(default)]
pub visibility: Option<CommunityVisibility>, pub visibility: Option<CommunityVisibility>,
@ -171,7 +167,6 @@ pub struct CommunityUpdateForm {
pub inbox_url: Option<DbUrl>, pub inbox_url: Option<DbUrl>,
pub moderators_url: Option<DbUrl>, pub moderators_url: Option<DbUrl>,
pub featured_url: Option<DbUrl>, pub featured_url: Option<DbUrl>,
pub hidden: Option<bool>,
pub posting_restricted_to_mods: Option<bool>, pub posting_restricted_to_mods: Option<bool>,
pub visibility: Option<CommunityVisibility>, pub visibility: Option<CommunityVisibility>,
pub description: Option<Option<String>>, pub description: Option<Option<String>>,

View file

@ -89,6 +89,8 @@ pub struct LocalSite {
#[cfg_attr(feature = "full", ts(optional))] #[cfg_attr(feature = "full", ts(optional))]
/// A default time range limit to apply to post sorts, in seconds. /// A default time range limit to apply to post sorts, in seconds.
pub default_post_time_range_seconds: Option<i32>, pub default_post_time_range_seconds: Option<i32>,
/// Block NSFW content being created
pub disallow_nsfw_content: bool,
pub users: i64, pub users: i64,
pub posts: i64, pub posts: i64,
pub comments: i64, pub comments: i64,
@ -101,8 +103,6 @@ pub struct LocalSite {
pub users_active_month: i64, pub users_active_month: i64,
/// The number of users with any activity in the last half year. /// The number of users with any activity in the last half year.
pub users_active_half_year: i64, pub users_active_half_year: i64,
/// Block NSFW content being created
pub disallow_nsfw_content: bool,
} }
#[derive(Clone, derive_new::new)] #[derive(Clone, derive_new::new)]

View file

@ -1,34 +1,37 @@
use crate::newtypes::{
CommentId,
CommunityId,
ModAddCommunityId,
ModAddId,
ModBanFromCommunityId,
ModBanId,
ModFeaturePostId,
ModHideCommunityId,
ModLockPostId,
ModRemoveCommentId,
ModRemoveCommunityId,
ModRemovePostId,
ModTransferCommunityId,
PersonId,
PostId,
};
#[cfg(feature = "full")] #[cfg(feature = "full")]
use crate::schema::{ use crate::schema::{
mod_add, mod_add,
mod_add_community, mod_add_community,
mod_ban, mod_ban,
mod_ban_from_community, mod_ban_from_community,
mod_change_community_visibility,
mod_feature_post, mod_feature_post,
mod_hide_community,
mod_lock_post, mod_lock_post,
mod_remove_comment, mod_remove_comment,
mod_remove_community, mod_remove_community,
mod_remove_post, mod_remove_post,
mod_transfer_community, mod_transfer_community,
}; };
use crate::{
newtypes::{
CommentId,
CommunityId,
ModAddCommunityId,
ModAddId,
ModBanFromCommunityId,
ModBanId,
ModChangeCommunityVisibilityId,
ModFeaturePostId,
ModLockPostId,
ModRemoveCommentId,
ModRemoveCommunityId,
ModRemovePostId,
ModTransferCommunityId,
PersonId,
PostId,
},
CommunityVisibility,
};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none; use serde_with::skip_serializing_none;
@ -210,29 +213,28 @@ pub struct ModBan {
} }
#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))] #[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
#[cfg_attr(feature = "full", diesel(table_name = mod_hide_community))] #[cfg_attr(feature = "full", diesel(table_name = mod_change_community_visibility))]
pub struct ModHideCommunityForm { pub struct ModChangeCommunityVisibilityForm {
pub community_id: CommunityId, pub community_id: CommunityId,
pub mod_person_id: PersonId, pub mod_person_id: PersonId,
pub hidden: Option<bool>,
pub reason: Option<String>, pub reason: Option<String>,
pub visibility: CommunityVisibility,
} }
#[skip_serializing_none] #[skip_serializing_none]
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] #[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "full", derive(Queryable, Selectable, Identifiable, TS))] #[cfg_attr(feature = "full", derive(Queryable, Selectable, Identifiable, TS))]
#[cfg_attr(feature = "full", diesel(table_name = mod_hide_community))] #[cfg_attr(feature = "full", diesel(table_name = mod_change_community_visibility))]
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))] #[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// When a community is hidden from public view. pub struct ModChangeCommunityVisibility {
pub struct ModHideCommunity { pub id: ModChangeCommunityVisibilityId,
pub id: ModHideCommunityId,
pub community_id: CommunityId, pub community_id: CommunityId,
pub mod_person_id: PersonId, pub mod_person_id: PersonId,
pub published: DateTime<Utc>, pub published: DateTime<Utc>,
#[cfg_attr(feature = "full", ts(optional))] #[cfg_attr(feature = "full", ts(optional))]
pub reason: Option<String>, pub reason: Option<String>,
pub hidden: bool, pub visibility: CommunityVisibility,
} }
#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))] #[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]

View file

@ -1,23 +1,26 @@
use crate::structs::{ use crate::{
AdminAllowInstanceView, structs::{
AdminBlockInstanceView, AdminAllowInstanceView,
AdminPurgeCommentView, AdminBlockInstanceView,
AdminPurgeCommunityView, AdminPurgeCommentView,
AdminPurgePersonView, AdminPurgeCommunityView,
AdminPurgePostView, AdminPurgePersonView,
ModAddCommunityView, AdminPurgePostView,
ModAddView, ModAddCommunityView,
ModBanFromCommunityView, ModAddView,
ModBanView, ModBanFromCommunityView,
ModFeaturePostView, ModBanView,
ModHideCommunityView, ModChangeCommunityVisibilityView,
ModLockPostView, ModFeaturePostView,
ModRemoveCommentView, ModLockPostView,
ModRemoveCommunityView, ModRemoveCommentView,
ModRemovePostView, ModRemoveCommunityView,
ModTransferCommunityView, ModRemovePostView,
ModlogCombinedView, ModTransferCommunityView,
ModlogCombinedViewInternal, ModlogCombinedView,
ModlogCombinedViewInternal,
},
utils::{filter_is_subscribed, filter_not_hidden_or_is_subscribed},
}; };
use diesel::{ use diesel::{
BoolExpressionMethods, BoolExpressionMethods,
@ -49,8 +52,8 @@ use lemmy_db_schema::{
mod_add_community, mod_add_community,
mod_ban, mod_ban,
mod_ban_from_community, mod_ban_from_community,
mod_change_community_visibility,
mod_feature_post, mod_feature_post,
mod_hide_community,
mod_lock_post, mod_lock_post,
mod_remove_comment, mod_remove_comment,
mod_remove_community, mod_remove_community,
@ -103,7 +106,7 @@ impl ModlogCombinedViewInternal {
.or(mod_ban::mod_person_id.eq(person::id)) .or(mod_ban::mod_person_id.eq(person::id))
.or(mod_ban_from_community::mod_person_id.eq(person::id)) .or(mod_ban_from_community::mod_person_id.eq(person::id))
.or(mod_feature_post::mod_person_id.eq(person::id)) .or(mod_feature_post::mod_person_id.eq(person::id))
.or(mod_hide_community::mod_person_id.eq(person::id)) .or(mod_change_community_visibility::mod_person_id.eq(person::id))
.or(mod_lock_post::mod_person_id.eq(person::id)) .or(mod_lock_post::mod_person_id.eq(person::id))
.or(mod_remove_comment::mod_person_id.eq(person::id)) .or(mod_remove_comment::mod_person_id.eq(person::id))
.or(mod_remove_community::mod_person_id.eq(person::id)) .or(mod_remove_community::mod_person_id.eq(person::id))
@ -167,7 +170,7 @@ impl ModlogCombinedViewInternal {
.is_not_null() .is_not_null()
.and(post::community_id.eq(community::id)), .and(post::community_id.eq(community::id)),
) )
.or(mod_hide_community::community_id.eq(community::id)) .or(mod_change_community_visibility::community_id.eq(community::id))
.or( .or(
mod_lock_post::id mod_lock_post::id
.is_not_null() .is_not_null()
@ -211,7 +214,7 @@ impl ModlogCombinedViewInternal {
.left_join(mod_ban::table) .left_join(mod_ban::table)
.left_join(mod_ban_from_community::table) .left_join(mod_ban_from_community::table)
.left_join(mod_feature_post::table) .left_join(mod_feature_post::table)
.left_join(mod_hide_community::table) .left_join(mod_change_community_visibility::table)
.left_join(mod_lock_post::table) .left_join(mod_lock_post::table)
.left_join(mod_remove_comment::table) .left_join(mod_remove_comment::table)
.left_join(mod_remove_community::table) .left_join(mod_remove_community::table)
@ -230,24 +233,25 @@ impl ModlogCombinedViewInternal {
impl PaginationCursorBuilder for ModlogCombinedView { impl PaginationCursorBuilder for ModlogCombinedView {
type CursorData = ModlogCombined; type CursorData = ModlogCombined;
fn to_cursor(&self) -> PaginationCursor { fn to_cursor(&self) -> PaginationCursor {
use ModlogCombinedView::*;
let (prefix, id) = match &self { let (prefix, id) = match &self {
ModlogCombinedView::AdminAllowInstance(v) => ('A', v.admin_allow_instance.id.0), AdminAllowInstance(v) => ('A', v.admin_allow_instance.id.0),
ModlogCombinedView::AdminBlockInstance(v) => ('B', v.admin_block_instance.id.0), AdminBlockInstance(v) => ('B', v.admin_block_instance.id.0),
ModlogCombinedView::AdminPurgeComment(v) => ('C', v.admin_purge_comment.id.0), AdminPurgeComment(v) => ('C', v.admin_purge_comment.id.0),
ModlogCombinedView::AdminPurgeCommunity(v) => ('D', v.admin_purge_community.id.0), AdminPurgeCommunity(v) => ('D', v.admin_purge_community.id.0),
ModlogCombinedView::AdminPurgePerson(v) => ('E', v.admin_purge_person.id.0), AdminPurgePerson(v) => ('E', v.admin_purge_person.id.0),
ModlogCombinedView::AdminPurgePost(v) => ('F', v.admin_purge_post.id.0), AdminPurgePost(v) => ('F', v.admin_purge_post.id.0),
ModlogCombinedView::ModAdd(v) => ('G', v.mod_add.id.0), ModAdd(v) => ('G', v.mod_add.id.0),
ModlogCombinedView::ModAddCommunity(v) => ('H', v.mod_add_community.id.0), ModAddCommunity(v) => ('H', v.mod_add_community.id.0),
ModlogCombinedView::ModBan(v) => ('I', v.mod_ban.id.0), ModBan(v) => ('I', v.mod_ban.id.0),
ModlogCombinedView::ModBanFromCommunity(v) => ('J', v.mod_ban_from_community.id.0), ModBanFromCommunity(v) => ('J', v.mod_ban_from_community.id.0),
ModlogCombinedView::ModFeaturePost(v) => ('K', v.mod_feature_post.id.0), ModFeaturePost(v) => ('K', v.mod_feature_post.id.0),
ModlogCombinedView::ModHideCommunity(v) => ('L', v.mod_hide_community.id.0), ModChangeCommunityVisibility(v) => ('L', v.mod_change_community_visibility.id.0),
ModlogCombinedView::ModLockPost(v) => ('M', v.mod_lock_post.id.0), ModLockPost(v) => ('M', v.mod_lock_post.id.0),
ModlogCombinedView::ModRemoveComment(v) => ('N', v.mod_remove_comment.id.0), ModRemoveComment(v) => ('N', v.mod_remove_comment.id.0),
ModlogCombinedView::ModRemoveCommunity(v) => ('O', v.mod_remove_community.id.0), ModRemoveCommunity(v) => ('O', v.mod_remove_community.id.0),
ModlogCombinedView::ModRemovePost(v) => ('P', v.mod_remove_post.id.0), ModRemovePost(v) => ('P', v.mod_remove_post.id.0),
ModlogCombinedView::ModTransferCommunity(v) => ('Q', v.mod_transfer_community.id.0), ModTransferCommunity(v) => ('Q', v.mod_transfer_community.id.0),
}; };
PaginationCursor::new(prefix, id) PaginationCursor::new(prefix, id)
} }
@ -275,7 +279,7 @@ impl PaginationCursorBuilder for ModlogCombinedView {
'I' => query.filter(modlog_combined::mod_ban_id.eq(id)), 'I' => query.filter(modlog_combined::mod_ban_id.eq(id)),
'J' => query.filter(modlog_combined::mod_ban_from_community_id.eq(id)), 'J' => query.filter(modlog_combined::mod_ban_from_community_id.eq(id)),
'K' => query.filter(modlog_combined::mod_feature_post_id.eq(id)), 'K' => query.filter(modlog_combined::mod_feature_post_id.eq(id)),
'L' => query.filter(modlog_combined::mod_hide_community_id.eq(id)), 'L' => query.filter(modlog_combined::mod_change_community_visibility_id.eq(id)),
'M' => query.filter(modlog_combined::mod_lock_post_id.eq(id)), 'M' => query.filter(modlog_combined::mod_lock_post_id.eq(id)),
'N' => query.filter(modlog_combined::mod_remove_comment_id.eq(id)), 'N' => query.filter(modlog_combined::mod_remove_comment_id.eq(id)),
'O' => query.filter(modlog_combined::mod_remove_community_id.eq(id)), 'O' => query.filter(modlog_combined::mod_remove_community_id.eq(id)),
@ -355,7 +359,9 @@ impl ModlogCombinedQuery<'_> {
} }
ModAdd => query.filter(modlog_combined::mod_add_id.is_not_null()), ModAdd => query.filter(modlog_combined::mod_add_id.is_not_null()),
ModBan => query.filter(modlog_combined::mod_ban_id.is_not_null()), ModBan => query.filter(modlog_combined::mod_ban_id.is_not_null()),
ModHideCommunity => query.filter(modlog_combined::mod_hide_community_id.is_not_null()), ModChangeCommunityVisibility => {
query.filter(modlog_combined::mod_change_community_visibility_id.is_not_null())
}
AdminPurgePerson => query.filter(modlog_combined::admin_purge_person_id.is_not_null()), AdminPurgePerson => query.filter(modlog_combined::admin_purge_person_id.is_not_null()),
AdminPurgeCommunity => { AdminPurgeCommunity => {
query.filter(modlog_combined::admin_purge_community_id.is_not_null()) query.filter(modlog_combined::admin_purge_community_id.is_not_null())
@ -367,13 +373,12 @@ impl ModlogCombinedQuery<'_> {
} }
} }
let is_subscribed = community_actions::followed.is_not_null();
query = match self.listing_type.unwrap_or(ListingType::All) { query = match self.listing_type.unwrap_or(ListingType::All) {
ListingType::All => query, ListingType::All => query,
ListingType::Subscribed => query.filter(is_subscribed), ListingType::Subscribed => query.filter(filter_is_subscribed()),
ListingType::Local => query ListingType::Local => query
.filter(community::local.eq(true)) .filter(community::local.eq(true))
.filter(community::hidden.eq(false).or(is_subscribed)), .filter(filter_not_hidden_or_is_subscribed()),
ListingType::ModeratorView => query.filter(community_actions::became_moderator.is_not_null()), ListingType::ModeratorView => query.filter(community_actions::became_moderator.is_not_null()),
}; };
@ -507,14 +512,16 @@ impl InternalToCombinedView for ModlogCombinedViewInternal {
community, community,
post, post,
})) }))
} else if let (Some(mod_hide_community), Some(community)) = } else if let (Some(mod_change_community_visibility), Some(community)) =
(v.mod_hide_community, v.community.clone()) (v.mod_change_community_visibility, v.community.clone())
{ {
Some(ModlogCombinedView::ModHideCommunity(ModHideCommunityView { Some(ModlogCombinedView::ModChangeCommunityVisibility(
mod_hide_community, ModChangeCommunityVisibilityView {
admin: v.moderator, mod_change_community_visibility,
community, moderator: v.moderator,
})) community,
},
))
} else if let (Some(mod_lock_post), Some(other_person), Some(community), Some(post)) = ( } else if let (Some(mod_lock_post), Some(other_person), Some(community), Some(post)) = (
v.mod_lock_post, v.mod_lock_post,
v.other_person.clone(), v.other_person.clone(),
@ -626,10 +633,10 @@ mod tests {
ModBanForm, ModBanForm,
ModBanFromCommunity, ModBanFromCommunity,
ModBanFromCommunityForm, ModBanFromCommunityForm,
ModChangeCommunityVisibility,
ModChangeCommunityVisibilityForm,
ModFeaturePost, ModFeaturePost,
ModFeaturePostForm, ModFeaturePostForm,
ModHideCommunity,
ModHideCommunityForm,
ModLockPost, ModLockPost,
ModLockPostForm, ModLockPostForm,
ModRemoveComment, ModRemoveComment,
@ -647,6 +654,7 @@ mod tests {
}, },
traits::Crud, traits::Crud,
utils::{build_db_pool_for_tests, DbPool}, utils::{build_db_pool_for_tests, DbPool},
CommunityVisibility,
ModlogActionType, ModlogActionType,
}; };
use lemmy_utils::error::LemmyResult; use lemmy_utils::error::LemmyResult;
@ -778,43 +786,49 @@ mod tests {
}; };
AdminPurgePost::create(pool, &form).await?; AdminPurgePost::create(pool, &form).await?;
let form = ModHideCommunityForm { let form = ModChangeCommunityVisibilityForm {
mod_person_id: data.timmy.id, mod_person_id: data.timmy.id,
community_id: data.community.id, community_id: data.community.id,
hidden: Some(true), visibility: CommunityVisibility::Unlisted,
reason: None, reason: None,
}; };
ModHideCommunity::create(pool, &form).await?; ModChangeCommunityVisibility::create(pool, &form).await?;
// A 2nd mod hide community, but to a different community, and with jessica // A 2nd mod hide community, but to a different community, and with jessica
let form = ModHideCommunityForm { let form = ModChangeCommunityVisibilityForm {
mod_person_id: data.jessica.id, mod_person_id: data.jessica.id,
community_id: data.community_2.id, community_id: data.community_2.id,
hidden: Some(true), visibility: CommunityVisibility::Unlisted,
reason: None, reason: None,
}; };
ModHideCommunity::create(pool, &form).await?; ModChangeCommunityVisibility::create(pool, &form).await?;
let modlog = ModlogCombinedQuery::default().list(pool).await?; let modlog = ModlogCombinedQuery::default().list(pool).await?;
assert_eq!(8, modlog.len()); assert_eq!(8, modlog.len());
if let ModlogCombinedView::ModHideCommunity(v) = &modlog[0] { if let ModlogCombinedView::ModChangeCommunityVisibility(v) = &modlog[0] {
assert_eq!(data.community_2.id, v.mod_hide_community.community_id); assert_eq!(
data.community_2.id,
v.mod_change_community_visibility.community_id
);
assert_eq!(data.community_2.id, v.community.id); assert_eq!(data.community_2.id, v.community.id);
assert_eq!( assert_eq!(
data.jessica.id, data.jessica.id,
v.admin.as_ref().map(|a| a.id).unwrap_or(PersonId(-1)) v.moderator.as_ref().map(|a| a.id).unwrap_or(PersonId(-1))
); );
} else { } else {
panic!("wrong type"); panic!("wrong type");
} }
if let ModlogCombinedView::ModHideCommunity(v) = &modlog[1] { if let ModlogCombinedView::ModChangeCommunityVisibility(v) = &modlog[1] {
assert_eq!(data.community.id, v.mod_hide_community.community_id); assert_eq!(
data.community.id,
v.mod_change_community_visibility.community_id
);
assert_eq!(data.community.id, v.community.id); assert_eq!(data.community.id, v.community.id);
assert_eq!( assert_eq!(
data.timmy.id, data.timmy.id,
v.admin.as_ref().map(|a| a.id).unwrap_or(PersonId(-1)) v.moderator.as_ref().map(|a| a.id).unwrap_or(PersonId(-1))
); );
} else { } else {
panic!("wrong type"); panic!("wrong type");
@ -906,7 +920,7 @@ mod tests {
// Filter by type // Filter by type
let modlog_type_filter = ModlogCombinedQuery { let modlog_type_filter = ModlogCombinedQuery {
type_: Some(ModlogActionType::ModHideCommunity), type_: Some(ModlogActionType::ModChangeCommunityVisibility),
..Default::default() ..Default::default()
} }
.list(pool) .list(pool)
@ -915,23 +929,29 @@ mod tests {
// 2 of these, one is jessicas // 2 of these, one is jessicas
assert_eq!(2, modlog_type_filter.len()); assert_eq!(2, modlog_type_filter.len());
if let ModlogCombinedView::ModHideCommunity(v) = &modlog_type_filter[0] { if let ModlogCombinedView::ModChangeCommunityVisibility(v) = &modlog_type_filter[0] {
assert_eq!(data.community_2.id, v.mod_hide_community.community_id); assert_eq!(
data.community_2.id,
v.mod_change_community_visibility.community_id
);
assert_eq!(data.community_2.id, v.community.id); assert_eq!(data.community_2.id, v.community.id);
assert_eq!( assert_eq!(
data.jessica.id, data.jessica.id,
v.admin.as_ref().map(|a| a.id).unwrap_or(PersonId(-1)) v.moderator.as_ref().map(|a| a.id).unwrap_or(PersonId(-1))
); );
} else { } else {
panic!("wrong type"); panic!("wrong type");
} }
if let ModlogCombinedView::ModHideCommunity(v) = &modlog_type_filter[1] { if let ModlogCombinedView::ModChangeCommunityVisibility(v) = &modlog_type_filter[1] {
assert_eq!(data.community.id, v.mod_hide_community.community_id); assert_eq!(
data.community.id,
v.mod_change_community_visibility.community_id
);
assert_eq!(data.community.id, v.community.id); assert_eq!(data.community.id, v.community.id);
assert_eq!( assert_eq!(
data.timmy.id, data.timmy.id,
v.admin.as_ref().map(|a| a.id).unwrap_or(PersonId(-1)) v.moderator.as_ref().map(|a| a.id).unwrap_or(PersonId(-1))
); );
} else { } else {
panic!("wrong type"); panic!("wrong type");

View file

@ -1,11 +1,14 @@
use crate::structs::{ use crate::{
CommentView, structs::{
CommunityView, CommentView,
LocalUserView, CommunityView,
PersonView, LocalUserView,
PostView, PersonView,
SearchCombinedView, PostView,
SearchCombinedViewInternal, SearchCombinedView,
SearchCombinedViewInternal,
},
utils::{filter_is_subscribed, filter_not_hidden_or_is_subscribed},
}; };
use diesel::{ use diesel::{
dsl::not, dsl::not,
@ -350,24 +353,19 @@ impl SearchCombinedQuery {
}; };
// Listing type // Listing type
let is_subscribed = community_actions::followed.is_not_null();
match self.listing_type.unwrap_or_default() { match self.listing_type.unwrap_or_default() {
ListingType::Subscribed => query = query.filter(is_subscribed), ListingType::Subscribed => query = query.filter(filter_is_subscribed()),
ListingType::Local => { ListingType::Local => {
query = query.filter( query = query.filter(
community::local community::local
.eq(true) .eq(true)
.and(community::hidden.eq(false).or(is_subscribed)) .and(filter_not_hidden_or_is_subscribed())
.or(search_combined::person_id.is_not_null().and(person::local)), .or(search_combined::person_id.is_not_null().and(person::local)),
); );
} }
ListingType::All => { ListingType::All => {
query = query.filter( query = query
community::hidden .filter(filter_not_hidden_or_is_subscribed().or(search_combined::person_id.is_not_null()))
.eq(false)
.or(is_subscribed)
.or(search_combined::person_id.is_not_null()),
)
} }
ListingType::ModeratorView => { ListingType::ModeratorView => {
query = query.filter(community_actions::became_moderator.is_not_null()); query = query.filter(community_actions::became_moderator.is_not_null());

View file

@ -972,7 +972,6 @@ mod tests {
description: None, description: None,
updated: None, updated: None,
banner: None, banner: None,
hidden: false,
posting_restricted_to_mods: false, posting_restricted_to_mods: false,
published: data.inserted_community.published, published: data.inserted_community.published,
instance_id: data.inserted_instance.id, instance_id: data.inserted_instance.id,
@ -1012,7 +1011,7 @@ mod tests {
pool, pool,
data.inserted_community.id, data.inserted_community.id,
&CommunityUpdateForm { &CommunityUpdateForm {
visibility: Some(CommunityVisibility::LocalOnly), visibility: Some(CommunityVisibility::LocalOnlyPrivate),
..Default::default() ..Default::default()
}, },
) )

View file

@ -1,4 +1,7 @@
use crate::structs::{CommunityModeratorView, CommunitySortType, CommunityView, PersonView}; use crate::{
structs::{CommunityModeratorView, CommunitySortType, CommunityView, PersonView},
utils::{filter_is_subscribed, filter_not_hidden_or_is_subscribed},
};
use diesel::{ use diesel::{
result::Error, result::Error,
BoolExpressionMethods, BoolExpressionMethods,
@ -13,11 +16,7 @@ use lemmy_db_schema::{
impls::local_user::LocalUserOptionHelper, impls::local_user::LocalUserOptionHelper,
newtypes::{CommunityId, PersonId}, newtypes::{CommunityId, PersonId},
schema::{community, community_actions, instance_actions, local_user}, schema::{community, community_actions, instance_actions, local_user},
source::{ source::{community::Community, local_user::LocalUser, site::Site},
community::{Community, CommunityFollowerState},
local_user::LocalUser,
site::Site,
},
utils::{functions::lower, get_conn, limit_and_offset, now, seconds_to_pg_interval, DbPool}, utils::{functions::lower, get_conn, limit_and_offset, now, seconds_to_pg_interval, DbPool},
ListingType, ListingType,
}; };
@ -130,22 +129,18 @@ impl CommunityQuery<'_> {
// Hide deleted and removed for non-admins or mods // Hide deleted and removed for non-admins or mods
if !o.is_mod_or_admin { if !o.is_mod_or_admin {
query = query.filter(Community::hide_removed_and_deleted()).filter( query = query
community::hidden .filter(Community::hide_removed_and_deleted())
.eq(false) .filter(filter_not_hidden_or_is_subscribed());
.or(community_actions::follow_state.is_not_null()),
);
} }
let is_subscribed = community_actions::follow_state.eq(Some(CommunityFollowerState::Accepted));
if let Some(listing_type) = o.listing_type { if let Some(listing_type) = o.listing_type {
query = match listing_type { query = match listing_type {
ListingType::All => query.filter(community::hidden.eq(false).or(is_subscribed)), ListingType::All => query.filter(filter_not_hidden_or_is_subscribed()),
ListingType::Subscribed => query.filter(is_subscribed), ListingType::Subscribed => query.filter(filter_is_subscribed()),
ListingType::Local => query ListingType::Local => query
.filter(community::local.eq(true)) .filter(community::local.eq(true))
.filter(community::hidden.eq(false).or(is_subscribed)), .filter(filter_not_hidden_or_is_subscribed()),
ListingType::ModeratorView => { ListingType::ModeratorView => {
query.filter(community_actions::became_moderator.is_not_null()) query.filter(community_actions::became_moderator.is_not_null())
} }
@ -386,7 +381,7 @@ mod tests {
pool, pool,
data.communities[0].id, data.communities[0].id,
&CommunityUpdateForm { &CommunityUpdateForm {
visibility: Some(CommunityVisibility::LocalOnly), visibility: Some(CommunityVisibility::LocalOnlyPrivate),
..Default::default() ..Default::default()
}, },
) )

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
structs::{PostPaginationCursor, PostView}, structs::{PostPaginationCursor, PostView},
utils::filter_blocked, utils::{filter_blocked, filter_is_subscribed, filter_not_hidden_or_is_subscribed},
}; };
use diesel::{ use diesel::{
debug_query, debug_query,
@ -460,15 +460,14 @@ impl<'a> PostQuery<'a> {
query = query.filter(post::creator_id.eq(creator_id)); query = query.filter(post::creator_id.eq(creator_id));
} }
let is_subscribed = community_actions::followed.is_not_null();
match o.listing_type.unwrap_or_default() { match o.listing_type.unwrap_or_default() {
ListingType::Subscribed => query = query.filter(is_subscribed), ListingType::Subscribed => query = query.filter(filter_is_subscribed()),
ListingType::Local => { ListingType::Local => {
query = query query = query
.filter(community::local.eq(true)) .filter(community::local.eq(true))
.filter(community::hidden.eq(false).or(is_subscribed)); .filter(filter_not_hidden_or_is_subscribed());
} }
ListingType::All => query = query.filter(community::hidden.eq(false).or(is_subscribed)), ListingType::All => query = query.filter(filter_not_hidden_or_is_subscribed()),
ListingType::ModeratorView => { ListingType::ModeratorView => {
query = query.filter(community_actions::became_moderator.is_not_null()); query = query.filter(community_actions::became_moderator.is_not_null());
} }
@ -1564,7 +1563,7 @@ mod tests {
pool, pool,
data.community.id, data.community.id,
&CommunityUpdateForm { &CommunityUpdateForm {
hidden: Some(true), visibility: Some(CommunityVisibility::Unlisted),
..Default::default() ..Default::default()
}, },
) )
@ -2010,7 +2009,6 @@ mod tests {
description: None, description: None,
updated: None, updated: None,
banner: None, banner: None,
hidden: false,
posting_restricted_to_mods: false, posting_restricted_to_mods: false,
published: inserted_community.published, published: inserted_community.published,
instance_id: data.instance.id, instance_id: data.instance.id,
@ -2056,7 +2054,7 @@ mod tests {
pool, pool,
data.community.id, data.community.id,
&CommunityUpdateForm { &CommunityUpdateForm {
visibility: Some(CommunityVisibility::LocalOnly), visibility: Some(CommunityVisibility::LocalOnlyPrivate),
..Default::default() ..Default::default()
}, },
) )

View file

@ -53,8 +53,8 @@ use lemmy_db_schema::{
ModAddCommunity, ModAddCommunity,
ModBan, ModBan,
ModBanFromCommunity, ModBanFromCommunity,
ModChangeCommunityVisibility,
ModFeaturePost, ModFeaturePost,
ModHideCommunity,
ModLockPost, ModLockPost,
ModRemoveComment, ModRemoveComment,
ModRemoveCommunity, ModRemoveCommunity,
@ -867,11 +867,11 @@ pub struct ModBanView {
#[cfg_attr(feature = "full", derive(TS, Queryable))] #[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))] #[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// When a community is hidden from public view. /// When the visibility of a community is changed
pub struct ModHideCommunityView { pub struct ModChangeCommunityVisibilityView {
pub mod_hide_community: ModHideCommunity, pub mod_change_community_visibility: ModChangeCommunityVisibility,
#[cfg_attr(feature = "full", ts(optional))] #[cfg_attr(feature = "full", ts(optional))]
pub admin: Option<Person>, pub moderator: Option<Person>,
pub community: Community, pub community: Community,
} }
@ -1068,7 +1068,7 @@ pub(crate) struct ModlogCombinedViewInternal {
#[cfg_attr(feature = "full", diesel(embed))] #[cfg_attr(feature = "full", diesel(embed))]
pub mod_feature_post: Option<ModFeaturePost>, pub mod_feature_post: Option<ModFeaturePost>,
#[cfg_attr(feature = "full", diesel(embed))] #[cfg_attr(feature = "full", diesel(embed))]
pub mod_hide_community: Option<ModHideCommunity>, pub mod_change_community_visibility: Option<ModChangeCommunityVisibility>,
#[cfg_attr(feature = "full", diesel(embed))] #[cfg_attr(feature = "full", diesel(embed))]
pub mod_lock_post: Option<ModLockPost>, pub mod_lock_post: Option<ModLockPost>,
#[cfg_attr(feature = "full", diesel(embed))] #[cfg_attr(feature = "full", diesel(embed))]
@ -1118,7 +1118,7 @@ pub enum ModlogCombinedView {
ModBan(ModBanView), ModBan(ModBanView),
ModBanFromCommunity(ModBanFromCommunityView), ModBanFromCommunity(ModBanFromCommunityView),
ModFeaturePost(ModFeaturePostView), ModFeaturePost(ModFeaturePostView),
ModHideCommunity(ModHideCommunityView), ModChangeCommunityVisibility(ModChangeCommunityVisibilityView),
ModLockPost(ModLockPostView), ModLockPost(ModLockPostView),
ModRemoveComment(ModRemoveCommentView), ModRemoveComment(ModRemoveCommentView),
ModRemoveCommunity(ModRemoveCommunityView), ModRemoveCommunity(ModRemoveCommunityView),

View file

@ -1,5 +1,13 @@
use diesel::{BoolExpressionMethods, ExpressionMethods}; use diesel::{
use lemmy_db_schema::schema::{community_actions, instance_actions, person_actions}; helper_types::{Eq, NotEq, Or},
BoolExpressionMethods,
ExpressionMethods,
};
use lemmy_db_schema::{
schema::{community, community_actions, instance_actions, person_actions},
source::community::CommunityFollowerState,
CommunityVisibility,
};
/// Hide all content from blocked communities and persons. Content from blocked instances is also /// Hide all content from blocked communities and persons. Content from blocked instances is also
/// hidden, unless the user followed the community explicitly. /// hidden, unless the user followed the community explicitly.
@ -11,3 +19,17 @@ pub(crate) fn filter_blocked() -> _ {
.and(community_actions::blocked.is_null()) .and(community_actions::blocked.is_null())
.and(person_actions::blocked.is_null()) .and(person_actions::blocked.is_null())
} }
type IsSubscribedType =
Eq<lemmy_db_schema::schema::community_actions::follow_state, Option<CommunityFollowerState>>;
pub(crate) fn filter_is_subscribed() -> IsSubscribedType {
community_actions::follow_state.eq(Some(CommunityFollowerState::Accepted))
}
type IsNotHiddenType = NotEq<lemmy_db_schema::schema::community::visibility, CommunityVisibility>;
pub(crate) fn filter_not_hidden_or_is_subscribed() -> Or<IsNotHiddenType, IsSubscribedType> {
let not_hidden = community::visibility.ne(CommunityVisibility::Unlisted);
not_hidden.or(filter_is_subscribed())
}

View file

@ -8,7 +8,6 @@ use lemmy_api_common::{
use lemmy_db_schema::{ use lemmy_db_schema::{
source::{community::Community, person::Person}, source::{community::Community, person::Person},
traits::ApubActor, traits::ApubActor,
CommunityVisibility,
ListingType, ListingType,
PostSortType, PostSortType,
}; };
@ -274,7 +273,7 @@ async fn get_feed_community(
let community = Community::read_from_name(&mut context.pool(), community_name, false) let community = Community::read_from_name(&mut context.pool(), community_name, false)
.await? .await?
.ok_or(LemmyErrorType::NotFound)?; .ok_or(LemmyErrorType::NotFound)?;
if community.visibility != CommunityVisibility::Public { if !community.visibility.can_view_without_login() {
return Err(LemmyErrorType::NotFound.into()); return Err(LemmyErrorType::NotFound.into());
} }

View file

@ -7,7 +7,6 @@ use lemmy_api_common::{context::LemmyContext, LemmyErrorType};
use lemmy_db_schema::{ use lemmy_db_schema::{
source::{community::Community, person::Person}, source::{community::Community, person::Person},
traits::ApubActor, traits::ApubActor,
CommunityVisibility,
}; };
use lemmy_utils::{ use lemmy_utils::{
cache_header::cache_3days, cache_header::cache_3days,
@ -57,7 +56,7 @@ async fn get_webfinger_response(
.ok() .ok()
.flatten() .flatten()
.and_then(|c| { .and_then(|c| {
if c.visibility == CommunityVisibility::Public { if c.visibility.can_federate() {
let id: Url = c.ap_id.into(); let id: Url = c.ap_id.into();
Some(id) Some(id)
} else { } else {

View file

@ -98,7 +98,6 @@ pub enum LemmyErrorType {
CommunityUserAlreadyBanned, CommunityUserAlreadyBanned,
CommunityBlockAlreadyExists, CommunityBlockAlreadyExists,
CommunityFollowerAlreadyExists, CommunityFollowerAlreadyExists,
CouldntUpdateCommunityHiddenStatus,
PersonBlockAlreadyExists, PersonBlockAlreadyExists,
UserAlreadyExists, UserAlreadyExists,
CouldntLikePost, CouldntLikePost,

View file

@ -0,0 +1,240 @@
-- recreate columns in the original order
ALTER TABLE community
ADD COLUMN hidden bool DEFAULT FALSE NOT NULL,
ADD COLUMN posting_restricted_to_mods_new bool NOT NULL DEFAULT FALSE,
ADD COLUMN instance_id_new int NOT NULL,
ADD COLUMN moderators_url_new varchar(255),
ADD COLUMN featured_url_new varchar(255),
ADD COLUMN visibility_new community_visibility NOT NULL DEFAULT 'Public',
ADD COLUMN description_new varchar(150),
ADD COLUMN random_number_new smallint NOT NULL DEFAULT random_smallint (),
ADD COLUMN subscribers_new bigint NOT NULL DEFAULT 0,
ADD COLUMN posts_new bigint NOT NULL DEFAULT 0,
ADD COLUMN comments_new bigint NOT NULL DEFAULT 0,
ADD COLUMN users_active_day_new bigint NOT NULL DEFAULT 0,
ADD COLUMN users_active_week_new bigint NOT NULL DEFAULT 0,
ADD COLUMN users_active_month_new bigint NOT NULL DEFAULT 0,
ADD COLUMN users_active_half_year_new bigint NOT NULL DEFAULT 0,
ADD COLUMN hot_rank_new double precision NOT NULL DEFAULT 0.0001,
ADD COLUMN subscribers_local_new bigint NOT NULL DEFAULT 0,
ADD COLUMN report_count_new smallint NOT NULL DEFAULT 0,
ADD COLUMN unresolved_report_count_new smallint NOT NULL DEFAULT 0,
ADD COLUMN interactions_month_new bigint NOT NULL DEFAULT 0;
UPDATE
community
SET
(posting_restricted_to_mods_new,
instance_id_new,
moderators_url_new,
featured_url_new,
visibility_new,
description_new,
random_number_new,
subscribers_new,
posts_new,
comments_new,
users_active_day_new,
users_active_week_new,
users_active_month_new,
users_active_half_year_new,
hot_rank_new,
subscribers_local_new,
report_count_new,
unresolved_report_count_new,
interactions_month_new) = (posting_restricted_to_mods,
instance_id,
moderators_url,
featured_url,
visibility,
description,
random_number,
subscribers,
posts,
comments,
users_active_day,
users_active_week,
users_active_month,
users_active_half_year,
hot_rank,
subscribers_local,
report_count,
unresolved_report_count,
interactions_month);
ALTER TABLE community
DROP COLUMN posting_restricted_to_mods,
DROP COLUMN instance_id,
DROP COLUMN moderators_url,
DROP COLUMN featured_url,
DROP COLUMN visibility,
DROP COLUMN description,
DROP COLUMN random_number,
DROP COLUMN subscribers,
DROP COLUMN posts,
DROP COLUMN comments,
DROP COLUMN users_active_day,
DROP COLUMN users_active_week,
DROP COLUMN users_active_month,
DROP COLUMN users_active_half_year,
DROP COLUMN hot_rank,
DROP COLUMN subscribers_local,
DROP COLUMN report_count,
DROP COLUMN unresolved_report_count,
DROP COLUMN interactions_month;
ALTER TABLE community RENAME COLUMN posting_restricted_to_mods_new TO posting_restricted_to_mods;
ALTER TABLE community RENAME COLUMN instance_id_new TO instance_id;
ALTER TABLE community RENAME COLUMN moderators_url_new TO moderators_url;
ALTER TABLE community RENAME COLUMN featured_url_new TO featured_url;
ALTER TABLE community RENAME COLUMN visibility_new TO visibility;
ALTER TABLE community RENAME COLUMN description_new TO description;
ALTER TABLE community RENAME COLUMN random_number_new TO random_number;
ALTER TABLE community RENAME COLUMN subscribers_new TO subscribers;
ALTER TABLE community RENAME COLUMN posts_new TO posts;
ALTER TABLE community RENAME COLUMN comments_new TO comments;
ALTER TABLE community RENAME COLUMN users_active_day_new TO users_active_day;
ALTER TABLE community RENAME COLUMN users_active_week_new TO users_active_week;
ALTER TABLE community RENAME COLUMN users_active_month_new TO users_active_month;
ALTER TABLE community RENAME COLUMN users_active_half_year_new TO users_active_half_year;
ALTER TABLE community RENAME COLUMN hot_rank_new TO hot_rank;
ALTER TABLE community RENAME COLUMN subscribers_local_new TO subscribers_local;
ALTER TABLE community RENAME COLUMN report_count_new TO report_count;
ALTER TABLE community RENAME COLUMN unresolved_report_count_new TO unresolved_report_count;
ALTER TABLE community RENAME COLUMN interactions_month_new TO interactions_month;
ALTER TABLE community
ADD CONSTRAINT community_featured_url_key UNIQUE (featured_url),
ADD CONSTRAINT community_moderators_url_key UNIQUE (moderators_url),
ADD CONSTRAINT community_instance_id_fkey FOREIGN KEY (instance_id) REFERENCES instance (id) ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
-- same changes as up.sql, but the other way round
UPDATE
community
SET
(hidden,
visibility) = (TRUE,
'Public')
WHERE
visibility = 'Unlisted';
ALTER TYPE community_visibility RENAME VALUE 'LocalOnlyPrivate' TO 'LocalOnly';
ALTER TYPE community_visibility RENAME TO community_visibility__;
CREATE TYPE community_visibility AS enum (
'Public',
'LocalOnly',
'Private'
);
ALTER TABLE community
ALTER COLUMN visibility DROP DEFAULT;
ALTER TABLE community
ALTER COLUMN visibility TYPE community_visibility
USING visibility::text::community_visibility;
ALTER TABLE community
ALTER COLUMN visibility SET DEFAULT 'Public';
CREATE INDEX idx_community_random_number ON community (random_number) INCLUDE (local, nsfw)
WHERE
NOT (deleted OR removed OR visibility = 'Private');
CREATE INDEX idx_community_nonzero_hotrank ON community USING btree (published)
WHERE (hot_rank <> (0)::double precision);
CREATE INDEX idx_community_subscribers ON community USING btree (subscribers DESC);
CREATE INDEX idx_community_users_active_month ON community USING btree (users_active_month DESC);
CREATE INDEX idx_community_hot ON public.community USING btree (hot_rank DESC);
REINDEX TABLE community;
-- revert modlog table changes
CREATE TABLE mod_hide_community (
id serial PRIMARY KEY,
community_id int REFERENCES community ON UPDATE CASCADE ON DELETE CASCADE NOT NULL,
mod_person_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE NOT NULL,
published timestamptz NOT NULL DEFAULT now(),
reason text,
hidden boolean DEFAULT FALSE NOT NULL
);
ALTER TABLE modlog_combined
DROP COLUMN mod_change_community_visibility_id,
ADD COLUMN mod_hide_community_id int REFERENCES mod_hide_community ON UPDATE CASCADE ON DELETE CASCADE,
ADD COLUMN mod_lock_post_id_new int,
ADD COLUMN mod_remove_comment_id_new int,
ADD COLUMN mod_remove_community_id_new int,
ADD COLUMN mod_remove_post_id_new int,
ADD COLUMN mod_transfer_community_id_new int;
UPDATE
modlog_combined
SET
(mod_lock_post_id_new,
mod_remove_comment_id_new,
mod_remove_community_id_new,
mod_remove_post_id_new,
mod_transfer_community_id_new) = (mod_lock_post_id,
mod_remove_comment_id,
mod_remove_community_id,
mod_remove_post_id,
mod_transfer_community_id);
ALTER TABLE modlog_combined
DROP COLUMN mod_lock_post_id,
DROP COLUMN mod_remove_comment_id,
DROP COLUMN mod_remove_community_id,
DROP COLUMN mod_remove_post_id,
DROP COLUMN mod_transfer_community_id;
ALTER TABLE modlog_combined RENAME COLUMN mod_lock_post_id_new TO mod_lock_post_id;
ALTER TABLE modlog_combined RENAME COLUMN mod_remove_comment_id_new TO mod_remove_comment_id;
ALTER TABLE modlog_combined RENAME COLUMN mod_remove_community_id_new TO mod_remove_community_id;
ALTER TABLE modlog_combined RENAME COLUMN mod_remove_post_id_new TO mod_remove_post_id;
ALTER TABLE modlog_combined RENAME COLUMN mod_transfer_community_id_new TO mod_transfer_community_id;
ALTER TABLE modlog_combined
ADD CONSTRAINT modlog_combined_mod_hide_community_id_key UNIQUE (mod_hide_community_id),
ADD CONSTRAINT modlog_combined_mod_lock_post_id_key UNIQUE (mod_lock_post_id),
ADD CONSTRAINT modlog_combined_mod_remove_comment_id_key UNIQUE (mod_remove_comment_id),
ADD CONSTRAINT modlog_combined_mod_remove_community_id_key UNIQUE (mod_remove_community_id),
ADD CONSTRAINT modlog_combined_mod_remove_post_id_key UNIQUE (mod_remove_post_id),
ADD CONSTRAINT modlog_combined_mod_transfer_community_id_key UNIQUE (mod_transfer_community_id),
ADD CONSTRAINT modlog_combined_mod_lock_post_id_fkey FOREIGN KEY (mod_lock_post_id) REFERENCES mod_lock_post (id) ON UPDATE CASCADE ON DELETE CASCADE,
ADD CONSTRAINT modlog_combined_mod_remove_comment_id_fkey FOREIGN KEY (mod_remove_comment_id) REFERENCES mod_remove_comment (id) ON UPDATE CASCADE ON DELETE CASCADE,
ADD CONSTRAINT modlog_combined_mod_remove_community_id_fkey FOREIGN KEY (mod_remove_community_id) REFERENCES mod_remove_community (id) ON UPDATE CASCADE ON DELETE CASCADE,
ADD CONSTRAINT modlog_combined_mod_remove_post_id_fkey FOREIGN KEY (mod_remove_post_id) REFERENCES mod_remove_post (id) ON UPDATE CASCADE ON DELETE CASCADE,
ADD CONSTRAINT modlog_combined_mod_transfer_community_id_fkey FOREIGN KEY (mod_transfer_community_id) REFERENCES mod_transfer_community (id) ON UPDATE CASCADE ON DELETE CASCADE,
ADD CONSTRAINT modlog_combined_check CHECK ((num_nonnulls (admin_allow_instance_id, admin_block_instance_id, admin_purge_comment_id, admin_purge_community_id, admin_purge_person_id, admin_purge_post_id, mod_add_id, mod_add_community_id, mod_ban_id, mod_ban_from_community_id, mod_feature_post_id, mod_hide_community_id, mod_lock_post_id, mod_remove_comment_id, mod_remove_community_id, mod_remove_post_id, mod_transfer_community_id) = 1));
DROP TABLE mod_change_community_visibility;
DROP TYPE community_visibility__;

View file

@ -0,0 +1,67 @@
-- Change community.visibility to allow values:
-- ('Public', 'LocalOnlyPublic', 'LocalOnlyPrivate','Private', 'Hidden')
-- rename old enum and add new one
ALTER TYPE community_visibility RENAME TO community_visibility__;
CREATE TYPE community_visibility AS enum (
'Public',
'LocalOnlyPublic',
'LocalOnly',
'Private',
'Unlisted'
);
-- drop default value and index which reference old enum
ALTER TABLE community
ALTER COLUMN visibility DROP DEFAULT;
DROP INDEX idx_community_random_number;
-- change the column type
ALTER TABLE community
ALTER COLUMN visibility TYPE community_visibility
USING visibility::text::community_visibility;
-- add default and index back in
ALTER TABLE community
ALTER COLUMN visibility SET DEFAULT 'Public';
CREATE INDEX idx_community_random_number ON community (random_number) INCLUDE (local, nsfw)
WHERE
NOT (deleted OR removed OR visibility = 'Private' OR visibility = 'Unlisted');
DROP TYPE community_visibility__ CASCADE;
ALTER TYPE community_visibility RENAME VALUE 'LocalOnly' TO 'LocalOnlyPrivate';
-- write hidden value to visibility column
UPDATE
community
SET
visibility = 'Unlisted'
WHERE
hidden;
-- drop the old hidden column
ALTER TABLE community
DROP COLUMN hidden;
-- change modlog tables
ALTER TABLE modlog_combined
DROP COLUMN mod_hide_community_id;
DROP TABLE mod_hide_community;
CREATE TABLE mod_change_community_visibility (
id serial PRIMARY KEY,
community_id int REFERENCES community ON UPDATE CASCADE ON DELETE CASCADE NOT NULL,
mod_person_id int REFERENCES person ON UPDATE CASCADE ON DELETE CASCADE NOT NULL,
published timestamptz NOT NULL DEFAULT now(),
reason text,
visibility community_visibility NOT NULL
);
ALTER TABLE modlog_combined
ADD COLUMN mod_change_community_visibility_id int REFERENCES mod_change_community_visibility (id) ON UPDATE CASCADE ON DELETE CASCADE,
ADD CONSTRAINT modlog_combined_check CHECK ((num_nonnulls (admin_allow_instance_id, admin_block_instance_id, admin_purge_comment_id, admin_purge_community_id, admin_purge_person_id, admin_purge_post_id, mod_add_id, mod_add_community_id, mod_ban_id, mod_ban_from_community_id, mod_feature_post_id, mod_change_community_visibility_id, mod_lock_post_id, mod_remove_comment_id, mod_remove_community_id, mod_remove_post_id, mod_transfer_community_id) = 1));

View file

@ -11,7 +11,6 @@ use lemmy_api::{
ban::ban_from_community, ban::ban_from_community,
block::user_block_community, block::user_block_community,
follow::follow_community, follow::follow_community,
hide::hide_community,
transfer::transfer_community, transfer::transfer_community,
}, },
local_user::{ local_user::{
@ -184,7 +183,6 @@ pub fn config(cfg: &mut ServiceConfig, rate_limit: &RateLimitCell) {
.wrap(rate_limit.message()) .wrap(rate_limit.message())
.route("", get().to(get_community)) .route("", get().to(get_community))
.route("", put().to(update_community)) .route("", put().to(update_community))
.route("/hide", put().to(hide_community))
.route("/list", get().to(list_communities)) .route("/list", get().to(list_communities))
.route("/follow", post().to(follow_community)) .route("/follow", post().to(follow_community))
.route("/block", post().to(user_block_community)) .route("/block", post().to(user_block_community))

View file

@ -11,7 +11,6 @@ use lemmy_api::{
ban::ban_from_community, ban::ban_from_community,
block::user_block_community, block::user_block_community,
follow::follow_community, follow::follow_community,
hide::hide_community,
pending_follows::{ pending_follows::{
approve::post_pending_follows_approve, approve::post_pending_follows_approve,
count::get_pending_follows_count, count::get_pending_follows_count,
@ -215,7 +214,6 @@ pub fn config(cfg: &mut ServiceConfig, rate_limit: &RateLimitCell) {
.route("", get().to(get_community)) .route("", get().to(get_community))
.route("", put().to(update_community)) .route("", put().to(update_community))
.route("/random", get().to(get_random_community)) .route("/random", get().to(get_random_community))
.route("/hide", put().to(hide_community))
.route("/list", get().to(list_communities)) .route("/list", get().to(list_communities))
.route("/follow", post().to(follow_community)) .route("/follow", post().to(follow_community))
.route("/report", post().to(create_community_report)) .route("/report", post().to(create_community_report))