Adding the full combined view queries.

This commit is contained in:
Dessalines 2024-12-09 14:34:53 -05:00
parent 6363e7d5db
commit 9d36f1f176
33 changed files with 913 additions and 1488 deletions

2
Cargo.lock generated
View file

@ -2720,7 +2720,9 @@ version = "0.19.6-beta.7"
dependencies = [
"diesel",
"diesel-async",
"i-love-jesus",
"lemmy_db_schema",
"lemmy_utils",
"serde",
"serde_with",
"ts-rs",

View file

@ -4,30 +4,10 @@ use lemmy_api_common::{
site::{GetModlog, GetModlogResponse},
utils::{check_community_mod_of_any_or_admin_action, check_private_instance},
};
use lemmy_db_schema::{source::local_site::LocalSite, ModlogActionType};
use lemmy_db_schema::source::local_site::LocalSite;
use lemmy_db_views::structs::LocalUserView;
use lemmy_db_views_moderator::structs::{
AdminAllowInstanceView,
AdminBlockInstanceView,
AdminPurgeCommentView,
AdminPurgeCommunityView,
AdminPurgePersonView,
AdminPurgePostView,
ModAddCommunityView,
ModAddView,
ModBanFromCommunityView,
ModBanView,
ModFeaturePostView,
ModHideCommunityView,
ModLockPostView,
ModRemoveCommentView,
ModRemoveCommunityView,
ModRemovePostView,
ModTransferCommunityView,
ModlogListParams,
};
use lemmy_db_views_moderator::{self, modlog_combined_view::ModlogCombinedQuery};
use lemmy_utils::error::LemmyResult;
use ModlogActionType::*;
#[tracing::instrument(skip(context))]
pub async fn get_mod_log(
@ -39,7 +19,7 @@ pub async fn get_mod_log(
check_private_instance(&local_user_view, &local_site)?;
let type_ = data.type_.unwrap_or(All);
let type_ = data.type_;
let community_id = data.community_id;
let is_mod_or_admin = if let Some(local_user_view) = local_user_view {
@ -56,150 +36,31 @@ pub async fn get_mod_log(
} else {
data.mod_person_id
};
let other_person_id = data.other_person_id;
let modded_person_id = data.modded_person_id;
let post_id = data.post_id;
let comment_id = data.comment_id;
let params = ModlogListParams {
// parse pagination token
let page_after = if let Some(pa) = &data.page_cursor {
Some(pa.read(&mut context.pool()).await?)
} else {
None
};
let page_back = data.page_back;
let modlog = ModlogCombinedQuery {
type_,
community_id,
mod_person_id,
other_person_id,
modded_person_id,
post_id,
comment_id,
page: data.page,
limit: data.limit,
hide_modlog_names,
};
let removed_posts = match type_ {
All | ModRemovePost => ModRemovePostView::list(&mut context.pool(), params).await?,
_ => Default::default(),
};
page_after,
page_back,
}
.list(&mut context.pool())
.await?;
let locked_posts = match type_ {
All | ModLockPost => ModLockPostView::list(&mut context.pool(), params).await?,
_ => Default::default(),
};
let featured_posts = match type_ {
All | ModFeaturePost => ModFeaturePostView::list(&mut context.pool(), params).await?,
_ => Default::default(),
};
let removed_comments = match type_ {
All | ModRemoveComment => ModRemoveCommentView::list(&mut context.pool(), params).await?,
_ => Default::default(),
};
let banned_from_community = match type_ {
All | ModBanFromCommunity => ModBanFromCommunityView::list(&mut context.pool(), params).await?,
_ => Default::default(),
};
let added_to_community = match type_ {
All | ModAddCommunity => ModAddCommunityView::list(&mut context.pool(), params).await?,
_ => Default::default(),
};
let transferred_to_community = match type_ {
All | ModTransferCommunity => {
ModTransferCommunityView::list(&mut context.pool(), params).await?
}
_ => Default::default(),
};
let hidden_communities = match type_ {
All | ModHideCommunity if other_person_id.is_none() => {
ModHideCommunityView::list(&mut context.pool(), params).await?
}
_ => Default::default(),
};
// These arrays are only for the full modlog, when a community isn't given
let (
banned,
added,
removed_communities,
admin_purged_persons,
admin_purged_communities,
admin_purged_posts,
admin_purged_comments,
admin_block_instance,
admin_allow_instance,
) = if data.community_id.is_none() {
(
match type_ {
All | ModBan => ModBanView::list(&mut context.pool(), params).await?,
_ => Default::default(),
},
match type_ {
All | ModAdd => ModAddView::list(&mut context.pool(), params).await?,
_ => Default::default(),
},
match type_ {
All | ModRemoveCommunity if other_person_id.is_none() => {
ModRemoveCommunityView::list(&mut context.pool(), params).await?
}
_ => Default::default(),
},
match type_ {
All | AdminPurgePerson if other_person_id.is_none() => {
AdminPurgePersonView::list(&mut context.pool(), params).await?
}
_ => Default::default(),
},
match type_ {
All | AdminPurgeCommunity if other_person_id.is_none() => {
AdminPurgeCommunityView::list(&mut context.pool(), params).await?
}
_ => Default::default(),
},
match type_ {
All | AdminPurgePost if other_person_id.is_none() => {
AdminPurgePostView::list(&mut context.pool(), params).await?
}
_ => Default::default(),
},
match type_ {
All | AdminPurgeComment if other_person_id.is_none() => {
AdminPurgeCommentView::list(&mut context.pool(), params).await?
}
_ => Default::default(),
},
match type_ {
All | AdminBlockInstance if other_person_id.is_none() => {
AdminBlockInstanceView::list(&mut context.pool(), params).await?
}
_ => Default::default(),
},
match type_ {
All | AdminAllowInstance if other_person_id.is_none() => {
AdminAllowInstanceView::list(&mut context.pool(), params).await?
}
_ => Default::default(),
},
)
} else {
Default::default()
};
// Return the jwt
Ok(Json(GetModlogResponse {
removed_posts,
locked_posts,
featured_posts,
removed_comments,
removed_communities,
banned_from_community,
banned,
added_to_community,
added,
transferred_to_community,
admin_purged_persons,
admin_purged_communities,
admin_purged_posts,
admin_purged_comments,
hidden_communities,
admin_block_instance,
admin_allow_instance,
}))
Ok(Json(GetModlogResponse { modlog }))
}

View file

@ -42,25 +42,7 @@ use lemmy_db_views_actor::structs::{
CommunityView,
PersonView,
};
use lemmy_db_views_moderator::structs::{
AdminAllowInstanceView,
AdminBlockInstanceView,
AdminPurgeCommentView,
AdminPurgeCommunityView,
AdminPurgePersonView,
AdminPurgePostView,
ModAddCommunityView,
ModAddView,
ModBanFromCommunityView,
ModBanView,
ModFeaturePostView,
ModHideCommunityView,
ModLockPostView,
ModRemoveCommentView,
ModRemoveCommunityView,
ModRemovePostView,
ModTransferCommunityView,
};
use lemmy_db_views_moderator::structs::{ModlogCombinedPaginationCursor, ModlogCombinedView};
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
#[cfg(feature = "full")]
@ -139,7 +121,7 @@ pub struct ResolveObjectResponse {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Fetches the modlog.
@ -149,17 +131,17 @@ pub struct GetModlog {
#[cfg_attr(feature = "full", ts(optional))]
pub community_id: Option<CommunityId>,
#[cfg_attr(feature = "full", ts(optional))]
pub page: Option<i64>,
#[cfg_attr(feature = "full", ts(optional))]
pub limit: Option<i64>,
#[cfg_attr(feature = "full", ts(optional))]
pub type_: Option<ModlogActionType>,
#[cfg_attr(feature = "full", ts(optional))]
pub other_person_id: Option<PersonId>,
pub modded_person_id: Option<PersonId>,
#[cfg_attr(feature = "full", ts(optional))]
pub post_id: Option<PostId>,
#[cfg_attr(feature = "full", ts(optional))]
pub comment_id: Option<CommentId>,
#[cfg_attr(feature = "full", ts(optional))]
pub page_cursor: Option<ModlogCombinedPaginationCursor>,
#[cfg_attr(feature = "full", ts(optional))]
pub page_back: Option<bool>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
@ -168,23 +150,7 @@ pub struct GetModlog {
/// The modlog fetch response.
// TODO this should be redone as a list of tagged enums
pub struct GetModlogResponse {
pub removed_posts: Vec<ModRemovePostView>,
pub locked_posts: Vec<ModLockPostView>,
pub featured_posts: Vec<ModFeaturePostView>,
pub removed_comments: Vec<ModRemoveCommentView>,
pub removed_communities: Vec<ModRemoveCommunityView>,
pub banned_from_community: Vec<ModBanFromCommunityView>,
pub banned: Vec<ModBanView>,
pub added_to_community: Vec<ModAddCommunityView>,
pub transferred_to_community: Vec<ModTransferCommunityView>,
pub added: Vec<ModAddView>,
pub admin_purged_persons: Vec<AdminPurgePersonView>,
pub admin_purged_communities: Vec<AdminPurgeCommunityView>,
pub admin_purged_posts: Vec<AdminPurgePostView>,
pub admin_purged_comments: Vec<AdminPurgeCommentView>,
pub hidden_communities: Vec<ModHideCommunityView>,
pub admin_block_instance: Vec<AdminBlockInstanceView>,
pub admin_allow_instance: Vec<AdminAllowInstanceView>,
pub modlog: Vec<ModlogCombinedView>,
}
#[skip_serializing_none]

View file

@ -1187,16 +1187,18 @@ fn build_proxied_image_url(
mod tests {
use super::*;
use lemmy_db_schema::source::{
comment::CommentInsertForm,
community::CommunityInsertForm,
person::PersonInsertForm,
post::PostInsertForm,
use lemmy_db_schema::{
source::{
comment::CommentInsertForm,
community::CommunityInsertForm,
person::PersonInsertForm,
post::PostInsertForm,
},
ModlogActionType,
};
use lemmy_db_views_moderator::structs::{
ModRemoveCommentView,
ModRemovePostView,
ModlogListParams,
use lemmy_db_views_moderator::{
modlog_combined_view::ModlogCombinedQuery,
structs::ModlogCombinedView,
};
use pretty_assertions::assert_eq;
use serial_test::serial;
@ -1332,45 +1334,58 @@ mod tests {
.await?;
// Verify that their posts and comments are removed.
let params = ModlogListParams {
community_id: None,
mod_person_id: None,
other_person_id: None,
post_id: None,
comment_id: None,
page: None,
limit: None,
hide_modlog_names: false,
};
// Posts
let post_modlog = ModRemovePostView::list(pool, params).await?;
let post_modlog = ModlogCombinedQuery {
type_: Some(ModlogActionType::ModRemovePost),
..Default::default()
}
.list(pool)
.await?;
assert_eq!(2, post_modlog.len());
let mod_removed_posts = post_modlog
.iter()
let posts_mapped = &post_modlog.iter().filter_map(|p| {
if let ModlogCombinedView::ModRemovePost(v) = p {
Some(v)
} else {
None
}
});
let mod_removed_posts = posts_mapped
.clone()
.map(|p| p.mod_remove_post.removed)
.collect::<Vec<bool>>();
assert_eq!(vec![true, true], mod_removed_posts);
let removed_posts = post_modlog
.iter()
let removed_posts = posts_mapped
.clone()
.map(|p| p.post.removed)
.collect::<Vec<bool>>();
assert_eq!(vec![true, true], removed_posts);
// Comments
let comment_modlog = ModRemoveCommentView::list(pool, params).await?;
let comment_modlog = ModlogCombinedQuery {
type_: Some(ModlogActionType::ModRemoveComment),
..Default::default()
}
.list(pool)
.await?;
assert_eq!(2, comment_modlog.len());
let mod_removed_comments = comment_modlog
.iter()
let comments_mapped = &comment_modlog.iter().filter_map(|c| {
if let ModlogCombinedView::ModRemoveComment(v) = c {
Some(v)
} else {
None
}
});
let mod_removed_comments = comments_mapped
.clone()
.map(|p| p.mod_remove_comment.removed)
.collect::<Vec<bool>>();
assert_eq!(vec![true, true], mod_removed_comments);
let removed_comments = comment_modlog
.iter()
let removed_comments = comments_mapped
.clone()
.map(|p| p.comment.removed)
.collect::<Vec<bool>>();
assert_eq!(vec![true, true], removed_comments);
@ -1386,34 +1401,60 @@ mod tests {
.await?;
// Posts
let post_modlog = ModRemovePostView::list(pool, params).await?;
let post_modlog = ModlogCombinedQuery {
type_: Some(ModlogActionType::ModRemovePost),
..Default::default()
}
.list(pool)
.await?;
assert_eq!(4, post_modlog.len());
let mod_restored_posts = post_modlog
.iter()
let posts_mapped = &post_modlog.iter().filter_map(|p| {
if let ModlogCombinedView::ModRemovePost(v) = p {
Some(v)
} else {
None
}
});
let mod_restored_posts = posts_mapped
.clone()
.map(|p| p.mod_remove_post.removed)
.collect::<Vec<bool>>();
assert_eq!(vec![false, false, true, true], mod_restored_posts);
let restored_posts = post_modlog
.iter()
let restored_posts = posts_mapped
.clone()
.map(|p| p.post.removed)
.collect::<Vec<bool>>();
// All of these will be false, cause its the current state of the post
assert_eq!(vec![false, false, false, false], restored_posts);
// Comments
let comment_modlog = ModRemoveCommentView::list(pool, params).await?;
let comment_modlog = ModlogCombinedQuery {
type_: Some(ModlogActionType::ModRemoveComment),
..Default::default()
}
.list(pool)
.await?;
assert_eq!(4, comment_modlog.len());
let mod_restored_comments = comment_modlog
.iter()
let comments_mapped = &comment_modlog.iter().filter_map(|c| {
if let ModlogCombinedView::ModRemoveComment(v) = c {
Some(v)
} else {
None
}
});
let mod_restored_comments = comments_mapped
.clone()
.map(|p| p.mod_remove_comment.removed)
.collect::<Vec<bool>>();
assert_eq!(vec![false, false, true, true], mod_restored_comments);
let restored_comments = comment_modlog
.iter()
let restored_comments = comments_mapped
.clone()
.map(|p| p.comment.removed)
.collect::<Vec<bool>>();
assert_eq!(vec![false, false, false, false], restored_comments);

View file

@ -761,3 +761,61 @@ CALL r.create_person_saved_combined_trigger ('post');
CALL r.create_person_saved_combined_trigger ('comment');
-- modlog: (17 tables)
-- admin_allow_instance
-- admin_block_instance
-- admin_purge_comment
-- admin_purge_community
-- admin_purge_person
-- admin_purge_post
-- mod_add
-- mod_add_community
-- mod_ban
-- mod_ban_from_community
-- mod_feature_post
-- mod_hide_community
-- mod_lock_post
-- mod_remove_comment
-- mod_remove_community
-- mod_remove_post
-- mod_transfer_community
CREATE PROCEDURE r.create_modlog_combined_trigger (table_name text)
LANGUAGE plpgsql
AS $a$
BEGIN
EXECUTE replace($b$ CREATE FUNCTION r.modlog_combined_thing_insert ( )
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
INSERT INTO modlog_combined (published, thing_id)
VALUES (NEW.published, NEW.id);
RETURN NEW;
END $$;
CREATE TRIGGER modlog_combined
AFTER INSERT ON thing
FOR EACH ROW
EXECUTE FUNCTION r.modlog_combined_thing_insert ( );
$b$,
'thing',
table_name);
END;
$a$;
CALL r.create_modlog_combined_trigger ('admin_allow_instance');
CALL r.create_modlog_combined_trigger ('admin_block_instance');
CALL r.create_modlog_combined_trigger ('admin_purge_comment');
CALL r.create_modlog_combined_trigger ('admin_purge_community');
CALL r.create_modlog_combined_trigger ('admin_purge_person');
CALL r.create_modlog_combined_trigger ('admin_purge_post');
CALL r.create_modlog_combined_trigger ('mod_add');
CALL r.create_modlog_combined_trigger ('mod_add_community');
CALL r.create_modlog_combined_trigger ('mod_ban');
CALL r.create_modlog_combined_trigger ('mod_ban_from_community');
CALL r.create_modlog_combined_trigger ('mod_feature_post');
CALL r.create_modlog_combined_trigger ('mod_hide_community');
CALL r.create_modlog_combined_trigger ('mod_lock_post');
CALL r.create_modlog_combined_trigger ('mod_remove_comment');
CALL r.create_modlog_combined_trigger ('mod_remove_community');
CALL r.create_modlog_combined_trigger ('mod_remove_post');
CALL r.create_modlog_combined_trigger ('mod_transfer_community');

View file

@ -275,6 +275,13 @@ pub enum FederationMode {
Disable,
}
pub trait InternalToCombinedView {
type CombinedView;
/// Maps the combined DB row to an enum
fn map_to_enum(&self) -> Option<Self::CombinedView>;
}
/// Wrapper for assert_eq! macro. Checks that vec matches the given length, and prints the
/// vec on failure.
#[macro_export]

View file

@ -203,87 +203,87 @@ pub struct ModlogCombinedId(i32);
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
#[cfg_attr(feature = "full", ts(export))]
pub struct AdminAllowInstanceId(i32);
pub struct AdminAllowInstanceId(pub i32);
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
#[cfg_attr(feature = "full", ts(export))]
pub struct AdminBlockInstanceId(i32);
pub struct AdminBlockInstanceId(pub i32);
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
#[cfg_attr(feature = "full", ts(export))]
pub struct AdminPurgePersonId(i32);
pub struct AdminPurgePersonId(pub i32);
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
#[cfg_attr(feature = "full", ts(export))]
pub struct AdminPurgeCommunityId(i32);
pub struct AdminPurgeCommunityId(pub i32);
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
#[cfg_attr(feature = "full", ts(export))]
pub struct AdminPurgeCommentId(i32);
pub struct AdminPurgeCommentId(pub i32);
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
#[cfg_attr(feature = "full", ts(export))]
pub struct AdminPurgePostId(i32);
pub struct AdminPurgePostId(pub i32);
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
#[cfg_attr(feature = "full", ts(export))]
pub struct ModRemovePostId(i32);
pub struct ModRemovePostId(pub i32);
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
#[cfg_attr(feature = "full", ts(export))]
pub struct ModRemoveCommentId(i32);
pub struct ModRemoveCommentId(pub i32);
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
#[cfg_attr(feature = "full", ts(export))]
pub struct ModRemoveCommunityId(i32);
pub struct ModRemoveCommunityId(pub i32);
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
#[cfg_attr(feature = "full", ts(export))]
pub struct ModLockPostId(i32);
pub struct ModLockPostId(pub i32);
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
#[cfg_attr(feature = "full", ts(export))]
pub struct ModFeaturePostId(i32);
pub struct ModFeaturePostId(pub i32);
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
#[cfg_attr(feature = "full", ts(export))]
pub struct ModBanFromCommunityId(i32);
pub struct ModBanFromCommunityId(pub i32);
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
#[cfg_attr(feature = "full", ts(export))]
pub struct ModBanId(i32);
pub struct ModBanId(pub i32);
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
#[cfg_attr(feature = "full", ts(export))]
pub struct ModHideCommunityId(i32);
pub struct ModHideCommunityId(pub i32);
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
#[cfg_attr(feature = "full", ts(export))]
pub struct ModAddCommunityId(i32);
pub struct ModAddCommunityId(pub i32);
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
#[cfg_attr(feature = "full", ts(export))]
pub struct ModTransferCommunityId(i32);
pub struct ModTransferCommunityId(pub i32);
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
#[cfg_attr(feature = "full", ts(export))]
pub struct ModAddId(i32);
pub struct ModAddId(pub i32);
impl DbUrl {
pub fn inner(&self) -> &Url {

View file

@ -32,10 +32,3 @@ pub mod site_view;
pub mod structs;
#[cfg(feature = "full")]
pub mod vote_view;
pub trait InternalToCombinedView {
type CombinedView;
/// Maps the combined DB row to an enum
fn map_to_enum(&self) -> Option<Self::CombinedView>;
}

View file

@ -1,13 +1,10 @@
use crate::{
structs::{
CommentView,
LocalUserView,
PersonContentCombinedPaginationCursor,
PersonContentCombinedView,
PersonContentViewInternal,
PostView,
},
InternalToCombinedView,
use crate::structs::{
CommentView,
LocalUserView,
PersonContentCombinedPaginationCursor,
PersonContentCombinedView,
PersonContentViewInternal,
PostView,
};
use diesel::{
result::Error,
@ -43,6 +40,7 @@ use lemmy_db_schema::{
community::CommunityFollower,
},
utils::{actions, actions_alias, functions::coalesce, get_conn, DbPool},
InternalToCombinedView,
};
use lemmy_utils::error::LemmyResult;

View file

@ -1,11 +1,8 @@
use crate::{
structs::{
LocalUserView,
PersonContentCombinedView,
PersonContentViewInternal,
PersonSavedCombinedPaginationCursor,
},
InternalToCombinedView,
use crate::structs::{
LocalUserView,
PersonContentCombinedView,
PersonContentViewInternal,
PersonSavedCombinedPaginationCursor,
};
use diesel::{
result::Error,
@ -40,6 +37,7 @@ use lemmy_db_schema::{
community::CommunityFollower,
},
utils::{actions, actions_alias, functions::coalesce, get_conn, DbPool},
InternalToCombinedView,
};
use lemmy_utils::error::LemmyResult;

View file

@ -1,14 +1,11 @@
use crate::{
structs::{
CommentReportView,
LocalUserView,
PostReportView,
PrivateMessageReportView,
ReportCombinedPaginationCursor,
ReportCombinedView,
ReportCombinedViewInternal,
},
InternalToCombinedView,
use crate::structs::{
CommentReportView,
LocalUserView,
PostReportView,
PrivateMessageReportView,
ReportCombinedPaginationCursor,
ReportCombinedView,
ReportCombinedViewInternal,
};
use diesel::{
result::Error,
@ -48,6 +45,7 @@ use lemmy_db_schema::{
community::CommunityFollower,
},
utils::{actions, actions_alias, functions::coalesce, get_conn, DbPool, ReverseTimestampKey},
InternalToCombinedView,
};
use lemmy_utils::error::LemmyResult;

View file

@ -122,25 +122,25 @@ pub struct PostReportView {
/// prevent ossification (api users love to make assumptions (e.g. parse stuff that looks like
/// numbers as numbers) about apis that aren't part of the spec
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(ts_rs::TS))]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
pub struct PaginationCursor(pub String);
/// like PaginationCursor but for the report_combined table
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(ts_rs::TS))]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
pub struct ReportCombinedPaginationCursor(pub String);
/// like PaginationCursor but for the person_content_combined table
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(ts_rs::TS))]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
pub struct PersonContentCombinedPaginationCursor(pub String);
/// like PaginationCursor but for the person_saved_combined table
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(ts_rs::TS))]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
pub struct PersonSavedCombinedPaginationCursor(pub String);

View file

@ -15,10 +15,12 @@ doctest = false
workspace = true
[features]
full = ["lemmy_db_schema/full", "diesel", "diesel-async", "ts-rs"]
full = ["lemmy_db_schema/full", "lemmy_utils", "i-love-jesus", "diesel", "diesel-async", "ts-rs"]
[dependencies]
lemmy_db_schema = { workspace = true }
lemmy_utils = { workspace = true, optional = true }
i-love-jesus = { workspace = true, optional = true }
diesel = { workspace = true, features = [
"postgres",
"chrono",

View file

@ -1,52 +0,0 @@
use crate::structs::{AdminAllowInstanceView, ModlogListParams};
use diesel::{
result::Error,
BoolExpressionMethods,
ExpressionMethods,
IntoSql,
JoinOnDsl,
NullableExpressionMethods,
QueryDsl,
};
use diesel_async::RunQueryDsl;
use lemmy_db_schema::{
newtypes::PersonId,
schema::{admin_allow_instance, instance, person},
utils::{get_conn, limit_and_offset, DbPool},
};
impl AdminAllowInstanceView {
pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?;
let admin_person_id_join = params.mod_person_id.unwrap_or(PersonId(-1));
let show_mod_names = !params.hide_modlog_names;
let show_mod_names_expr = show_mod_names.as_sql::<diesel::sql_types::Bool>();
let admin_names_join = admin_allow_instance::admin_person_id
.eq(person::id)
.and(show_mod_names_expr.or(person::id.eq(admin_person_id_join)));
let mut query = admin_allow_instance::table
.left_join(person::table.on(admin_names_join))
.inner_join(instance::table)
.select((
admin_allow_instance::all_columns,
instance::all_columns,
person::all_columns.nullable(),
))
.into_boxed();
if let Some(admin_person_id) = params.mod_person_id {
query = query.filter(admin_allow_instance::admin_person_id.eq(admin_person_id));
};
let (limit, offset) = limit_and_offset(params.page, params.limit)?;
query
.limit(limit)
.offset(offset)
.order_by(admin_allow_instance::when_.desc())
.load::<Self>(conn)
.await
}
}

View file

@ -1,52 +0,0 @@
use crate::structs::{AdminBlockInstanceView, ModlogListParams};
use diesel::{
result::Error,
BoolExpressionMethods,
ExpressionMethods,
IntoSql,
JoinOnDsl,
NullableExpressionMethods,
QueryDsl,
};
use diesel_async::RunQueryDsl;
use lemmy_db_schema::{
newtypes::PersonId,
schema::{admin_block_instance, instance, person},
utils::{get_conn, limit_and_offset, DbPool},
};
impl AdminBlockInstanceView {
pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?;
let admin_person_id_join = params.mod_person_id.unwrap_or(PersonId(-1));
let show_mod_names = !params.hide_modlog_names;
let show_mod_names_expr = show_mod_names.as_sql::<diesel::sql_types::Bool>();
let admin_names_join = admin_block_instance::admin_person_id
.eq(person::id)
.and(show_mod_names_expr.or(person::id.eq(admin_person_id_join)));
let mut query = admin_block_instance::table
.left_join(person::table.on(admin_names_join))
.inner_join(instance::table)
.select((
admin_block_instance::all_columns,
instance::all_columns,
person::all_columns.nullable(),
))
.into_boxed();
if let Some(admin_person_id) = params.mod_person_id {
query = query.filter(admin_block_instance::admin_person_id.eq(admin_person_id));
};
let (limit, offset) = limit_and_offset(params.page, params.limit)?;
query
.limit(limit)
.offset(offset)
.order_by(admin_block_instance::when_.desc())
.load::<Self>(conn)
.await
}
}

View file

@ -1,57 +0,0 @@
use crate::structs::{AdminPurgeCommentView, ModlogListParams};
use diesel::{
result::Error,
BoolExpressionMethods,
ExpressionMethods,
IntoSql,
JoinOnDsl,
NullableExpressionMethods,
QueryDsl,
};
use diesel_async::RunQueryDsl;
use lemmy_db_schema::{
newtypes::PersonId,
schema::{admin_purge_comment, person, post},
utils::{get_conn, limit_and_offset, DbPool},
};
impl AdminPurgeCommentView {
pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?;
let admin_person_id_join = params.mod_person_id.unwrap_or(PersonId(-1));
let show_mod_names = !params.hide_modlog_names;
let show_mod_names_expr = show_mod_names.as_sql::<diesel::sql_types::Bool>();
let admin_names_join = admin_purge_comment::admin_person_id
.eq(person::id)
.and(show_mod_names_expr.or(person::id.eq(admin_person_id_join)));
let mut query = admin_purge_comment::table
.left_join(person::table.on(admin_names_join))
.inner_join(post::table)
.select((
admin_purge_comment::all_columns,
person::all_columns.nullable(),
post::all_columns,
))
.into_boxed();
if let Some(admin_person_id) = params.mod_person_id {
query = query.filter(admin_purge_comment::admin_person_id.eq(admin_person_id));
};
// If a post or comment ID is given, then don't find any results
if params.post_id.is_some() || params.comment_id.is_some() {
return Ok(vec![]);
}
let (limit, offset) = limit_and_offset(params.page, params.limit)?;
query
.limit(limit)
.offset(offset)
.order_by(admin_purge_comment::when_.desc())
.load::<AdminPurgeCommentView>(conn)
.await
}
}

View file

@ -1,55 +0,0 @@
use crate::structs::{AdminPurgeCommunityView, ModlogListParams};
use diesel::{
result::Error,
BoolExpressionMethods,
ExpressionMethods,
IntoSql,
JoinOnDsl,
NullableExpressionMethods,
QueryDsl,
};
use diesel_async::RunQueryDsl;
use lemmy_db_schema::{
newtypes::PersonId,
schema::{admin_purge_community, person},
utils::{get_conn, limit_and_offset, DbPool},
};
impl AdminPurgeCommunityView {
pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?;
let admin_person_id_join = params.mod_person_id.unwrap_or(PersonId(-1));
let show_mod_names = !params.hide_modlog_names;
let show_mod_names_expr = show_mod_names.as_sql::<diesel::sql_types::Bool>();
let admin_names_join = admin_purge_community::admin_person_id
.eq(person::id)
.and(show_mod_names_expr.or(person::id.eq(admin_person_id_join)));
let mut query = admin_purge_community::table
.left_join(person::table.on(admin_names_join))
.select((
admin_purge_community::all_columns,
person::all_columns.nullable(),
))
.into_boxed();
if let Some(admin_person_id) = params.mod_person_id {
query = query.filter(admin_purge_community::admin_person_id.eq(admin_person_id));
};
// If a post or comment ID is given, then don't find any results
if params.post_id.is_some() || params.comment_id.is_some() {
return Ok(vec![]);
}
let (limit, offset) = limit_and_offset(params.page, params.limit)?;
query
.limit(limit)
.offset(offset)
.order_by(admin_purge_community::when_.desc())
.load::<AdminPurgeCommunityView>(conn)
.await
}
}

View file

@ -1,55 +0,0 @@
use crate::structs::{AdminPurgePersonView, ModlogListParams};
use diesel::{
result::Error,
BoolExpressionMethods,
ExpressionMethods,
IntoSql,
JoinOnDsl,
NullableExpressionMethods,
QueryDsl,
};
use diesel_async::RunQueryDsl;
use lemmy_db_schema::{
newtypes::PersonId,
schema::{admin_purge_person, person},
utils::{get_conn, limit_and_offset, DbPool},
};
impl AdminPurgePersonView {
pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?;
let admin_person_id_join = params.mod_person_id.unwrap_or(PersonId(-1));
let show_mod_names = !params.hide_modlog_names;
let show_mod_names_expr = show_mod_names.as_sql::<diesel::sql_types::Bool>();
let admin_names_join = admin_purge_person::admin_person_id
.eq(person::id)
.and(show_mod_names_expr.or(person::id.eq(admin_person_id_join)));
let mut query = admin_purge_person::table
.left_join(person::table.on(admin_names_join))
.select((
admin_purge_person::all_columns,
person::all_columns.nullable(),
))
.into_boxed();
if let Some(admin_person_id) = params.mod_person_id {
query = query.filter(admin_purge_person::admin_person_id.eq(admin_person_id));
};
// If a post or comment ID is given, then don't find any results
if params.post_id.is_some() || params.comment_id.is_some() {
return Ok(vec![]);
}
let (limit, offset) = limit_and_offset(params.page, params.limit)?;
query
.limit(limit)
.offset(offset)
.order_by(admin_purge_person::when_.desc())
.load::<AdminPurgePersonView>(conn)
.await
}
}

View file

@ -1,57 +0,0 @@
use crate::structs::{AdminPurgePostView, ModlogListParams};
use diesel::{
result::Error,
BoolExpressionMethods,
ExpressionMethods,
IntoSql,
JoinOnDsl,
NullableExpressionMethods,
QueryDsl,
};
use diesel_async::RunQueryDsl;
use lemmy_db_schema::{
newtypes::PersonId,
schema::{admin_purge_post, community, person},
utils::{get_conn, limit_and_offset, DbPool},
};
impl AdminPurgePostView {
pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?;
let admin_person_id_join = params.mod_person_id.unwrap_or(PersonId(-1));
let show_mod_names = !params.hide_modlog_names;
let show_mod_names_expr = show_mod_names.as_sql::<diesel::sql_types::Bool>();
let admin_names_join = admin_purge_post::admin_person_id
.eq(person::id)
.and(show_mod_names_expr.or(person::id.eq(admin_person_id_join)));
let mut query = admin_purge_post::table
.left_join(person::table.on(admin_names_join))
.inner_join(community::table)
.select((
admin_purge_post::all_columns,
person::all_columns.nullable(),
community::all_columns,
))
.into_boxed();
if let Some(admin_person_id) = params.mod_person_id {
query = query.filter(admin_purge_post::admin_person_id.eq(admin_person_id));
};
// If a post or comment ID is given, then don't find any results
if params.post_id.is_some() || params.comment_id.is_some() {
return Ok(vec![]);
}
let (limit, offset) = limit_and_offset(params.page, params.limit)?;
query
.limit(limit)
.offset(offset)
.order_by(admin_purge_post::when_.desc())
.load::<AdminPurgePostView>(conn)
.await
}
}

View file

@ -1,35 +1,3 @@
#[cfg(feature = "full")]
pub mod admin_allow_instance;
#[cfg(feature = "full")]
pub mod admin_block_instance;
#[cfg(feature = "full")]
pub mod admin_purge_comment_view;
#[cfg(feature = "full")]
pub mod admin_purge_community_view;
#[cfg(feature = "full")]
pub mod admin_purge_person_view;
#[cfg(feature = "full")]
pub mod admin_purge_post_view;
#[cfg(feature = "full")]
pub mod mod_add_community_view;
#[cfg(feature = "full")]
pub mod mod_add_view;
#[cfg(feature = "full")]
pub mod mod_ban_from_community_view;
#[cfg(feature = "full")]
pub mod mod_ban_view;
#[cfg(feature = "full")]
pub mod mod_feature_post_view;
#[cfg(feature = "full")]
pub mod mod_hide_community_view;
#[cfg(feature = "full")]
pub mod mod_lock_post_view;
#[cfg(feature = "full")]
pub mod mod_remove_comment_view;
#[cfg(feature = "full")]
pub mod mod_remove_community_view;
#[cfg(feature = "full")]
pub mod mod_remove_post_view;
#[cfg(feature = "full")]
pub mod mod_transfer_community_view;
pub mod modlog_combined_view;
pub mod structs;

View file

@ -1,69 +0,0 @@
use crate::structs::{ModAddCommunityView, ModlogListParams};
use diesel::{
result::Error,
BoolExpressionMethods,
ExpressionMethods,
IntoSql,
JoinOnDsl,
NullableExpressionMethods,
QueryDsl,
};
use diesel_async::RunQueryDsl;
use lemmy_db_schema::{
newtypes::PersonId,
schema::{community, mod_add_community, person},
utils::{get_conn, limit_and_offset, DbPool},
};
impl ModAddCommunityView {
pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?;
let person_alias_1 = diesel::alias!(person as person1);
let admin_person_id_join = params.mod_person_id.unwrap_or(PersonId(-1));
let show_mod_names = !params.hide_modlog_names;
let show_mod_names_expr = show_mod_names.as_sql::<diesel::sql_types::Bool>();
let admin_names_join = mod_add_community::mod_person_id
.eq(person::id)
.and(show_mod_names_expr.or(person::id.eq(admin_person_id_join)));
let mut query = mod_add_community::table
.left_join(person::table.on(admin_names_join))
.inner_join(community::table)
.inner_join(
person_alias_1.on(mod_add_community::other_person_id.eq(person_alias_1.field(person::id))),
)
.select((
mod_add_community::all_columns,
person::all_columns.nullable(),
community::all_columns,
person_alias_1.fields(person::all_columns),
))
.into_boxed();
if let Some(mod_person_id) = params.mod_person_id {
query = query.filter(mod_add_community::mod_person_id.eq(mod_person_id));
};
if let Some(community_id) = params.community_id {
query = query.filter(mod_add_community::community_id.eq(community_id));
};
if let Some(other_person_id) = params.other_person_id {
query = query.filter(person_alias_1.field(person::id).eq(other_person_id));
};
// If a post or comment ID is given, then don't find any results
if params.post_id.is_some() || params.comment_id.is_some() {
return Ok(vec![]);
}
let (limit, offset) = limit_and_offset(params.page, params.limit)?;
query
.limit(limit)
.offset(offset)
.order_by(mod_add_community::when_.desc())
.load::<ModAddCommunityView>(conn)
.await
}
}

View file

@ -1,61 +0,0 @@
use crate::structs::{ModAddView, ModlogListParams};
use diesel::{
result::Error,
BoolExpressionMethods,
ExpressionMethods,
IntoSql,
JoinOnDsl,
NullableExpressionMethods,
QueryDsl,
};
use diesel_async::RunQueryDsl;
use lemmy_db_schema::{
newtypes::PersonId,
schema::{mod_add, person},
utils::{get_conn, limit_and_offset, DbPool},
};
impl ModAddView {
pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?;
let person_alias_1 = diesel::alias!(person as person1);
let admin_person_id_join = params.mod_person_id.unwrap_or(PersonId(-1));
let show_mod_names = !params.hide_modlog_names;
let show_mod_names_expr = show_mod_names.as_sql::<diesel::sql_types::Bool>();
let admin_names_join = mod_add::mod_person_id
.eq(person::id)
.and(show_mod_names_expr.or(person::id.eq(admin_person_id_join)));
let mut query = mod_add::table
.left_join(person::table.on(admin_names_join))
.inner_join(person_alias_1.on(mod_add::other_person_id.eq(person_alias_1.field(person::id))))
.select((
mod_add::all_columns,
person::all_columns.nullable(),
person_alias_1.fields(person::all_columns),
))
.into_boxed();
if let Some(mod_person_id) = params.mod_person_id {
query = query.filter(mod_add::mod_person_id.eq(mod_person_id));
};
if let Some(other_person_id) = params.other_person_id {
query = query.filter(person_alias_1.field(person::id).eq(other_person_id));
};
// If a post or comment ID is given, then don't find any results
if params.post_id.is_some() || params.comment_id.is_some() {
return Ok(vec![]);
}
let (limit, offset) = limit_and_offset(params.page, params.limit)?;
query
.limit(limit)
.offset(offset)
.order_by(mod_add::when_.desc())
.load::<ModAddView>(conn)
.await
}
}

View file

@ -1,71 +0,0 @@
use crate::structs::{ModBanFromCommunityView, ModlogListParams};
use diesel::{
result::Error,
BoolExpressionMethods,
ExpressionMethods,
IntoSql,
JoinOnDsl,
NullableExpressionMethods,
QueryDsl,
};
use diesel_async::RunQueryDsl;
use lemmy_db_schema::{
newtypes::PersonId,
schema::{community, mod_ban_from_community, person},
utils::{get_conn, limit_and_offset, DbPool},
};
impl ModBanFromCommunityView {
pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?;
let person_alias_1 = diesel::alias!(person as person1);
let admin_person_id_join = params.mod_person_id.unwrap_or(PersonId(-1));
let show_mod_names = !params.hide_modlog_names;
let show_mod_names_expr = show_mod_names.as_sql::<diesel::sql_types::Bool>();
let admin_names_join = mod_ban_from_community::mod_person_id
.eq(person::id)
.and(show_mod_names_expr.or(person::id.eq(admin_person_id_join)));
let mut query = mod_ban_from_community::table
.left_join(person::table.on(admin_names_join))
.inner_join(community::table)
.inner_join(
person_alias_1
.on(mod_ban_from_community::other_person_id.eq(person_alias_1.field(person::id))),
)
.select((
mod_ban_from_community::all_columns,
person::all_columns.nullable(),
community::all_columns,
person_alias_1.fields(person::all_columns),
))
.into_boxed();
if let Some(mod_person_id) = params.mod_person_id {
query = query.filter(mod_ban_from_community::mod_person_id.eq(mod_person_id));
};
if let Some(community_id) = params.community_id {
query = query.filter(mod_ban_from_community::community_id.eq(community_id));
};
if let Some(other_person_id) = params.other_person_id {
query = query.filter(mod_ban_from_community::other_person_id.eq(other_person_id));
};
// If a post or comment ID is given, then don't find any results
if params.post_id.is_some() || params.comment_id.is_some() {
return Ok(vec![]);
}
let (limit, offset) = limit_and_offset(params.page, params.limit)?;
query
.limit(limit)
.offset(offset)
.order_by(mod_ban_from_community::when_.desc())
.load::<ModBanFromCommunityView>(conn)
.await
}
}

View file

@ -1,61 +0,0 @@
use crate::structs::{ModBanView, ModlogListParams};
use diesel::{
result::Error,
BoolExpressionMethods,
ExpressionMethods,
IntoSql,
JoinOnDsl,
NullableExpressionMethods,
QueryDsl,
};
use diesel_async::RunQueryDsl;
use lemmy_db_schema::{
newtypes::PersonId,
schema::{mod_ban, person},
utils::{get_conn, limit_and_offset, DbPool},
};
impl ModBanView {
pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?;
let person_alias_1 = diesel::alias!(person as person1);
let admin_person_id_join = params.mod_person_id.unwrap_or(PersonId(-1));
let show_mod_names = !params.hide_modlog_names;
let show_mod_names_expr = show_mod_names.as_sql::<diesel::sql_types::Bool>();
let admin_names_join = mod_ban::mod_person_id
.eq(person::id)
.and(show_mod_names_expr.or(person::id.eq(admin_person_id_join)));
let mut query = mod_ban::table
.left_join(person::table.on(admin_names_join))
.inner_join(person_alias_1.on(mod_ban::other_person_id.eq(person_alias_1.field(person::id))))
.select((
mod_ban::all_columns,
person::all_columns.nullable(),
person_alias_1.fields(person::all_columns),
))
.into_boxed();
if let Some(mod_person_id) = params.mod_person_id {
query = query.filter(mod_ban::mod_person_id.eq(mod_person_id));
};
if let Some(other_person_id) = params.other_person_id {
query = query.filter(person_alias_1.field(person::id).eq(other_person_id));
};
// If a post or comment ID is given, then don't find any results
if params.post_id.is_some() || params.comment_id.is_some() {
return Ok(vec![]);
}
let (limit, offset) = limit_and_offset(params.page, params.limit)?;
query
.limit(limit)
.offset(offset)
.order_by(mod_ban::when_.desc())
.load::<ModBanView>(conn)
.await
}
}

View file

@ -1,72 +0,0 @@
use crate::structs::{ModFeaturePostView, ModlogListParams};
use diesel::{
result::Error,
BoolExpressionMethods,
ExpressionMethods,
IntoSql,
JoinOnDsl,
NullableExpressionMethods,
QueryDsl,
};
use diesel_async::RunQueryDsl;
use lemmy_db_schema::{
newtypes::PersonId,
schema::{community, mod_feature_post, person, post},
utils::{get_conn, limit_and_offset, DbPool},
};
impl ModFeaturePostView {
pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?;
let person_alias_1 = diesel::alias!(person as person1);
let admin_person_id_join = params.mod_person_id.unwrap_or(PersonId(-1));
let show_mod_names = !params.hide_modlog_names;
let show_mod_names_expr = show_mod_names.as_sql::<diesel::sql_types::Bool>();
let admin_names_join = mod_feature_post::mod_person_id
.eq(person::id)
.and(show_mod_names_expr.or(person::id.eq(admin_person_id_join)));
let mut query = mod_feature_post::table
.left_join(person::table.on(admin_names_join))
.inner_join(post::table)
.inner_join(person_alias_1.on(post::creator_id.eq(person_alias_1.field(person::id))))
.inner_join(community::table.on(post::community_id.eq(community::id)))
.select((
mod_feature_post::all_columns,
person::all_columns.nullable(),
post::all_columns,
community::all_columns,
))
.into_boxed();
if let Some(community_id) = params.community_id {
query = query.filter(post::community_id.eq(community_id));
};
if let Some(mod_person_id) = params.mod_person_id {
query = query.filter(mod_feature_post::mod_person_id.eq(mod_person_id));
};
if let Some(other_person_id) = params.other_person_id {
query = query.filter(person_alias_1.field(person::id).eq(other_person_id));
};
if let Some(post_id) = params.post_id {
query = query.filter(post::id.eq(post_id));
}
// If a comment ID is given, then don't find any results
if params.comment_id.is_some() {
return Ok(vec![]);
}
let (limit, offset) = limit_and_offset(params.page, params.limit)?;
query
.limit(limit)
.offset(offset)
.order_by(mod_feature_post::when_.desc())
.load::<ModFeaturePostView>(conn)
.await
}
}

View file

@ -1,62 +0,0 @@
use crate::structs::{ModHideCommunityView, ModlogListParams};
use diesel::{
result::Error,
BoolExpressionMethods,
ExpressionMethods,
IntoSql,
JoinOnDsl,
NullableExpressionMethods,
QueryDsl,
};
use diesel_async::RunQueryDsl;
use lemmy_db_schema::{
newtypes::PersonId,
schema::{community, mod_hide_community, person},
utils::{get_conn, limit_and_offset, DbPool},
};
impl ModHideCommunityView {
// Pass in mod_id as admin_id because only admins can do this action
pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?;
let admin_person_id_join = params.mod_person_id.unwrap_or(PersonId(-1));
let show_mod_names = !params.hide_modlog_names;
let show_mod_names_expr = show_mod_names.as_sql::<diesel::sql_types::Bool>();
let admin_names_join = mod_hide_community::mod_person_id
.eq(person::id)
.and(show_mod_names_expr.or(person::id.eq(admin_person_id_join)));
let mut query = mod_hide_community::table
.left_join(person::table.on(admin_names_join))
.inner_join(community::table.on(mod_hide_community::community_id.eq(community::id)))
.select((
mod_hide_community::all_columns,
person::all_columns.nullable(),
community::all_columns,
))
.into_boxed();
if let Some(community_id) = params.community_id {
query = query.filter(mod_hide_community::community_id.eq(community_id));
};
if let Some(admin_id) = params.mod_person_id {
query = query.filter(mod_hide_community::mod_person_id.eq(admin_id));
};
// If a post or comment ID is given, then don't find any results
if params.post_id.is_some() || params.comment_id.is_some() {
return Ok(vec![]);
}
let (limit, offset) = limit_and_offset(params.page, params.limit)?;
query
.limit(limit)
.offset(offset)
.order_by(mod_hide_community::when_.desc())
.load::<ModHideCommunityView>(conn)
.await
}
}

