Combined tables try 2

This commit is contained in:
Dessalines 2024-11-26 09:27:05 -05:00
parent 7304ef3261
commit 39b3ec2473
11 changed files with 354 additions and 4 deletions

View file

@ -179,6 +179,12 @@ pub struct LtreeDef(pub String);
#[cfg_attr(feature = "full", ts(export))]
pub struct DbUrl(pub(crate) Box<Url>);
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "full", derive(DieselNewType, TS))]
#[cfg_attr(feature = "full", ts(export))]
/// The report combined id
pub struct ReportCombinedId(i32);
impl DbUrl {
pub fn inner(&self) -> &Url {
&self.0

View file

@ -856,6 +856,15 @@ diesel::table! {
}
}
diesel::table! {
report_combined (id) {
id -> Int4,
published -> Timestamptz,
post_report_id -> Nullable<Int4>,
comment_report_id -> Nullable<Int4>,
}
}
diesel::table! {
secret (id) {
id -> Int4,
@ -1006,6 +1015,8 @@ diesel::joinable!(post_report -> post (post_id));
diesel::joinable!(private_message_report -> private_message (private_message_id));
diesel::joinable!(registration_application -> local_user (local_user_id));
diesel::joinable!(registration_application -> person (admin_id));
diesel::joinable!(report_combined -> comment_report (comment_report_id));
diesel::joinable!(report_combined -> post_report (post_report_id));
diesel::joinable!(site -> instance (instance_id));
diesel::joinable!(site_aggregates -> site (site_id));
diesel::joinable!(site_language -> language (language_id));
@ -1072,6 +1083,7 @@ diesel::allow_tables_to_appear_in_same_query!(
received_activity,
registration_application,
remote_image,
report_combined,
secret,
sent_activity,
site,

View file

@ -0,0 +1 @@
pub mod report;

View file

@ -0,0 +1,22 @@
use crate::newtypes::{CommentReportId, PostReportId, ReportCombinedId};
#[cfg(feature = "full")]
use crate::schema::report_combined;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
#[cfg(feature = "full")]
use ts_rs::TS;
#[skip_serializing_none]
#[derive(PartialEq, Eq, Serialize, Deserialize, Debug, Clone)]
#[cfg_attr(feature = "full", derive(Identifiable, Queryable, Selectable, TS))]
#[cfg_attr(feature = "full", diesel(table_name = report_combined))]
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
#[cfg_attr(feature = "full", ts(export))]
/// A combined reports table.
pub struct ReportCombined {
pub id: ReportCombinedId,
pub published: DateTime<Utc>,
pub post_report_id: Option<PostReportId>,
pub comment_report_id: Option<CommentReportId>,
}

View file

@ -5,6 +5,7 @@ use url::Url;
pub mod activity;
pub mod actor_language;
pub mod captcha_answer;
pub mod combined;
pub mod comment;
pub mod comment_reply;
pub mod comment_report;

View file

@ -22,6 +22,8 @@ pub mod private_message_view;
#[cfg(feature = "full")]
pub mod registration_application_view;
#[cfg(feature = "full")]
pub mod report_combined_view;
#[cfg(feature = "full")]
pub mod site_view;
pub mod structs;
#[cfg(feature = "full")]

View file

@ -136,15 +136,15 @@ fn queries<'a>() -> Queries<
query = query.order_by(post_report::published.desc());
}
let (limit, offset) = limit_and_offset(options.page, options.limit)?;
query = query.limit(limit).offset(offset);
// If its not an admin, get only the ones you mod
if !user.local_user.admin {
query = query.filter(community_actions::became_moderator.is_not_null());
}
let (limit, offset) = limit_and_offset(options.page, options.limit)?;
query = query.limit(limit).offset(offset);
query.load::<PostReportView>(&mut conn).await
};

View file

@ -0,0 +1,238 @@
use crate::structs::{
LocalUserView,
PostOrCommentReportViewTemp,
PostReportView,
ReportCombinedView,
};
use diesel::{
pg::Pg,
result::Error,
BoolExpressionMethods,
ExpressionMethods,
JoinOnDsl,
NullableExpressionMethods,
QueryDsl,
};
use diesel_async::RunQueryDsl;
use lemmy_db_schema::{
aliases::{self, creator_community_actions},
newtypes::{CommunityId, PersonId, PostReportId},
schema::{
comment_report,
community,
community_actions,
local_user,
person,
person_actions,
post,
post_actions,
post_aggregates,
post_report,
report_combined,
},
source::community::CommunityFollower,
utils::{
actions,
actions_alias,
functions::coalesce,
get_conn,
limit_and_offset,
DbConn,
DbPool,
ListFn,
Queries,
ReadFn,
},
};
use lemmy_utils::error::LemmyResult;
impl ReportCombinedView {
/// returns the current unresolved report count for the communities you mod
pub async fn get_report_count(
pool: &mut DbPool<'_>,
my_person_id: PersonId,
admin: bool,
community_id: Option<CommunityId>,
) -> Result<i64, Error> {
use diesel::dsl::count;
let conn = &mut get_conn(pool).await?;
let mut query = post_report::table
.inner_join(post::table)
.filter(post_report::resolved.eq(false))
.into_boxed();
if let Some(community_id) = community_id {
query = query.filter(post::community_id.eq(community_id))
}
// If its not an admin, get only the ones you mod
if !admin {
query
.inner_join(
community_actions::table.on(
community_actions::community_id
.eq(post::community_id)
.and(community_actions::person_id.eq(my_person_id))
.and(community_actions::became_moderator.is_not_null()),
),
)
.select(count(post_report::id))
.first::<i64>(conn)
.await
} else {
query
.select(count(post_report::id))
.first::<i64>(conn)
.await
}
}
}
#[derive(Default)]
pub struct ReportCombinedQuery {
pub community_id: Option<CommunityId>,
pub page: Option<i64>,
pub limit: Option<i64>,
pub unresolved_only: bool,
}
impl ReportCombinedQuery {
pub async fn list(
self,
pool: &mut DbPool<'_>,
user: &LocalUserView,
) -> LemmyResult<Vec<PostOrCommentReportViewTemp>> {
let options = self;
let conn = &mut get_conn(pool).await?;
let mut query = report_combined::table
.left_join(post_report::table)
.left_join(comment_report::table)
// .inner_join(post::table)
// .inner_join(community::table.on(post::community_id.eq(community::id)))
.left_join(
person::table.on(
post_report::creator_id
.eq(person::id)
.or(comment_report::creator_id.eq(person::id)),
),
)
// .inner_join(aliases::person1.on(post::creator_id.eq(aliases::person1.field(person::id))))
// .left_join(actions_alias(
// creator_community_actions,
// post::creator_id,
// post::community_id,
// ))
// .left_join(actions(
// community_actions::table,
// Some(my_person_id),
// post::community_id,
// ))
// .left_join(
// local_user::table.on(
// post::creator_id
// .eq(local_user::person_id)
// .and(local_user::admin.eq(true)),
// ),
// )
// .left_join(actions(post_actions::table, Some(my_person_id), post::id))
// .left_join(actions(
// person_actions::table,
// Some(my_person_id),
// post::creator_id,
// ))
// .inner_join(post_aggregates::table.on(post_report::post_id.eq(post_aggregates::post_id)))
// .left_join(
// aliases::person2
// .on(post_report::resolver_id.eq(aliases::person2.field(person::id).nullable())),
// )
.select((
post_report::all_columns.nullable(),
comment_report::all_columns.nullable(),
// post::all_columns,
// community::all_columns,
person::all_columns.nullable(),
// aliases::person1.fields(person::all_columns),
// creator_community_actions
// .field(community_actions::received_ban)
// .nullable()
// .is_not_null(),
// creator_community_actions
// .field(community_actions::became_moderator)
// .nullable()
// .is_not_null(),
// local_user::admin.nullable().is_not_null(),
// CommunityFollower::select_subscribed_type(),
// post_actions::saved.nullable().is_not_null(),
// post_actions::read.nullable().is_not_null(),
// post_actions::hidden.nullable().is_not_null(),
// person_actions::blocked.nullable().is_not_null(),
// post_actions::like_score.nullable(),
// coalesce(
// post_aggregates::comments.nullable() - post_actions::read_comments_amount.nullable(),
// post_aggregates::comments,
// ),
// post_aggregates::all_columns,
// aliases::person2.fields(person::all_columns.nullable()),
))
.into_boxed();
// if let Some(community_id) = options.community_id {
// query = query.filter(post::community_id.eq(community_id));
// }
// if let Some(post_id) = options.post_id {
// query = query.filter(post::id.eq(post_id));
// }
// If viewing all reports, order by newest, but if viewing unresolved only, show the oldest
// first (FIFO)
// if options.unresolved_only {
// query = query
// .filter(post_report::resolved.eq(false))
// .order_by(post_report::published.asc());
// } else {
// query = query.order_by(post_report::published.desc());
// }
// If its not an admin, get only the ones you mod
// if !user.local_user.admin {
// query = query.filter(community_actions::became_moderator.is_not_null());
// }
let (limit, offset) = limit_and_offset(options.page, options.limit)?;
query = query.limit(limit).offset(offset);
let res = query.load::<ReportCombinedView>(conn).await?;
let out = res
.iter()
.filter_map(map_to_post_or_comment_view_tmp)
.collect();
Ok(out)
}
}
fn map_to_post_or_comment_view_tmp(
view: &ReportCombinedView,
) -> Option<PostOrCommentReportViewTemp> {
// If it has post_report, you know the other fields are defined
if let (Some(post_report), Some(post_creator)) = (view.post_report.clone(), view.creator.clone())
{
Some(PostOrCommentReportViewTemp::Post {
post_report,
post_creator,
})
} else if let (Some(comment_report), Some(comment_creator)) =
(view.comment_report.clone(), view.creator.clone())
{
Some(PostOrCommentReportViewTemp::Comment {
comment_report,
comment_creator,
})
} else {
None
}
}
// TODO add tests

View file

@ -237,3 +237,56 @@ pub struct LocalImageView {
pub local_image: LocalImage,
pub person: Person,
}
#[skip_serializing_none]
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
#[cfg_attr(feature = "full", derive(TS, Queryable))]
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
// TODO TS shouldn't be necessary here, since this shouldn't be used externally
#[cfg_attr(feature = "full", ts(export))]
/// A combined report view
pub struct ReportCombinedView {
// Post-specific
pub post_report: Option<PostReport>,
// pub post_creator: Person,
// pub unread_comments: i64,
// pub post_counts: PostAggregates,
// #[cfg_attr(feature = "full", ts(optional))]
// pub resolver: Option<Person>,
// Comment-specific
pub comment_report: Option<CommentReport>,
// pub comment_creator: Person,
// pub comment: Comment,
// pub comment_counts: CommentAggregates,
// Shared
// pub post: Post,
// pub community: Community,
// pub creator: Person,
// pub creator_banned_from_community: bool,
// pub creator_is_moderator: bool,
// pub creator_is_admin: bool,
// pub subscribed: SubscribedType,
// pub saved: bool,
// pub read: bool,
// pub hidden: bool,
// pub creator_blocked: bool,
// #[cfg_attr(feature = "full", ts(optional))]
// pub my_vote: Option<i16>,
// ---
pub creator: Option<Person>,
}
pub enum PostOrCommentReportView {
Post(PostReportView),
Comment(CommentReportView),
}
pub enum PostOrCommentReportViewTemp {
Post {
post_report: PostReport,
post_creator: Person,
},
Comment {
comment_report: CommentReport,
comment_creator: Person,
},
}

View file

@ -0,0 +1 @@
DROP TABLE report_combined;

View file

@ -0,0 +1,14 @@
CREATE TABLE report_combined (
id serial PRIMARY KEY,
published timestamptz not null,
post_report_id int REFERENCES post_report ON UPDATE CASCADE ON DELETE CASCADE,
comment_report_id int REFERENCES comment_report ON UPDATE CASCADE ON DELETE CASCADE,
UNIQUE (post_report_id, comment_report_id)
);
CREATE INDEX idx_report_combined_published on report_combined (published desc);
-- TODO do history update
-- TODO do triggers in replaceable schema