mirror of
https://github.com/AtHeartEngineer/lemmy.git
synced 2026-01-09 05:18:04 -05:00
Adding a can_mod field to CommentView, PostView, and CommunityView. (#5398)
* Adding a can_mod field to CommentView, PostView, and CommunityView. - Also removes the moderators from GetPost, as that should no longer be necessary. - Fixes #4365 * Adding can_mod to reply variants. * Addressing PR comments. * Hiding comment.content for non-admins / mods. - Uses the local_user_can_mod function now. - Fixes #5232
This commit is contained in:
@@ -4,13 +4,7 @@ use lemmy_db_schema::{
|
||||
PostFeatureType,
|
||||
PostSortType,
|
||||
};
|
||||
use lemmy_db_views::structs::{
|
||||
CommunityModeratorView,
|
||||
CommunityView,
|
||||
PaginationCursor,
|
||||
PostView,
|
||||
VoteView,
|
||||
};
|
||||
use lemmy_db_views::structs::{CommunityView, PaginationCursor, PostView, VoteView};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::skip_serializing_none;
|
||||
#[cfg(feature = "full")]
|
||||
@@ -77,7 +71,6 @@ pub struct GetPost {
|
||||
pub struct GetPostResponse {
|
||||
pub post_view: PostView,
|
||||
pub community_view: CommunityView,
|
||||
pub moderators: Vec<CommunityModeratorView>,
|
||||
/// A list of cross-posts, or other times / communities this link has been posted to.
|
||||
pub cross_posts: Vec<PostView>,
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ use lemmy_db_schema::{
|
||||
};
|
||||
use lemmy_db_views::{
|
||||
post::post_view::PostQuery,
|
||||
structs::{CommunityModeratorView, CommunityView, LocalUserView, PostView, SiteView},
|
||||
structs::{CommunityView, LocalUserView, PostView, SiteView},
|
||||
};
|
||||
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
|
||||
|
||||
@@ -84,8 +84,6 @@ pub async fn get_post(
|
||||
)
|
||||
.await?;
|
||||
|
||||
let moderators = CommunityModeratorView::for_community(&mut context.pool(), community_id).await?;
|
||||
|
||||
// Fetch the cross_posts
|
||||
let cross_posts = if let Some(url) = &post_view.post.url {
|
||||
let mut x_posts = PostQuery {
|
||||
@@ -108,7 +106,6 @@ pub async fn get_post(
|
||||
Ok(Json(GetPostResponse {
|
||||
post_view,
|
||||
community_view,
|
||||
moderators,
|
||||
cross_posts,
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::{
|
||||
diesel::{DecoratableTarget, OptionalExtension},
|
||||
impls::local_user::local_user_can_mod,
|
||||
newtypes::{CommentId, DbUrl, PersonId},
|
||||
schema::{comment, comment_actions},
|
||||
source::comment::{
|
||||
@@ -16,9 +17,10 @@ use crate::{
|
||||
};
|
||||
use chrono::{DateTime, Utc};
|
||||
use diesel::{
|
||||
dsl::insert_into,
|
||||
dsl::{case_when, insert_into, not},
|
||||
expression::SelectableHelper,
|
||||
result::Error,
|
||||
BoolExpressionMethods,
|
||||
ExpressionMethods,
|
||||
NullableExpressionMethods,
|
||||
QueryDsl,
|
||||
@@ -124,6 +126,33 @@ impl Comment {
|
||||
}
|
||||
}
|
||||
|
||||
/// 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());
|
||||
let content = case_when(can_view_content, comment::content).otherwise("");
|
||||
|
||||
(
|
||||
comment::id,
|
||||
comment::creator_id,
|
||||
comment::post_id,
|
||||
content,
|
||||
comment::removed,
|
||||
comment::published,
|
||||
comment::updated,
|
||||
comment::deleted,
|
||||
comment::ap_id,
|
||||
comment::local,
|
||||
comment::path,
|
||||
comment::distinguished,
|
||||
comment::language_id,
|
||||
)
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Crud for Comment {
|
||||
type InsertForm = CommentInsertForm;
|
||||
|
||||
@@ -33,7 +33,7 @@ use crate::{
|
||||
use chrono::{DateTime, Utc};
|
||||
use diesel::{
|
||||
deserialize,
|
||||
dsl::{self, exists, insert_into, not},
|
||||
dsl::{exists, insert_into, not},
|
||||
expression::SelectableHelper,
|
||||
pg::Pg,
|
||||
result::Error,
|
||||
@@ -398,10 +398,6 @@ impl Bannable for CommunityPersonBan {
|
||||
}
|
||||
|
||||
impl CommunityFollower {
|
||||
pub fn select_subscribed_type() -> dsl::Nullable<community_actions::follow_state> {
|
||||
community_actions::follow_state.nullable()
|
||||
}
|
||||
|
||||
/// Check if a remote instance has any followers on local instance. For this it is enough to check
|
||||
/// if any follow relation is stored. Dont use this for local community.
|
||||
pub async fn check_has_local_followers(
|
||||
@@ -440,6 +436,14 @@ impl CommunityFollower {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
// I'd really like to have these on the impl, but unfortunately they have to be top level,
|
||||
// according to https://diesel.rs/guides/composing-applications.html
|
||||
#[diesel::dsl::auto_type]
|
||||
pub fn community_follower_select_subscribed_type() -> _ {
|
||||
community_actions::follow_state.nullable()
|
||||
}
|
||||
|
||||
impl Queryable<sql_types::Nullable<crate::schema::sql_types::CommunityFollowerState>, Pg>
|
||||
for SubscribedType
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::{
|
||||
aliases::creator_community_actions,
|
||||
newtypes::{CommunityId, DbUrl, LanguageId, LocalUserId, PersonId},
|
||||
schema::{community, community_actions, local_user, person, registration_application},
|
||||
source::{
|
||||
@@ -19,9 +20,12 @@ use bcrypt::{hash, DEFAULT_COST};
|
||||
use diesel::{
|
||||
dsl::{insert_into, not, IntervalDsl},
|
||||
result::Error,
|
||||
BoolExpressionMethods,
|
||||
CombineDsl,
|
||||
ExpressionMethods,
|
||||
JoinOnDsl,
|
||||
NullableExpressionMethods,
|
||||
PgExpressionMethods,
|
||||
QueryDsl,
|
||||
};
|
||||
use diesel_async::RunQueryDsl;
|
||||
@@ -295,6 +299,29 @@ impl LocalUser {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
// I'd really like to have these on the impl, but unfortunately they have to be top level,
|
||||
// according to https://diesel.rs/guides/composing-applications.html
|
||||
/// 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() -> _ {
|
||||
let am_admin = local_user::admin.nullable();
|
||||
let creator_became_moderator = creator_community_actions
|
||||
.field(community_actions::became_moderator)
|
||||
.nullable();
|
||||
|
||||
let am_higher_mod = community_actions::became_moderator
|
||||
.nullable()
|
||||
.le(creator_became_moderator);
|
||||
|
||||
am_admin.or(am_higher_mod).is_not_distinct_from(true)
|
||||
}
|
||||
|
||||
/// Adds some helper functions for an optional LocalUser
|
||||
pub trait LocalUserOptionHelper {
|
||||
fn person_id(&self) -> Option<PersonId>;
|
||||
|
||||
@@ -23,9 +23,10 @@ pub mod sensitive;
|
||||
pub mod schema;
|
||||
#[cfg(feature = "full")]
|
||||
pub mod aliases {
|
||||
use crate::schema::{community_actions, person};
|
||||
use crate::schema::{community_actions, local_user, person};
|
||||
diesel::alias!(
|
||||
community_actions as creator_community_actions: CreatorCommunityActions,
|
||||
local_user as creator_local_user: CreatorLocalUser,
|
||||
person as person1: Person1,
|
||||
person as person2: Person2,
|
||||
);
|
||||
|
||||
@@ -20,7 +20,8 @@ use diesel::{
|
||||
use diesel_async::RunQueryDsl;
|
||||
use i_love_jesus::PaginatedQueryBuilder;
|
||||
use lemmy_db_schema::{
|
||||
aliases::{self, creator_community_actions},
|
||||
aliases::{self, creator_community_actions, creator_local_user},
|
||||
impls::{community::community_follower_select_subscribed_type, local_user::local_user_can_mod},
|
||||
newtypes::PersonId,
|
||||
schema::{
|
||||
comment,
|
||||
@@ -44,10 +45,7 @@ use lemmy_db_schema::{
|
||||
private_message,
|
||||
tag,
|
||||
},
|
||||
source::{
|
||||
combined::inbox::{inbox_combined_keys as key, InboxCombined},
|
||||
community::CommunityFollower,
|
||||
},
|
||||
source::combined::inbox::{inbox_combined_keys as key, InboxCombined},
|
||||
traits::InternalToCombinedView,
|
||||
utils::{functions::coalesce, get_conn, DbPool},
|
||||
InboxDataType,
|
||||
@@ -98,10 +96,12 @@ impl InboxCombinedViewInternal {
|
||||
|
||||
let community_join = post::community_id.eq(community::id);
|
||||
|
||||
let local_user_join = local_user::table.on(
|
||||
let local_user_join = local_user::table.on(local_user::person_id.nullable().eq(my_person_id));
|
||||
|
||||
let creator_local_user_join = creator_local_user.on(
|
||||
item_creator
|
||||
.eq(local_user::person_id)
|
||||
.and(local_user::admin.eq(true)),
|
||||
.eq(creator_local_user.field(local_user::person_id))
|
||||
.and(creator_local_user.field(local_user::admin).eq(true)),
|
||||
);
|
||||
|
||||
let post_aggregates_join = post_aggregates::table.on(post::id.eq(post_aggregates::post_id));
|
||||
@@ -167,6 +167,7 @@ impl InboxCombinedViewInternal {
|
||||
.left_join(comment_aggregates_join)
|
||||
.left_join(creator_community_actions_join)
|
||||
.left_join(local_user_join)
|
||||
.left_join(creator_local_user_join)
|
||||
.left_join(community_actions_join)
|
||||
.left_join(instance_actions_join)
|
||||
.left_join(post_actions_join)
|
||||
@@ -307,10 +308,13 @@ impl InboxCombinedQuery {
|
||||
comment_aggregates::all_columns.nullable(),
|
||||
comment_actions::saved.nullable(),
|
||||
comment_actions::like_score.nullable(),
|
||||
CommunityFollower::select_subscribed_type(),
|
||||
community_follower_select_subscribed_type(),
|
||||
person::all_columns,
|
||||
aliases::person1.fields(person::all_columns),
|
||||
local_user::admin.nullable().is_not_null(),
|
||||
creator_local_user
|
||||
.field(local_user::admin)
|
||||
.nullable()
|
||||
.is_not_null(),
|
||||
creator_community_actions
|
||||
.field(community_actions::became_moderator)
|
||||
.nullable()
|
||||
@@ -321,6 +325,7 @@ impl InboxCombinedQuery {
|
||||
.is_not_null(),
|
||||
person_actions::blocked.nullable().is_not_null(),
|
||||
community_actions::received_ban.nullable().is_not_null(),
|
||||
local_user_can_mod(),
|
||||
))
|
||||
.into_boxed();
|
||||
|
||||
@@ -447,6 +452,7 @@ impl InternalToCombinedView for InboxCombinedViewInternal {
|
||||
saved: v.comment_saved,
|
||||
my_vote: v.my_comment_vote,
|
||||
banned_from_community: v.banned_from_community,
|
||||
can_mod: v.can_mod,
|
||||
}))
|
||||
} else if let (
|
||||
Some(person_comment_mention),
|
||||
@@ -478,6 +484,7 @@ impl InternalToCombinedView for InboxCombinedViewInternal {
|
||||
saved: v.comment_saved,
|
||||
my_vote: v.my_comment_vote,
|
||||
banned_from_community: v.banned_from_community,
|
||||
can_mod: v.can_mod,
|
||||
},
|
||||
))
|
||||
} else if let (
|
||||
@@ -513,6 +520,7 @@ impl InternalToCombinedView for InboxCombinedViewInternal {
|
||||
image_details: v.image_details,
|
||||
post_tags: v.post_tags,
|
||||
banned_from_community: v.banned_from_community,
|
||||
can_mod: v.can_mod,
|
||||
}))
|
||||
} else if let Some(private_message) = v.private_message {
|
||||
Some(InboxCombinedView::PrivateMessage(PrivateMessageView {
|
||||
|
||||
@@ -18,7 +18,8 @@ use diesel::{
|
||||
use diesel_async::RunQueryDsl;
|
||||
use i_love_jesus::PaginatedQueryBuilder;
|
||||
use lemmy_db_schema::{
|
||||
aliases::creator_community_actions,
|
||||
aliases::{creator_community_actions, creator_local_user},
|
||||
impls::{community::community_follower_select_subscribed_type, local_user::local_user_can_mod},
|
||||
newtypes::PersonId,
|
||||
schema::{
|
||||
comment,
|
||||
@@ -38,10 +39,7 @@ use lemmy_db_schema::{
|
||||
post_tag,
|
||||
tag,
|
||||
},
|
||||
source::{
|
||||
combined::person_content::{person_content_combined_keys as key, PersonContentCombined},
|
||||
community::CommunityFollower,
|
||||
},
|
||||
source::combined::person_content::{person_content_combined_keys as key, PersonContentCombined},
|
||||
traits::InternalToCombinedView,
|
||||
utils::{functions::coalesce, get_conn, DbPool},
|
||||
PersonContentType,
|
||||
@@ -86,11 +84,12 @@ impl PersonContentCombinedViewInternal {
|
||||
.eq(item_creator),
|
||||
),
|
||||
);
|
||||
let local_user_join = local_user::table.on(local_user::person_id.nullable().eq(my_person_id));
|
||||
|
||||
let local_user_join = local_user::table.on(
|
||||
let creator_local_user_join = creator_local_user.on(
|
||||
item_creator
|
||||
.eq(local_user::person_id)
|
||||
.and(local_user::admin.eq(true)),
|
||||
.eq(creator_local_user.field(local_user::person_id))
|
||||
.and(creator_local_user.field(local_user::admin).eq(true)),
|
||||
);
|
||||
|
||||
let community_actions_join = community_actions::table.on(
|
||||
@@ -132,6 +131,7 @@ impl PersonContentCombinedViewInternal {
|
||||
.inner_join(community_join)
|
||||
.left_join(creator_community_actions_join)
|
||||
.left_join(local_user_join)
|
||||
.left_join(creator_local_user_join)
|
||||
.left_join(community_actions_join)
|
||||
.left_join(post_actions_join)
|
||||
.left_join(person_actions_join)
|
||||
@@ -179,10 +179,12 @@ impl PersonContentCombinedViewInternal {
|
||||
),
|
||||
);
|
||||
|
||||
let local_user_join = local_user::table.on(
|
||||
let local_user_join = local_user::table.on(local_user::person_id.nullable().eq(my_person_id));
|
||||
|
||||
let creator_local_user_join = creator_local_user.on(
|
||||
item_creator
|
||||
.eq(local_user::person_id)
|
||||
.and(local_user::admin.eq(true)),
|
||||
.eq(creator_local_user.field(local_user::person_id))
|
||||
.and(creator_local_user.field(local_user::admin).eq(true)),
|
||||
);
|
||||
|
||||
let community_actions_join = community_actions::table.on(
|
||||
@@ -224,6 +226,7 @@ impl PersonContentCombinedViewInternal {
|
||||
.inner_join(community_join)
|
||||
.left_join(creator_community_actions_join)
|
||||
.left_join(local_user_join)
|
||||
.left_join(creator_local_user_join)
|
||||
.left_join(community_actions_join)
|
||||
.left_join(post_actions_join)
|
||||
.left_join(person_actions_join)
|
||||
@@ -327,8 +330,11 @@ impl PersonContentCombinedQuery {
|
||||
post::all_columns,
|
||||
community::all_columns,
|
||||
person::all_columns,
|
||||
CommunityFollower::select_subscribed_type(),
|
||||
local_user::admin.nullable().is_not_null(),
|
||||
community_follower_select_subscribed_type(),
|
||||
creator_local_user
|
||||
.field(local_user::admin)
|
||||
.nullable()
|
||||
.is_not_null(),
|
||||
creator_community_actions
|
||||
.field(community_actions::became_moderator)
|
||||
.nullable()
|
||||
@@ -339,6 +345,7 @@ impl PersonContentCombinedQuery {
|
||||
.is_not_null(),
|
||||
person_actions::blocked.nullable().is_not_null(),
|
||||
community_actions::received_ban.nullable().is_not_null(),
|
||||
local_user_can_mod(),
|
||||
))
|
||||
.into_boxed();
|
||||
|
||||
@@ -404,6 +411,7 @@ impl InternalToCombinedView for PersonContentCombinedViewInternal {
|
||||
saved: v.comment_saved,
|
||||
my_vote: v.my_comment_vote,
|
||||
banned_from_community: v.banned_from_community,
|
||||
can_mod: v.can_mod,
|
||||
}))
|
||||
} else {
|
||||
Some(PersonContentCombinedView::Post(PostView {
|
||||
@@ -424,6 +432,7 @@ impl InternalToCombinedView for PersonContentCombinedViewInternal {
|
||||
image_details: v.image_details,
|
||||
banned_from_community: v.banned_from_community,
|
||||
tags: v.post_tags,
|
||||
can_mod: v.can_mod,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,8 @@ use diesel::{
|
||||
use diesel_async::RunQueryDsl;
|
||||
use i_love_jesus::PaginatedQueryBuilder;
|
||||
use lemmy_db_schema::{
|
||||
aliases::creator_community_actions,
|
||||
aliases::{creator_community_actions, creator_local_user},
|
||||
impls::{community::community_follower_select_subscribed_type, local_user::local_user_can_mod},
|
||||
schema::{
|
||||
comment,
|
||||
comment_actions,
|
||||
@@ -32,10 +33,7 @@ use lemmy_db_schema::{
|
||||
post_tag,
|
||||
tag,
|
||||
},
|
||||
source::{
|
||||
combined::person_saved::{person_saved_combined_keys as key, PersonSavedCombined},
|
||||
community::CommunityFollower,
|
||||
},
|
||||
source::combined::person_saved::{person_saved_combined_keys as key, PersonSavedCombined},
|
||||
traits::InternalToCombinedView,
|
||||
utils::{functions::coalesce, get_conn, DbPool},
|
||||
PersonContentType,
|
||||
@@ -124,8 +122,11 @@ impl PersonSavedCombinedQuery {
|
||||
post::all_columns,
|
||||
community::all_columns,
|
||||
person::all_columns,
|
||||
CommunityFollower::select_subscribed_type(),
|
||||
local_user::admin.nullable().is_not_null(),
|
||||
community_follower_select_subscribed_type(),
|
||||
creator_local_user
|
||||
.field(local_user::admin)
|
||||
.nullable()
|
||||
.is_not_null(),
|
||||
creator_community_actions
|
||||
.field(community_actions::became_moderator)
|
||||
.nullable()
|
||||
@@ -136,6 +137,7 @@ impl PersonSavedCombinedQuery {
|
||||
.is_not_null(),
|
||||
person_actions::blocked.nullable().is_not_null(),
|
||||
community_actions::received_ban.nullable().is_not_null(),
|
||||
local_user_can_mod(),
|
||||
))
|
||||
.into_boxed();
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ use diesel_async::RunQueryDsl;
|
||||
use i_love_jesus::PaginatedQueryBuilder;
|
||||
use lemmy_db_schema::{
|
||||
aliases::{self, creator_community_actions},
|
||||
impls::community::community_follower_select_subscribed_type,
|
||||
newtypes::{CommunityId, PersonId, PostId},
|
||||
schema::{
|
||||
comment,
|
||||
@@ -43,10 +44,7 @@ use lemmy_db_schema::{
|
||||
private_message_report,
|
||||
report_combined,
|
||||
},
|
||||
source::{
|
||||
combined::report::{report_combined_keys as key, ReportCombined},
|
||||
community::CommunityFollower,
|
||||
},
|
||||
source::combined::report::{report_combined_keys as key, ReportCombined},
|
||||
traits::InternalToCombinedView,
|
||||
utils::{functions::coalesce, get_conn, DbPool, ReverseTimestampKey},
|
||||
ReportType,
|
||||
@@ -301,7 +299,7 @@ impl ReportCombinedQuery {
|
||||
person::all_columns,
|
||||
aliases::person1.fields(person::all_columns.nullable()),
|
||||
community::all_columns.nullable(),
|
||||
CommunityFollower::select_subscribed_type(),
|
||||
community_follower_select_subscribed_type(),
|
||||
aliases::person2.fields(person::all_columns.nullable()),
|
||||
local_user::admin.nullable().is_not_null(),
|
||||
creator_community_actions
|
||||
|
||||
@@ -22,7 +22,8 @@ use diesel::{
|
||||
use diesel_async::RunQueryDsl;
|
||||
use i_love_jesus::PaginatedQueryBuilder;
|
||||
use lemmy_db_schema::{
|
||||
aliases::creator_community_actions,
|
||||
aliases::{creator_community_actions, creator_local_user},
|
||||
impls::{community::community_follower_select_subscribed_type, local_user::local_user_can_mod},
|
||||
newtypes::{CommunityId, PersonId},
|
||||
schema::{
|
||||
comment,
|
||||
@@ -43,10 +44,7 @@ use lemmy_db_schema::{
|
||||
search_combined,
|
||||
tag,
|
||||
},
|
||||
source::{
|
||||
combined::search::{search_combined_keys as key, SearchCombined},
|
||||
community::CommunityFollower,
|
||||
},
|
||||
source::combined::search::{search_combined_keys as key, SearchCombined},
|
||||
traits::InternalToCombinedView,
|
||||
utils::{
|
||||
functions::coalesce,
|
||||
@@ -118,10 +116,13 @@ impl SearchCombinedViewInternal {
|
||||
.eq(item_creator),
|
||||
),
|
||||
);
|
||||
let local_user_join = local_user::table.on(
|
||||
|
||||
let local_user_join = local_user::table.on(local_user::person_id.nullable().eq(my_person_id));
|
||||
|
||||
let creator_local_user_join = creator_local_user.on(
|
||||
item_creator
|
||||
.eq(local_user::person_id)
|
||||
.and(local_user::admin.eq(true)),
|
||||
.eq(creator_local_user.field(local_user::person_id))
|
||||
.and(creator_local_user.field(local_user::admin).eq(true)),
|
||||
);
|
||||
|
||||
let community_actions_join = community_actions::table.on(
|
||||
@@ -169,6 +170,7 @@ impl SearchCombinedViewInternal {
|
||||
.left_join(community_join)
|
||||
.left_join(creator_community_actions_join)
|
||||
.left_join(local_user_join)
|
||||
.left_join(creator_local_user_join)
|
||||
.left_join(community_actions_join)
|
||||
.left_join(post_actions_join)
|
||||
.left_join(person_actions_join)
|
||||
@@ -279,7 +281,7 @@ impl SearchCombinedQuery {
|
||||
community::all_columns.nullable(),
|
||||
community_aggregates::all_columns.nullable(),
|
||||
community_actions::blocked.nullable().is_not_null(),
|
||||
CommunityFollower::select_subscribed_type(),
|
||||
community_follower_select_subscribed_type(),
|
||||
// Person
|
||||
person_aggregates::all_columns.nullable(),
|
||||
// // Shared
|
||||
@@ -295,6 +297,7 @@ impl SearchCombinedQuery {
|
||||
.is_not_null(),
|
||||
person_actions::blocked.nullable().is_not_null(),
|
||||
community_actions::received_ban.nullable().is_not_null(),
|
||||
local_user_can_mod(),
|
||||
))
|
||||
.into_boxed();
|
||||
|
||||
@@ -461,6 +464,7 @@ impl InternalToCombinedView for SearchCombinedViewInternal {
|
||||
saved: v.comment_saved,
|
||||
my_vote: v.my_comment_vote,
|
||||
banned_from_community: v.banned_from_community,
|
||||
can_mod: v.can_mod,
|
||||
}))
|
||||
} else if let (
|
||||
Some(post),
|
||||
@@ -493,6 +497,7 @@ impl InternalToCombinedView for SearchCombinedViewInternal {
|
||||
image_details: v.image_details,
|
||||
banned_from_community: v.banned_from_community,
|
||||
tags: v.post_tags,
|
||||
can_mod: v.can_mod,
|
||||
}))
|
||||
} else if let (Some(community), Some(counts)) = (v.community, v.community_counts) {
|
||||
Some(SearchCombinedView::Community(CommunityView {
|
||||
@@ -501,6 +506,7 @@ impl InternalToCombinedView for SearchCombinedViewInternal {
|
||||
subscribed: v.subscribed,
|
||||
blocked: v.community_blocked,
|
||||
banned_from_community: v.banned_from_community,
|
||||
can_mod: v.can_mod,
|
||||
}))
|
||||
} else if let (Some(person), Some(counts)) = (v.item_creator, v.item_creator_counts) {
|
||||
Some(SearchCombinedView::Person(PersonView {
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
use crate::structs::{CommentSlimView, CommentView};
|
||||
use diesel::{
|
||||
dsl::{exists, not},
|
||||
dsl::exists,
|
||||
result::Error,
|
||||
BoolExpressionMethods,
|
||||
ExpressionMethods,
|
||||
JoinOnDsl,
|
||||
NullableExpressionMethods,
|
||||
PgTextExpressionMethods,
|
||||
QueryDsl,
|
||||
SelectableHelper,
|
||||
};
|
||||
@@ -23,13 +22,14 @@ use lemmy_db_schema::{
|
||||
community,
|
||||
community_actions,
|
||||
instance_actions,
|
||||
local_user,
|
||||
local_user_language,
|
||||
person,
|
||||
person_actions,
|
||||
post,
|
||||
},
|
||||
source::{community::CommunityFollowerState, local_user::LocalUser, site::Site},
|
||||
utils::{fuzzy_search, get_conn, limit_and_offset, now, seconds_to_pg_interval, DbPool},
|
||||
utils::{get_conn, limit_and_offset, now, seconds_to_pg_interval, DbPool},
|
||||
CommentSortType,
|
||||
CommunityVisibility,
|
||||
ListingType,
|
||||
@@ -75,6 +75,8 @@ impl CommentView {
|
||||
),
|
||||
);
|
||||
|
||||
let local_user_join = local_user::table.on(local_user::person_id.nullable().eq(my_person_id));
|
||||
|
||||
comment::table
|
||||
.inner_join(person::table)
|
||||
.inner_join(post::table)
|
||||
@@ -85,6 +87,7 @@ impl CommentView {
|
||||
.left_join(person_actions_join)
|
||||
.left_join(instance_actions_join)
|
||||
.left_join(comment_creator_community_actions_join)
|
||||
.left_join(local_user_join)
|
||||
}
|
||||
|
||||
pub async fn read(
|
||||
@@ -121,8 +124,7 @@ impl CommentView {
|
||||
res.my_vote = Some(0);
|
||||
}
|
||||
|
||||
let is_admin = my_local_user.map(|u| u.admin).unwrap_or(false);
|
||||
Ok(handle_deleted(res, is_admin))
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub fn map_to_slim(self) -> CommentSlimView {
|
||||
@@ -138,6 +140,7 @@ impl CommentView {
|
||||
saved: self.saved,
|
||||
creator_blocked: self.creator_blocked,
|
||||
my_vote: self.my_vote,
|
||||
can_mod: self.can_mod,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -152,7 +155,6 @@ pub struct CommentQuery<'a> {
|
||||
pub parent_path: Option<Ltree>,
|
||||
pub creator_id: Option<PersonId>,
|
||||
pub local_user: Option<&'a LocalUser>,
|
||||
pub search_term: Option<String>,
|
||||
pub liked_only: Option<bool>,
|
||||
pub disliked_only: Option<bool>,
|
||||
pub page: Option<i64>,
|
||||
@@ -184,14 +186,6 @@ impl CommentQuery<'_> {
|
||||
if let Some(parent_path) = o.parent_path.as_ref() {
|
||||
query = query.filter(comment::path.contained_by(parent_path));
|
||||
};
|
||||
//filtering out removed and deleted comments from search
|
||||
if let Some(search_term) = o.search_term {
|
||||
query = query.filter(
|
||||
comment::content
|
||||
.ilike(fuzzy_search(&search_term))
|
||||
.and(not(comment::removed.or(comment::deleted))),
|
||||
);
|
||||
};
|
||||
|
||||
if let Some(community_id) = o.community_id {
|
||||
query = query.filter(post::community_id.eq(community_id));
|
||||
@@ -330,26 +324,10 @@ impl CommentQuery<'_> {
|
||||
.load::<CommentView>(conn)
|
||||
.await?;
|
||||
|
||||
let is_admin = o.local_user.map(|u| u.admin).unwrap_or(false);
|
||||
|
||||
// Note: deleted and removed comments are done on the front side
|
||||
Ok(
|
||||
res
|
||||
.into_iter()
|
||||
.map(|c| handle_deleted(c, is_admin))
|
||||
.collect(),
|
||||
)
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
/// Only show deleted / removed content for admins.
|
||||
fn handle_deleted(mut c: CommentView, is_admin: bool) -> CommentView {
|
||||
if !is_admin && (c.comment.deleted || c.comment.removed) {
|
||||
c.comment.content = String::new();
|
||||
}
|
||||
c
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[expect(clippy::indexing_slicing)]
|
||||
mod tests {
|
||||
@@ -380,7 +358,7 @@ mod tests {
|
||||
},
|
||||
instance::Instance,
|
||||
language::Language,
|
||||
local_user::{LocalUser, LocalUserInsertForm},
|
||||
local_user::{LocalUser, LocalUserInsertForm, LocalUserUpdateForm},
|
||||
local_user_vote_display_mode::LocalUserVoteDisplayMode,
|
||||
person::{Person, PersonInsertForm},
|
||||
person_block::{PersonBlock, PersonBlockForm},
|
||||
@@ -565,6 +543,7 @@ mod tests {
|
||||
|
||||
let mut expected_comment_view_with_person = expected_comment_view_no_person.clone();
|
||||
expected_comment_view_with_person.my_vote = Some(1);
|
||||
expected_comment_view_with_person.can_mod = true;
|
||||
|
||||
let read_comment_views_no_person = CommentQuery {
|
||||
sort: (Some(CommentSortType::Old)),
|
||||
@@ -904,6 +883,7 @@ mod tests {
|
||||
subscribed: SubscribedType::NotSubscribed,
|
||||
saved: None,
|
||||
creator_blocked: false,
|
||||
can_mod: false,
|
||||
comment: Comment {
|
||||
id: data.inserted_comment_0.id,
|
||||
content: "Comment 0".into(),
|
||||
@@ -1253,6 +1233,16 @@ mod tests {
|
||||
Comment::update(pool, data.inserted_comment_0.id, &form).await?;
|
||||
|
||||
// Read as normal user, content is cleared
|
||||
// Timmy leaves admin
|
||||
LocalUser::update(
|
||||
pool,
|
||||
data.timmy_local_user_view.local_user.id,
|
||||
&LocalUserUpdateForm {
|
||||
admin: Some(false),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
data.timmy_local_user_view.local_user.admin = false;
|
||||
let comment_view = CommentView::read(
|
||||
pool,
|
||||
@@ -1272,6 +1262,15 @@ mod tests {
|
||||
assert_eq!("", comment_listing[0].comment.content);
|
||||
|
||||
// Read as admin, content is returned
|
||||
LocalUser::update(
|
||||
pool,
|
||||
data.timmy_local_user_view.local_user.id,
|
||||
&LocalUserUpdateForm {
|
||||
admin: Some(true),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
data.timmy_local_user_view.local_user.admin = true;
|
||||
let comment_view = CommentView::read(
|
||||
pool,
|
||||
|
||||
@@ -12,10 +12,11 @@ use diesel::{
|
||||
};
|
||||
use diesel_async::RunQueryDsl;
|
||||
use lemmy_db_schema::{
|
||||
impls::community::community_follower_select_subscribed_type,
|
||||
newtypes::{CommunityId, DbUrl, InstanceId, PersonId},
|
||||
schema::{community, community_actions, person},
|
||||
source::{
|
||||
community::{Community, CommunityFollower, CommunityFollowerState},
|
||||
community::{Community, CommunityFollowerState},
|
||||
person::Person,
|
||||
},
|
||||
utils::{get_conn, limit_and_offset, DbPool},
|
||||
@@ -150,7 +151,7 @@ impl CommunityFollowerView {
|
||||
person::all_columns,
|
||||
community::all_columns,
|
||||
is_new_instance,
|
||||
CommunityFollower::select_subscribed_type(),
|
||||
community_follower_select_subscribed_type(),
|
||||
))
|
||||
.into_boxed();
|
||||
if all_communities {
|
||||
|
||||
@@ -12,7 +12,7 @@ use diesel_async::RunQueryDsl;
|
||||
use lemmy_db_schema::{
|
||||
impls::local_user::LocalUserOptionHelper,
|
||||
newtypes::{CommunityId, PersonId},
|
||||
schema::{community, community_actions, community_aggregates, instance_actions},
|
||||
schema::{community, community_actions, community_aggregates, instance_actions, local_user},
|
||||
source::{
|
||||
community::{Community, CommunityFollowerState},
|
||||
local_user::LocalUser,
|
||||
@@ -38,10 +38,13 @@ impl CommunityView {
|
||||
.and(instance_actions::person_id.nullable().eq(person_id)),
|
||||
);
|
||||
|
||||
let local_user_join = local_user::table.on(local_user::person_id.nullable().eq(person_id));
|
||||
|
||||
community::table
|
||||
.inner_join(community_aggregates::table)
|
||||
.left_join(community_actions_join)
|
||||
.left_join(instance_actions_join)
|
||||
.left_join(local_user_join)
|
||||
}
|
||||
|
||||
pub async fn read(
|
||||
@@ -209,6 +212,8 @@ mod tests {
|
||||
CommunityFollowerForm,
|
||||
CommunityFollowerState,
|
||||
CommunityInsertForm,
|
||||
CommunityModerator,
|
||||
CommunityModeratorForm,
|
||||
CommunityUpdateForm,
|
||||
},
|
||||
instance::Instance,
|
||||
@@ -216,7 +221,7 @@ mod tests {
|
||||
person::{Person, PersonInsertForm},
|
||||
site::Site,
|
||||
},
|
||||
traits::{Crud, Followable},
|
||||
traits::{Crud, Followable, Joinable},
|
||||
utils::{build_db_pool_for_tests, DbPool},
|
||||
CommunityVisibility,
|
||||
SubscribedType,
|
||||
@@ -446,4 +451,56 @@ mod tests {
|
||||
|
||||
cleanup(data, pool).await
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
async fn can_mod() -> LemmyResult<()> {
|
||||
let pool = &build_db_pool_for_tests();
|
||||
let pool = &mut pool.into();
|
||||
let data = init_data(pool).await?;
|
||||
|
||||
// Make sure can_mod is false for all of them.
|
||||
CommunityQuery {
|
||||
local_user: Some(&data.local_user),
|
||||
..Default::default()
|
||||
}
|
||||
.list(&data.site, pool)
|
||||
.await?
|
||||
.into_iter()
|
||||
.for_each(|c| assert!(!c.can_mod));
|
||||
|
||||
let person_id = data.local_user.person_id;
|
||||
|
||||
// Now join the mod team of test community 1 and 2
|
||||
let mod_form_1 = CommunityModeratorForm {
|
||||
community_id: data.communities[0].id,
|
||||
person_id,
|
||||
};
|
||||
CommunityModerator::join(pool, &mod_form_1).await?;
|
||||
|
||||
let mod_form_2 = CommunityModeratorForm {
|
||||
community_id: data.communities[1].id,
|
||||
person_id,
|
||||
};
|
||||
CommunityModerator::join(pool, &mod_form_2).await?;
|
||||
|
||||
let mod_query = CommunityQuery {
|
||||
local_user: Some(&data.local_user),
|
||||
..Default::default()
|
||||
}
|
||||
.list(&data.site, pool)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|c| (c.community.name, c.can_mod))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let expected_communities = vec![
|
||||
("test_community_1".to_owned(), true),
|
||||
("test_community_2".to_owned(), true),
|
||||
("test_community_3".to_owned(), false),
|
||||
];
|
||||
assert_eq!(expected_communities, mod_query);
|
||||
|
||||
cleanup(data, pool).await
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -11,6 +11,7 @@ use diesel::{
|
||||
use diesel_async::RunQueryDsl;
|
||||
use lemmy_db_schema::{
|
||||
aliases::{self, creator_community_actions},
|
||||
impls::community::community_follower_select_subscribed_type,
|
||||
newtypes::{CommentReportId, PersonId},
|
||||
schema::{
|
||||
comment,
|
||||
@@ -24,7 +25,6 @@ use lemmy_db_schema::{
|
||||
person_actions,
|
||||
post,
|
||||
},
|
||||
source::community::CommunityFollower,
|
||||
utils::{functions::coalesce, get_conn, DbPool},
|
||||
};
|
||||
|
||||
@@ -135,7 +135,7 @@ impl CommentReportView {
|
||||
.is_not_null(),
|
||||
local_user::admin.nullable().is_not_null(),
|
||||
person_actions::blocked.nullable().is_not_null(),
|
||||
CommunityFollower::select_subscribed_type(),
|
||||
community_follower_select_subscribed_type(),
|
||||
comment_actions::saved.nullable(),
|
||||
comment_actions::like_score.nullable(),
|
||||
aliases::person2.fields(person::all_columns).nullable(),
|
||||
|
||||
@@ -10,6 +10,7 @@ use diesel::{
|
||||
use diesel_async::RunQueryDsl;
|
||||
use lemmy_db_schema::{
|
||||
aliases::{self, creator_community_actions},
|
||||
impls::community::community_follower_select_subscribed_type,
|
||||
newtypes::{PersonId, PostReportId},
|
||||
schema::{
|
||||
community,
|
||||
@@ -22,7 +23,6 @@ use lemmy_db_schema::{
|
||||
post_aggregates,
|
||||
post_report,
|
||||
},
|
||||
source::community::CommunityFollower,
|
||||
utils::{functions::coalesce, get_conn, DbPool},
|
||||
};
|
||||
|
||||
@@ -119,7 +119,7 @@ impl PostReportView {
|
||||
.nullable()
|
||||
.is_not_null(),
|
||||
local_user::admin.nullable().is_not_null(),
|
||||
CommunityFollower::select_subscribed_type(),
|
||||
community_follower_select_subscribed_type(),
|
||||
post_actions::saved.nullable(),
|
||||
post_actions::read.nullable().is_not_null(),
|
||||
post_actions::hidden.nullable().is_not_null(),
|
||||
|
||||
@@ -3,12 +3,14 @@ use chrono::{DateTime, Utc};
|
||||
use diesel::{
|
||||
deserialize::FromSqlRow,
|
||||
dsl::exists,
|
||||
|
||||
dsl::Nullable,
|
||||
expression::AsExpression,
|
||||
sql_types,
|
||||
BoolExpressionMethods,
|
||||
ExpressionMethods,
|
||||
NullableExpressionMethods,
|
||||
PgExpressionMethods,
|
||||
QueryDsl,
|
||||
Queryable,
|
||||
Selectable,
|
||||
@@ -73,9 +75,11 @@ use lemmy_db_schema::{
|
||||
};
|
||||
#[cfg(feature = "full")]
|
||||
use lemmy_db_schema::{
|
||||
aliases::{creator_community_actions, person1},
|
||||
aliases::{creator_community_actions, creator_local_user, person1},
|
||||
impls::comment::comment_select_remove_deletes,
|
||||
impls::community::community_follower_select_subscribed_type,
|
||||
impls::local_user::local_user_can_mod,
|
||||
schema::{comment, comment_actions, community_actions, local_user, person, person_actions},
|
||||
source::community::CommunityFollower,
|
||||
utils::functions::coalesce,
|
||||
Person1AliasAllColumnsTuple,
|
||||
};
|
||||
@@ -119,7 +123,11 @@ pub struct CommentReportView {
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// A comment view.
|
||||
pub struct CommentView {
|
||||
#[cfg_attr(feature = "full", diesel(embed))]
|
||||
#[cfg_attr(feature = "full",
|
||||
diesel(
|
||||
select_expression = comment_select_remove_deletes()
|
||||
)
|
||||
)]
|
||||
pub comment: Comment,
|
||||
#[cfg_attr(feature = "full", diesel(embed))]
|
||||
pub creator: Person,
|
||||
@@ -159,21 +167,17 @@ pub struct CommentView {
|
||||
#[cfg_attr(feature = "full",
|
||||
diesel(
|
||||
select_expression =
|
||||
exists(
|
||||
local_user::table.filter(
|
||||
comment::creator_id
|
||||
.eq(local_user::person_id)
|
||||
.and(local_user::admin.eq(true))
|
||||
)
|
||||
)
|
||||
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)),
|
||||
))
|
||||
)
|
||||
)]
|
||||
pub creator_is_admin: bool,
|
||||
#[cfg_attr(feature = "full",
|
||||
diesel(
|
||||
select_expression_type = Nullable<community_actions::follow_state>,
|
||||
select_expression =
|
||||
CommunityFollower::select_subscribed_type(),
|
||||
select_expression = community_follower_select_subscribed_type(),
|
||||
)
|
||||
)]
|
||||
pub subscribed: SubscribedType,
|
||||
@@ -201,6 +205,12 @@ pub struct CommentView {
|
||||
)
|
||||
)]
|
||||
pub my_vote: Option<i16>,
|
||||
#[cfg_attr(feature = "full",
|
||||
diesel(
|
||||
select_expression = local_user_can_mod()
|
||||
)
|
||||
)]
|
||||
pub can_mod: bool,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
@@ -224,6 +234,7 @@ pub struct CommentSlimView {
|
||||
pub creator_blocked: bool,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub my_vote: Option<i16>,
|
||||
pub can_mod: bool,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
@@ -343,6 +354,7 @@ pub struct PostView {
|
||||
pub my_vote: Option<i16>,
|
||||
pub unread_comments: i64,
|
||||
pub tags: PostTags,
|
||||
pub can_mod: bool,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
@@ -513,6 +525,7 @@ pub(crate) struct PersonContentCombinedViewInternal {
|
||||
pub item_creator_banned_from_community: bool,
|
||||
pub item_creator_blocked: bool,
|
||||
pub banned_from_community: bool,
|
||||
pub can_mod: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
||||
@@ -570,8 +583,7 @@ pub struct CommunityView {
|
||||
pub community: Community,
|
||||
#[cfg_attr(feature = "full",
|
||||
diesel(
|
||||
select_expression_type = Nullable<community_actions::follow_state>,
|
||||
select_expression = CommunityFollower::select_subscribed_type()
|
||||
select_expression = community_follower_select_subscribed_type()
|
||||
)
|
||||
)]
|
||||
pub subscribed: SubscribedType,
|
||||
@@ -589,6 +601,14 @@ pub struct CommunityView {
|
||||
)
|
||||
)]
|
||||
pub banned_from_community: bool,
|
||||
#[cfg_attr(feature = "full",
|
||||
diesel(
|
||||
select_expression = local_user::admin.nullable()
|
||||
.or(community_actions::became_moderator.nullable().is_not_null())
|
||||
.is_not_distinct_from(true)
|
||||
)
|
||||
)]
|
||||
pub can_mod: bool,
|
||||
}
|
||||
|
||||
/// The community sort types. See here for descriptions: https://join-lemmy.org/docs/en/users/03-votes-and-ranking.html
|
||||
@@ -637,6 +657,7 @@ pub struct PersonCommentMentionView {
|
||||
pub creator_blocked: bool,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub my_vote: Option<i16>,
|
||||
pub can_mod: bool,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
@@ -669,6 +690,7 @@ pub struct PersonPostMentionView {
|
||||
pub my_vote: Option<i16>,
|
||||
pub unread_comments: i64,
|
||||
pub post_tags: PostTags,
|
||||
pub can_mod: bool,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
@@ -696,6 +718,7 @@ pub struct CommentReplyView {
|
||||
pub creator_blocked: bool,
|
||||
#[cfg_attr(feature = "full", ts(optional))]
|
||||
pub my_vote: Option<i16>,
|
||||
pub can_mod: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
||||
@@ -789,6 +812,7 @@ pub struct InboxCombinedViewInternal {
|
||||
pub item_creator_banned_from_community: bool,
|
||||
pub item_creator_blocked: bool,
|
||||
pub banned_from_community: bool,
|
||||
pub can_mod: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
||||
@@ -1167,6 +1191,7 @@ pub(crate) struct SearchCombinedViewInternal {
|
||||
pub item_creator_banned_from_community: bool,
|
||||
pub item_creator_blocked: bool,
|
||||
pub banned_from_community: bool,
|
||||
pub can_mod: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
||||
|
||||
Reference in New Issue
Block a user