View file

@ -1,73 +0,0 @@
use crate::structs::{ModLockPostView, ModlogListParams};
use diesel::{
result::Error,
BoolExpressionMethods,
ExpressionMethods,
IntoSql,
JoinOnDsl,
NullableExpressionMethods,
QueryDsl,
};
use diesel_async::RunQueryDsl;
use lemmy_db_schema::{
newtypes::PersonId,
schema::{community, mod_lock_post, person, post},
utils::{get_conn, limit_and_offset, DbPool},
};
impl ModLockPostView {
pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?;
let person_alias_1 = diesel::alias!(person as person1);
let admin_person_id_join = params.mod_person_id.unwrap_or(PersonId(-1));
let show_mod_names = !params.hide_modlog_names;
let show_mod_names_expr = show_mod_names.as_sql::<diesel::sql_types::Bool>();
let admin_names_join = mod_lock_post::mod_person_id
.eq(person::id)
.and(show_mod_names_expr.or(person::id.eq(admin_person_id_join)));
let mut query = mod_lock_post::table
.left_join(person::table.on(admin_names_join))
.inner_join(post::table)
.inner_join(community::table.on(post::community_id.eq(community::id)))
.inner_join(person_alias_1.on(post::creator_id.eq(person_alias_1.field(person::id))))
.select((
mod_lock_post::all_columns,
person::all_columns.nullable(),
post::all_columns,
community::all_columns,
))
.into_boxed();
if let Some(community_id) = params.community_id {
query = query.filter(post::community_id.eq(community_id));
};
if let Some(mod_person_id) = params.mod_person_id {
query = query.filter(mod_lock_post::mod_person_id.eq(mod_person_id));
};
if let Some(other_person_id) = params.other_person_id {
query = query.filter(person_alias_1.field(person::id).eq(other_person_id));
};
if let Some(post_id) = params.post_id {
query = query.filter(post::id.eq(post_id));
}
// If a comment ID is given, then don't find any results
if params.comment_id.is_some() {
return Ok(vec![]);
}
let (limit, offset) = limit_and_offset(params.page, params.limit)?;
query
.limit(limit)
.offset(offset)
.order_by(mod_lock_post::when_.desc())
.load::<ModLockPostView>(conn)
.await
}
}

