diff --git a/Cargo.lock b/Cargo.lock index c7d3d1766..82f84439e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3407,6 +3407,7 @@ dependencies = [ name = "lemmy_db_views_comment" version = "1.0.0-alpha.7" dependencies = [ + "chrono", "diesel", "diesel-async", "diesel_ltree", @@ -3523,6 +3524,7 @@ name = "lemmy_db_views_local_user" version = "1.0.0-alpha.7" dependencies = [ "actix-web", + "chrono", "diesel", "diesel-async", "i-love-jesus", @@ -3559,6 +3561,7 @@ dependencies = [ name = "lemmy_db_views_notification" version = "1.0.0-alpha.7" dependencies = [ + "chrono", "diesel", "diesel-async", "i-love-jesus", @@ -3577,6 +3580,7 @@ dependencies = [ name = "lemmy_db_views_person" version = "1.0.0-alpha.7" dependencies = [ + "chrono", "diesel", "diesel-async", "i-love-jesus", @@ -3596,6 +3600,7 @@ dependencies = [ name = "lemmy_db_views_person_content_combined" version = "1.0.0-alpha.7" dependencies = [ + "chrono", "derive-new", "diesel", "diesel-async", @@ -3618,6 +3623,7 @@ dependencies = [ name = "lemmy_db_views_person_liked_combined" version = "1.0.0-alpha.7" dependencies = [ + "chrono", "diesel", "diesel-async", "i-love-jesus", @@ -3639,6 +3645,7 @@ dependencies = [ name = "lemmy_db_views_person_saved_combined" version = "1.0.0-alpha.7" dependencies = [ + "chrono", "diesel", "diesel-async", "i-love-jesus", @@ -3749,6 +3756,7 @@ dependencies = [ name = "lemmy_db_views_search_combined" version = "1.0.0-alpha.7" dependencies = [ + "chrono", "diesel", "diesel-async", "i-love-jesus", diff --git a/crates/api/api_crud/src/user/create.rs b/crates/api/api_crud/src/user/create.rs index 5a1015417..01eda6428 100644 --- a/crates/api/api_crud/src/user/create.rs +++ b/crates/api/api_crud/src/user/create.rs @@ -167,6 +167,7 @@ pub async fn register( person, local_user, banned: false, + ban_expires_at: None, }) } .scope_boxed() @@ -410,6 +411,7 @@ pub async fn authenticate_with_oauth( person, local_user, banned: false, + ban_expires_at: None, }) } .scope_boxed() diff --git a/crates/db_schema/src/utils.rs b/crates/db_schema/src/utils.rs index 751fd673d..2b879fd00 100644 --- a/crates/db_schema/src/utils.rs +++ b/crates/db_schema/src/utils.rs @@ -510,6 +510,8 @@ pub mod functions { } define_sql_function!(#[sql_name = "coalesce"] fn coalesce_2_nullable(x: diesel::sql_types::Nullable, y: diesel::sql_types::Nullable) -> diesel::sql_types::Nullable); + + define_sql_function!(#[sql_name = "coalesce"] fn coalesce_3_nullable(x: diesel::sql_types::Nullable, y: diesel::sql_types::Nullable, z: diesel::sql_types::Nullable) -> diesel::sql_types::Nullable); } pub const DELETED_REPLACEMENT_TEXT: &str = "*Permanently Deleted*"; diff --git a/crates/db_schema/src/utils/queries.rs b/crates/db_schema/src/utils/queries.rs deleted file mode 100644 index 89f041f46..000000000 --- a/crates/db_schema/src/utils/queries.rs +++ /dev/null @@ -1,460 +0,0 @@ -use crate::{ - aliases::{ - creator_community_actions, - creator_community_instance_actions, - creator_home_instance_actions, - creator_local_instance_actions, - creator_local_user, - my_instance_persons_actions, - person1, - person2, - }, - newtypes::{InstanceId, PersonId}, - MyInstancePersonsActionsAllColumnsTuple, - Person1AliasAllColumnsTuple, - Person2AliasAllColumnsTuple, -}; -use diesel::{ - dsl::{case_when, exists, not}, - expression::SqlLiteral, - helper_types::{Eq, NotEq, Nullable}, - sql_types::Json, - BoolExpressionMethods, - ExpressionMethods, - JoinOnDsl, - NullableExpressionMethods, - PgExpressionMethods, - QueryDsl, -}; -use lemmy_db_schema_file::{ - enums::{CommunityFollowerState, CommunityVisibility}, - schema::{ - comment, - comment_actions, - community, - community_actions, - image_details, - instance_actions, - local_site, - local_user, - multi_community, - multi_community_entry, - person, - person_actions, - post, - post_actions, - post_tag, - tag, - }, -}; - -/// Hide all content from blocked communities and persons. Content from blocked instances is also -/// hidden, unless the user followed the community explicitly. -#[diesel::dsl::auto_type] -pub fn filter_blocked() -> _ { - instance_actions::blocked_communities_at - .is_null() - .or(community_actions::followed_at.is_not_null()) - .and(community_actions::blocked_at.is_null()) - .and(person_actions::blocked_at.is_null()) - .and( - my_instance_persons_actions - .field(instance_actions::blocked_persons_at) - .is_null(), - ) -} - -/// Checks that the creator_local_user is an admin. -#[diesel::dsl::auto_type] -pub fn creator_is_admin() -> _ { - creator_local_user - .field(local_user::admin) - .nullable() - .is_not_distinct_from(true) -} - -/// Checks that the local_user is an admin. -#[diesel::dsl::auto_type] -pub fn local_user_is_admin() -> _ { - local_user::admin.nullable().is_not_distinct_from(true) -} - -/// Checks to see if the comment creator is an admin. -#[diesel::dsl::auto_type] -pub fn comment_creator_is_admin() -> _ { - exists( - creator_local_user.filter( - comment::creator_id - .eq(creator_local_user.field(local_user::person_id)) - .and(creator_local_user.field(local_user::admin).eq(true)), - ), - ) -} - -#[diesel::dsl::auto_type] -pub fn post_creator_is_admin() -> _ { - exists( - creator_local_user.filter( - post::creator_id - .eq(creator_local_user.field(local_user::person_id)) - .and(creator_local_user.field(local_user::admin).eq(true)), - ), - ) -} - -#[diesel::dsl::auto_type] -pub fn creator_is_moderator() -> _ { - creator_community_actions - .field(community_actions::became_moderator_at) - .nullable() - .is_not_null() -} - -#[diesel::dsl::auto_type] -pub fn creator_banned_from_community() -> _ { - creator_community_actions - .field(community_actions::received_ban_at) - .nullable() - .is_not_null() -} - -#[diesel::dsl::auto_type] -pub fn creator_home_banned() -> _ { - creator_home_instance_actions - .field(instance_actions::received_ban_at) - .nullable() - .is_not_null() -} - -#[diesel::dsl::auto_type] -/// Checks to see if a user is site banned from any of these places: -/// - Their own instance -/// - The local instance -pub fn creator_banned() -> _ { - let local_ban = creator_local_instance_actions - .field(instance_actions::received_ban_at) - .nullable() - .is_not_null(); - local_ban.or(creator_home_banned()) -} - -/// Similar to creator_banned(), but also checks if creator was banned from instance where the -/// community is hosted. -#[diesel::dsl::auto_type] -pub fn creator_banned_within_community() -> _ { - let community_ban = creator_community_instance_actions - .field(instance_actions::received_ban_at) - .nullable() - .is_not_null(); - creator_banned().or(community_ban) -} - -#[diesel::dsl::auto_type] -pub fn creator_local_user_admin_join() -> _ { - creator_local_user.on( - person::id - .eq(creator_local_user.field(local_user::person_id)) - .and(creator_local_user.field(local_user::admin).eq(true)), - ) -} - -#[diesel::dsl::auto_type] -fn am_higher_mod() -> _ { - let i_became_moderator = community_actions::became_moderator_at.nullable(); - - let creator_became_moderator = creator_community_actions - .field(community_actions::became_moderator_at) - .nullable(); - - i_became_moderator.is_not_null().and( - creator_became_moderator - .ge(i_became_moderator) - .is_distinct_from(false), - ) -} - -/// Checks to see if you can mod an item. -/// -/// Caveat: Since admin status isn't federated or ordered, it can't know whether -/// item creator is a federated admin, or a higher admin. -/// The back-end will reject an action for admin that is higher via -/// LocalUser::is_higher_mod_or_admin_check -#[diesel::dsl::auto_type] -pub fn local_user_can_mod() -> _ { - local_user_is_admin().or(not(creator_is_admin()).and(am_higher_mod())) -} - -/// Checks to see if you can mod a post. -#[diesel::dsl::auto_type] -pub fn local_user_can_mod_post() -> _ { - local_user_is_admin().or(not(post_creator_is_admin()).and(am_higher_mod())) -} - -/// Checks to see if you can mod a comment. -#[diesel::dsl::auto_type] -pub fn local_user_can_mod_comment() -> _ { - local_user_is_admin().or(not(comment_creator_is_admin()).and(am_higher_mod())) -} - -/// A special type of can_mod for communities, which dont have creators. -#[diesel::dsl::auto_type] -pub fn local_user_community_can_mod() -> _ { - let am_admin = local_user::admin.nullable(); - let am_moderator = community_actions::became_moderator_at - .nullable() - .is_not_null(); - am_admin.or(am_moderator).is_not_distinct_from(true) -} - -/// Selects the comment columns, but gives an empty string for content when -/// deleted or removed, and you're not a mod/admin. -#[diesel::dsl::auto_type] -pub fn comment_select_remove_deletes() -> _ { - let deleted_or_removed = comment::deleted.or(comment::removed); - - // You can only view the content if it hasn't been removed, or you can mod. - let can_view_content = not(deleted_or_removed).or(local_user_can_mod_comment()); - let content = case_when(can_view_content, comment::content).otherwise(""); - - ( - comment::id, - comment::creator_id, - comment::post_id, - content, - comment::removed, - comment::published_at, - comment::updated_at, - comment::deleted, - comment::ap_id, - comment::local, - comment::path, - comment::distinguished, - comment::language_id, - comment::score, - comment::upvotes, - comment::downvotes, - comment::child_count, - comment::hot_rank, - comment::controversy_rank, - comment::report_count, - comment::unresolved_report_count, - comment::federation_pending, - ) -} - -#[diesel::dsl::auto_type] -// Gets the post tags set on a specific post -pub fn post_tags_fragment() -> _ { - let sel: SqlLiteral = diesel::dsl::sql::("json_agg(tag.*)"); - post_tag::table - .inner_join(tag::table) - .select(sel) - .filter(post_tag::post_id.eq(post::id)) - .filter(tag::deleted.eq(false)) - .single_value() -} - -#[diesel::dsl::auto_type] -/// Gets the post tags available within a specific community -pub fn community_post_tags_fragment() -> _ { - let sel: SqlLiteral = diesel::dsl::sql::("json_agg(tag.*)"); - tag::table - .select(sel) - .filter(tag::community_id.eq(community::id)) - .filter(tag::deleted.eq(false)) - .single_value() -} - -/// The select for the person1 alias. -pub fn person1_select() -> Person1AliasAllColumnsTuple { - person1.fields(person::all_columns) -} - -/// The select for the person2 alias. -pub fn person2_select() -> Person2AliasAllColumnsTuple { - person2.fields(person::all_columns) -} - -type IsSubscribedType = - Eq>; - -pub fn filter_is_subscribed() -> IsSubscribedType { - community_actions::follow_state.eq(Some(CommunityFollowerState::Accepted)) -} - -type IsNotUnlistedType = - NotEq; - -#[diesel::dsl::auto_type] -pub fn filter_not_unlisted_or_is_subscribed() -> _ { - let not_unlisted: IsNotUnlistedType = community::visibility.ne(CommunityVisibility::Unlisted); - let is_subscribed: IsSubscribedType = filter_is_subscribed(); - not_unlisted.or(is_subscribed) -} - -#[diesel::dsl::auto_type] -pub fn community_join() -> _ { - community::table.on(post::community_id.eq(community::id)) -} - -#[diesel::dsl::auto_type] -pub fn creator_home_instance_actions_join() -> _ { - creator_home_instance_actions.on( - creator_home_instance_actions - .field(instance_actions::instance_id) - .eq(person::instance_id) - .and( - creator_home_instance_actions - .field(instance_actions::person_id) - .eq(person::id), - ), - ) -} -#[diesel::dsl::auto_type] -pub fn creator_community_instance_actions_join() -> _ { - creator_community_instance_actions.on( - creator_home_instance_actions - .field(instance_actions::instance_id) - .eq(community::instance_id) - .and( - creator_community_instance_actions - .field(instance_actions::person_id) - .eq(person::id), - ), - ) -} - -/// join with instance actions for local instance -/// -/// Requires annotation for return type, see https://docs.diesel.rs/2.2.x/diesel/dsl/attr.auto_type.html#annotating-types -#[diesel::dsl::auto_type] -pub fn creator_local_instance_actions_join(local_instance_id: InstanceId) -> _ { - creator_local_instance_actions.on( - creator_local_instance_actions - .field(instance_actions::instance_id) - .eq(local_instance_id) - .and( - creator_local_instance_actions - .field(instance_actions::person_id) - .eq(person::id), - ), - ) -} - -/// Your instance actions for the community's instance. -#[diesel::dsl::auto_type] -pub fn my_instance_communities_actions_join(my_person_id: Option) -> _ { - instance_actions::table.on( - instance_actions::instance_id - .eq(community::instance_id) - .and(instance_actions::person_id.nullable().eq(my_person_id)), - ) -} - -/// Your instance actions for the person's instance. -#[diesel::dsl::auto_type] -pub fn my_instance_persons_actions_join(my_person_id: Option) -> _ { - instance_actions::table.on( - instance_actions::instance_id - .eq(person::instance_id) - .and(instance_actions::person_id.nullable().eq(my_person_id)), - ) -} - -/// The select for the my_instance_persons_actions alias -pub fn my_instance_persons_actions_select() -> Nullable { - my_instance_persons_actions - .fields(instance_actions::all_columns) - .nullable() -} - -/// Your instance actions for the person's instance. -/// A dupe of the above function, but aliased -#[diesel::dsl::auto_type] -pub fn my_instance_persons_actions_join_1(my_person_id: Option) -> _ { - my_instance_persons_actions.on( - my_instance_persons_actions - .field(instance_actions::instance_id) - .eq(person::instance_id) - .and( - my_instance_persons_actions - .field(instance_actions::person_id) - .nullable() - .eq(my_person_id), - ), - ) -} -#[diesel::dsl::auto_type] -pub fn image_details_join() -> _ { - image_details::table.on(post::thumbnail_url.eq(image_details::link.nullable())) -} - -#[diesel::dsl::auto_type] -pub fn my_community_actions_join(my_person_id: Option) -> _ { - community_actions::table.on( - community_actions::community_id - .eq(community::id) - .and(community_actions::person_id.nullable().eq(my_person_id)), - ) -} - -#[diesel::dsl::auto_type] -pub fn my_post_actions_join(my_person_id: Option) -> _ { - post_actions::table.on( - post_actions::post_id - .eq(post::id) - .and(post_actions::person_id.nullable().eq(my_person_id)), - ) -} - -#[diesel::dsl::auto_type] -pub fn my_comment_actions_join(my_person_id: Option) -> _ { - comment_actions::table.on( - comment_actions::comment_id - .eq(comment::id) - .and(comment_actions::person_id.nullable().eq(my_person_id)), - ) -} - -#[diesel::dsl::auto_type] -pub fn my_person_actions_join(my_person_id: Option) -> _ { - person_actions::table.on( - person_actions::target_id - .eq(person::id) - .and(person_actions::person_id.nullable().eq(my_person_id)), - ) -} - -#[diesel::dsl::auto_type] -pub fn my_local_user_admin_join(my_person_id: Option) -> _ { - local_user::table.on( - local_user::person_id - .nullable() - .eq(my_person_id) - .and(local_user::admin.eq(true)), - ) -} - -#[diesel::dsl::auto_type] -pub fn creator_community_actions_join() -> _ { - creator_community_actions.on( - creator_community_actions - .field(community_actions::community_id) - .eq(community::id) - .and( - creator_community_actions - .field(community_actions::person_id) - .eq(person::id), - ), - ) -} - -#[diesel::dsl::auto_type] -pub fn suggested_communities() -> _ { - community::id.eq_any( - local_site::table - .left_join(multi_community::table.inner_join(multi_community_entry::table)) - .filter(multi_community_entry::community_id.is_not_null()) - .select(multi_community_entry::community_id.assume_not_null()), - ) -} diff --git a/crates/db_schema/src/utils/queries/filters.rs b/crates/db_schema/src/utils/queries/filters.rs new file mode 100644 index 000000000..d81afcc11 --- /dev/null +++ b/crates/db_schema/src/utils/queries/filters.rs @@ -0,0 +1,63 @@ +use crate::aliases::my_instance_persons_actions; +use diesel::{ + helper_types::{Eq, NotEq}, + BoolExpressionMethods, + ExpressionMethods, + NullableExpressionMethods, + QueryDsl, +}; +use lemmy_db_schema_file::{ + enums::{CommunityFollowerState, CommunityVisibility}, + schema::{ + community, + community_actions, + instance_actions, + local_site, + multi_community, + multi_community_entry, + person_actions, + }, +}; + +/// Hide all content from blocked communities and persons. Content from blocked instances is also +/// hidden, unless the user followed the community explicitly. +#[diesel::dsl::auto_type] +pub fn filter_blocked() -> _ { + instance_actions::blocked_communities_at + .is_null() + .or(community_actions::followed_at.is_not_null()) + .and(community_actions::blocked_at.is_null()) + .and(person_actions::blocked_at.is_null()) + .and( + my_instance_persons_actions + .field(instance_actions::blocked_persons_at) + .is_null(), + ) +} + +type IsSubscribedType = + Eq>; + +pub fn filter_is_subscribed() -> IsSubscribedType { + community_actions::follow_state.eq(Some(CommunityFollowerState::Accepted)) +} + +type IsNotUnlistedType = + NotEq; + +#[diesel::dsl::auto_type] +pub fn filter_not_unlisted_or_is_subscribed() -> _ { + let not_unlisted: IsNotUnlistedType = community::visibility.ne(CommunityVisibility::Unlisted); + let is_subscribed: IsSubscribedType = filter_is_subscribed(); + not_unlisted.or(is_subscribed) +} + +#[diesel::dsl::auto_type] +pub fn filter_suggested_communities() -> _ { + community::id.eq_any( + local_site::table + .left_join(multi_community::table.inner_join(multi_community_entry::table)) + .filter(multi_community_entry::community_id.is_not_null()) + .select(multi_community_entry::community_id.assume_not_null()), + ) +} diff --git a/crates/db_schema/src/utils/queries/joins.rs b/crates/db_schema/src/utils/queries/joins.rs new file mode 100644 index 000000000..1da707bc3 --- /dev/null +++ b/crates/db_schema/src/utils/queries/joins.rs @@ -0,0 +1,184 @@ +use crate::{ + aliases::{ + creator_community_actions, + creator_community_instance_actions, + creator_home_instance_actions, + creator_local_instance_actions, + creator_local_user, + my_instance_persons_actions, + }, + newtypes::{InstanceId, PersonId}, +}; +use diesel::{BoolExpressionMethods, ExpressionMethods, JoinOnDsl, NullableExpressionMethods}; +use lemmy_db_schema_file::schema::{ + comment, + comment_actions, + community, + community_actions, + image_details, + instance_actions, + local_user, + person, + person_actions, + post, + post_actions, +}; + +#[diesel::dsl::auto_type] +pub fn creator_local_user_admin_join() -> _ { + creator_local_user.on( + person::id + .eq(creator_local_user.field(local_user::person_id)) + .and(creator_local_user.field(local_user::admin).eq(true)), + ) +} + +#[diesel::dsl::auto_type] +pub fn community_join() -> _ { + community::table.on(post::community_id.eq(community::id)) +} +#[diesel::dsl::auto_type] +pub fn creator_home_instance_actions_join() -> _ { + creator_home_instance_actions.on( + creator_home_instance_actions + .field(instance_actions::instance_id) + .eq(person::instance_id) + .and( + creator_home_instance_actions + .field(instance_actions::person_id) + .eq(person::id), + ), + ) +} +#[diesel::dsl::auto_type] +pub fn creator_community_instance_actions_join() -> _ { + creator_community_instance_actions.on( + creator_home_instance_actions + .field(instance_actions::instance_id) + .eq(community::instance_id) + .and( + creator_community_instance_actions + .field(instance_actions::person_id) + .eq(person::id), + ), + ) +} + +/// join with instance actions for local instance +/// +/// Requires annotation for return type, see https://docs.diesel.rs/2.2.x/diesel/dsl/attr.auto_type.html#annotating-types +#[diesel::dsl::auto_type] +pub fn creator_local_instance_actions_join(local_instance_id: InstanceId) -> _ { + creator_local_instance_actions.on( + creator_local_instance_actions + .field(instance_actions::instance_id) + .eq(local_instance_id) + .and( + creator_local_instance_actions + .field(instance_actions::person_id) + .eq(person::id), + ), + ) +} + +/// Your instance actions for the community's instance. +#[diesel::dsl::auto_type] +pub fn my_instance_communities_actions_join(my_person_id: Option) -> _ { + instance_actions::table.on( + instance_actions::instance_id + .eq(community::instance_id) + .and(instance_actions::person_id.nullable().eq(my_person_id)), + ) +} + +/// Your instance actions for the person's instance. +#[diesel::dsl::auto_type] +pub fn my_instance_persons_actions_join(my_person_id: Option) -> _ { + instance_actions::table.on( + instance_actions::instance_id + .eq(person::instance_id) + .and(instance_actions::person_id.nullable().eq(my_person_id)), + ) +} + +/// Your instance actions for the person's instance. +/// A dupe of the above function, but aliased +#[diesel::dsl::auto_type] +pub fn my_instance_persons_actions_join_1(my_person_id: Option) -> _ { + my_instance_persons_actions.on( + my_instance_persons_actions + .field(instance_actions::instance_id) + .eq(person::instance_id) + .and( + my_instance_persons_actions + .field(instance_actions::person_id) + .nullable() + .eq(my_person_id), + ), + ) +} + +#[diesel::dsl::auto_type] +pub fn image_details_join() -> _ { + image_details::table.on(post::thumbnail_url.eq(image_details::link.nullable())) +} + +#[diesel::dsl::auto_type] +pub fn my_community_actions_join(my_person_id: Option) -> _ { + community_actions::table.on( + community_actions::community_id + .eq(community::id) + .and(community_actions::person_id.nullable().eq(my_person_id)), + ) +} + +#[diesel::dsl::auto_type] +pub fn my_post_actions_join(my_person_id: Option) -> _ { + post_actions::table.on( + post_actions::post_id + .eq(post::id) + .and(post_actions::person_id.nullable().eq(my_person_id)), + ) +} + +#[diesel::dsl::auto_type] +pub fn my_comment_actions_join(my_person_id: Option) -> _ { + comment_actions::table.on( + comment_actions::comment_id + .eq(comment::id) + .and(comment_actions::person_id.nullable().eq(my_person_id)), + ) +} + +#[diesel::dsl::auto_type] +pub fn my_person_actions_join(my_person_id: Option) -> _ { + person_actions::table.on( + person_actions::target_id + .eq(person::id) + .and(person_actions::person_id.nullable().eq(my_person_id)), + ) +} + +#[diesel::dsl::auto_type] +pub fn my_local_user_admin_join(my_person_id: Option) -> _ { + local_user::table.on( + local_user::person_id + .nullable() + .eq(my_person_id) + .and(local_user::admin.eq(true)), + ) +} + +#[diesel::dsl::auto_type] +pub fn creator_community_actions_join() -> _ { + creator_community_actions.on( + creator_community_actions + .field(community_actions::community_id) + .eq(community::id) + .and( + creator_community_actions + .field(community_actions::person_id) + .eq(person::id), + ), + ) +} diff --git a/crates/db_schema/src/utils/queries/mod.rs b/crates/db_schema/src/utils/queries/mod.rs new file mode 100644 index 000000000..076c5fe14 --- /dev/null +++ b/crates/db_schema/src/utils/queries/mod.rs @@ -0,0 +1,3 @@ +pub mod filters; +pub mod joins; +pub mod selects; diff --git a/crates/db_schema/src/utils/queries/selects.rs b/crates/db_schema/src/utils/queries/selects.rs new file mode 100644 index 000000000..6e8de364b --- /dev/null +++ b/crates/db_schema/src/utils/queries/selects.rs @@ -0,0 +1,320 @@ +use crate::{ + aliases::{ + creator_community_actions, + creator_community_instance_actions, + creator_home_instance_actions, + creator_local_instance_actions, + creator_local_user, + my_instance_persons_actions, + person1, + person2, + CreatorCommunityInstanceActions, + CreatorHomeInstanceActions, + CreatorLocalInstanceActions, + }, + utils::functions::{coalesce_2_nullable, coalesce_3_nullable}, + MyInstancePersonsActionsAllColumnsTuple, + Person1AliasAllColumnsTuple, + Person2AliasAllColumnsTuple, +}; +use diesel::{ + dsl::{case_when, exists, not}, + expression::SqlLiteral, + helper_types::Nullable, + query_source::AliasedField, + sql_types::{Json, Timestamptz}, + BoolExpressionMethods, + ExpressionMethods, + NullableExpressionMethods, + PgExpressionMethods, + QueryDsl, +}; +use lemmy_db_schema_file::schema::{ + comment, + community, + community_actions, + instance_actions, + local_user, + person, + post, + post_tag, + tag, +}; + +/// Checks that the creator_local_user is an admin. +#[diesel::dsl::auto_type] +pub fn creator_is_admin() -> _ { + creator_local_user + .field(local_user::admin) + .nullable() + .is_not_distinct_from(true) +} + +/// Checks that the local_user is an admin. +#[diesel::dsl::auto_type] +pub fn local_user_is_admin() -> _ { + local_user::admin.nullable().is_not_distinct_from(true) +} + +/// Checks to see if the comment creator is an admin. +#[diesel::dsl::auto_type] +pub fn comment_creator_is_admin() -> _ { + exists( + creator_local_user.filter( + comment::creator_id + .eq(creator_local_user.field(local_user::person_id)) + .and(creator_local_user.field(local_user::admin).eq(true)), + ), + ) +} + +#[diesel::dsl::auto_type] +pub fn post_creator_is_admin() -> _ { + exists( + creator_local_user.filter( + post::creator_id + .eq(creator_local_user.field(local_user::person_id)) + .and(creator_local_user.field(local_user::admin).eq(true)), + ), + ) +} + +#[diesel::dsl::auto_type] +pub fn creator_is_moderator() -> _ { + creator_community_actions + .field(community_actions::became_moderator_at) + .nullable() + .is_not_null() +} + +#[diesel::dsl::auto_type] +pub fn creator_banned_from_community() -> _ { + creator_community_actions + .field(community_actions::received_ban_at) + .nullable() + .is_not_null() +} + +#[diesel::dsl::auto_type] +pub fn creator_ban_expires_from_community() -> _ { + creator_community_actions + .field(community_actions::ban_expires_at) + .nullable() +} + +#[diesel::dsl::auto_type] +/// Checks to see if a creator is banned from the local instance. +fn creator_local_banned() -> _ { + creator_local_instance_actions + .field(instance_actions::received_ban_at) + .nullable() + .is_not_null() +} + +#[diesel::dsl::auto_type] +fn creator_local_ban_expires() -> _ { + creator_local_instance_actions + .field(instance_actions::ban_expires_at) + .nullable() +} + +#[diesel::dsl::auto_type] +/// Checks to see if a creator is banned from their community's instance +fn creator_community_instance_banned() -> _ { + creator_community_instance_actions + .field(instance_actions::received_ban_at) + .nullable() + .is_not_null() +} + +#[diesel::dsl::auto_type] +fn creator_community_instance_ban_expires() -> _ { + creator_community_instance_actions + .field(instance_actions::ban_expires_at) + .nullable() +} + +#[diesel::dsl::auto_type] +/// Checks to see if a creator is banned from their home instance +pub fn creator_home_banned() -> _ { + creator_home_instance_actions + .field(instance_actions::received_ban_at) + .nullable() + .is_not_null() +} + +#[diesel::dsl::auto_type] +/// Checks to see if a creator is banned from their home instance +pub fn creator_home_ban_expires() -> _ { + creator_home_instance_actions + .field(instance_actions::ban_expires_at) + .nullable() +} + +#[diesel::dsl::auto_type] +/// Checks to see if a user is site banned from any of these places: +/// - Their own instance +/// - The local instance +pub fn creator_local_home_banned() -> _ { + creator_local_banned().or(creator_home_banned()) +} + +pub type CreatorLocalHomeBanExpiresType = coalesce_2_nullable< + Timestamptz, + Nullable>, + Nullable>, +>; + +pub fn creator_local_home_ban_expires() -> CreatorLocalHomeBanExpiresType { + coalesce_2_nullable(creator_local_ban_expires(), creator_home_ban_expires()) +} + +/// Checks to see if a user is site banned from any of these places: +/// - The local instance +/// - Their own instance +/// - The community instance. +#[diesel::dsl::auto_type] +pub fn creator_local_home_community_banned() -> _ { + creator_local_banned() + .or(creator_home_banned()) + .or(creator_community_instance_banned()) +} + +pub type CreatorLocalHomeCommunityBanExpiresType = coalesce_3_nullable< + Timestamptz, + Nullable>, + Nullable>, + Nullable>, +>; + +pub fn creator_local_home_community_ban_expires() -> CreatorLocalHomeCommunityBanExpiresType { + coalesce_3_nullable( + creator_local_ban_expires(), + creator_home_ban_expires(), + creator_community_instance_ban_expires(), + ) +} + +#[diesel::dsl::auto_type] +fn am_higher_mod() -> _ { + let i_became_moderator = community_actions::became_moderator_at.nullable(); + + let creator_became_moderator = creator_community_actions + .field(community_actions::became_moderator_at) + .nullable(); + + i_became_moderator.is_not_null().and( + creator_became_moderator + .ge(i_became_moderator) + .is_distinct_from(false), + ) +} + +/// Checks to see if you can mod an item. +/// +/// Caveat: Since admin status isn't federated or ordered, it can't know whether +/// item creator is a federated admin, or a higher admin. +/// The back-end will reject an action for admin that is higher via +/// LocalUser::is_higher_mod_or_admin_check +#[diesel::dsl::auto_type] +pub fn local_user_can_mod() -> _ { + local_user_is_admin().or(not(creator_is_admin()).and(am_higher_mod())) +} + +/// Checks to see if you can mod a post. +#[diesel::dsl::auto_type] +pub fn local_user_can_mod_post() -> _ { + local_user_is_admin().or(not(post_creator_is_admin()).and(am_higher_mod())) +} + +/// Checks to see if you can mod a comment. +#[diesel::dsl::auto_type] +pub fn local_user_can_mod_comment() -> _ { + local_user_is_admin().or(not(comment_creator_is_admin()).and(am_higher_mod())) +} + +/// A special type of can_mod for communities, which dont have creators. +#[diesel::dsl::auto_type] +pub fn local_user_community_can_mod() -> _ { + let am_admin = local_user::admin.nullable(); + let am_moderator = community_actions::became_moderator_at + .nullable() + .is_not_null(); + am_admin.or(am_moderator).is_not_distinct_from(true) +} + +/// Selects the comment columns, but gives an empty string for content when +/// deleted or removed, and you're not a mod/admin. +#[diesel::dsl::auto_type] +pub fn comment_select_remove_deletes() -> _ { + let deleted_or_removed = comment::deleted.or(comment::removed); + + // You can only view the content if it hasn't been removed, or you can mod. + let can_view_content = not(deleted_or_removed).or(local_user_can_mod_comment()); + let content = case_when(can_view_content, comment::content).otherwise(""); + + ( + comment::id, + comment::creator_id, + comment::post_id, + content, + comment::removed, + comment::published_at, + comment::updated_at, + comment::deleted, + comment::ap_id, + comment::local, + comment::path, + comment::distinguished, + comment::language_id, + comment::score, + comment::upvotes, + comment::downvotes, + comment::child_count, + comment::hot_rank, + comment::controversy_rank, + comment::report_count, + comment::unresolved_report_count, + comment::federation_pending, + ) +} + +#[diesel::dsl::auto_type] +// Gets the post tags set on a specific post +pub fn post_tags_fragment() -> _ { + let sel: SqlLiteral = diesel::dsl::sql::("json_agg(tag.*)"); + post_tag::table + .inner_join(tag::table) + .select(sel) + .filter(post_tag::post_id.eq(post::id)) + .filter(tag::deleted.eq(false)) + .single_value() +} + +#[diesel::dsl::auto_type] +/// Gets the post tags available within a specific community +pub fn community_post_tags_fragment() -> _ { + let sel: SqlLiteral = diesel::dsl::sql::("json_agg(tag.*)"); + tag::table + .select(sel) + .filter(tag::community_id.eq(community::id)) + .filter(tag::deleted.eq(false)) + .single_value() +} + +/// The select for the person1 alias. +pub fn person1_select() -> Person1AliasAllColumnsTuple { + person1.fields(person::all_columns) +} + +/// The select for the person2 alias. +pub fn person2_select() -> Person2AliasAllColumnsTuple { + person2.fields(person::all_columns) +} + +/// The select for the my_instance_persons_actions alias +pub fn my_instance_persons_actions_select() -> Nullable { + my_instance_persons_actions + .fields(instance_actions::all_columns) + .nullable() +} diff --git a/crates/db_views/comment/Cargo.toml b/crates/db_views/comment/Cargo.toml index c9937e8a0..4cff1b438 100644 --- a/crates/db_views/comment/Cargo.toml +++ b/crates/db_views/comment/Cargo.toml @@ -45,6 +45,7 @@ serde = { workspace = true } serde_with = { workspace = true } ts-rs = { workspace = true, optional = true } i-love-jesus = { workspace = true, optional = true } +chrono = { workspace = true } [dev-dependencies] lemmy_db_views_local_user = { workspace = true } diff --git a/crates/db_views/comment/src/impls.rs b/crates/db_views/comment/src/impls.rs index 1de06b1a8..d28ed60c2 100644 --- a/crates/db_views/comment/src/impls.rs +++ b/crates/db_views/comment/src/impls.rs @@ -26,18 +26,19 @@ use lemmy_db_schema::{ now, paginate, queries::{ - creator_community_actions_join, - creator_community_instance_actions_join, - creator_home_instance_actions_join, - creator_local_instance_actions_join, - filter_blocked, - my_comment_actions_join, - my_community_actions_join, - my_instance_communities_actions_join, - my_instance_persons_actions_join_1, - my_local_user_admin_join, - my_person_actions_join, - suggested_communities, + filters::{filter_blocked, filter_suggested_communities}, + joins::{ + creator_community_actions_join, + creator_community_instance_actions_join, + creator_home_instance_actions_join, + creator_local_instance_actions_join, + my_comment_actions_join, + my_community_actions_join, + my_instance_communities_actions_join, + my_instance_persons_actions_join_1, + my_local_user_admin_join, + my_person_actions_join, + }, }, seconds_to_pg_interval, DbPool, @@ -202,7 +203,7 @@ impl CommentQuery<'_> { ListingType::ModeratorView => { query.filter(community_actions::became_moderator_at.is_not_null()) } - ListingType::Suggested => query.filter(suggested_communities()), + ListingType::Suggested => query.filter(filter_suggested_communities()), }; if !o.local_user.show_bot_accounts() { @@ -463,6 +464,7 @@ mod tests { local_user: inserted_timmy_local_user.clone(), person: inserted_timmy_person.clone(), banned: false, + ban_expires_at: None, }; let site_form = SiteInsertForm::new("test site".to_string(), inserted_instance.id); let site = Site::create(pool, &site_form).await?; diff --git a/crates/db_views/comment/src/lib.rs b/crates/db_views/comment/src/lib.rs index db14c02e9..08fd2335e 100644 --- a/crates/db_views/comment/src/lib.rs +++ b/crates/db_views/comment/src/lib.rs @@ -1,3 +1,4 @@ +use chrono::{DateTime, Utc}; use lemmy_db_schema::source::{ comment::{Comment, CommentActions}, community::{Community, CommunityActions}, @@ -10,14 +11,17 @@ use serde_with::skip_serializing_none; #[cfg(feature = "full")] use { diesel::{Queryable, Selectable}, - lemmy_db_schema::utils::queries::{ + lemmy_db_schema::utils::queries::selects::{ comment_creator_is_admin, comment_select_remove_deletes, + creator_ban_expires_from_community, creator_banned_from_community, - creator_banned_within_community, creator_is_moderator, + creator_local_home_community_ban_expires, + creator_local_home_community_banned, local_user_can_mod_comment, post_tags_fragment, + CreatorLocalHomeCommunityBanExpiresType, }, }; @@ -71,10 +75,17 @@ pub struct CommentView { pub can_mod: bool, #[cfg_attr(feature = "full", diesel( - select_expression = creator_banned_within_community() + select_expression = creator_local_home_community_banned() ) )] pub creator_banned: bool, + #[cfg_attr(feature = "full", + diesel( + select_expression_type = CreatorLocalHomeCommunityBanExpiresType, + select_expression = creator_local_home_community_ban_expires() + ) + )] + pub creator_ban_expires_at: Option>, #[cfg_attr(feature = "full", diesel( select_expression = creator_is_moderator() @@ -87,6 +98,12 @@ pub struct CommentView { ) )] pub creator_banned_from_community: bool, + #[cfg_attr(feature = "full", + diesel( + select_expression = creator_ban_expires_from_community() + ) + )] + pub creator_community_ban_expires_at: Option>, } #[skip_serializing_none] diff --git a/crates/db_views/community/src/impls.rs b/crates/db_views/community/src/impls.rs index 0d0af4482..c20e0aa04 100644 --- a/crates/db_views/community/src/impls.rs +++ b/crates/db_views/community/src/impls.rs @@ -17,12 +17,16 @@ use lemmy_db_schema::{ now, paginate, queries::{ - filter_is_subscribed, - filter_not_unlisted_or_is_subscribed, - my_community_actions_join, - my_instance_communities_actions_join, - my_local_user_admin_join, - suggested_communities, + filters::{ + filter_is_subscribed, + filter_not_unlisted_or_is_subscribed, + filter_suggested_communities, + }, + joins::{ + my_community_actions_join, + my_instance_communities_actions_join, + my_local_user_admin_join, + }, }, seconds_to_pg_interval, DbPool, @@ -144,7 +148,7 @@ impl CommunityQuery<'_> { ListingType::ModeratorView => { query.filter(community_actions::became_moderator_at.is_not_null()) } - ListingType::Suggested => query.filter(suggested_communities()), + ListingType::Suggested => query.filter(filter_suggested_communities()), }; } diff --git a/crates/db_views/community/src/lib.rs b/crates/db_views/community/src/lib.rs index c73b63970..e15a83697 100644 --- a/crates/db_views/community/src/lib.rs +++ b/crates/db_views/community/src/lib.rs @@ -9,7 +9,10 @@ use serde_with::skip_serializing_none; #[cfg(feature = "full")] use { diesel::{Queryable, Selectable}, - lemmy_db_schema::utils::queries::{community_post_tags_fragment, local_user_community_can_mod}, + lemmy_db_schema::utils::queries::selects::{ + community_post_tags_fragment, + local_user_community_can_mod, + }, }; pub mod api; diff --git a/crates/db_views/local_user/Cargo.toml b/crates/db_views/local_user/Cargo.toml index 214be75d9..54764c6d5 100644 --- a/crates/db_views/local_user/Cargo.toml +++ b/crates/db_views/local_user/Cargo.toml @@ -38,6 +38,7 @@ serde_with = { workspace = true } ts-rs = { workspace = true, optional = true } actix-web = { workspace = true, optional = true } i-love-jesus = { workspace = true, optional = true } +chrono = { workspace = true } [dev-dependencies] serial_test = { workspace = true } diff --git a/crates/db_views/local_user/src/impls.rs b/crates/db_views/local_user/src/impls.rs index 4fabf2595..458e380de 100644 --- a/crates/db_views/local_user/src/impls.rs +++ b/crates/db_views/local_user/src/impls.rs @@ -23,7 +23,7 @@ use lemmy_db_schema::{ get_conn, now, paginate, - queries::creator_home_instance_actions_join, + queries::joins::creator_home_instance_actions_join, DbPool, }, }; diff --git a/crates/db_views/local_user/src/lib.rs b/crates/db_views/local_user/src/lib.rs index 29bf1157c..b22d74164 100644 --- a/crates/db_views/local_user/src/lib.rs +++ b/crates/db_views/local_user/src/lib.rs @@ -1,9 +1,10 @@ +use chrono::{DateTime, Utc}; use lemmy_db_schema::source::{local_user::LocalUser, person::Person}; use serde::{Deserialize, Serialize}; #[cfg(feature = "full")] use { diesel::{Queryable, Selectable}, - lemmy_db_schema::utils::queries::creator_home_banned, + lemmy_db_schema::utils::queries::selects::{creator_home_ban_expires, creator_home_banned}, }; pub mod api; @@ -27,4 +28,10 @@ pub struct LocalUserView { ) )] pub banned: bool, + #[cfg_attr(feature = "full", + diesel( + select_expression = creator_home_ban_expires() + ) + )] + pub ban_expires_at: Option>, } diff --git a/crates/db_views/modlog_combined/src/impls.rs b/crates/db_views/modlog_combined/src/impls.rs index e9808f9c8..9822cbef8 100644 --- a/crates/db_views/modlog_combined/src/impls.rs +++ b/crates/db_views/modlog_combined/src/impls.rs @@ -42,7 +42,11 @@ use lemmy_db_schema::{ get_conn, limit_fetch, paginate, - queries::{filter_is_subscribed, filter_not_unlisted_or_is_subscribed, suggested_communities}, + queries::filters::{ + filter_is_subscribed, + filter_not_unlisted_or_is_subscribed, + filter_suggested_communities, + }, DbPool, }, ModlogActionType, @@ -380,7 +384,7 @@ impl ModlogCombinedQuery<'_> { ListingType::ModeratorView => { query.filter(community_actions::became_moderator_at.is_not_null()) } - ListingType::Suggested => query.filter(suggested_communities()), + ListingType::Suggested => query.filter(filter_suggested_communities()), }; // Sorting by published diff --git a/crates/db_views/modlog_combined/src/lib.rs b/crates/db_views/modlog_combined/src/lib.rs index 6d1a45abf..b8dd345e6 100644 --- a/crates/db_views/modlog_combined/src/lib.rs +++ b/crates/db_views/modlog_combined/src/lib.rs @@ -33,7 +33,7 @@ use serde_with::skip_serializing_none; #[cfg(feature = "full")] use { diesel::{dsl::Nullable, NullableExpressionMethods, Queryable, Selectable}, - lemmy_db_schema::{utils::queries::person1_select, Person1AliasAllColumnsTuple}, + lemmy_db_schema::{utils::queries::selects::person1_select, Person1AliasAllColumnsTuple}, }; pub mod api; diff --git a/crates/db_views/notification/Cargo.toml b/crates/db_views/notification/Cargo.toml index 59f11f70b..f146f92b5 100644 --- a/crates/db_views/notification/Cargo.toml +++ b/crates/db_views/notification/Cargo.toml @@ -39,5 +39,6 @@ serde = { workspace = true } ts-rs = { workspace = true, optional = true } i-love-jesus = { workspace = true, optional = true } serde_with = { workspace = true } +chrono = { workspace = true } [dev-dependencies] diff --git a/crates/db_views/notification/src/impls.rs b/crates/db_views/notification/src/impls.rs index 1fab10bc3..d7454107d 100644 --- a/crates/db_views/notification/src/impls.rs +++ b/crates/db_views/notification/src/impls.rs @@ -23,20 +23,22 @@ use lemmy_db_schema::{ limit_fetch, paginate, queries::{ - community_join, - creator_community_actions_join, - creator_home_instance_actions_join, - creator_local_instance_actions_join, - creator_local_user_admin_join, - filter_blocked, - image_details_join, - my_comment_actions_join, - my_community_actions_join, - my_instance_communities_actions_join, - my_instance_persons_actions_join_1, - my_local_user_admin_join, - my_person_actions_join, - my_post_actions_join, + filters::filter_blocked, + joins::{ + community_join, + creator_community_actions_join, + creator_home_instance_actions_join, + creator_local_instance_actions_join, + creator_local_user_admin_join, + image_details_join, + my_comment_actions_join, + my_community_actions_join, + my_instance_communities_actions_join, + my_instance_persons_actions_join_1, + my_local_user_admin_join, + my_person_actions_join, + my_post_actions_join, + }, }, DbPool, }, @@ -294,8 +296,10 @@ fn map_to_enum(v: NotificationViewInternal) -> Option { post_tags: v.post_tags, can_mod: v.can_mod, creator_banned: v.creator_banned, + creator_ban_expires_at: v.creator_ban_expires_at, creator_is_moderator: v.creator_is_moderator, creator_banned_from_community: v.creator_banned_from_community, + creator_community_ban_expires_at: v.creator_community_ban_expires_at, }) } else if let (Some(post), Some(community)) = (v.post, v.community) { NotificationData::Post(PostView { @@ -310,8 +314,10 @@ fn map_to_enum(v: NotificationViewInternal) -> Option { tags: v.post_tags, can_mod: v.can_mod, creator_banned: v.creator_banned, + creator_ban_expires_at: v.creator_ban_expires_at, creator_is_moderator: v.creator_is_moderator, creator_banned_from_community: v.creator_banned_from_community, + creator_community_ban_expires_at: v.creator_community_ban_expires_at, }) } else if let Some(private_message) = v.private_message { NotificationData::PrivateMessage(PrivateMessageView { diff --git a/crates/db_views/notification/src/lib.rs b/crates/db_views/notification/src/lib.rs index 1b27a5ee1..821011876 100644 --- a/crates/db_views/notification/src/lib.rs +++ b/crates/db_views/notification/src/lib.rs @@ -1,3 +1,4 @@ +use chrono::{DateTime, Utc}; use lemmy_db_schema::{ newtypes::PaginationCursor, source::{ @@ -21,14 +22,17 @@ use serde_with::skip_serializing_none; use { diesel::{Queryable, Selectable}, lemmy_db_schema::{ - utils::queries::{ - creator_banned, + utils::queries::selects::{ + creator_ban_expires_from_community, creator_banned_from_community, creator_is_admin, creator_is_moderator, + creator_local_home_ban_expires, + creator_local_home_banned, local_user_can_mod, person1_select, post_tags_fragment, + CreatorLocalHomeBanExpiresType, }, Person1AliasAllColumnsTuple, }, @@ -91,10 +95,17 @@ struct NotificationViewInternal { can_mod: bool, #[cfg_attr(feature = "full", diesel( - select_expression = creator_banned() + select_expression = creator_local_home_banned() ) )] creator_banned: bool, + #[cfg_attr(feature = "full", + diesel( + select_expression_type = CreatorLocalHomeBanExpiresType, + select_expression = creator_local_home_ban_expires() + ) + )] + pub creator_ban_expires_at: Option>, #[cfg_attr(feature = "full", diesel( select_expression = creator_is_moderator() @@ -107,6 +118,12 @@ struct NotificationViewInternal { ) )] creator_banned_from_community: bool, + #[cfg_attr(feature = "full", + diesel( + select_expression = creator_ban_expires_from_community() + ) + )] + pub creator_community_ban_expires_at: Option>, } #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] diff --git a/crates/db_views/person/Cargo.toml b/crates/db_views/person/Cargo.toml index 0477a2662..6e476deee 100644 --- a/crates/db_views/person/Cargo.toml +++ b/crates/db_views/person/Cargo.toml @@ -42,6 +42,7 @@ serde = { workspace = true } serde_with = { workspace = true } ts-rs = { workspace = true, optional = true } i-love-jesus = { workspace = true, optional = true } +chrono = { workspace = true } [dev-dependencies] serial_test = { workspace = true } diff --git a/crates/db_views/person/src/impls.rs b/crates/db_views/person/src/impls.rs index 0daee2117..bc840b098 100644 --- a/crates/db_views/person/src/impls.rs +++ b/crates/db_views/person/src/impls.rs @@ -10,7 +10,7 @@ use lemmy_db_schema::{ get_conn, limit_fetch, paginate, - queries::{ + queries::joins::{ creator_home_instance_actions_join, creator_local_instance_actions_join, my_person_actions_join, diff --git a/crates/db_views/person/src/lib.rs b/crates/db_views/person/src/lib.rs index ee2d11190..cfcb00ad4 100644 --- a/crates/db_views/person/src/lib.rs +++ b/crates/db_views/person/src/lib.rs @@ -1,9 +1,17 @@ +use chrono::{DateTime, Utc}; use lemmy_db_schema::source::person::{Person, PersonActions}; use serde::{Deserialize, Serialize}; #[cfg(feature = "full")] use { diesel::{helper_types::Nullable, NullableExpressionMethods, Queryable, Selectable}, - lemmy_db_schema::utils::{functions::coalesce, queries::creator_banned}, + lemmy_db_schema::utils::{ + functions::coalesce, + queries::selects::{ + creator_local_home_ban_expires, + creator_local_home_banned, + CreatorLocalHomeBanExpiresType, + }, + }, lemmy_db_schema_file::schema::local_user, }; @@ -31,8 +39,15 @@ pub struct PersonView { pub person_actions: Option, #[cfg_attr(feature = "full", diesel( - select_expression = creator_banned() + select_expression = creator_local_home_banned() ) )] pub creator_banned: bool, + #[cfg_attr(feature = "full", + diesel( + select_expression_type = CreatorLocalHomeBanExpiresType, + select_expression = creator_local_home_ban_expires() + ) + )] + pub creator_ban_expires_at: Option>, } diff --git a/crates/db_views/person_content_combined/Cargo.toml b/crates/db_views/person_content_combined/Cargo.toml index b64698279..faa187d8f 100644 --- a/crates/db_views/person_content_combined/Cargo.toml +++ b/crates/db_views/person_content_combined/Cargo.toml @@ -46,6 +46,7 @@ ts-rs = { workspace = true, optional = true } i-love-jesus = { workspace = true, optional = true } derive-new = { workspace = true } serde_with = { workspace = true } +chrono = { workspace = true } [dev-dependencies] pretty_assertions = { workspace = true } diff --git a/crates/db_views/person_content_combined/src/impls.rs b/crates/db_views/person_content_combined/src/impls.rs index 130210880..a6ab2054a 100644 --- a/crates/db_views/person_content_combined/src/impls.rs +++ b/crates/db_views/person_content_combined/src/impls.rs @@ -24,7 +24,7 @@ use lemmy_db_schema::{ get_conn, limit_fetch, paginate, - queries::{ + queries::joins::{ community_join, creator_community_actions_join, creator_home_instance_actions_join, @@ -240,8 +240,10 @@ impl InternalToCombinedView for PersonContentCombinedViewInternal { post_tags: v.post_tags, can_mod: v.can_mod, creator_banned: v.creator_banned, + creator_ban_expires_at: v.creator_ban_expires_at, creator_is_moderator: v.creator_is_moderator, creator_banned_from_community: v.creator_banned_from_community, + creator_community_ban_expires_at: v.creator_community_ban_expires_at, })) } else { Some(PersonContentCombinedView::Post(PostView { @@ -256,8 +258,10 @@ impl InternalToCombinedView for PersonContentCombinedViewInternal { tags: v.post_tags, can_mod: v.can_mod, creator_banned: v.creator_banned, + creator_ban_expires_at: v.creator_ban_expires_at, creator_is_moderator: v.creator_is_moderator, creator_banned_from_community: v.creator_banned_from_community, + creator_community_ban_expires_at: v.creator_community_ban_expires_at, })) } } diff --git a/crates/db_views/person_content_combined/src/lib.rs b/crates/db_views/person_content_combined/src/lib.rs index 6e58dc6e3..512a35c87 100644 --- a/crates/db_views/person_content_combined/src/lib.rs +++ b/crates/db_views/person_content_combined/src/lib.rs @@ -1,3 +1,4 @@ +use chrono::{DateTime, Utc}; use lemmy_db_schema::{ newtypes::{PaginationCursor, PersonId}, source::{ @@ -18,13 +19,16 @@ use serde_with::skip_serializing_none; #[cfg(feature = "full")] use { diesel::{Queryable, Selectable}, - lemmy_db_schema::utils::queries::{ - creator_banned, + lemmy_db_schema::utils::queries::selects::{ + creator_ban_expires_from_community, creator_banned_from_community, creator_is_admin, creator_is_moderator, + creator_local_home_ban_expires, + creator_local_home_banned, local_user_can_mod, post_tags_fragment, + CreatorLocalHomeBanExpiresType, }, lemmy_db_views_local_user::LocalUserView, @@ -78,10 +82,17 @@ pub(crate) struct PersonContentCombinedViewInternal { pub can_mod: bool, #[cfg_attr(feature = "full", diesel( - select_expression = creator_banned() + select_expression = creator_local_home_banned() ) )] pub creator_banned: bool, + #[cfg_attr(feature = "full", + diesel( + select_expression_type = CreatorLocalHomeBanExpiresType, + select_expression = creator_local_home_ban_expires() + ) + )] + pub creator_ban_expires_at: Option>, #[cfg_attr(feature = "full", diesel( select_expression = creator_is_moderator() @@ -94,6 +105,12 @@ pub(crate) struct PersonContentCombinedViewInternal { ) )] pub creator_banned_from_community: bool, + #[cfg_attr(feature = "full", + diesel( + select_expression = creator_ban_expires_from_community() + ) + )] + pub creator_community_ban_expires_at: Option>, } #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] diff --git a/crates/db_views/person_liked_combined/Cargo.toml b/crates/db_views/person_liked_combined/Cargo.toml index 46c0b4811..3d693f780 100644 --- a/crates/db_views/person_liked_combined/Cargo.toml +++ b/crates/db_views/person_liked_combined/Cargo.toml @@ -46,6 +46,7 @@ serde = { workspace = true } serde_with = { workspace = true } ts-rs = { workspace = true, optional = true } i-love-jesus = { workspace = true, optional = true } +chrono = { workspace = true } [dev-dependencies] pretty_assertions = { workspace = true } diff --git a/crates/db_views/person_liked_combined/src/impls.rs b/crates/db_views/person_liked_combined/src/impls.rs index 0d558d93c..cbfcbfba4 100644 --- a/crates/db_views/person_liked_combined/src/impls.rs +++ b/crates/db_views/person_liked_combined/src/impls.rs @@ -23,7 +23,7 @@ use lemmy_db_schema::{ get_conn, limit_fetch, paginate, - queries::{ + queries::joins::{ community_join, creator_community_actions_join, creator_community_instance_actions_join, @@ -230,8 +230,10 @@ impl InternalToCombinedView for PersonLikedCombinedViewInternal { post_tags: v.post_tags, can_mod: v.can_mod, creator_banned: v.creator_banned, + creator_ban_expires_at: v.creator_ban_expires_at, creator_is_moderator: v.creator_is_moderator, creator_banned_from_community: v.creator_banned_from_community, + creator_community_ban_expires_at: v.creator_community_ban_expires_at, })) } else { Some(PersonLikedCombinedView::Post(PostView { @@ -246,8 +248,10 @@ impl InternalToCombinedView for PersonLikedCombinedViewInternal { tags: v.post_tags, can_mod: v.can_mod, creator_banned: v.creator_banned, + creator_ban_expires_at: v.creator_ban_expires_at, creator_is_moderator: v.creator_is_moderator, creator_banned_from_community: v.creator_banned_from_community, + creator_community_ban_expires_at: v.creator_community_ban_expires_at, })) } } @@ -296,6 +300,7 @@ mod tests { local_user: timmy_local_user, person: timmy.clone(), banned: false, + ban_expires_at: None, }; let sara_form = PersonInsertForm::test_form(instance.id, "sara_pcv"); diff --git a/crates/db_views/person_liked_combined/src/lib.rs b/crates/db_views/person_liked_combined/src/lib.rs index 544099304..1bc3e9e9a 100644 --- a/crates/db_views/person_liked_combined/src/lib.rs +++ b/crates/db_views/person_liked_combined/src/lib.rs @@ -1,3 +1,4 @@ +use chrono::{DateTime, Utc}; use lemmy_db_schema::{ newtypes::PaginationCursor, source::{ @@ -19,13 +20,16 @@ use serde_with::skip_serializing_none; #[cfg(feature = "full")] use { diesel::{Queryable, Selectable}, - lemmy_db_schema::utils::queries::{ + lemmy_db_schema::utils::queries::selects::{ + creator_ban_expires_from_community, creator_banned_from_community, - creator_banned_within_community, creator_is_admin, creator_is_moderator, + creator_local_home_community_ban_expires, + creator_local_home_community_banned, local_user_can_mod, post_tags_fragment, + CreatorLocalHomeCommunityBanExpiresType, }, lemmy_db_views_local_user::LocalUserView, }; @@ -78,10 +82,17 @@ pub(crate) struct PersonLikedCombinedViewInternal { pub can_mod: bool, #[cfg_attr(feature = "full", diesel( - select_expression = creator_banned_within_community() + select_expression = creator_local_home_community_banned() ) )] pub creator_banned: bool, + #[cfg_attr(feature = "full", + diesel( + select_expression_type = CreatorLocalHomeCommunityBanExpiresType, + select_expression = creator_local_home_community_ban_expires() + ) + )] + pub creator_ban_expires_at: Option>, #[cfg_attr(feature = "full", diesel( select_expression = creator_is_moderator() @@ -94,6 +105,12 @@ pub(crate) struct PersonLikedCombinedViewInternal { ) )] pub creator_banned_from_community: bool, + #[cfg_attr(feature = "full", + diesel( + select_expression = creator_ban_expires_from_community() + ) + )] + pub creator_community_ban_expires_at: Option>, } #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] diff --git a/crates/db_views/person_saved_combined/Cargo.toml b/crates/db_views/person_saved_combined/Cargo.toml index 9fe1f5170..68a6392c3 100644 --- a/crates/db_views/person_saved_combined/Cargo.toml +++ b/crates/db_views/person_saved_combined/Cargo.toml @@ -46,6 +46,7 @@ serde = { workspace = true } ts-rs = { workspace = true, optional = true } i-love-jesus = { workspace = true, optional = true } serde_with = { workspace = true } +chrono = { workspace = true } [dev-dependencies] pretty_assertions = { workspace = true } diff --git a/crates/db_views/person_saved_combined/src/impls.rs b/crates/db_views/person_saved_combined/src/impls.rs index f1fe5cdc3..a7c99d3d8 100644 --- a/crates/db_views/person_saved_combined/src/impls.rs +++ b/crates/db_views/person_saved_combined/src/impls.rs @@ -23,7 +23,7 @@ use lemmy_db_schema::{ get_conn, limit_fetch, paginate, - queries::{ + queries::joins::{ community_join, creator_community_actions_join, creator_community_instance_actions_join, @@ -219,8 +219,10 @@ impl InternalToCombinedView for PersonSavedCombinedViewInternal { post_tags: v.post_tags, can_mod: v.can_mod, creator_banned: v.creator_banned, + creator_ban_expires_at: v.creator_ban_expires_at, creator_is_moderator: v.creator_is_moderator, creator_banned_from_community: v.creator_banned_from_community, + creator_community_ban_expires_at: v.creator_community_ban_expires_at, })) } else { Some(PersonSavedCombinedView::Post(PostView { @@ -235,8 +237,10 @@ impl InternalToCombinedView for PersonSavedCombinedViewInternal { tags: v.post_tags, can_mod: v.can_mod, creator_banned: v.creator_banned, + creator_ban_expires_at: v.creator_ban_expires_at, creator_is_moderator: v.creator_is_moderator, creator_banned_from_community: v.creator_banned_from_community, + creator_community_ban_expires_at: v.creator_community_ban_expires_at, })) } } @@ -284,6 +288,7 @@ mod tests { local_user: timmy_local_user, person: timmy.clone(), banned: false, + ban_expires_at: None, }; let sara_form = PersonInsertForm::test_form(instance.id, "sara_pcv"); diff --git a/crates/db_views/person_saved_combined/src/lib.rs b/crates/db_views/person_saved_combined/src/lib.rs index 2f4fc320b..30942ba67 100644 --- a/crates/db_views/person_saved_combined/src/lib.rs +++ b/crates/db_views/person_saved_combined/src/lib.rs @@ -1,3 +1,4 @@ +use chrono::{DateTime, Utc}; use lemmy_db_schema::{ newtypes::PaginationCursor, source::{ @@ -18,13 +19,16 @@ use serde_with::skip_serializing_none; #[cfg(feature = "full")] use { diesel::{Queryable, Selectable}, - lemmy_db_schema::utils::queries::{ + lemmy_db_schema::utils::queries::selects::{ + creator_ban_expires_from_community, creator_banned_from_community, - creator_banned_within_community, creator_is_admin, creator_is_moderator, + creator_local_home_community_ban_expires, + creator_local_home_community_banned, local_user_can_mod, post_tags_fragment, + CreatorLocalHomeCommunityBanExpiresType, }, lemmy_db_views_local_user::LocalUserView, @@ -78,10 +82,17 @@ pub(crate) struct PersonSavedCombinedViewInternal { pub can_mod: bool, #[cfg_attr(feature = "full", diesel( - select_expression = creator_banned_within_community() + select_expression = creator_local_home_community_banned() ) )] pub creator_banned: bool, + #[cfg_attr(feature = "full", + diesel( + select_expression_type = CreatorLocalHomeCommunityBanExpiresType, + select_expression = creator_local_home_community_ban_expires() + ) + )] + pub creator_ban_expires_at: Option>, #[cfg_attr(feature = "full", diesel( select_expression = creator_is_moderator() @@ -94,6 +105,12 @@ pub(crate) struct PersonSavedCombinedViewInternal { ) )] pub creator_banned_from_community: bool, + #[cfg_attr(feature = "full", + diesel( + select_expression = creator_ban_expires_from_community() + ) + )] + pub creator_community_ban_expires_at: Option>, } #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] diff --git a/crates/db_views/post/src/impls.rs b/crates/db_views/post/src/impls.rs index 33b4e29eb..993873333 100644 --- a/crates/db_views/post/src/impls.rs +++ b/crates/db_views/post/src/impls.rs @@ -32,21 +32,25 @@ use lemmy_db_schema::{ now, paginate, queries::{ - creator_community_actions_join, - creator_community_instance_actions_join, - creator_home_instance_actions_join, - creator_local_instance_actions_join, - filter_blocked, - filter_is_subscribed, - filter_not_unlisted_or_is_subscribed, - image_details_join, - my_community_actions_join, - my_instance_communities_actions_join, - my_instance_persons_actions_join_1, - my_local_user_admin_join, - my_person_actions_join, - my_post_actions_join, - suggested_communities, + filters::{ + filter_blocked, + filter_is_subscribed, + filter_not_unlisted_or_is_subscribed, + filter_suggested_communities, + }, + joins::{ + creator_community_actions_join, + creator_community_instance_actions_join, + creator_home_instance_actions_join, + creator_local_instance_actions_join, + image_details_join, + my_community_actions_join, + my_instance_communities_actions_join, + my_instance_persons_actions_join_1, + my_local_user_admin_join, + my_person_actions_join, + my_post_actions_join, + }, }, seconds_to_pg_interval, Commented, @@ -400,7 +404,7 @@ impl PostQuery<'_> { ListingType::ModeratorView => { query = query.filter(community_actions::became_moderator_at.is_not_null()); } - ListingType::Suggested => query = query.filter(suggested_communities()), + ListingType::Suggested => query = query.filter(filter_suggested_communities()), } if !o.show_nsfw.unwrap_or(o.local_user.show_nsfw(site)) { @@ -568,7 +572,7 @@ mod tests { impls::{PostQuery, PostSortType}, PostView, }; - use chrono::Utc; + use chrono::{DateTime, Days, Utc}; use diesel_async::SimpleAsyncConnection; use diesel_uplete::UpleteCount; use lemmy_db_schema::{ @@ -791,17 +795,20 @@ mod tests { local_user: inserted_tegan_local_user, person: inserted_tegan_person, banned: false, + ban_expires_at: None, }; let john = LocalUserView { local_user: inserted_john_local_user, person: inserted_john_person, banned: false, + ban_expires_at: None, }; let bot = LocalUserView { local_user: inserted_bot_local_user, person: inserted_bot_person, banned: false, + ban_expires_at: None, }; Ok(Data { @@ -2076,10 +2083,17 @@ mod tests { Ok(()) } + /// Use microseconds for date checks + /// + /// Necessary because postgres uses micros, but rust uses nanos + fn micros(dt: DateTime) -> i64 { + dt.timestamp_micros() + } + #[test_context(Data)] #[tokio::test] #[serial] - async fn post_listing_local_user_banned(data: &mut Data) -> LemmyResult<()> { + async fn post_listing_creator_banned(data: &mut Data) -> LemmyResult<()> { let pool = &data.pool(); let pool = &mut pool.into(); @@ -2097,9 +2111,11 @@ mod tests { }; let banned_post = Post::create(pool, &post_form).await?; + let expires_at = Utc::now().checked_add_days(Days::new(1)); + InstanceActions::ban( pool, - &InstanceBanForm::new(banned_person.id, data.instance.id, None), + &InstanceBanForm::new(banned_person.id, data.instance.id, expires_at), ) .await?; @@ -2115,7 +2131,66 @@ mod tests { assert!(post_view.creator_banned); - assert!(post_view.creator_banned); + // Make sure the expires at is correct + assert_eq!( + expires_at.map(micros), + post_view.creator_ban_expires_at.map(micros) + ); + + Person::delete(pool, banned_person.id).await?; + Ok(()) + } + + #[test_context(Data)] + #[tokio::test] + #[serial] + async fn post_listing_creator_community_banned(data: &mut Data) -> LemmyResult<()> { + let pool = &data.pool(); + let pool = &mut pool.into(); + + let banned_person_form = PersonInsertForm::test_form(data.instance.id, "jarvis"); + + let banned_person = Person::create(pool, &banned_person_form).await?; + + let post_form = PostInsertForm { + language_id: Some(LanguageId(1)), + ..PostInsertForm::new( + "banned jarvis post".to_string(), + banned_person.id, + data.community.id, + ) + }; + let banned_post = Post::create(pool, &post_form).await?; + + let expires_at = Utc::now().checked_add_days(Days::new(1)); + + CommunityActions::ban( + pool, + &CommunityPersonBanForm { + ban_expires_at: Some(expires_at), + ..CommunityPersonBanForm::new(data.community.id, banned_person.id) + }, + ) + .await?; + + // Let john read their post + let post_view = PostView::read( + pool, + banned_post.id, + Some(&data.john.local_user), + data.instance.id, + false, + ) + .await?; + + assert!(post_view.creator_banned_from_community); + assert!(!post_view.creator_banned); + + // Make sure the expires at is correct + assert_eq!( + expires_at.map(micros), + post_view.creator_community_ban_expires_at.map(micros) + ); Person::delete(pool, banned_person.id).await?; Ok(()) diff --git a/crates/db_views/post/src/lib.rs b/crates/db_views/post/src/lib.rs index db587aafb..14fa83de2 100644 --- a/crates/db_views/post/src/lib.rs +++ b/crates/db_views/post/src/lib.rs @@ -1,3 +1,4 @@ +use chrono::{DateTime, Utc}; use lemmy_db_schema::source::{ community::{Community, CommunityActions}, images::ImageDetails, @@ -12,13 +13,16 @@ use serde_with::skip_serializing_none; #[cfg(feature = "full")] use { diesel::{Queryable, Selectable}, - lemmy_db_schema::utils::queries::{ + lemmy_db_schema::utils::queries::selects::{ + creator_ban_expires_from_community, creator_banned_from_community, - creator_banned_within_community, creator_is_moderator, + creator_local_home_ban_expires, + creator_local_home_community_banned, local_user_can_mod_post, post_creator_is_admin, post_tags_fragment, + CreatorLocalHomeBanExpiresType, }, }; @@ -67,10 +71,17 @@ pub struct PostView { pub can_mod: bool, #[cfg_attr(feature = "full", diesel( - select_expression = creator_banned_within_community() + select_expression = creator_local_home_community_banned() ) )] pub creator_banned: bool, + #[cfg_attr(feature = "full", + diesel( + select_expression_type = CreatorLocalHomeBanExpiresType, + select_expression = creator_local_home_ban_expires() + ) + )] + pub creator_ban_expires_at: Option>, #[cfg_attr(feature = "full", diesel( select_expression = creator_is_moderator() @@ -83,4 +94,10 @@ pub struct PostView { ) )] pub creator_banned_from_community: bool, + #[cfg_attr(feature = "full", + diesel( + select_expression = creator_ban_expires_from_community() + ) + )] + pub creator_community_ban_expires_at: Option>, } diff --git a/crates/db_views/private_message/src/lib.rs b/crates/db_views/private_message/src/lib.rs index 22fafaefd..a38ec6263 100644 --- a/crates/db_views/private_message/src/lib.rs +++ b/crates/db_views/private_message/src/lib.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "full")] use { diesel::{Queryable, Selectable}, - lemmy_db_schema::utils::queries::person1_select, + lemmy_db_schema::utils::queries::selects::person1_select, lemmy_db_schema::Person1AliasAllColumnsTuple, }; diff --git a/crates/db_views/registration_applications/src/lib.rs b/crates/db_views/registration_applications/src/lib.rs index 472e25025..7b4d18a2f 100644 --- a/crates/db_views/registration_applications/src/lib.rs +++ b/crates/db_views/registration_applications/src/lib.rs @@ -8,7 +8,7 @@ use serde_with::skip_serializing_none; #[cfg(feature = "full")] use { diesel::{helper_types::Nullable, NullableExpressionMethods, Queryable, Selectable}, - lemmy_db_schema::{utils::queries::person1_select, Person1AliasAllColumnsTuple}, + lemmy_db_schema::{utils::queries::selects::person1_select, Person1AliasAllColumnsTuple}, }; pub mod api; diff --git a/crates/db_views/report_combined/src/impls.rs b/crates/db_views/report_combined/src/impls.rs index 3b70afdba..fd06f6a77 100644 --- a/crates/db_views/report_combined/src/impls.rs +++ b/crates/db_views/report_combined/src/impls.rs @@ -41,7 +41,7 @@ use lemmy_db_schema::{ get_conn, limit_fetch, paginate, - queries::{ + queries::joins::{ creator_community_instance_actions_join, creator_home_instance_actions_join, creator_local_instance_actions_join, @@ -622,6 +622,7 @@ mod tests { local_user: timmy_local_user, person: inserted_timmy.clone(), banned: false, + ban_expires_at: None, }; // Make an admin, to be able to see private message reports. @@ -633,6 +634,7 @@ mod tests { local_user: admin_local_user, person: inserted_admin.clone(), banned: false, + ban_expires_at: None, }; let sara_form = PersonInsertForm::test_form(inserted_instance.id, "sara_rcv"); diff --git a/crates/db_views/report_combined/src/lib.rs b/crates/db_views/report_combined/src/lib.rs index fad36f26f..48ce924ed 100644 --- a/crates/db_views/report_combined/src/lib.rs +++ b/crates/db_views/report_combined/src/lib.rs @@ -1,3 +1,4 @@ +use chrono::{DateTime, Utc}; use lemmy_db_schema::source::{ combined::report::ReportCombined, comment::{Comment, CommentActions}, @@ -15,13 +16,16 @@ use serde_with::skip_serializing_none; #[cfg(feature = "full")] use { diesel::{dsl::Nullable, NullableExpressionMethods, Queryable, Selectable}, - lemmy_db_schema::utils::queries::{ + lemmy_db_schema::utils::queries::selects::{ + creator_ban_expires_from_community, creator_banned_from_community, - creator_banned_within_community, creator_is_moderator, + creator_local_home_community_ban_expires, + creator_local_home_community_banned, local_user_is_admin, person1_select, person2_select, + CreatorLocalHomeCommunityBanExpiresType, }, lemmy_db_schema::{Person1AliasAllColumnsTuple, Person2AliasAllColumnsTuple}, lemmy_db_views_local_user::LocalUserView, @@ -82,16 +86,29 @@ pub struct ReportCombinedViewInternal { pub creator_is_moderator: bool, #[cfg_attr(feature = "full", diesel( - select_expression = creator_banned_within_community() + select_expression = creator_local_home_community_banned() ) )] pub creator_banned: bool, + #[cfg_attr(feature = "full", + diesel( + select_expression_type = CreatorLocalHomeCommunityBanExpiresType, + select_expression = creator_local_home_community_ban_expires() + ) + )] + pub creator_ban_expires_at: Option>, #[cfg_attr(feature = "full", diesel( select_expression = creator_banned_from_community() ) )] pub creator_banned_from_community: bool, + #[cfg_attr(feature = "full", + diesel( + select_expression = creator_ban_expires_from_community() + ) + )] + pub creator_community_ban_expires_at: Option>, #[cfg_attr(feature = "full", diesel(embed))] pub community: Option, #[cfg_attr(feature = "full", diesel(embed))] diff --git a/crates/db_views/search_combined/Cargo.toml b/crates/db_views/search_combined/Cargo.toml index da7bbe36c..cd351209e 100644 --- a/crates/db_views/search_combined/Cargo.toml +++ b/crates/db_views/search_combined/Cargo.toml @@ -53,6 +53,7 @@ serde = { workspace = true } ts-rs = { workspace = true, optional = true } i-love-jesus = { workspace = true, optional = true } serde_with = { workspace = true } +chrono = { workspace = true } [dev-dependencies] pretty_assertions = { workspace = true } diff --git a/crates/db_views/search_combined/src/impls.rs b/crates/db_views/search_combined/src/impls.rs index 0ae2586ec..96d114f9a 100644 --- a/crates/db_views/search_combined/src/impls.rs +++ b/crates/db_views/search_combined/src/impls.rs @@ -34,19 +34,23 @@ use lemmy_db_schema::{ now, paginate, queries::{ - creator_community_actions_join, - creator_home_instance_actions_join, - creator_local_instance_actions_join, - creator_local_user_admin_join, - filter_is_subscribed, - filter_not_unlisted_or_is_subscribed, - image_details_join, - my_comment_actions_join, - my_community_actions_join, - my_local_user_admin_join, - my_person_actions_join, - my_post_actions_join, - suggested_communities, + filters::{ + filter_is_subscribed, + filter_not_unlisted_or_is_subscribed, + filter_suggested_communities, + }, + joins::{ + creator_community_actions_join, + creator_home_instance_actions_join, + creator_local_instance_actions_join, + creator_local_user_admin_join, + image_details_join, + my_comment_actions_join, + my_community_actions_join, + my_local_user_admin_join, + my_person_actions_join, + my_post_actions_join, + }, }, seconds_to_pg_interval, DbPool, @@ -338,7 +342,7 @@ impl SearchCombinedQuery { ListingType::ModeratorView => { query.filter(community_actions::became_moderator_at.is_not_null()) } - ListingType::Suggested => query.filter(suggested_communities()), + ListingType::Suggested => query.filter(filter_suggested_communities()), }; // Filter by the time range if let Some(time_range_seconds) = self.time_range_seconds { @@ -430,8 +434,10 @@ impl InternalToCombinedView for SearchCombinedViewInternal { post_tags: v.post_tags, can_mod: v.can_mod, creator_banned: v.creator_banned, + creator_ban_expires_at: v.creator_ban_expires_at, creator_is_moderator: v.creator_is_moderator, creator_banned_from_community: v.creator_banned_from_community, + creator_community_ban_expires_at: v.creator_community_ban_expires_at, })) } else if let (Some(post), Some(creator), Some(community)) = (v.post, v.item_creator.clone(), v.community.clone()) @@ -448,8 +454,10 @@ impl InternalToCombinedView for SearchCombinedViewInternal { tags: v.post_tags, can_mod: v.can_mod, creator_banned: v.creator_banned, + creator_ban_expires_at: v.creator_ban_expires_at, creator_is_moderator: v.creator_is_moderator, creator_banned_from_community: v.creator_banned_from_community, + creator_community_ban_expires_at: v.creator_community_ban_expires_at, })) } else if let Some(community) = v.community { Some(SearchCombinedView::Community(CommunityView { @@ -469,6 +477,7 @@ impl InternalToCombinedView for SearchCombinedViewInternal { is_admin: v.item_creator_is_admin, person_actions: v.person_actions, creator_banned: v.creator_banned, + creator_ban_expires_at: v.creator_ban_expires_at, })) } else { None @@ -536,6 +545,7 @@ mod tests { local_user: timmy_local_user, person: timmy.clone(), banned: false, + ban_expires_at: None, }; let community_form = CommunityInsertForm { diff --git a/crates/db_views/search_combined/src/lib.rs b/crates/db_views/search_combined/src/lib.rs index fd73f9468..9918c5659 100644 --- a/crates/db_views/search_combined/src/lib.rs +++ b/crates/db_views/search_combined/src/lib.rs @@ -1,3 +1,4 @@ +use chrono::{DateTime, Utc}; use lemmy_db_schema::{ newtypes::{CommunityId, PaginationCursor, PersonId}, source::{ @@ -23,14 +24,18 @@ use serde_with::skip_serializing_none; #[cfg(feature = "full")] use { diesel::{Queryable, Selectable}, - lemmy_db_schema::utils::queries::{ + lemmy_db_schema::utils::queries::selects::{ community_post_tags_fragment, - creator_banned, + creator_ban_expires_from_community, + creator_banned_from_community, creator_is_admin, + creator_is_moderator, + creator_local_home_ban_expires, + creator_local_home_banned, local_user_can_mod, post_tags_fragment, + CreatorLocalHomeBanExpiresType, }, - lemmy_db_schema::utils::queries::{creator_banned_from_community, creator_is_moderator}, lemmy_db_views_local_user::LocalUserView, }; @@ -92,10 +97,17 @@ pub(crate) struct SearchCombinedViewInternal { pub can_mod: bool, #[cfg_attr(feature = "full", diesel( - select_expression = creator_banned() + select_expression = creator_local_home_banned() ) )] pub creator_banned: bool, + #[cfg_attr(feature = "full", + diesel( + select_expression_type = CreatorLocalHomeBanExpiresType, + select_expression = creator_local_home_ban_expires() + ) + )] + pub creator_ban_expires_at: Option>, #[cfg_attr(feature = "full", diesel( select_expression = creator_is_moderator() @@ -108,6 +120,12 @@ pub(crate) struct SearchCombinedViewInternal { ) )] pub creator_banned_from_community: bool, + #[cfg_attr(feature = "full", + diesel( + select_expression = creator_ban_expires_from_community() + ) + )] + pub creator_community_ban_expires_at: Option>, } #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] diff --git a/crates/db_views/vote/src/impls.rs b/crates/db_views/vote/src/impls.rs index 0a293b81a..3790bc153 100644 --- a/crates/db_views/vote/src/impls.rs +++ b/crates/db_views/vote/src/impls.rs @@ -17,9 +17,8 @@ use lemmy_db_schema::{ limit_fetch, paginate, queries::{ - creator_banned, - creator_home_instance_actions_join, - creator_local_instance_actions_join, + joins::{creator_home_instance_actions_join, creator_local_instance_actions_join}, + selects::creator_local_home_banned, }, DbPool, }, @@ -89,7 +88,7 @@ impl VoteView { .filter(post_actions::like_score.is_not_null()) .select(( person::all_columns, - creator_banned(), + creator_local_home_banned(), creator_community_actions .field(community_actions::received_ban_at) .nullable() @@ -163,7 +162,7 @@ impl VoteView { .filter(comment_actions::like_score.is_not_null()) .select(( person::all_columns, - creator_banned(), + creator_local_home_banned(), creator_community_actions .field(community_actions::received_ban_at) .nullable()