update/fix migration, add some doc

also run cargo fmt/clippy
This commit is contained in:
eiknat 2020-11-03 21:15:11 -05:00
parent 438414a64b
commit 9e604b4038
16 changed files with 207 additions and 131 deletions

View file

@ -1,11 +1,11 @@
use crate::{ use crate::{
check_community_ban, check_community_ban,
collect_moderated_communities,
get_post, get_post,
get_user_from_jwt, get_user_from_jwt,
get_user_from_jwt_opt, get_user_from_jwt_opt,
is_mod_or_admin, is_mod_or_admin,
Perform, Perform,
collect_moderated_communities,
}; };
use actix_web::web::Data; use actix_web::web::Data;
use lemmy_apub::{ApubLikeableType, ApubObjectType}; use lemmy_apub::{ApubLikeableType, ApubObjectType};
@ -20,9 +20,9 @@ use lemmy_db::{
Crud, Crud,
Likeable, Likeable,
ListingType, ListingType,
Reportable,
Saveable, Saveable,
SortType, SortType,
Reportable,
}; };
use lemmy_structs::{blocking, comment::*, send_local_notifs}; use lemmy_structs::{blocking, comment::*, send_local_notifs};
use lemmy_utils::{ use lemmy_utils::{
@ -32,9 +32,12 @@ use lemmy_utils::{
ConnectionId, ConnectionId,
LemmyError, LemmyError,
}; };
use lemmy_websocket::{messages::{SendComment, SendUserRoomMessage}, LemmyContext, UserOperation}; use lemmy_websocket::{
messages::{SendComment, SendModRoomMessage, SendUserRoomMessage},
LemmyContext,
UserOperation,
};
use std::str::FromStr; use std::str::FromStr;
use lemmy_websocket::messages::SendModRoomMessage;
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl Perform for CreateComment { impl Perform for CreateComment {
@ -687,6 +690,7 @@ impl Perform for GetComments {
} }
} }
/// Creates a comment report and notifies the moderators of the community
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl Perform for CreateCommentReport { impl Perform for CreateCommentReport {
type Response = CreateCommentReportResponse; type Response = CreateCommentReportResponse;
@ -707,27 +711,30 @@ impl Perform for CreateCommentReport {
if reason.len() > 1000 { if reason.len() > 1000 {
return Err(APIError::err("report_too_long").into()); return Err(APIError::err("report_too_long").into());
} }
let user_id = user.id; let user_id = user.id;
let comment_id = data.comment_id; let comment_id = data.comment_id;
let comment = blocking(context.pool(), move |conn| { let comment = blocking(context.pool(), move |conn| {
CommentView::read(&conn, comment_id, None) CommentView::read(&conn, comment_id, None)
}).await??; })
.await??;
check_community_ban(user_id, comment.community_id, context.pool()).await?; check_community_ban(user_id, comment.community_id, context.pool()).await?;
let report_form = CommentReportForm { let report_form = CommentReportForm {
creator_id: user_id, creator_id: user_id,
comment_id, comment_id,
comment_text: comment.content, original_comment_text: comment.content,
reason: data.reason.to_owned(), reason: data.reason.to_owned(),
}; };
let report = match blocking(context.pool(), move |conn| { let report = match blocking(context.pool(), move |conn| {
CommentReport::report(conn, &report_form) CommentReport::report(conn, &report_form)
}).await? { })
.await?
{
Ok(report) => report, Ok(report) => report,
Err(_e) => return Err(APIError::err("couldnt_create_report").into()) Err(_e) => return Err(APIError::err("couldnt_create_report").into()),
}; };
let res = CreateCommentReportResponse { success: true }; let res = CreateCommentReportResponse { success: true };
@ -750,6 +757,7 @@ impl Perform for CreateCommentReport {
} }
} }
/// Resolves or unresolves a comment report and notifies the moderators of the community
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl Perform for ResolveCommentReport { impl Perform for ResolveCommentReport {
type Response = ResolveCommentReportResponse; type Response = ResolveCommentReportResponse;
@ -765,7 +773,8 @@ impl Perform for ResolveCommentReport {
let report_id = data.report_id; let report_id = data.report_id;
let report = blocking(context.pool(), move |conn| { let report = blocking(context.pool(), move |conn| {
CommentReportView::read(&conn, report_id) CommentReportView::read(&conn, report_id)
}).await??; })
.await??;
let user_id = user.id; 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?;
@ -779,8 +788,8 @@ impl Perform for ResolveCommentReport {
} }
}; };
if blocking(context.pool(),resolve_fun).await?.is_err() { if blocking(context.pool(), resolve_fun).await?.is_err() {
return Err(APIError::err("couldnt_resolve_report").into()) return Err(APIError::err("couldnt_resolve_report").into());
}; };
let report_id = data.report_id; let report_id = data.report_id;
@ -800,6 +809,8 @@ impl Perform for ResolveCommentReport {
} }
} }
/// Lists comment reports for a community if an id is supplied
/// or returns all comment reports for communities a user moderates
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl Perform for ListCommentReports { impl Perform for ListCommentReports {
type Response = ListCommentReportsResponse; type Response = ListCommentReportsResponse;
@ -814,18 +825,19 @@ impl Perform for ListCommentReports {
let user_id = user.id; let user_id = user.id;
let community_id = data.community; let community_id = data.community;
let community_ids = collect_moderated_communities(user_id, community_id, context.pool()).await?; let community_ids =
collect_moderated_communities(user_id, community_id, context.pool()).await?;
let page = data.page; let page = data.page;
let limit = data.limit; let limit = data.limit;
let comments = blocking(context.pool(), move |conn| { let comments = blocking(context.pool(), move |conn| {
CommentReportQueryBuilder::create(conn) CommentReportQueryBuilder::create(conn)
.community_ids(community_ids) .community_ids(community_ids)
.page(page) .page(page)
.limit(limit) .limit(limit)
.list() .list()
}) })
.await??; .await??;
let res = ListCommentReportsResponse { comments }; let res = ListCommentReportsResponse { comments };
@ -838,4 +850,4 @@ impl Perform for ListCommentReports {
Ok(res) Ok(res)
} }
} }