View file

@ -1,75 +0,0 @@
use crate::structs::{ModRemoveCommentView, ModlogListParams};
use diesel::{
result::Error,
BoolExpressionMethods,
ExpressionMethods,
IntoSql,
JoinOnDsl,
NullableExpressionMethods,
QueryDsl,
};
use diesel_async::RunQueryDsl;
use lemmy_db_schema::{
newtypes::PersonId,
schema::{comment, community, mod_remove_comment, person, post},
utils::{get_conn, limit_and_offset, DbPool},
};
impl ModRemoveCommentView {
pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?;
let person_alias_1 = diesel::alias!(lemmy_db_schema::schema::person as person1);
let admin_person_id_join = params.mod_person_id.unwrap_or(PersonId(-1));
let show_mod_names = !params.hide_modlog_names;
let show_mod_names_expr = show_mod_names.as_sql::<diesel::sql_types::Bool>();
let admin_names_join = mod_remove_comment::mod_person_id
.eq(person::id)
.and(show_mod_names_expr.or(person::id.eq(admin_person_id_join)));
let mut query = mod_remove_comment::table
.left_join(person::table.on(admin_names_join))
.inner_join(comment::table)
.inner_join(person_alias_1.on(comment::creator_id.eq(person_alias_1.field(person::id))))
.inner_join(post::table.on(comment::post_id.eq(post::id)))
.inner_join(community::table.on(post::community_id.eq(community::id)))
.select((
mod_remove_comment::all_columns,
person::all_columns.nullable(),
comment::all_columns,
person_alias_1.fields(person::all_columns),
post::all_columns,
community::all_columns,
))
.into_boxed();
if let Some(community_id) = params.community_id {
query = query.filter(post::community_id.eq(community_id));
};
if let Some(mod_person_id) = params.mod_person_id {
query = query.filter(mod_remove_comment::mod_person_id.eq(mod_person_id));
};
if let Some(other_person_id) = params.other_person_id {
query = query.filter(person_alias_1.field(person::id).eq(other_person_id));
};
if let Some(comment_id) = params.comment_id {
query = query.filter(comment::id.eq(comment_id));
}
// If a post ID is given, then don't find any results
if params.post_id.is_some() {
return Ok(vec![]);
}
let (limit, offset) = limit_and_offset(params.page, params.limit)?;
query
.limit(limit)
.offset(offset)
.order_by(mod_remove_comment::when_.desc())
.load::<ModRemoveCommentView>(conn)
.await
}
}

