From 05c3e471ae57d7565cc0e7131cf8f63b75cb79b2 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Wed, 16 Dec 2020 22:03:03 -0500 Subject: [PATCH] Adding report views. --- lemmy_api/src/comment.rs | 14 +- lemmy_api/src/post.rs | 12 +- lemmy_api/src/user.rs | 4 +- lemmy_db/src/comment_report.rs | 235 --------------------- lemmy_db/src/lib.rs | 3 - lemmy_db/src/post_report.rs | 245 ---------------------- lemmy_db/src/schema.rs | 37 ++++ lemmy_db/src/source/comment_report.rs | 73 +++++++ lemmy_db/src/source/mod.rs | 2 + lemmy_db/src/source/post_report.rs | 77 +++++++ lemmy_db/src/source/user.rs | 96 ++++++++- lemmy_db/src/views/comment_report_view.rs | 193 +++++++++++++++++ lemmy_db/src/views/mod.rs | 2 + lemmy_db/src/views/post_report_view.rs | 178 ++++++++++++++++ lemmy_structs/src/comment.rs | 4 +- lemmy_structs/src/post.rs | 14 +- 16 files changed, 684 insertions(+), 505 deletions(-) delete mode 100644 lemmy_db/src/comment_report.rs delete mode 100644 lemmy_db/src/post_report.rs create mode 100644 lemmy_db/src/source/comment_report.rs create mode 100644 lemmy_db/src/source/post_report.rs create mode 100644 lemmy_db/src/views/comment_report_view.rs create mode 100644 lemmy_db/src/views/post_report_view.rs diff --git a/lemmy_api/src/comment.rs b/lemmy_api/src/comment.rs index b39444efd..689fe4b8a 100644 --- a/lemmy_api/src/comment.rs +++ b/lemmy_api/src/comment.rs @@ -10,9 +10,15 @@ use crate::{ use actix_web::web::Data; use lemmy_apub::{ApubLikeableType, ApubObjectType}; use lemmy_db::{ - comment_report::*, - source::{comment::*, moderator::*, post::*, user::*}, + source::{ + comment::*, + comment_report::{CommentReport, CommentReportForm}, + moderator::*, + post::*, + user::*, + }, views::{ + comment_report_view::{CommentReportQueryBuilder, CommentReportView}, comment_view::{CommentQueryBuilder, CommentView}, site_view::SiteView, }, @@ -776,7 +782,7 @@ impl Perform for ResolveCommentReport { .await??; let user_id = user.id; - is_mod_or_admin(context.pool(), user_id, report.community_id).await?; + is_mod_or_admin(context.pool(), user_id, report.community.id).await?; let resolved = data.resolved; let resolve_fun = move |conn: &'_ _| { @@ -800,7 +806,7 @@ impl Perform for ResolveCommentReport { context.chat_server().do_send(SendModRoomMessage { op: UserOperation::ResolveCommentReport, response: res.clone(), - community_id: report.community_id, + community_id: report.community.id, websocket_id, }); diff --git a/lemmy_api/src/post.rs b/lemmy_api/src/post.rs index 02da229fd..22f95877a 100644 --- a/lemmy_api/src/post.rs +++ b/lemmy_api/src/post.rs @@ -11,11 +11,15 @@ use actix_web::web::Data; use lemmy_apub::{ApubLikeableType, ApubObjectType}; use lemmy_db::{ naive_now, - post_report::*, - source::{moderator::*, post::*}, + source::{ + moderator::*, + post::*, + post_report::{PostReport, PostReportForm}, + }, views::{ comment_view::CommentQueryBuilder, community::{community_moderator_view::CommunityModeratorView, community_view::CommunityView}, + post_report_view::{PostReportQueryBuilder, PostReportView}, post_view::{PostQueryBuilder, PostView}, site_view::SiteView, }, @@ -835,7 +839,7 @@ impl Perform for ResolvePostReport { .await??; let user_id = user.id; - is_mod_or_admin(context.pool(), user_id, report.community_id).await?; + is_mod_or_admin(context.pool(), user_id, report.community.id).await?; let resolved = data.resolved; let resolve_fun = move |conn: &'_ _| { @@ -858,7 +862,7 @@ impl Perform for ResolvePostReport { context.chat_server().do_send(SendModRoomMessage { op: UserOperation::ResolvePostReport, response: res.clone(), - community_id: report.community_id, + community_id: report.community.id, websocket_id, }); diff --git a/lemmy_api/src/user.rs b/lemmy_api/src/user.rs index 327a1a426..f31e42e5a 100644 --- a/lemmy_api/src/user.rs +++ b/lemmy_api/src/user.rs @@ -15,10 +15,8 @@ use captcha::{gen, Difficulty}; use chrono::Duration; use lemmy_apub::ApubObjectType; use lemmy_db::{ - comment_report::CommentReportView, diesel_option_overwrite, naive_now, - post_report::PostReportView, source::{ comment::*, community::*, @@ -31,11 +29,13 @@ use lemmy_db::{ user_mention::*, }, views::{ + comment_report_view::CommentReportView, comment_view::CommentQueryBuilder, community::{ community_follower_view::CommunityFollowerView, community_moderator_view::CommunityModeratorView, }, + post_report_view::PostReportView, post_view::PostQueryBuilder, private_message_view::{PrivateMessageQueryBuilder, PrivateMessageView}, site_view::SiteView, diff --git a/lemmy_db/src/comment_report.rs b/lemmy_db/src/comment_report.rs deleted file mode 100644 index 240b73430..000000000 --- a/lemmy_db/src/comment_report.rs +++ /dev/null @@ -1,235 +0,0 @@ -use diesel::{dsl::*, pg::Pg, result::Error, *}; -use serde::{Deserialize, Serialize}; - -use crate::{ - limit_and_offset, - naive_now, - schema::comment_report, - source::comment::Comment, - MaybeOptional, - Reportable, -}; - -table! { - comment_report_view (id) { - id -> Int4, - creator_id -> Int4, - comment_id -> Int4, - original_comment_text -> Text, - reason -> Text, - resolved -> Bool, - resolver_id -> Nullable, - published -> Timestamp, - updated -> Nullable, - post_id -> Int4, - current_comment_text -> Text, - community_id -> Int4, - creator_actor_id -> Text, - creator_name -> Varchar, - creator_preferred_username -> Nullable, - creator_avatar -> Nullable, - creator_local -> Bool, - comment_creator_id -> Int4, - comment_creator_actor_id -> Text, - comment_creator_name -> Varchar, - comment_creator_preferred_username -> Nullable, - comment_creator_avatar -> Nullable, - comment_creator_local -> Bool, - resolver_actor_id -> Nullable, - resolver_name -> Nullable, - resolver_preferred_username -> Nullable, - resolver_avatar -> Nullable, - resolver_local -> Nullable, - } -} - -#[derive(Identifiable, Queryable, Associations, PartialEq, Debug, Serialize)] -#[belongs_to(Comment)] -#[table_name = "comment_report"] -pub struct CommentReport { - pub id: i32, - pub creator_id: i32, - pub comment_id: i32, - pub original_comment_text: String, - pub reason: String, - pub resolved: bool, - pub resolver_id: Option, - pub published: chrono::NaiveDateTime, - pub updated: Option, -} - -#[derive(Insertable, AsChangeset, Clone)] -#[table_name = "comment_report"] -pub struct CommentReportForm { - pub creator_id: i32, - pub comment_id: i32, - pub original_comment_text: String, - pub reason: String, -} - -impl Reportable for CommentReport { - /// creates a comment report and returns it - /// - /// * `conn` - the postgres connection - /// * `comment_report_form` - the filled CommentReportForm to insert - fn report(conn: &PgConnection, comment_report_form: &CommentReportForm) -> Result { - use crate::schema::comment_report::dsl::*; - insert_into(comment_report) - .values(comment_report_form) - .get_result::(conn) - } - - /// resolve a comment report - /// - /// * `conn` - the postgres connection - /// * `report_id` - the id of the report to resolve - /// * `by_resolver_id` - the id of the user resolving the report - fn resolve(conn: &PgConnection, report_id: i32, by_resolver_id: i32) -> Result { - use crate::schema::comment_report::dsl::*; - update(comment_report.find(report_id)) - .set(( - resolved.eq(true), - resolver_id.eq(by_resolver_id), - updated.eq(naive_now()), - )) - .execute(conn) - } - - /// unresolve a comment report - /// - /// * `conn` - the postgres connection - /// * `report_id` - the id of the report to unresolve - /// * `by_resolver_id` - the id of the user unresolving the report - fn unresolve(conn: &PgConnection, report_id: i32, by_resolver_id: i32) -> Result { - use crate::schema::comment_report::dsl::*; - update(comment_report.find(report_id)) - .set(( - resolved.eq(false), - resolver_id.eq(by_resolver_id), - updated.eq(naive_now()), - )) - .execute(conn) - } -} - -#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, Clone)] -#[table_name = "comment_report_view"] -pub struct CommentReportView { - pub id: i32, - pub creator_id: i32, - pub comment_id: i32, - pub original_comment_text: String, - pub reason: String, - pub resolved: bool, - pub resolver_id: Option, - pub published: chrono::NaiveDateTime, - pub updated: Option, - pub post_id: i32, - pub current_comment_text: String, - pub community_id: i32, - pub creator_actor_id: String, - pub creator_name: String, - pub creator_preferred_username: Option, - pub creator_avatar: Option, - pub creator_local: bool, - pub comment_creator_id: i32, - pub comment_creator_actor_id: String, - pub comment_creator_name: String, - pub comment_creator_preferred_username: Option, - pub comment_creator_avatar: Option, - pub comment_creator_local: bool, - pub resolver_actor_id: Option, - pub resolver_name: Option, - pub resolver_preferred_username: Option, - pub resolver_avatar: Option, - pub resolver_local: Option, -} - -pub struct CommentReportQueryBuilder<'a> { - conn: &'a PgConnection, - query: comment_report_view::BoxedQuery<'a, Pg>, - for_community_ids: Option>, - page: Option, - limit: Option, - resolved: Option, -} - -impl CommentReportView { - /// returns the CommentReportView for the provided report_id - /// - /// * `report_id` - the report id to obtain - pub fn read(conn: &PgConnection, report_id: i32) -> Result { - use super::comment_report::comment_report_view::dsl::*; - comment_report_view.find(report_id).first::(conn) - } - - /// returns the current unresolved comment report count for the supplied community ids - /// - /// * `community_ids` - a Vec of community_ids to get a count for - pub fn get_report_count(conn: &PgConnection, community_ids: &[i32]) -> Result { - use super::comment_report::comment_report_view::dsl::*; - comment_report_view - .filter(resolved.eq(false).and(community_id.eq_any(community_ids))) - .select(count(id)) - .first::(conn) - } -} - -impl<'a> CommentReportQueryBuilder<'a> { - pub fn create(conn: &'a PgConnection) -> Self { - use super::comment_report::comment_report_view::dsl::*; - - let query = comment_report_view.into_boxed(); - - CommentReportQueryBuilder { - conn, - query, - for_community_ids: None, - page: None, - limit: None, - resolved: Some(false), - } - } - - pub fn community_ids>>(mut self, community_ids: T) -> Self { - self.for_community_ids = community_ids.get_optional(); - self - } - - pub fn page>(mut self, page: T) -> Self { - self.page = page.get_optional(); - self - } - - pub fn limit>(mut self, limit: T) -> Self { - self.limit = limit.get_optional(); - self - } - - pub fn resolved>(mut self, resolved: T) -> Self { - self.resolved = resolved.get_optional(); - self - } - - pub fn list(self) -> Result, Error> { - use super::comment_report::comment_report_view::dsl::*; - - let mut query = self.query; - - if let Some(comm_ids) = self.for_community_ids { - query = query.filter(community_id.eq_any(comm_ids)); - } - - if let Some(resolved_flag) = self.resolved { - query = query.filter(resolved.eq(resolved_flag)); - } - - let (limit, offset) = limit_and_offset(self.page, self.limit); - - query - .order_by(published.asc()) - .limit(limit) - .offset(offset) - .load::(self.conn) - } -} diff --git a/lemmy_db/src/lib.rs b/lemmy_db/src/lib.rs index 6b026f95d..387e38a28 100644 --- a/lemmy_db/src/lib.rs +++ b/lemmy_db/src/lib.rs @@ -11,9 +11,6 @@ use regex::Regex; use serde::{Deserialize, Serialize}; use std::{env, env::VarError}; -pub mod comment_report; -pub mod post_report; - pub mod aggregates; pub mod schema; pub mod source; diff --git a/lemmy_db/src/post_report.rs b/lemmy_db/src/post_report.rs deleted file mode 100644 index 230368c5c..000000000 --- a/lemmy_db/src/post_report.rs +++ /dev/null @@ -1,245 +0,0 @@ -use diesel::{dsl::*, pg::Pg, result::Error, *}; -use serde::{Deserialize, Serialize}; - -use crate::{ - limit_and_offset, - naive_now, - schema::post_report, - source::post::Post, - MaybeOptional, - Reportable, -}; - -table! { - post_report_view (id) { - id -> Int4, - creator_id -> Int4, - post_id -> Int4, - original_post_name -> Varchar, - original_post_url -> Nullable, - original_post_body -> Nullable, - reason -> Text, - resolved -> Bool, - resolver_id -> Nullable, - published -> Timestamp, - updated -> Nullable, - current_post_name -> Varchar, - current_post_url -> Nullable, - current_post_body -> Nullable, - community_id -> Int4, - creator_actor_id -> Text, - creator_name -> Varchar, - creator_preferred_username -> Nullable, - creator_avatar -> Nullable, - creator_local -> Bool, - post_creator_id -> Int4, - post_creator_actor_id -> Text, - post_creator_name -> Varchar, - post_creator_preferred_username -> Nullable, - post_creator_avatar -> Nullable, - post_creator_local -> Bool, - resolver_actor_id -> Nullable, - resolver_name -> Nullable, - resolver_preferred_username -> Nullable, - resolver_avatar -> Nullable, - resolver_local -> Nullable, - } -} - -#[derive(Identifiable, Queryable, Associations, PartialEq, Serialize, Deserialize, Debug)] -#[belongs_to(Post)] -#[table_name = "post_report"] -pub struct PostReport { - pub id: i32, - pub creator_id: i32, - pub post_id: i32, - pub original_post_name: String, - pub original_post_url: Option, - pub original_post_body: Option, - pub reason: String, - pub resolved: bool, - pub resolver_id: Option, - pub published: chrono::NaiveDateTime, - pub updated: Option, -} - -#[derive(Insertable, AsChangeset, Clone)] -#[table_name = "post_report"] -pub struct PostReportForm { - pub creator_id: i32, - pub post_id: i32, - pub original_post_name: String, - pub original_post_url: Option, - pub original_post_body: Option, - pub reason: String, -} - -impl Reportable for PostReport { - /// creates a post report and returns it - /// - /// * `conn` - the postgres connection - /// * `post_report_form` - the filled CommentReportForm to insert - fn report(conn: &PgConnection, post_report_form: &PostReportForm) -> Result { - use crate::schema::post_report::dsl::*; - insert_into(post_report) - .values(post_report_form) - .get_result::(conn) - } - - /// resolve a post report - /// - /// * `conn` - the postgres connection - /// * `report_id` - the id of the report to resolve - /// * `by_resolver_id` - the id of the user resolving the report - fn resolve(conn: &PgConnection, report_id: i32, by_resolver_id: i32) -> Result { - use crate::schema::post_report::dsl::*; - update(post_report.find(report_id)) - .set(( - resolved.eq(true), - resolver_id.eq(by_resolver_id), - updated.eq(naive_now()), - )) - .execute(conn) - } - - /// resolve a post report - /// - /// * `conn` - the postgres connection - /// * `report_id` - the id of the report to unresolve - /// * `by_resolver_id` - the id of the user unresolving the report - fn unresolve(conn: &PgConnection, report_id: i32, by_resolver_id: i32) -> Result { - use crate::schema::post_report::dsl::*; - update(post_report.find(report_id)) - .set(( - resolved.eq(false), - resolver_id.eq(by_resolver_id), - updated.eq(naive_now()), - )) - .execute(conn) - } -} - -#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, Clone)] -#[table_name = "post_report_view"] -pub struct PostReportView { - pub id: i32, - pub creator_id: i32, - pub post_id: i32, - pub original_post_name: String, - pub original_post_url: Option, - pub original_post_body: Option, - pub reason: String, - pub resolved: bool, - pub resolver_id: Option, - pub published: chrono::NaiveDateTime, - pub updated: Option, - pub current_post_name: String, - pub current_post_url: Option, - pub current_post_body: Option, - pub community_id: i32, - pub creator_actor_id: String, - pub creator_name: String, - pub creator_preferred_username: Option, - pub creator_avatar: Option, - pub creator_local: bool, - pub post_creator_id: i32, - pub post_creator_actor_id: String, - pub post_creator_name: String, - pub post_creator_preferred_username: Option, - pub post_creator_avatar: Option, - pub post_creator_local: bool, - pub resolver_actor_id: Option, - pub resolver_name: Option, - pub resolver_preferred_username: Option, - pub resolver_avatar: Option, - pub resolver_local: Option, -} - -impl PostReportView { - /// returns the PostReportView for the provided report_id - /// - /// * `report_id` - the report id to obtain - pub fn read(conn: &PgConnection, report_id: i32) -> Result { - use super::post_report::post_report_view::dsl::*; - post_report_view.find(report_id).first::(conn) - } - - /// returns the current unresolved post report count for the supplied community ids - /// - /// * `community_ids` - a Vec of community_ids to get a count for - pub fn get_report_count(conn: &PgConnection, community_ids: &[i32]) -> Result { - use super::post_report::post_report_view::dsl::*; - post_report_view - .filter(resolved.eq(false).and(community_id.eq_any(community_ids))) - .select(count(id)) - .first::(conn) - } -} - -pub struct PostReportQueryBuilder<'a> { - conn: &'a PgConnection, - query: post_report_view::BoxedQuery<'a, Pg>, - for_community_ids: Option>, - page: Option, - limit: Option, - resolved: Option, -} - -impl<'a> PostReportQueryBuilder<'a> { - pub fn create(conn: &'a PgConnection) -> Self { - use super::post_report::post_report_view::dsl::*; - - let query = post_report_view.into_boxed(); - - PostReportQueryBuilder { - conn, - query, - for_community_ids: None, - page: None, - limit: None, - resolved: Some(false), - } - } - - pub fn community_ids>>(mut self, community_ids: T) -> Self { - self.for_community_ids = community_ids.get_optional(); - self - } - - pub fn page>(mut self, page: T) -> Self { - self.page = page.get_optional(); - self - } - - pub fn limit>(mut self, limit: T) -> Self { - self.limit = limit.get_optional(); - self - } - - pub fn resolved>(mut self, resolved: T) -> Self { - self.resolved = resolved.get_optional(); - self - } - - pub fn list(self) -> Result, Error> { - use super::post_report::post_report_view::dsl::*; - - let mut query = self.query; - - if let Some(comm_ids) = self.for_community_ids { - query = query.filter(community_id.eq_any(comm_ids)); - } - - if let Some(resolved_flag) = self.resolved { - query = query.filter(resolved.eq(resolved_flag)); - } - - let (limit, offset) = limit_and_offset(self.page, self.limit); - - query - .order_by(published.asc()) - .limit(limit) - .offset(offset) - .load::(self.conn) - } -} diff --git a/lemmy_db/src/schema.rs b/lemmy_db/src/schema.rs index cbfce8761..75883df57 100644 --- a/lemmy_db/src/schema.rs +++ b/lemmy_db/src/schema.rs @@ -615,9 +615,45 @@ table! { } } +table! { + user_alias_2 (id) { + id -> Int4, + name -> Varchar, + preferred_username -> Nullable, + password_encrypted -> Text, + email -> Nullable, + avatar -> Nullable, + admin -> Bool, + banned -> Bool, + published -> Timestamp, + updated -> Nullable, + show_nsfw -> Bool, + theme -> Varchar, + default_sort_type -> Int2, + default_listing_type -> Int2, + lang -> Varchar, + show_avatars -> Bool, + send_notifications_to_email -> Bool, + matrix_user_id -> Nullable, + actor_id -> Varchar, + bio -> Nullable, + local -> Bool, + private_key -> Nullable, + public_key -> Nullable, + last_refreshed_at -> Timestamp, + banner -> Nullable, + deleted -> Bool, + } +} + joinable!(comment_alias_1 -> user_alias_1 (creator_id)); joinable!(comment -> comment_alias_1 (parent_id)); joinable!(user_mention -> user_alias_1 (recipient_id)); +joinable!(post -> user_alias_1 (creator_id)); +joinable!(comment -> user_alias_1 (creator_id)); + +joinable!(post_report -> user_alias_2 (resolver_id)); +joinable!(comment_report -> user_alias_2 (resolver_id)); joinable!(comment -> post (post_id)); joinable!(comment -> user_ (creator_id)); @@ -708,4 +744,5 @@ allow_tables_to_appear_in_same_query!( user_mention, comment_alias_1, user_alias_1, + user_alias_2, ); diff --git a/lemmy_db/src/source/comment_report.rs b/lemmy_db/src/source/comment_report.rs new file mode 100644 index 000000000..a53759916 --- /dev/null +++ b/lemmy_db/src/source/comment_report.rs @@ -0,0 +1,73 @@ +use diesel::{dsl::*, result::Error, *}; +use serde::{Deserialize, Serialize}; + +use crate::{naive_now, schema::comment_report, source::comment::Comment, Reportable}; + +#[derive(Identifiable, Queryable, Associations, PartialEq, Serialize, Deserialize, Debug, Clone)] +#[belongs_to(Comment)] +#[table_name = "comment_report"] +pub struct CommentReport { + pub id: i32, + pub creator_id: i32, + pub comment_id: i32, + pub original_comment_text: String, + pub reason: String, + pub resolved: bool, + pub resolver_id: Option, + pub published: chrono::NaiveDateTime, + pub updated: Option, +} + +#[derive(Insertable, AsChangeset, Clone)] +#[table_name = "comment_report"] +pub struct CommentReportForm { + pub creator_id: i32, + pub comment_id: i32, + pub original_comment_text: String, + pub reason: String, +} + +impl Reportable for CommentReport { + /// creates a comment report and returns it + /// + /// * `conn` - the postgres connection + /// * `comment_report_form` - the filled CommentReportForm to insert + fn report(conn: &PgConnection, comment_report_form: &CommentReportForm) -> Result { + use crate::schema::comment_report::dsl::*; + insert_into(comment_report) + .values(comment_report_form) + .get_result::(conn) + } + + /// resolve a comment report + /// + /// * `conn` - the postgres connection + /// * `report_id` - the id of the report to resolve + /// * `by_resolver_id` - the id of the user resolving the report + fn resolve(conn: &PgConnection, report_id: i32, by_resolver_id: i32) -> Result { + use crate::schema::comment_report::dsl::*; + update(comment_report.find(report_id)) + .set(( + resolved.eq(true), + resolver_id.eq(by_resolver_id), + updated.eq(naive_now()), + )) + .execute(conn) + } + + /// unresolve a comment report + /// + /// * `conn` - the postgres connection + /// * `report_id` - the id of the report to unresolve + /// * `by_resolver_id` - the id of the user unresolving the report + fn unresolve(conn: &PgConnection, report_id: i32, by_resolver_id: i32) -> Result { + use crate::schema::comment_report::dsl::*; + update(comment_report.find(report_id)) + .set(( + resolved.eq(false), + resolver_id.eq(by_resolver_id), + updated.eq(naive_now()), + )) + .execute(conn) + } +} diff --git a/lemmy_db/src/source/mod.rs b/lemmy_db/src/source/mod.rs index 2247cd889..211194a44 100644 --- a/lemmy_db/src/source/mod.rs +++ b/lemmy_db/src/source/mod.rs @@ -1,10 +1,12 @@ pub mod activity; pub mod category; pub mod comment; +pub mod comment_report; pub mod community; pub mod moderator; pub mod password_reset_request; pub mod post; +pub mod post_report; pub mod private_message; pub mod site; pub mod user; diff --git a/lemmy_db/src/source/post_report.rs b/lemmy_db/src/source/post_report.rs new file mode 100644 index 000000000..6de82a257 --- /dev/null +++ b/lemmy_db/src/source/post_report.rs @@ -0,0 +1,77 @@ +use diesel::{dsl::*, result::Error, *}; +use serde::{Deserialize, Serialize}; + +use crate::{naive_now, schema::post_report, source::post::Post, Reportable}; + +#[derive(Identifiable, Queryable, Associations, PartialEq, Serialize, Deserialize, Debug, Clone)] +#[belongs_to(Post)] +#[table_name = "post_report"] +pub struct PostReport { + pub id: i32, + pub creator_id: i32, + pub post_id: i32, + pub original_post_name: String, + pub original_post_url: Option, + pub original_post_body: Option, + pub reason: String, + pub resolved: bool, + pub resolver_id: Option, + pub published: chrono::NaiveDateTime, + pub updated: Option, +} + +#[derive(Insertable, AsChangeset, Clone)] +#[table_name = "post_report"] +pub struct PostReportForm { + pub creator_id: i32, + pub post_id: i32, + pub original_post_name: String, + pub original_post_url: Option, + pub original_post_body: Option, + pub reason: String, +} + +impl Reportable for PostReport { + /// creates a post report and returns it + /// + /// * `conn` - the postgres connection + /// * `post_report_form` - the filled CommentReportForm to insert + fn report(conn: &PgConnection, post_report_form: &PostReportForm) -> Result { + use crate::schema::post_report::dsl::*; + insert_into(post_report) + .values(post_report_form) + .get_result::(conn) + } + + /// resolve a post report + /// + /// * `conn` - the postgres connection + /// * `report_id` - the id of the report to resolve + /// * `by_resolver_id` - the id of the user resolving the report + fn resolve(conn: &PgConnection, report_id: i32, by_resolver_id: i32) -> Result { + use crate::schema::post_report::dsl::*; + update(post_report.find(report_id)) + .set(( + resolved.eq(true), + resolver_id.eq(by_resolver_id), + updated.eq(naive_now()), + )) + .execute(conn) + } + + /// resolve a post report + /// + /// * `conn` - the postgres connection + /// * `report_id` - the id of the report to unresolve + /// * `by_resolver_id` - the id of the user unresolving the report + fn unresolve(conn: &PgConnection, report_id: i32, by_resolver_id: i32) -> Result { + use crate::schema::post_report::dsl::*; + update(post_report.find(report_id)) + .set(( + resolved.eq(false), + resolver_id.eq(by_resolver_id), + updated.eq(naive_now()), + )) + .execute(conn) + } +} diff --git a/lemmy_db/src/source/user.rs b/lemmy_db/src/source/user.rs index 0bd68a509..601e6e8c6 100644 --- a/lemmy_db/src/source/user.rs +++ b/lemmy_db/src/source/user.rs @@ -1,7 +1,7 @@ use crate::{ is_email_regex, naive_now, - schema::{user_, user_::dsl::*, user_alias_1}, + schema::{user_, user_::dsl::*, user_alias_1, user_alias_2}, ApubObject, Crud, }; @@ -153,7 +153,7 @@ pub struct UserSafeAlias1 { pub deleted: bool, } -mod safe_type_alias { +mod safe_type_alias_1 { use crate::{schema::user_alias_1::columns::*, source::user::UserAlias1, ToSafe}; type Columns = ( id, @@ -195,6 +195,98 @@ mod safe_type_alias { } } +#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize)] +#[table_name = "user_alias_2"] +pub struct UserAlias2 { + pub id: i32, + pub name: String, + pub preferred_username: Option, + pub password_encrypted: String, + pub email: Option, + pub avatar: Option, + pub admin: bool, + pub banned: bool, + pub published: chrono::NaiveDateTime, + pub updated: Option, + pub show_nsfw: bool, + pub theme: String, + pub default_sort_type: i16, + pub default_listing_type: i16, + pub lang: String, + pub show_avatars: bool, + pub send_notifications_to_email: bool, + pub matrix_user_id: Option, + pub actor_id: String, + pub bio: Option, + pub local: bool, + pub private_key: Option, + pub public_key: Option, + pub last_refreshed_at: chrono::NaiveDateTime, + pub banner: Option, + pub deleted: bool, +} + +#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize)] +#[table_name = "user_alias_2"] +pub struct UserSafeAlias2 { + pub id: i32, + pub name: String, + pub preferred_username: Option, + pub avatar: Option, + pub admin: bool, + pub banned: bool, + pub published: chrono::NaiveDateTime, + pub updated: Option, + pub matrix_user_id: Option, + pub actor_id: String, + pub bio: Option, + pub local: bool, + pub banner: Option, + pub deleted: bool, +} + +mod safe_type_alias_2 { + use crate::{schema::user_alias_2::columns::*, source::user::UserAlias2, ToSafe}; + type Columns = ( + id, + name, + preferred_username, + avatar, + admin, + banned, + published, + updated, + matrix_user_id, + actor_id, + bio, + local, + banner, + deleted, + ); + + impl ToSafe for UserAlias2 { + type SafeColumns = Columns; + fn safe_columns_tuple() -> Self::SafeColumns { + ( + id, + name, + preferred_username, + avatar, + admin, + banned, + published, + updated, + matrix_user_id, + actor_id, + bio, + local, + banner, + deleted, + ) + } + } +} + #[derive(Insertable, AsChangeset, Clone)] #[table_name = "user_"] pub struct UserForm { diff --git a/lemmy_db/src/views/comment_report_view.rs b/lemmy_db/src/views/comment_report_view.rs new file mode 100644 index 000000000..540bb7569 --- /dev/null +++ b/lemmy_db/src/views/comment_report_view.rs @@ -0,0 +1,193 @@ +use crate::{ + limit_and_offset, + schema::{comment, comment_report, community, post, user_, user_alias_1, user_alias_2}, + source::{ + comment::Comment, + comment_report::CommentReport, + community::{Community, CommunitySafe}, + post::Post, + user::{UserAlias1, UserAlias2, UserSafe, UserSafeAlias1, UserSafeAlias2, User_}, + }, + views::ViewToVec, + MaybeOptional, + ToSafe, +}; +use diesel::{result::Error, *}; +use serde::Serialize; + +#[derive(Debug, PartialEq, Serialize, Clone)] +pub struct CommentReportView { + pub comment_report: CommentReport, + pub comment: Comment, + pub post: Post, + pub community: CommunitySafe, + pub creator: UserSafe, + pub comment_creator: UserSafeAlias1, + pub resolver: Option, +} + +type CommentReportViewTuple = ( + CommentReport, + Comment, + Post, + CommunitySafe, + UserSafe, + UserSafeAlias1, + Option, +); + +impl CommentReportView { + /// returns the CommentReportView for the provided report_id + /// + /// * `report_id` - the report id to obtain + pub fn read(conn: &PgConnection, report_id: i32) -> Result { + let (comment_report, comment, post, community, creator, comment_creator, resolver) = + comment_report::table + .find(report_id) + .inner_join(comment::table) + .inner_join(post::table.on(comment::post_id.eq(post::id))) + .inner_join(community::table.on(post::community_id.eq(community::id))) + .inner_join(user_::table.on(comment_report::creator_id.eq(user_::id))) + .inner_join(user_alias_1::table.on(post::creator_id.eq(user_alias_1::id))) + .left_join( + user_alias_2::table.on(comment_report::resolver_id.eq(user_alias_2::id.nullable())), + ) + .select(( + comment_report::all_columns, + comment::all_columns, + post::all_columns, + Community::safe_columns_tuple(), + User_::safe_columns_tuple(), + UserAlias1::safe_columns_tuple(), + UserAlias2::safe_columns_tuple().nullable(), + )) + .first::(conn)?; + + Ok(Self { + comment_report, + comment, + post, + community, + creator, + comment_creator, + resolver, + }) + } + + /// returns the current unresolved post report count for the supplied community ids + /// + /// * `community_ids` - a Vec of community_ids to get a count for + /// TODO this eq_any is a bad way to do this, would be better to join to communitymoderator + /// for a user id + pub fn get_report_count(conn: &PgConnection, community_ids: &[i32]) -> Result { + use diesel::dsl::*; + comment_report::table + .inner_join(comment::table) + .inner_join(post::table.on(comment::post_id.eq(post::id))) + .filter( + comment_report::resolved + .eq(false) + .and(post::community_id.eq_any(community_ids)), + ) + .select(count(comment_report::id)) + .first::(conn) + } +} + +pub struct CommentReportQueryBuilder<'a> { + conn: &'a PgConnection, + community_ids: Option>, // TODO bad way to do this + page: Option, + limit: Option, + resolved: Option, +} + +impl<'a> CommentReportQueryBuilder<'a> { + pub fn create(conn: &'a PgConnection) -> Self { + CommentReportQueryBuilder { + conn, + community_ids: None, + page: None, + limit: None, + resolved: Some(false), + } + } + + pub fn community_ids>>(mut self, community_ids: T) -> Self { + self.community_ids = community_ids.get_optional(); + self + } + + pub fn page>(mut self, page: T) -> Self { + self.page = page.get_optional(); + self + } + + pub fn limit>(mut self, limit: T) -> Self { + self.limit = limit.get_optional(); + self + } + + pub fn resolved>(mut self, resolved: T) -> Self { + self.resolved = resolved.get_optional(); + self + } + + pub fn list(self) -> Result, Error> { + let mut query = comment_report::table + .inner_join(comment::table) + .inner_join(post::table.on(comment::post_id.eq(post::id))) + .inner_join(community::table.on(post::community_id.eq(community::id))) + .inner_join(user_::table.on(comment_report::creator_id.eq(user_::id))) + .inner_join(user_alias_1::table.on(post::creator_id.eq(user_alias_1::id))) + .left_join( + user_alias_2::table.on(comment_report::resolver_id.eq(user_alias_2::id.nullable())), + ) + .select(( + comment_report::all_columns, + comment::all_columns, + post::all_columns, + Community::safe_columns_tuple(), + User_::safe_columns_tuple(), + UserAlias1::safe_columns_tuple(), + UserAlias2::safe_columns_tuple().nullable(), + )) + .into_boxed(); + + if let Some(comm_ids) = self.community_ids { + query = query.filter(post::community_id.eq_any(comm_ids)); + } + + if let Some(resolved_flag) = self.resolved { + query = query.filter(comment_report::resolved.eq(resolved_flag)); + } + + let (limit, offset) = limit_and_offset(self.page, self.limit); + + let res = query + .order_by(comment_report::published.asc()) + .limit(limit) + .offset(offset) + .load::(self.conn)?; + + Ok(CommentReportView::to_vec(res)) + } +} + +impl ViewToVec for CommentReportView { + type DbTuple = CommentReportViewTuple; + fn to_vec(posts: Vec) -> Vec { + posts + .iter() + .map(|a| Self { + comment_report: a.0.to_owned(), + comment: a.1.to_owned(), + post: a.2.to_owned(), + community: a.3.to_owned(), + creator: a.4.to_owned(), + comment_creator: a.5.to_owned(), + resolver: a.6.to_owned(), + }) + .collect::>() + } +} diff --git a/lemmy_db/src/views/mod.rs b/lemmy_db/src/views/mod.rs index ee9a82f5b..3cac0bd3d 100644 --- a/lemmy_db/src/views/mod.rs +++ b/lemmy_db/src/views/mod.rs @@ -1,6 +1,8 @@ +pub mod comment_report_view; pub mod comment_view; pub mod community; pub mod moderator; +pub mod post_report_view; pub mod post_view; pub mod private_message_view; pub mod site_view; diff --git a/lemmy_db/src/views/post_report_view.rs b/lemmy_db/src/views/post_report_view.rs new file mode 100644 index 000000000..d39adfd5c --- /dev/null +++ b/lemmy_db/src/views/post_report_view.rs @@ -0,0 +1,178 @@ +use crate::{ + limit_and_offset, + schema::{community, post, post_report, user_, user_alias_1, user_alias_2}, + source::{ + community::{Community, CommunitySafe}, + post::Post, + post_report::PostReport, + user::{UserAlias1, UserAlias2, UserSafe, UserSafeAlias1, UserSafeAlias2, User_}, + }, + views::ViewToVec, + MaybeOptional, + ToSafe, +}; +use diesel::{result::Error, *}; +use serde::Serialize; + +#[derive(Debug, PartialEq, Serialize, Clone)] +pub struct PostReportView { + pub post_report: PostReport, + pub post: Post, + pub community: CommunitySafe, + pub creator: UserSafe, + pub post_creator: UserSafeAlias1, + pub resolver: Option, +} + +type PostReportViewTuple = ( + PostReport, + Post, + CommunitySafe, + UserSafe, + UserSafeAlias1, + Option, +); + +impl PostReportView { + /// returns the PostReportView for the provided report_id + /// + /// * `report_id` - the report id to obtain + pub fn read(conn: &PgConnection, report_id: i32) -> Result { + let (post_report, post, community, creator, post_creator, resolver) = post_report::table + .find(report_id) + .inner_join(post::table) + .inner_join(community::table.on(post::community_id.eq(community::id))) + .inner_join(user_::table.on(post_report::creator_id.eq(user_::id))) + .inner_join(user_alias_1::table.on(post::creator_id.eq(user_alias_1::id))) + .left_join(user_alias_2::table.on(post_report::resolver_id.eq(user_alias_2::id.nullable()))) + .select(( + post_report::all_columns, + post::all_columns, + Community::safe_columns_tuple(), + User_::safe_columns_tuple(), + UserAlias1::safe_columns_tuple(), + UserAlias2::safe_columns_tuple().nullable(), + )) + .first::(conn)?; + + Ok(Self { + post_report, + post, + community, + creator, + post_creator, + resolver, + }) + } + + /// returns the current unresolved post report count for the supplied community ids + /// + /// * `community_ids` - a Vec of community_ids to get a count for + /// TODO this eq_any is a bad way to do this, would be better to join to communitymoderator + /// for a user id + pub fn get_report_count(conn: &PgConnection, community_ids: &[i32]) -> Result { + use diesel::dsl::*; + post_report::table + .inner_join(post::table) + .filter( + post_report::resolved + .eq(false) + .and(post::community_id.eq_any(community_ids)), + ) + .select(count(post_report::id)) + .first::(conn) + } +} + +pub struct PostReportQueryBuilder<'a> { + conn: &'a PgConnection, + community_ids: Option>, // TODO bad way to do this + page: Option, + limit: Option, + resolved: Option, +} + +impl<'a> PostReportQueryBuilder<'a> { + pub fn create(conn: &'a PgConnection) -> Self { + PostReportQueryBuilder { + conn, + community_ids: None, + page: None, + limit: None, + resolved: Some(false), + } + } + + pub fn community_ids>>(mut self, community_ids: T) -> Self { + self.community_ids = community_ids.get_optional(); + self + } + + pub fn page>(mut self, page: T) -> Self { + self.page = page.get_optional(); + self + } + + pub fn limit>(mut self, limit: T) -> Self { + self.limit = limit.get_optional(); + self + } + + pub fn resolved>(mut self, resolved: T) -> Self { + self.resolved = resolved.get_optional(); + self + } + + pub fn list(self) -> Result, Error> { + let mut query = post_report::table + .inner_join(post::table) + .inner_join(community::table.on(post::community_id.eq(community::id))) + .inner_join(user_::table.on(post_report::creator_id.eq(user_::id))) + .inner_join(user_alias_1::table.on(post::creator_id.eq(user_alias_1::id))) + .left_join(user_alias_2::table.on(post_report::resolver_id.eq(user_alias_2::id.nullable()))) + .select(( + post_report::all_columns, + post::all_columns, + Community::safe_columns_tuple(), + User_::safe_columns_tuple(), + UserAlias1::safe_columns_tuple(), + UserAlias2::safe_columns_tuple().nullable(), + )) + .into_boxed(); + + if let Some(comm_ids) = self.community_ids { + query = query.filter(post::community_id.eq_any(comm_ids)); + } + + if let Some(resolved_flag) = self.resolved { + query = query.filter(post_report::resolved.eq(resolved_flag)); + } + + let (limit, offset) = limit_and_offset(self.page, self.limit); + + let res = query + .order_by(post_report::published.asc()) + .limit(limit) + .offset(offset) + .load::(self.conn)?; + + Ok(PostReportView::to_vec(res)) + } +} + +impl ViewToVec for PostReportView { + type DbTuple = PostReportViewTuple; + fn to_vec(posts: Vec) -> Vec { + posts + .iter() + .map(|a| Self { + post_report: a.0.to_owned(), + post: a.1.to_owned(), + community: a.2.to_owned(), + creator: a.3.to_owned(), + post_creator: a.4.to_owned(), + resolver: a.5.to_owned(), + }) + .collect::>() + } +} diff --git a/lemmy_structs/src/comment.rs b/lemmy_structs/src/comment.rs index 277499f49..be10906aa 100644 --- a/lemmy_structs/src/comment.rs +++ b/lemmy_structs/src/comment.rs @@ -1,4 +1,4 @@ -use lemmy_db::{comment_report::CommentReportView, views::comment_view::CommentView}; +use lemmy_db::views::{comment_report_view::CommentReportView, comment_view::CommentView}; use serde::{Deserialize, Serialize}; #[derive(Deserialize)] @@ -111,7 +111,7 @@ pub struct ListCommentReports { pub auth: String, } -#[derive(Serialize, Deserialize, Clone, Debug)] +#[derive(Serialize, Clone, Debug)] pub struct ListCommentReportsResponse { pub comments: Vec, } diff --git a/lemmy_structs/src/post.rs b/lemmy_structs/src/post.rs index bf0af2f8a..fe6a059e2 100644 --- a/lemmy_structs/src/post.rs +++ b/lemmy_structs/src/post.rs @@ -1,10 +1,8 @@ -use lemmy_db::{ - post_report::PostReportView, - views::{ - comment_view::CommentView, - community::{community_moderator_view::CommunityModeratorView, community_view::CommunityView}, - post_view::PostView, - }, +use lemmy_db::views::{ + comment_view::CommentView, + community::{community_moderator_view::CommunityModeratorView, community_view::CommunityView}, + post_report_view::PostReportView, + post_view::PostView, }; use serde::{Deserialize, Serialize}; @@ -150,7 +148,7 @@ pub struct ListPostReports { pub auth: String, } -#[derive(Serialize, Deserialize, Clone, Debug)] +#[derive(Serialize, Clone, Debug)] pub struct ListPostReportsResponse { pub posts: Vec, }