View file

@ -36,12 +36,11 @@ use lemmy_utils::{
LemmyError, LemmyError,
}; };
use lemmy_websocket::{ use lemmy_websocket::{
messages::{GetCommunityUsersOnline, JoinCommunityRoom, SendCommunityRoomMessage}, messages::{GetCommunityUsersOnline, JoinCommunityRoom, JoinModRoom, SendCommunityRoomMessage},
LemmyContext, LemmyContext,
UserOperation, UserOperation,
}; };
use std::str::FromStr; use std::str::FromStr;
use lemmy_websocket::messages::JoinModRoom;
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl Perform for GetCommunity { impl Perform for GetCommunity {

View file

@ -100,6 +100,13 @@ pub(in crate) async fn check_community_ban(
} }
} }
/// Returns a list of communities that the user moderates
/// or if a community_id is supplied validates the user is a moderator
/// of that community and returns the community id in a vec
///
/// * `user_id` - the user id of the moderator
/// * `community_id` - optional community id to check for moderator privileges
/// * `pool` - the diesel db pool
pub(in crate) async fn collect_moderated_communities( pub(in crate) async fn collect_moderated_communities(
user_id: i32, user_id: i32,
community_id: Option<i32>, community_id: Option<i32>,
@ -112,7 +119,8 @@ pub(in crate) async fn collect_moderated_communities(
} else { } else {
let ids = blocking(pool, move |conn: &'_ _| { let ids = blocking(pool, move |conn: &'_ _| {
CommunityModerator::get_user_moderated_communities(conn, user_id) CommunityModerator::get_user_moderated_communities(conn, user_id)
}).await??; })
.await??;
Ok(ids) Ok(ids)
} }
} }
@ -195,9 +203,7 @@ pub async fn match_websocket_operation(
UserOperation::CommunityJoin => { UserOperation::CommunityJoin => {
do_websocket_operation::<CommunityJoin>(context, id, op, data).await do_websocket_operation::<CommunityJoin>(context, id, op, data).await
} }
UserOperation::ModJoin => { UserOperation::ModJoin => do_websocket_operation::<ModJoin>(context, id, op, data).await,
do_websocket_operation::<ModJoin>(context, id, op, data).await
}
UserOperation::SaveUserSettings => { UserOperation::SaveUserSettings => {
do_websocket_operation::<SaveUserSettings>(context, id, op, data).await do_websocket_operation::<SaveUserSettings>(context, id, op, data).await
} }

View file

@ -1,11 +1,11 @@
use crate::{ use crate::{
check_community_ban, check_community_ban,
check_optional_url, check_optional_url,
collect_moderated_communities,
get_user_from_jwt, get_user_from_jwt,
get_user_from_jwt_opt, get_user_from_jwt_opt,
is_mod_or_admin, is_mod_or_admin,
Perform, Perform,
collect_moderated_communities,
}; };
use actix_web::web::Data; use actix_web::web::Data;
use lemmy_apub::{ApubLikeableType, ApubObjectType}; use lemmy_apub::{ApubLikeableType, ApubObjectType};
@ -21,9 +21,9 @@ use lemmy_db::{
Crud, Crud,
Likeable, Likeable,
ListingType, ListingType,
Reportable,
Saveable, Saveable,
SortType, SortType,
Reportable,
}; };
use lemmy_structs::{blocking, post::*}; use lemmy_structs::{blocking, post::*};
use lemmy_utils::{ use lemmy_utils::{
@ -35,13 +35,7 @@ use lemmy_utils::{
LemmyError, LemmyError,
}; };
use lemmy_websocket::{ use lemmy_websocket::{
messages::{ messages::{GetPostUsersOnline, JoinPostRoom, SendModRoomMessage, SendPost, SendUserRoomMessage},
GetPostUsersOnline,
JoinPostRoom,
SendModRoomMessage,
SendPost,
SendUserRoomMessage
},
LemmyContext, LemmyContext,
UserOperation, UserOperation,
}; };
@ -751,6 +745,7 @@ impl Perform for PostJoin {
} }
} }
/// Creates a post report and notifies the moderators of the community
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl Perform for CreatePostReport { impl Perform for CreatePostReport {
type Response = CreatePostReportResponse; type Response = CreatePostReportResponse;
@ -771,29 +766,32 @@ impl Perform for CreatePostReport {
if reason.len() > 1000 { if reason.len() > 1000 {
return Err(APIError::err("report_too_long").into()); return Err(APIError::err("report_too_long").into());
} }
let user_id = user.id; let user_id = user.id;
let post_id = data.post_id; let post_id = data.post_id;
let post = blocking(context.pool(), move |conn| { let post = blocking(context.pool(), move |conn| {
PostView::read(&conn, post_id, None) PostView::read(&conn, post_id, None)
}).await??; })
.await??;
check_community_ban(user_id, post.community_id, context.pool()).await?; check_community_ban(user_id, post.community_id, context.pool()).await?;
let report_form = PostReportForm { let report_form = PostReportForm {
creator_id: user_id, creator_id: user_id,
post_id, post_id,
post_name: post.name, original_post_name: post.name,
post_url: post.url, original_post_url: post.url,
post_body: post.body, original_post_body: post.body,
reason: data.reason.to_owned(), reason: data.reason.to_owned(),
}; };
let report = match blocking(context.pool(), move |conn| { let report = match blocking(context.pool(), move |conn| {
PostReport::report(conn, &report_form) PostReport::report(conn, &report_form)
}).await? { })
.await?
{
Ok(report) => report, Ok(report) => report,
Err(_e) => return Err(APIError::err("couldnt_create_report").into()) Err(_e) => return Err(APIError::err("couldnt_create_report").into()),
}; };
let res = CreatePostReportResponse { success: true }; let res = CreatePostReportResponse { success: true };
@ -816,6 +814,7 @@ impl Perform for CreatePostReport {
} }
} }
/// Resolves or unresolves a post report and notifies the moderators of the community
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl Perform for ResolvePostReport { impl Perform for ResolvePostReport {
type Response = ResolvePostReportResponse; type Response = ResolvePostReportResponse;
@ -831,7 +830,8 @@ impl Perform for ResolvePostReport {
let report_id = data.report_id; let report_id = data.report_id;
let report = blocking(context.pool(), move |conn| { let report = blocking(context.pool(), move |conn| {
PostReportView::read(&conn, report_id) PostReportView::read(&conn, report_id)
}).await??; })
.await??;
let user_id = user.id; 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?;
@ -850,8 +850,8 @@ impl Perform for ResolvePostReport {
resolved: true, resolved: true,
}; };
if blocking(context.pool(),resolve_fun).await?.is_err() { if blocking(context.pool(), resolve_fun).await?.is_err() {
return Err(APIError::err("couldnt_resolve_report").into()) return Err(APIError::err("couldnt_resolve_report").into());
}; };
context.chat_server().do_send(SendModRoomMessage { context.chat_server().do_send(SendModRoomMessage {
@ -865,6 +865,8 @@ impl Perform for ResolvePostReport {
} }
} }
/// Lists post reports for a community if an id is supplied
/// or returns all post reports for communities a user moderates
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl Perform for ListPostReports { impl Perform for ListPostReports {
type Response = ListPostReportsResponse; type Response = ListPostReportsResponse;
@ -879,18 +881,19 @@ impl Perform for ListPostReports {
let user_id = user.id; let user_id = user.id;
let community_id = data.community; let community_id = data.community;
let community_ids = collect_moderated_communities(user_id, community_id, context.pool()).await?; let community_ids =
collect_moderated_communities(user_id, community_id, context.pool()).await?;
let page = data.page; let page = data.page;
let limit = data.limit; let limit = data.limit;
let posts = blocking(context.pool(), move |conn| { let posts = blocking(context.pool(), move |conn| {
PostReportQueryBuilder::create(conn) PostReportQueryBuilder::create(conn)
.community_ids(community_ids) .community_ids(community_ids)
.page(page) .page(page)
.limit(limit) .limit(limit)
.list() .list()
}) })
.await??; .await??;
let res = ListPostReportsResponse { posts }; let res = ListPostReportsResponse { posts };

View file

@ -2,11 +2,11 @@ use crate::{
captcha_espeak_wav_base64, captcha_espeak_wav_base64,
check_optional_url, check_optional_url,
claims::Claims, claims::Claims,
collect_moderated_communities,
get_user_from_jwt, get_user_from_jwt,
get_user_from_jwt_opt, get_user_from_jwt_opt,
is_admin, is_admin,
Perform, Perform,
collect_moderated_communities
}; };
use actix_web::web::Data; use actix_web::web::Data;
use anyhow::Context; use anyhow::Context;
@ -1312,7 +1312,8 @@ impl Perform for GetReportCount {
let user_id = user.id; let user_id = user.id;
let community_id = data.community; let community_id = data.community;
let community_ids = collect_moderated_communities(user_id, community_id, context.pool()).await?; let community_ids =
collect_moderated_communities(user_id, community_id, context.pool()).await?;
let res = { let res = {
if community_ids.is_empty() { if community_ids.is_empty() {
@ -1323,12 +1324,16 @@ impl Perform for GetReportCount {
} }
} else { } else {
let ids = community_ids.clone(); let ids = community_ids.clone();
let comment_reports = blocking(context.pool(), move |conn| let comment_reports = blocking(context.pool(), move |conn| {
CommentReportView::get_report_count(conn, &ids)).await??; CommentReportView::get_report_count(conn, &ids)
})
.await??;
let ids = community_ids.clone(); let ids = community_ids.clone();
let post_reports = blocking(context.pool(), move |conn| let post_reports = blocking(context.pool(), move |conn| {
PostReportView::get_report_count(conn, &ids)).await??; PostReportView::get_report_count(conn, &ids)
})
.await??;
GetReportCountResponse { GetReportCountResponse {
community: data.community, community: data.community,

View file

@ -1,14 +1,21 @@
use diesel::{dsl::*, pg::Pg, result::Error, *}; use diesel::{dsl::*, pg::Pg, result::Error, *};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{limit_and_offset, MaybeOptional, schema::comment_report, comment::Comment, Reportable, naive_now}; use crate::{
comment::Comment,
limit_and_offset,
naive_now,
schema::comment_report,
MaybeOptional,
Reportable,
};
table! { table! {
comment_report_view (id) { comment_report_view (id) {
id -> Int4, id -> Int4,
creator_id -> Int4, creator_id -> Int4,
comment_id -> Int4, comment_id -> Int4,
comment_text -> Text, original_comment_text -> Text,
reason -> Text, reason -> Text,
resolved -> Bool, resolved -> Bool,
resolver_id -> Nullable<Int4>, resolver_id -> Nullable<Int4>,
@ -43,7 +50,7 @@ pub struct CommentReport {
pub id: i32, pub id: i32,
pub creator_id: i32, pub creator_id: i32,
pub comment_id: i32, pub comment_id: i32,
pub comment_text: String, pub original_comment_text: String,
pub reason: String, pub reason: String,
pub resolved: bool, pub resolved: bool,
pub resolver_id: Option<i32>, pub resolver_id: Option<i32>,
@ -56,11 +63,15 @@ pub struct CommentReport {
pub struct CommentReportForm { pub struct CommentReportForm {
pub creator_id: i32, pub creator_id: i32,
pub comment_id: i32, pub comment_id: i32,
pub comment_text: String, pub original_comment_text: String,
pub reason: String, pub reason: String,
} }
impl Reportable<CommentReportForm> for CommentReport { impl Reportable<CommentReportForm> 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<Self, Error> { fn report(conn: &PgConnection, comment_report_form: &CommentReportForm) -> Result<Self, Error> {
use crate::schema::comment_report::dsl::*; use crate::schema::comment_report::dsl::*;
insert_into(comment_report) insert_into(comment_report)
@ -68,6 +79,11 @@ impl Reportable<CommentReportForm> for CommentReport {
.get_result::<Self>(conn) .get_result::<Self>(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<usize, Error> { fn resolve(conn: &PgConnection, report_id: i32, by_resolver_id: i32) -> Result<usize, Error> {
use crate::schema::comment_report::dsl::*; use crate::schema::comment_report::dsl::*;
update(comment_report.find(report_id)) update(comment_report.find(report_id))
@ -79,6 +95,11 @@ impl Reportable<CommentReportForm> for CommentReport {
.execute(conn) .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<usize, Error> { fn unresolve(conn: &PgConnection, report_id: i32, by_resolver_id: i32) -> Result<usize, Error> {
use crate::schema::comment_report::dsl::*; use crate::schema::comment_report::dsl::*;
update(comment_report.find(report_id)) update(comment_report.find(report_id))
@ -91,15 +112,13 @@ impl Reportable<CommentReportForm> for CommentReport {
} }
} }
#[derive( #[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, Clone)]
Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, Clone,
)]
#[table_name = "comment_report_view"] #[table_name = "comment_report_view"]
pub struct CommentReportView { pub struct CommentReportView {
pub id: i32, pub id: i32,
pub creator_id: i32, pub creator_id: i32,
pub comment_id: i32, pub comment_id: i32,
pub comment_text: String, pub original_comment_text: String,
pub reason: String, pub reason: String,
pub resolved: bool, pub resolved: bool,
pub resolver_id: Option<i32>, pub resolver_id: Option<i32>,
@ -136,19 +155,23 @@ pub struct CommentReportQueryBuilder<'a> {
} }
impl CommentReportView { 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<Self, Error> { pub fn read(conn: &PgConnection, report_id: i32) -> Result<Self, Error> {
use super::comment_report::comment_report_view::dsl::*; use super::comment_report::comment_report_view::dsl::*;
comment_report_view comment_report_view.find(report_id).first::<Self>(conn)
.find(report_id)
.first::<Self>(conn)
} }
pub fn get_report_count(conn: &PgConnection, community_ids: &Vec<i32>) -> Result<i32, Error> { /// returns the current unresolved comment report count for the supplied community ids
///
/// * `community_ids` - a Vec<i32> of community_ids to get a count for
pub fn get_report_count(conn: &PgConnection, community_ids: &Vec<i32>) -> Result<i64, Error> {
use super::comment_report::comment_report_view::dsl::*; use super::comment_report::comment_report_view::dsl::*;
comment_report_view comment_report_view
.filter(resolved.eq(false).and(community_id.eq_any(community_ids))) .filter(resolved.eq(false).and(community_id.eq_any(community_ids)))
.select(sql::<sql_types::Integer>("COUNT(*)")) .select(count(id))
.first::<i32>(conn) .first::<i64>(conn)
} }
} }

View file

@ -225,12 +225,15 @@ impl CommunityModerator {
diesel::delete(community_moderator.filter(community_id.eq(for_community_id))).execute(conn) diesel::delete(community_moderator.filter(community_id.eq(for_community_id))).execute(conn)
} }
pub fn get_user_moderated_communities(conn: &PgConnection, for_user_id: i32) -> Result<Vec<i32>, Error> { pub fn get_user_moderated_communities(
conn: &PgConnection,
for_user_id: i32,
) -> Result<Vec<i32>, Error> {
use crate::schema::community_moderator::dsl::*; use crate::schema::community_moderator::dsl::*;
community_moderator community_moderator
.filter(user_id.eq(for_user_id)) .filter(user_id.eq(for_user_id))
.select(community_id) .select(community_id)
.load::<i32>(conn) .load::<i32>(conn)
} }
} }

View file

@ -113,14 +113,14 @@ pub trait Readable<T> {
pub trait Reportable<T> { pub trait Reportable<T> {
fn report(conn: &PgConnection, form: &T) -> Result<Self, Error> fn report(conn: &PgConnection, form: &T) -> Result<Self, Error>
where where
Self: Sized; Self: Sized;
fn resolve(conn: &PgConnection, report_id: i32, resolver_id: i32) -> Result<usize, Error> fn resolve(conn: &PgConnection, report_id: i32, resolver_id: i32) -> Result<usize, Error>
where where
Self: Sized; Self: Sized;
fn unresolve(conn: &PgConnection, report_id: i32, resolver_id: i32) -> Result<usize, Error> fn unresolve(conn: &PgConnection, report_id: i32, resolver_id: i32) -> Result<usize, Error>
where where
Self: Sized; Self: Sized;
} }
pub trait MaybeOptional<T> { pub trait MaybeOptional<T> {

View file

@ -1,16 +1,23 @@
use diesel::{dsl::*, pg::Pg, result::Error, *}; use diesel::{dsl::*, pg::Pg, result::Error, *};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{limit_and_offset, MaybeOptional, schema::post_report, post::Post, Reportable, naive_now}; use crate::{
limit_and_offset,
naive_now,
post::Post,
schema::post_report,
MaybeOptional,
Reportable,
};
table! { table! {
post_report_view (id) { post_report_view (id) {
id -> Int4, id -> Int4,
creator_id -> Int4, creator_id -> Int4,
post_id -> Int4, post_id -> Int4,
post_name -> Varchar, original_post_name -> Varchar,
post_url -> Nullable<Text>, original_post_url -> Nullable<Text>,
post_body -> Nullable<Text>, original_post_body -> Nullable<Text>,
reason -> Text, reason -> Text,
resolved -> Bool, resolved -> Bool,
resolver_id -> Nullable<Int4>, resolver_id -> Nullable<Int4>,
@ -46,9 +53,9 @@ pub struct PostReport {
pub id: i32, pub id: i32,
pub creator_id: i32, pub creator_id: i32,
pub post_id: i32, pub post_id: i32,
pub post_name: String, pub original_post_name: String,
pub post_url: Option<String>, pub original_post_url: Option<String>,
pub post_body: Option<String>, pub original_post_body: Option<String>,
pub reason: String, pub reason: String,
pub resolved: bool, pub resolved: bool,
pub resolver_id: Option<i32>, pub resolver_id: Option<i32>,
@ -61,13 +68,17 @@ pub struct PostReport {
pub struct PostReportForm { pub struct PostReportForm {
pub creator_id: i32, pub creator_id: i32,
pub post_id: i32, pub post_id: i32,
pub post_name: String, pub original_post_name: String,
pub post_url: Option<String>, pub original_post_url: Option<String>,
pub post_body: Option<String>, pub original_post_body: Option<String>,
pub reason: String, pub reason: String,
} }
impl Reportable<PostReportForm> for PostReport { impl Reportable<PostReportForm> 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<Self, Error> { fn report(conn: &PgConnection, post_report_form: &PostReportForm) -> Result<Self, Error> {
use crate::schema::post_report::dsl::*; use crate::schema::post_report::dsl::*;
insert_into(post_report) insert_into(post_report)
@ -75,6 +86,11 @@ impl Reportable<PostReportForm> for PostReport {
.get_result::<Self>(conn) .get_result::<Self>(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<usize, Error> { fn resolve(conn: &PgConnection, report_id: i32, by_resolver_id: i32) -> Result<usize, Error> {
use crate::schema::post_report::dsl::*; use crate::schema::post_report::dsl::*;
update(post_report.find(report_id)) update(post_report.find(report_id))
@ -86,6 +102,11 @@ impl Reportable<PostReportForm> for PostReport {
.execute(conn) .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<usize, Error> { fn unresolve(conn: &PgConnection, report_id: i32, by_resolver_id: i32) -> Result<usize, Error> {
use crate::schema::post_report::dsl::*; use crate::schema::post_report::dsl::*;
update(post_report.find(report_id)) update(post_report.find(report_id))
@ -98,17 +119,15 @@ impl Reportable<PostReportForm> for PostReport {
} }
} }
#[derive( #[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, Clone)]
Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, Clone,
)]
#[table_name = "post_report_view"] #[table_name = "post_report_view"]
pub struct PostReportView { pub struct PostReportView {
pub id: i32, pub id: i32,
pub creator_id: i32, pub creator_id: i32,
pub post_id: i32, pub post_id: i32,
pub post_name: String, pub original_post_name: String,
pub post_url: Option<String>, pub original_post_url: Option<String>,
pub post_body: Option<String>, pub original_post_body: Option<String>,
pub reason: String, pub reason: String,
pub resolved: bool, pub resolved: bool,
pub resolver_id: Option<i32>, pub resolver_id: Option<i32>,
@ -137,19 +156,23 @@ pub struct PostReportView {
} }
impl PostReportView { 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<Self, Error> { pub fn read(conn: &PgConnection, report_id: i32) -> Result<Self, Error> {
use super::post_report::post_report_view::dsl::*; use super::post_report::post_report_view::dsl::*;
post_report_view post_report_view.find(report_id).first::<Self>(conn)
.find(report_id)
.first::<Self>(conn)
} }
pub fn get_report_count(conn: &PgConnection, community_ids: &Vec<i32>) -> Result<i32, Error> { /// returns the current unresolved post report count for the supplied community ids
///
/// * `community_ids` - a Vec<i32> of community_ids to get a count for
pub fn get_report_count(conn: &PgConnection, community_ids: &Vec<i32>) -> Result<i64, Error> {
use super::post_report::post_report_view::dsl::*; use super::post_report::post_report_view::dsl::*;
post_report_view post_report_view
.filter(resolved.eq(false).and(community_id.eq_any(community_ids))) .filter(resolved.eq(false).and(community_id.eq_any(community_ids)))
.select(sql::<sql_types::Integer>("COUNT(*)")) .select(count(id))
.first::<i32>(conn) .first::<i64>(conn)
} }
} }

View file

@ -86,7 +86,7 @@ table! {
id -> Int4, id -> Int4,
creator_id -> Int4, creator_id -> Int4,
comment_id -> Int4, comment_id -> Int4,
comment_text -> Text, original_comment_text -> Text,
reason -> Text, reason -> Text,
resolved -> Bool, resolved -> Bool,
resolver_id -> Nullable<Int4>, resolver_id -> Nullable<Int4>,
@ -389,9 +389,9 @@ table! {
id -> Int4, id -> Int4,
creator_id -> Int4, creator_id -> Int4,
post_id -> Int4, post_id -> Int4,
post_name -> Varchar, original_post_name -> Varchar,
post_url -> Nullable<Text>, original_post_url -> Nullable<Text>,
post_body -> Nullable<Text>, original_post_body -> Nullable<Text>,
reason -> Text, reason -> Text,
resolved -> Bool, resolved -> Bool,
resolver_id -> Nullable<Int4>, resolver_id -> Nullable<Int4>,

View file

@ -1,7 +1,4 @@
use lemmy_db::{ use lemmy_db::{comment_report::CommentReportView, comment_view::CommentView};
comment_view::CommentView,
comment_report::CommentReportView,
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Deserialize)] #[derive(Deserialize)]

View file

@ -247,6 +247,6 @@ pub struct GetReportCount {
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
pub struct GetReportCountResponse { pub struct GetReportCountResponse {
pub community: Option<i32>, pub community: Option<i32>,
pub comment_reports: i32, pub comment_reports: i64,
pub post_reports: i32, pub post_reports: i64,
} }

View file

@ -260,8 +260,8 @@ impl ChatServer {
community_id: CommunityId, community_id: CommunityId,
websocket_id: Option<ConnectionId>, websocket_id: Option<ConnectionId>,
) -> Result<(), LemmyError> ) -> Result<(), LemmyError>
where where
Response: Serialize, Response: Serialize,
{ {
let res_str = &serialize_websocket_message(op, response)?; let res_str = &serialize_websocket_message(op, response)?;
if let Some(sessions) = self.mod_rooms.get(&community_id) { if let Some(sessions) = self.mod_rooms.get(&community_id) {

View file

@ -121,8 +121,8 @@ where
} }
impl<Response> Handler<SendModRoomMessage<Response>> for ChatServer impl<Response> Handler<SendModRoomMessage<Response>> for ChatServer
where where
Response: Serialize, Response: Serialize,
{ {
type Result = (); type Result = ();

View file

@ -2,7 +2,7 @@ create table comment_report (
id serial primary key, id serial primary key,
creator_id int references user_ on update cascade on delete cascade not null, -- user reporting comment creator_id int references user_ on update cascade on delete cascade not null, -- user reporting comment
comment_id int references comment on update cascade on delete cascade not null, -- comment being reported comment_id int references comment on update cascade on delete cascade not null, -- comment being reported
comment_text text not null, original_comment_text text not null,
reason text not null, reason text not null,
resolved bool not null default false, resolved bool not null default false,
resolver_id int references user_ on update cascade on delete cascade, -- user resolving report resolver_id int references user_ on update cascade on delete cascade, -- user resolving report
@ -15,9 +15,9 @@ create table post_report (
id serial primary key, id serial primary key,
creator_id int references user_ on update cascade on delete cascade not null, -- user reporting post creator_id int references user_ on update cascade on delete cascade not null, -- user reporting post
post_id int references post on update cascade on delete cascade not null, -- post being reported post_id int references post on update cascade on delete cascade not null, -- post being reported
post_name varchar(100) not null, original_post_name varchar(100) not null,
post_url text, original_post_url text,
post_body text, original_post_body text,
reason text not null, reason text not null,
resolved bool not null default false, resolved bool not null default false,
resolver_id int references user_ on update cascade on delete cascade, -- user resolving report resolver_id int references user_ on update cascade on delete cascade, -- user resolving report
@ -54,7 +54,7 @@ from comment_report cr
left join comment c on c.id = cr.comment_id left join comment c on c.id = cr.comment_id
left join post p on p.id = c.post_id left join post p on p.id = c.post_id
left join user_ u on u.id = c.creator_id left join user_ u on u.id = c.creator_id
left join user_ f on f.id = cr.creator_id; left join user_ f on f.id = cr.creator_id
left join user_ r on r.id = cr.resolver_id; left join user_ r on r.id = cr.resolver_id;
create or replace view post_report_view as create or replace view post_report_view as
@ -63,7 +63,6 @@ p.name as current_post_name,
p.url as current_post_url, p.url as current_post_url,
p.body as current_post_body, p.body as current_post_body,
p.community_id, p.community_id,
f.name as creator_name,
-- report creator details -- report creator details
f.actor_id as creator_actor_id, f.actor_id as creator_actor_id,
f.name as creator_name, f.name as creator_name,
@ -86,5 +85,5 @@ r.local as resolver_local
from post_report pr from post_report pr
left join post p on p.id = pr.post_id left join post p on p.id = pr.post_id
left join user_ u on u.id = p.creator_id left join user_ u on u.id = p.creator_id
left join user_ f on f.id = pr.creator_id; left join user_ f on f.id = pr.creator_id
left join user_ r on r.id = pr.resolver_id; left join user_ r on r.id = pr.resolver_id;

View file

@ -82,8 +82,11 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) {
.route("/save", web::put().to(route_post::<SavePost>)) .route("/save", web::put().to(route_post::<SavePost>))
.route("/join", web::post().to(route_post::<PostJoin>)) .route("/join", web::post().to(route_post::<PostJoin>))
.route("/report", web::post().to(route_post::<CreatePostReport>)) .route("/report", web::post().to(route_post::<CreatePostReport>))
.route("/report/resolve", web::put().to(route_post::<ResolvePostReport>)) .route(
.route("/report/list", web::get().to(route_get::<ListPostReports>)) "/report/resolve",
web::put().to(route_post::<ResolvePostReport>),
)
.route("/report/list", web::get().to(route_get::<ListPostReports>)),
) )
// Comment // Comment
.service( .service(
@ -101,8 +104,14 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) {
.route("/save", web::put().to(route_post::<SaveComment>)) .route("/save", web::put().to(route_post::<SaveComment>))
.route("/list", web::get().to(route_get::<GetComments>)) .route("/list", web::get().to(route_get::<GetComments>))
.route("/report", web::post().to(route_post::<CreateCommentReport>)) .route("/report", web::post().to(route_post::<CreateCommentReport>))
.route("/report/resolve", web::put().to(route_post::<ResolveCommentReport>)) .route(
.route("/report/list", web::get().to(route_get::<ListCommentReports>)) "/report/resolve",
web::put().to(route_post::<ResolveCommentReport>),
)
.route(
"/report/list",
web::get().to(route_get::<ListCommentReports>),
),
) )
// Private Message // Private Message
.service( .service(
@ -171,10 +180,7 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) {
"/save_user_settings", "/save_user_settings",
web::put().to(route_post::<SaveUserSettings>), web::put().to(route_post::<SaveUserSettings>),
) )
.route( .route("/report_count", web::get().to(route_get::<GetReportCount>)),
"/report_count",
web::get().to(route_get::<GetReportCount>)
),
) )
// Admin Actions // Admin Actions
.service( .service(