View file

@ -1,56 +0,0 @@
use crate::structs::{ModRemoveCommunityView, ModlogListParams};
use diesel::{
result::Error,
BoolExpressionMethods,
ExpressionMethods,
IntoSql,
JoinOnDsl,
NullableExpressionMethods,
QueryDsl,
};
use diesel_async::RunQueryDsl;
use lemmy_db_schema::{
newtypes::PersonId,
schema::{community, mod_remove_community, person},
utils::{get_conn, limit_and_offset, DbPool},
};
impl ModRemoveCommunityView {
pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?;
let admin_person_id_join = params.mod_person_id.unwrap_or(PersonId(-1));
let show_mod_names = !params.hide_modlog_names;
let show_mod_names_expr = show_mod_names.as_sql::<diesel::sql_types::Bool>();
let admin_names_join = mod_remove_community::mod_person_id
.eq(person::id)
.and(show_mod_names_expr.or(person::id.eq(admin_person_id_join)));
let mut query = mod_remove_community::table
.left_join(person::table.on(admin_names_join))
.inner_join(community::table)
.select((
mod_remove_community::all_columns,
person::all_columns.nullable(),
community::all_columns,
))
.into_boxed();
if let Some(mod_person_id) = params.mod_person_id {
query = query.filter(mod_remove_community::mod_person_id.eq(mod_person_id));
};
// If a post or comment ID is given, then don't find any results
if params.post_id.is_some() || params.comment_id.is_some() {
return Ok(vec![]);
}
let (limit, offset) = limit_and_offset(params.page, params.limit)?;
query
.limit(limit)
.offset(offset)
.order_by(mod_remove_community::when_.desc())
.load::<ModRemoveCommunityView>(conn)
.await
}
}

View file

@ -1,73 +0,0 @@
use crate::structs::{ModRemovePostView, ModlogListParams};
use diesel::{
result::Error,
BoolExpressionMethods,
ExpressionMethods,
IntoSql,
JoinOnDsl,
NullableExpressionMethods,
QueryDsl,
};
use diesel_async::RunQueryDsl;
use lemmy_db_schema::{
newtypes::PersonId,
schema::{community, mod_remove_post, person, post},
utils::{get_conn, limit_and_offset, DbPool},
};
impl ModRemovePostView {
pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?;
let person_alias_1 = diesel::alias!(person as person1);
let admin_person_id_join = params.mod_person_id.unwrap_or(PersonId(-1));
let show_mod_names = !params.hide_modlog_names;
let show_mod_names_expr = show_mod_names.as_sql::<diesel::sql_types::Bool>();
let admin_names_join = mod_remove_post::mod_person_id
.eq(person::id)
.and(show_mod_names_expr.or(person::id.eq(admin_person_id_join)));
let mut query = mod_remove_post::table
.left_join(person::table.on(admin_names_join))
.inner_join(post::table)
.inner_join(community::table.on(post::community_id.eq(community::id)))
.inner_join(person_alias_1.on(post::creator_id.eq(person_alias_1.field(person::id))))
.select((
mod_remove_post::all_columns,
person::all_columns.nullable(),
post::all_columns,
community::all_columns,
))
.into_boxed();
if let Some(community_id) = params.community_id {
query = query.filter(post::community_id.eq(community_id));
};
if let Some(mod_person_id) = params.mod_person_id {
query = query.filter(mod_remove_post::mod_person_id.eq(mod_person_id));
};
if let Some(other_person_id) = params.other_person_id {
query = query.filter(person_alias_1.field(person::id).eq(other_person_id));
};
if let Some(post_id) = params.post_id {
query = query.filter(post::id.eq(post_id));
}
// If a comment ID is given, then don't find any results
if params.comment_id.is_some() {
return Ok(vec![]);
}
let (limit, offset) = limit_and_offset(params.page, params.limit)?;
query
.limit(limit)
.offset(offset)
.order_by(mod_remove_post::when_.desc())
.load::<ModRemovePostView>(conn)
.await
}
}

View file

@ -1,71 +0,0 @@
use crate::structs::{ModTransferCommunityView, ModlogListParams};
use diesel::{
result::Error,
BoolExpressionMethods,
ExpressionMethods,
IntoSql,
JoinOnDsl,
NullableExpressionMethods,
QueryDsl,
};
use diesel_async::RunQueryDsl;
use lemmy_db_schema::{
newtypes::PersonId,
schema::{community, mod_transfer_community, person},
utils::{get_conn, limit_and_offset, DbPool},
};
impl ModTransferCommunityView {
pub async fn list(pool: &mut DbPool<'_>, params: ModlogListParams) -> Result<Vec<Self>, Error> {
let conn = &mut get_conn(pool).await?;
let person_alias_1 = diesel::alias!(person as person1);
let admin_person_id_join = params.mod_person_id.unwrap_or(PersonId(-1));
let show_mod_names = !params.hide_modlog_names;
let show_mod_names_expr = show_mod_names.as_sql::<diesel::sql_types::Bool>();
let admin_names_join = mod_transfer_community::mod_person_id
.eq(person::id)
.and(show_mod_names_expr.or(person::id.eq(admin_person_id_join)));
let mut query = mod_transfer_community::table
.left_join(person::table.on(admin_names_join))
.inner_join(community::table)
.inner_join(
person_alias_1
.on(mod_transfer_community::other_person_id.eq(person_alias_1.field(person::id))),
)
.select((
mod_transfer_community::all_columns,
person::all_columns.nullable(),
community::all_columns,
person_alias_1.fields(person::all_columns),
))
.into_boxed();
if let Some(mod_person_id) = params.mod_person_id {
query = query.filter(mod_transfer_community::mod_person_id.eq(mod_person_id));
};
if let Some(community_id) = params.community_id {
query = query.filter(mod_transfer_community::community_id.eq(community_id));
};
if let Some(other_person_id) = params.other_person_id {
query = query.filter(person_alias_1.field(person::id).eq(other_person_id));
};
// If a post or comment ID is given, then don't find any results
if params.post_id.is_some() || params.comment_id.is_some() {
return Ok(vec![]);
}
let (limit, offset) = limit_and_offset(params.page, params.limit)?;
query
.limit(limit)
.offset(offset)
.order_by(mod_transfer_community::when_.desc())
.load::<ModTransferCommunityView>(conn)
.await
}
}

View file

@ -0,0 +1,608 @@
use crate::structs::{
AdminAllowInstanceView,
AdminBlockInstanceView,
AdminPurgeCommentView,
AdminPurgeCommunityView,
AdminPurgePersonView,
AdminPurgePostView,
ModAddCommunityView,
ModAddView,
ModBanFromCommunityView,
ModBanView,
ModFeaturePostView,
ModHideCommunityView,
ModLockPostView,
ModRemoveCommentView,
ModRemoveCommunityView,
ModRemovePostView,
ModTransferCommunityView,
ModlogCombinedPaginationCursor,
ModlogCombinedView,
ModlogCombinedViewInternal,
};
use diesel::{
result::Error,
BoolExpressionMethods,
ExpressionMethods,
IntoSql,
JoinOnDsl,
NullableExpressionMethods,
QueryDsl,
SelectableHelper,
};
use diesel_async::RunQueryDsl;
use i_love_jesus::PaginatedQueryBuilder;
use lemmy_db_schema::{
aliases,
newtypes::{CommentId, CommunityId, PersonId, PostId},
schema::{
admin_allow_instance,
admin_block_instance,
admin_purge_comment,
admin_purge_community,
admin_purge_person,
admin_purge_post,
comment,
community,
instance,
mod_add,
mod_add_community,
mod_ban,
mod_ban_from_community,
mod_feature_post,
mod_hide_community,
mod_lock_post,
mod_remove_comment,
mod_remove_community,
mod_remove_post,
mod_transfer_community,
modlog_combined,
person,
post,
},
source::combined::modlog::{modlog_combined_keys as key, ModlogCombined},
utils::{get_conn, DbPool},
InternalToCombinedView,
ModlogActionType,
};
use lemmy_utils::error::LemmyResult;
impl ModlogCombinedPaginationCursor {
// get cursor for page that starts immediately after the given post
pub fn after_post(view: &ModlogCombinedView) -> ModlogCombinedPaginationCursor {
let (prefix, id) = match view {
ModlogCombinedView::AdminAllowInstance(v) => {
("AdminAllowInstance", v.admin_allow_instance.id.0)
}
ModlogCombinedView::AdminBlockInstance(v) => {
("AdminBlockInstance", v.admin_block_instance.id.0)
}
ModlogCombinedView::AdminPurgeComment(v) => ("AdminPurgeComment", v.admin_purge_comment.id.0),
ModlogCombinedView::AdminPurgeCommunity(v) => {
("AdminPurgeCommunity", v.admin_purge_community.id.0)
}
ModlogCombinedView::AdminPurgePerson(v) => ("AdminPurgePerson", v.admin_purge_person.id.0),
ModlogCombinedView::AdminPurgePost(v) => ("AdminPurgePost", v.admin_purge_post.id.0),
ModlogCombinedView::ModAdd(v) => ("ModAdd", v.mod_add.id.0),
ModlogCombinedView::ModAddCommunity(v) => ("ModAddCommunity", v.mod_add_community.id.0),
ModlogCombinedView::ModBan(v) => ("ModBan", v.mod_ban.id.0),
ModlogCombinedView::ModBanFromCommunity(v) => {
("ModBanFromCommunity", v.mod_ban_from_community.id.0)
}
ModlogCombinedView::ModFeaturePost(v) => ("ModFeaturePost", v.mod_feature_post.id.0),
ModlogCombinedView::ModHideCommunity(v) => ("ModHideCommunity", v.mod_hide_community.id.0),
ModlogCombinedView::ModLockPost(v) => ("ModLockPost", v.mod_lock_post.id.0),
ModlogCombinedView::ModRemoveComment(v) => ("ModRemoveComment", v.mod_remove_comment.id.0),
ModlogCombinedView::ModRemoveCommunity(v) => {
("ModRemoveCommunity", v.mod_remove_community.id.0)
}
ModlogCombinedView::ModRemovePost(v) => ("ModRemovePost", v.mod_remove_post.id.0),
ModlogCombinedView::ModTransferCommunity(v) => {
("ModTransferCommunity", v.mod_transfer_community.id.0)
}
};
// hex encoding to prevent ossification
ModlogCombinedPaginationCursor(format!("{prefix}{id:x}"))
}
pub async fn read(&self, pool: &mut DbPool<'_>) -> Result<PaginationCursorData, Error> {
let err_msg = || Error::QueryBuilderError("Could not parse pagination token".into());
let mut query = modlog_combined::table
.select(ModlogCombined::as_select())
.into_boxed();
let (prefix, id_str) = self.0.split_at_checked(1).ok_or_else(err_msg)?;
let id = i32::from_str_radix(id_str, 16).map_err(|_err| err_msg())?;
query = match prefix {
"AdminAllowInstance" => query.filter(modlog_combined::admin_allow_instance_id.eq(id)),
"AdminBlockInstance" => query.filter(modlog_combined::admin_block_instance_id.eq(id)),
"AdminPurgeComment" => query.filter(modlog_combined::admin_purge_comment_id.eq(id)),
"AdminPurgeCommunity" => query.filter(modlog_combined::admin_purge_community_id.eq(id)),
"AdminPurgePerson" => query.filter(modlog_combined::admin_purge_person_id.eq(id)),
"AdminPurgePost" => query.filter(modlog_combined::admin_purge_post_id.eq(id)),
"ModAdd" => query.filter(modlog_combined::mod_add_id.eq(id)),
"ModAddCommunity" => query.filter(modlog_combined::mod_add_community_id.eq(id)),
"ModBan" => query.filter(modlog_combined::mod_ban_id.eq(id)),
"ModBanFromCommunity" => query.filter(modlog_combined::mod_ban_from_community_id.eq(id)),
"ModFeaturePost" => query.filter(modlog_combined::mod_feature_post_id.eq(id)),
"ModHideCommunity" => query.filter(modlog_combined::mod_hide_community_id.eq(id)),
"ModLockPost" => query.filter(modlog_combined::mod_lock_post_id.eq(id)),
"ModRemoveComment" => query.filter(modlog_combined::mod_remove_comment_id.eq(id)),
"ModRemoveCommunity" => query.filter(modlog_combined::mod_remove_community_id.eq(id)),
"ModRemovePost" => query.filter(modlog_combined::mod_remove_post_id.eq(id)),
"ModTransferCommunity" => query.filter(modlog_combined::mod_transfer_community_id.eq(id)),
_ => return Err(err_msg()),
};
let token = query.first(&mut get_conn(pool).await?).await?;
Ok(PaginationCursorData(token))
}
}
#[derive(Clone)]
pub struct PaginationCursorData(ModlogCombined);
#[derive(Default)]
/// Querying / filtering the modlog.
pub struct ModlogCombinedQuery {
pub type_: Option<ModlogActionType>,
pub comment_id: Option<CommentId>,
pub post_id: Option<PostId>,
pub community_id: Option<CommunityId>,
pub hide_modlog_names: bool,
pub mod_person_id: Option<PersonId>,
pub modded_person_id: Option<PersonId>,
pub page_after: Option<PaginationCursorData>,
pub page_back: Option<bool>,
}
impl ModlogCombinedQuery {
pub async fn list(self, pool: &mut DbPool<'_>) -> LemmyResult<Vec<ModlogCombinedView>> {
let conn = &mut get_conn(pool).await?;
let mod_person = self.mod_person_id.unwrap_or(PersonId(-1));
let show_mod_names = !self.hide_modlog_names;
let show_mod_names_expr = show_mod_names.as_sql::<diesel::sql_types::Bool>();
let modded_person = aliases::person1.field(person::id);
// The query for the admin / mod person
// It needs an OR condition to every mod table
// After this you can use person::id to refer to the moderator
let moderator_names_join = show_mod_names_expr.or(person::id.eq(mod_person)).and(
admin_allow_instance::admin_person_id
.eq(person::id)
.or(admin_block_instance::admin_person_id.eq(person::id))
.or(admin_purge_comment::admin_person_id.eq(person::id))
.or(admin_purge_community::admin_person_id.eq(person::id))
.or(admin_purge_person::admin_person_id.eq(person::id))
.or(admin_purge_post::admin_person_id.eq(person::id))
.or(mod_add::mod_person_id.eq(person::id))
.or(mod_add_community::mod_person_id.eq(person::id))
.or(mod_ban::mod_person_id.eq(person::id))
.or(mod_ban_from_community::mod_person_id.eq(person::id))
.or(mod_feature_post::mod_person_id.eq(person::id))
.or(mod_hide_community::mod_person_id.eq(person::id))
.or(mod_lock_post::mod_person_id.eq(person::id))
.or(mod_remove_comment::mod_person_id.eq(person::id))
.or(mod_remove_community::mod_person_id.eq(person::id))
.or(mod_remove_post::mod_person_id.eq(person::id))
.or(mod_transfer_community::mod_person_id.eq(person::id)),
);
let modded_person_join = mod_add::other_person_id
.eq(modded_person)
.or(mod_add_community::other_person_id.eq(modded_person))
.or(mod_ban::other_person_id.eq(modded_person))
.or(mod_ban_from_community::other_person_id.eq(modded_person))
// Some tables don't have the modded_person_id directly, so you need to join
.or(
mod_feature_post::id
.is_not_null()
.and(post::creator_id.eq(modded_person)),
)
.or(
mod_lock_post::id
.is_not_null()
.and(post::creator_id.eq(modded_person)),
)
.or(
mod_remove_comment::id
.is_not_null()
.and(comment::creator_id.eq(modded_person)),
)
.or(
mod_remove_post::id
.is_not_null()
.and(post::creator_id.eq(modded_person)),
)
.or(mod_transfer_community::other_person_id.eq(modded_person));
let comment_join = mod_remove_comment::comment_id.eq(comment::id);
let post_join = admin_purge_comment::post_id
.eq(post::id)
.or(mod_feature_post::post_id.eq(post::id))
.or(mod_lock_post::post_id.eq(post::id))
.or(
mod_remove_comment::id
.is_not_null()
.and(comment::post_id.eq(post::id)),
)
.or(mod_remove_post::post_id.eq(post::id));
let community_join = admin_purge_post::community_id
.eq(community::id)
.or(mod_add_community::community_id.eq(community::id))
.or(mod_ban_from_community::community_id.eq(community::id))
.or(
mod_feature_post::id
.is_not_null()
.and(post::community_id.eq(community::id)),
)
.or(mod_hide_community::community_id.eq(community::id))
.or(
mod_lock_post::id
.is_not_null()
.and(post::community_id.eq(community::id)),
)
.or(
mod_remove_comment::id
.is_not_null()
.and(post::community_id.eq(community::id)),
)
.or(mod_remove_community::community_id.eq(community::id))
.or(
mod_remove_post::id
.is_not_null()
.and(post::community_id.eq(community::id)),
)
.or(mod_transfer_community::community_id.eq(community::id));
let instance_join = admin_allow_instance::instance_id
.eq(instance::id)
.or(admin_block_instance::instance_id.eq(instance::id));
let mut query = modlog_combined::table
.left_join(admin_allow_instance::table)
.left_join(admin_block_instance::table)
.left_join(admin_purge_comment::table)
.left_join(admin_purge_community::table)
.left_join(admin_purge_person::table)
.left_join(admin_purge_post::table)
.left_join(mod_add::table)
.left_join(mod_add_community::table)
.left_join(mod_ban::table)
.left_join(mod_ban_from_community::table)
.left_join(mod_feature_post::table)
.left_join(mod_hide_community::table)
.left_join(mod_lock_post::table)
.left_join(mod_remove_comment::table)
.left_join(mod_remove_community::table)
.left_join(mod_remove_post::table)
.left_join(mod_transfer_community::table)
// The moderator
.left_join(person::table.on(moderator_names_join))
// The comment
.left_join(comment::table.on(comment_join))
// The post
.left_join(post::table.on(post_join))
// The community
.left_join(community::table.on(community_join))
// The instance
.left_join(instance::table.on(instance_join))
// The modded person
.left_join(aliases::person1.on(modded_person_join))
.select((
admin_allow_instance::all_columns.nullable(),
admin_block_instance::all_columns.nullable(),
admin_purge_comment::all_columns.nullable(),
admin_purge_community::all_columns.nullable(),
admin_purge_person::all_columns.nullable(),
admin_purge_post::all_columns.nullable(),
mod_add::all_columns.nullable(),
mod_add_community::all_columns.nullable(),
mod_ban::all_columns.nullable(),
mod_ban_from_community::all_columns.nullable(),
mod_feature_post::all_columns.nullable(),
mod_hide_community::all_columns.nullable(),
mod_lock_post::all_columns.nullable(),
mod_remove_comment::all_columns.nullable(),
mod_remove_community::all_columns.nullable(),
mod_remove_post::all_columns.nullable(),
mod_transfer_community::all_columns.nullable(),
// Shared
person::all_columns.nullable(),
aliases::person1.fields(person::all_columns).nullable(),
instance::all_columns.nullable(),
community::all_columns.nullable(),
post::all_columns.nullable(),
comment::all_columns.nullable(),
))
.into_boxed();
if let Some(mod_person_id) = self.mod_person_id {
query = query.filter(person::id.eq(mod_person_id));
};
if let Some(modded_person_id) = self.modded_person_id {
query = query.filter(modded_person.eq(modded_person_id));
};
if let Some(community_id) = self.community_id {
query = query.filter(community::id.eq(community_id))
}
if let Some(post_id) = self.post_id {
query = query.filter(post::id.eq(post_id))
}
if let Some(comment_id) = self.comment_id {
query = query.filter(comment::id.eq(comment_id))
}
if let Some(type_) = self.type_ {
query = match type_ {
ModlogActionType::All => query,
ModlogActionType::ModRemovePost => {
query.filter(modlog_combined::mod_remove_post_id.is_not_null())
}
ModlogActionType::ModLockPost => {
query.filter(modlog_combined::mod_lock_post_id.is_not_null())
}
ModlogActionType::ModFeaturePost => {
query.filter(modlog_combined::mod_feature_post_id.is_not_null())
}
ModlogActionType::ModRemoveComment => {
query.filter(modlog_combined::mod_remove_comment_id.is_not_null())
}
ModlogActionType::ModRemoveCommunity => {
query.filter(modlog_combined::mod_remove_community_id.is_not_null())
}
ModlogActionType::ModBanFromCommunity => {
query.filter(modlog_combined::mod_ban_from_community_id.is_not_null())
}
ModlogActionType::ModAddCommunity => {
query.filter(modlog_combined::mod_add_community_id.is_not_null())
}
ModlogActionType::ModTransferCommunity => {
query.filter(modlog_combined::mod_transfer_community_id.is_not_null())
}
ModlogActionType::ModAdd => query.filter(modlog_combined::mod_add_id.is_not_null()),
ModlogActionType::ModBan => query.filter(modlog_combined::mod_ban_id.is_not_null()),
ModlogActionType::ModHideCommunity => {
query.filter(modlog_combined::mod_hide_community_id.is_not_null())
}
ModlogActionType::AdminPurgePerson => {
query.filter(modlog_combined::admin_purge_person_id.is_not_null())
}
ModlogActionType::AdminPurgeCommunity => {
query.filter(modlog_combined::admin_purge_community_id.is_not_null())
}
ModlogActionType::AdminPurgePost => {
query.filter(modlog_combined::admin_purge_post_id.is_not_null())
}
ModlogActionType::AdminPurgeComment => {
query.filter(modlog_combined::admin_purge_comment_id.is_not_null())
}
ModlogActionType::AdminBlockInstance => {
query.filter(modlog_combined::admin_block_instance_id.is_not_null())
}
ModlogActionType::AdminAllowInstance => {
query.filter(modlog_combined::admin_allow_instance_id.is_not_null())
}
}
}
let mut query = PaginatedQueryBuilder::new(query);
let page_after = self.page_after.map(|c| c.0);
if self.page_back.unwrap_or_default() {
query = query.before(page_after).limit_and_offset_from_end();
} else {
query = query.after(page_after);
}
// Tie breaker
query = query.then_desc(key::published).then_desc(key::id);
let res = query.load::<ModlogCombinedViewInternal>(conn).await?;
// Map the query results to the enum
let out = res.into_iter().filter_map(|u| u.map_to_enum()).collect();
Ok(out)
}
}
impl InternalToCombinedView for ModlogCombinedViewInternal {
type CombinedView = ModlogCombinedView;
fn map_to_enum(&self) -> Option<Self::CombinedView> {
// Use for a short alias
let v = self.clone();
if let (Some(admin_allow_instance), Some(instance)) =
(v.admin_allow_instance, v.instance.clone())
{
Some(ModlogCombinedView::AdminAllowInstance(
AdminAllowInstanceView {
admin_allow_instance,
instance,
admin: v.moderator,
},
))
} else if let (Some(admin_block_instance), Some(instance)) =
(v.admin_block_instance, v.instance)
{
Some(ModlogCombinedView::AdminBlockInstance(
AdminBlockInstanceView {
admin_block_instance,
instance,
admin: v.moderator,
},
))
} else if let (Some(admin_purge_comment), Some(post)) = (v.admin_purge_comment, v.post.clone())
{
Some(ModlogCombinedView::AdminPurgeComment(
AdminPurgeCommentView {
admin_purge_comment,
post,
admin: v.moderator,
},
))
} else if let Some(admin_purge_community) = v.admin_purge_community {
Some(ModlogCombinedView::AdminPurgeCommunity(
AdminPurgeCommunityView {
admin_purge_community,
admin: v.moderator,
},
))
} else if let Some(admin_purge_person) = v.admin_purge_person {
Some(ModlogCombinedView::AdminPurgePerson(AdminPurgePersonView {
admin_purge_person,
admin: v.moderator,
}))
} else if let (Some(admin_purge_post), Some(community)) =
(v.admin_purge_post, v.community.clone())
{
Some(ModlogCombinedView::AdminPurgePost(AdminPurgePostView {
admin_purge_post,
admin: v.moderator,
community,
}))
} else if let (Some(mod_add), Some(modded_person)) = (v.mod_add, v.modded_person.clone()) {
Some(ModlogCombinedView::ModAdd(ModAddView {
mod_add,
moderator: v.moderator,
modded_person,
}))
} else if let (Some(mod_add_community), Some(modded_person), Some(community)) = (
v.mod_add_community,
v.modded_person.clone(),
v.community.clone(),
) {
Some(ModlogCombinedView::ModAddCommunity(ModAddCommunityView {
mod_add_community,
moderator: v.moderator,
modded_person,
community,
}))
} else if let (Some(mod_ban), Some(modded_person)) = (v.mod_ban, v.modded_person.clone()) {
Some(ModlogCombinedView::ModBan(ModBanView {
mod_ban,
moderator: v.moderator,
modded_person,
}))
} else if let (Some(mod_ban_from_community), Some(modded_person), Some(community)) = (
v.mod_ban_from_community,
v.modded_person.clone(),
v.community.clone(),
) {
Some(ModlogCombinedView::ModBanFromCommunity(
ModBanFromCommunityView {
mod_ban_from_community,
moderator: v.moderator,
modded_person,
community,
},
))
} else if let (Some(mod_feature_post), Some(modded_person), Some(community), Some(post)) = (
v.mod_feature_post,
v.modded_person.clone(),
v.community.clone(),
v.post.clone(),
) {
Some(ModlogCombinedView::ModFeaturePost(ModFeaturePostView {
mod_feature_post,
moderator: v.moderator,
modded_person,
community,
post,
}))
} else if let (Some(mod_hide_community), Some(community)) =
(v.mod_hide_community, v.community.clone())
{
Some(ModlogCombinedView::ModHideCommunity(ModHideCommunityView {
mod_hide_community,
admin: v.moderator,
community,
}))
} else if let (Some(mod_lock_post), Some(modded_person), Some(community), Some(post)) = (
v.mod_lock_post,
v.modded_person.clone(),
v.community.clone(),
v.post.clone(),
) {
Some(ModlogCombinedView::ModLockPost(ModLockPostView {
mod_lock_post,
moderator: v.moderator,
modded_person,
community,
post,
}))
} else if let (
Some(mod_remove_comment),
Some(modded_person),
Some(community),
Some(post),
Some(comment),
) = (
v.mod_remove_comment,
v.modded_person.clone(),
v.community.clone(),
v.post.clone(),
v.comment,
) {
Some(ModlogCombinedView::ModRemoveComment(ModRemoveCommentView {
mod_remove_comment,
moderator: v.moderator,
modded_person,
community,
post,
comment,
}))
} else if let (Some(mod_remove_community), Some(community)) =
(v.mod_remove_community, v.community.clone())
{
Some(ModlogCombinedView::ModRemoveCommunity(
ModRemoveCommunityView {
mod_remove_community,
moderator: v.moderator,
community,
},
))
} else if let (Some(mod_remove_post), Some(modded_person), Some(community), Some(post)) = (
v.mod_remove_post,
v.modded_person.clone(),
v.community.clone(),
v.post.clone(),
) {
Some(ModlogCombinedView::ModRemovePost(ModRemovePostView {
mod_remove_post,
moderator: v.moderator,
modded_person,
community,
post,
}))
} else if let (Some(mod_transfer_community), Some(modded_person), Some(community)) = (
v.mod_transfer_community,
v.modded_person.clone(),
v.community.clone(),
) {
Some(ModlogCombinedView::ModTransferCommunity(
ModTransferCommunityView {
mod_transfer_community,
moderator: v.moderator,
modded_person,
community,
},
))
} else {
None
}
}
}
// TODO add tests, especially for all the filters

View file

@ -1,37 +1,34 @@
#[cfg(feature = "full")]
use diesel::Queryable;
use lemmy_db_schema::{
newtypes::{CommentId, CommunityId, PersonId, PostId},
source::{
comment::Comment,
community::Community,
instance::Instance,
mod_log::{
admin::{
AdminAllowInstance,
AdminBlockInstance,
AdminPurgeComment,
AdminPurgeCommunity,
AdminPurgePerson,
AdminPurgePost,
},
moderator::{
ModAdd,
ModAddCommunity,
ModBan,
ModBanFromCommunity,
ModFeaturePost,
ModHideCommunity,
ModLockPost,
ModRemoveComment,
ModRemoveCommunity,
ModRemovePost,
ModTransferCommunity,
},
use lemmy_db_schema::source::{
comment::Comment,
community::Community,
instance::Instance,
mod_log::{
admin::{
AdminAllowInstance,
AdminBlockInstance,
AdminPurgeComment,
AdminPurgeCommunity,
AdminPurgePerson,
AdminPurgePost,
},
moderator::{
ModAdd,
ModAddCommunity,
ModBan,
ModBanFromCommunity,
ModFeaturePost,
ModHideCommunity,
ModLockPost,
ModRemoveComment,
ModRemoveCommunity,
ModRemovePost,
ModTransferCommunity,
},
person::Person,
post::Post,
},
person::Person,
post::Post,
};
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
@ -39,7 +36,7 @@ use serde_with::skip_serializing_none;
use ts_rs::TS;
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone)]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
#[cfg_attr(feature = "full", ts(export))]
@ -53,7 +50,7 @@ pub struct ModAddCommunityView {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone)]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
#[cfg_attr(feature = "full", ts(export))]
@ -66,7 +63,7 @@ pub struct ModAddView {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone)]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
#[cfg_attr(feature = "full", ts(export))]
@ -76,11 +73,11 @@ pub struct ModBanFromCommunityView {
#[cfg_attr(feature = "full", ts(optional))]
pub moderator: Option<Person>,
pub community: Community,
pub banned_person: Person,
pub modded_person: Person,
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone)]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
#[cfg_attr(feature = "full", ts(export))]
@ -89,11 +86,11 @@ pub struct ModBanView {
pub mod_ban: ModBan,
#[cfg_attr(feature = "full", ts(optional))]
pub moderator: Option<Person>,
pub banned_person: Person,
pub modded_person: Person,
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone)]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
#[cfg_attr(feature = "full", ts(export))]
@ -106,7 +103,7 @@ pub struct ModHideCommunityView {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone)]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
#[cfg_attr(feature = "full", ts(export))]
@ -115,12 +112,13 @@ pub struct ModLockPostView {
pub mod_lock_post: ModLockPost,
#[cfg_attr(feature = "full", ts(optional))]
pub moderator: Option<Person>,
pub modded_person: Person,
pub post: Post,
pub community: Community,
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone)]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
#[cfg_attr(feature = "full", ts(export))]
@ -129,14 +127,14 @@ pub struct ModRemoveCommentView {
pub mod_remove_comment: ModRemoveComment,
#[cfg_attr(feature = "full", ts(optional))]
pub moderator: Option<Person>,
pub modded_person: Person,
pub comment: Comment,
pub commenter: Person,
pub post: Post,
pub community: Community,
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone)]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
#[cfg_attr(feature = "full", ts(export))]
@ -149,7 +147,7 @@ pub struct ModRemoveCommunityView {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone)]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
#[cfg_attr(feature = "full", ts(export))]
@ -158,12 +156,13 @@ pub struct ModRemovePostView {
pub mod_remove_post: ModRemovePost,
#[cfg_attr(feature = "full", ts(optional))]
pub moderator: Option<Person>,
pub modded_person: Person,
pub post: Post,
pub community: Community,
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone)]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
#[cfg_attr(feature = "full", ts(export))]
@ -172,12 +171,13 @@ pub struct ModFeaturePostView {
pub mod_feature_post: ModFeaturePost,
#[cfg_attr(feature = "full", ts(optional))]
pub moderator: Option<Person>,
pub modded_person: Person,
pub post: Post,
pub community: Community,
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone)]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
#[cfg_attr(feature = "full", ts(export))]
@ -191,7 +191,7 @@ pub struct ModTransferCommunityView {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone)]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
#[cfg_attr(feature = "full", ts(export))]
@ -204,7 +204,7 @@ pub struct AdminPurgeCommentView {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone)]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
#[cfg_attr(feature = "full", ts(export))]
@ -216,7 +216,7 @@ pub struct AdminPurgeCommunityView {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone)]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
#[cfg_attr(feature = "full", ts(export))]
@ -228,7 +228,7 @@ pub struct AdminPurgePersonView {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone)]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
#[cfg_attr(feature = "full", ts(export))]
@ -241,7 +241,7 @@ pub struct AdminPurgePostView {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone)]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
#[cfg_attr(feature = "full", ts(export))]
@ -254,59 +254,56 @@ pub struct AdminBlockInstanceView {
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone)]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
#[cfg_attr(feature = "full", ts(export))]
/// When an admin purges a post.
pub struct AdminAllowInstanceView {
pub admin_block_instance: AdminAllowInstance,
pub admin_allow_instance: AdminAllowInstance,
pub instance: Instance,
#[cfg_attr(feature = "full", ts(optional))]
pub admin: Option<Person>,
}
#[skip_serializing_none]
#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
#[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
/// like PaginationCursor but for the modlog_combined
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
/// Querying / filtering the modlog.
pub struct ModlogListParams {
#[cfg_attr(feature = "full", ts(optional))]
pub community_id: Option<CommunityId>,
#[cfg_attr(feature = "full", ts(optional))]
pub mod_person_id: Option<PersonId>,
#[cfg_attr(feature = "full", ts(optional))]
pub other_person_id: Option<PersonId>,
#[cfg_attr(feature = "full", ts(optional))]
pub post_id: Option<PostId>,
#[cfg_attr(feature = "full", ts(optional))]
pub comment_id: Option<CommentId>,
#[cfg_attr(feature = "full", ts(optional))]
pub page: Option<i64>,
#[cfg_attr(feature = "full", ts(optional))]
// TODO page_after, page_back
pub limit: Option<i64>,
pub hide_modlog_names: bool,
}
pub struct ModlogCombinedPaginationCursor(pub String);
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(Queryable))]
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
/// A combined modlog view
pub struct ModlogCombinedViewInternal {
// Post-specific
// Specific
pub admin_allow_instance: Option<AdminAllowInstance>,
pub admin_block_instance: Option<AdminBlockInstance>,
pub admin_purge_comment: Option<AdminPurgeComment>,
pub admin_purge_community: Option<AdminPurgeCommunity>,
pub admin_purge_person: Option<AdminPurgePerson>,
pub admin_purge_post: Option<AdminPurgePost>,
pub mod_add: Option<ModAdd>,
pub mod_add_community: Option<ModAddCommunity>,
pub mod_ban: Option<ModBan>,
pub mod_ban_from_community: Option<ModBanFromCommunity>,
pub mod_feature_post: Option<ModFeaturePost>,
pub mod_hide_community: Option<ModHideCommunity>,
pub mod_lock_post: Option<ModLockPost>,
pub mod_remove_comment: Option<ModRemoveComment>,
pub mod_remove_community: Option<ModRemoveCommunity>,
pub mod_remove_post: Option<ModRemovePost>,
pub mod_transfer_community: Option<ModTransferCommunity>,
// Specific fields
// Shared
pub report_creator: Person,
pub item_creator: Person,
pub moderator: Option<Person>,
pub modded_person: Option<Person>,
pub instance: Option<Instance>,
pub community: Option<Community>,
pub subscribed: SubscribedType,
pub resolver: Option<Person>,
pub item_creator_is_admin: bool,
pub item_creator_banned_from_community: bool,
pub item_creator_is_moderator: bool,
pub item_creator_blocked: bool,
pub post: Option<Post>,
pub comment: Option<Comment>,
}
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]