reports: split post/comment out again, add some other fixes
This commit is contained in:
parent
e8e0890341
commit
2cd2a4df45
18 changed files with 710 additions and 601 deletions
|
@ -5,11 +5,13 @@ use crate::{
|
||||||
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};
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
comment::*,
|
comment::*,
|
||||||
|
comment_report::*,
|
||||||
comment_view::*,
|
comment_view::*,
|
||||||
moderator::*,
|
moderator::*,
|
||||||
post::*,
|
post::*,
|
||||||
|
@ -20,6 +22,7 @@ use lemmy_db::{
|
||||||
ListingType,
|
ListingType,
|
||||||
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::{
|
||||||
|
@ -29,7 +32,7 @@ use lemmy_utils::{
|
||||||
ConnectionId,
|
ConnectionId,
|
||||||
LemmyError,
|
LemmyError,
|
||||||
};
|
};
|
||||||
use lemmy_websocket::{messages::SendComment, LemmyContext, UserOperation};
|
use lemmy_websocket::{messages::{SendComment, SendUserRoomMessage}, LemmyContext, UserOperation};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
|
@ -682,3 +685,153 @@ impl Perform for GetComments {
|
||||||
Ok(GetCommentsResponse { comments })
|
Ok(GetCommentsResponse { comments })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait(?Send)]
|
||||||
|
impl Perform for CreateCommentReport {
|
||||||
|
type Response = CreateCommentReportResponse;
|
||||||
|
|
||||||
|
async fn perform(
|
||||||
|
&self,
|
||||||
|
context: &Data<LemmyContext>,
|
||||||
|
_websocket_id: Option<ConnectionId>,
|
||||||
|
) -> Result<CreateCommentReportResponse, LemmyError> {
|
||||||
|
let data: &CreateCommentReport = &self;
|
||||||
|
let user = get_user_from_jwt(&data.auth, context.pool()).await?;
|
||||||
|
|
||||||
|
// check size of report and check for whitespace
|
||||||
|
let reason = data.reason.trim();
|
||||||
|
if reason.is_empty() {
|
||||||
|
return Err(APIError::err("report_reason_required").into());
|
||||||
|
}
|
||||||
|
if reason.len() > 1000 {
|
||||||
|
return Err(APIError::err("report_too_long").into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let user_id = user.id;
|
||||||
|
let comment_id = data.comment_id;
|
||||||
|
let comment = blocking(context.pool(), move |conn| {
|
||||||
|
CommentView::read(&conn, comment_id, None)
|
||||||
|
}).await??;
|
||||||
|
|
||||||
|
check_community_ban(user_id, comment.community_id, context.pool()).await?;
|
||||||
|
|
||||||
|
let report_form = CommentReportForm {
|
||||||
|
creator_id: user_id,
|
||||||
|
comment_id,
|
||||||
|
comment_text: comment.content,
|
||||||
|
reason: data.reason.to_owned(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let _report = match blocking(context.pool(), move |conn| {
|
||||||
|
CommentReport::report(conn, &report_form)
|
||||||
|
}).await? {
|
||||||
|
Ok(report) => report,
|
||||||
|
Err(_e) => return Err(APIError::err("couldnt_create_report").into())
|
||||||
|
};
|
||||||
|
|
||||||
|
// to build on this, the user should get a success response, however
|
||||||
|
// mods should get a different response with more details
|
||||||
|
let res = CreateCommentReportResponse { success: true };
|
||||||
|
|
||||||
|
// TODO this needs to use a SendModRoomMessage
|
||||||
|
// context.chat_server().do_send(SendUserRoomMessage {
|
||||||
|
// op: UserOperation::CreateReport,
|
||||||
|
// response: res.clone(),
|
||||||
|
// recipient_id: user.id,
|
||||||
|
// websocket_id,
|
||||||
|
// });
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait(?Send)]
|
||||||
|
impl Perform for ResolveCommentReport {
|
||||||
|
type Response = ResolveCommentReportResponse;
|
||||||
|
|
||||||
|
async fn perform(
|
||||||
|
&self,
|
||||||
|
context: &Data<LemmyContext>,
|
||||||
|
_websocket_id: Option<ConnectionId>,
|
||||||
|
) -> Result<ResolveCommentReportResponse, LemmyError> {
|
||||||
|
let data: &ResolveCommentReport = &self;
|
||||||
|
let user = get_user_from_jwt(&data.auth, context.pool()).await?;
|
||||||
|
|
||||||
|
let report_id = data.report_id;
|
||||||
|
let report = blocking(context.pool(), move |conn| {
|
||||||
|
CommentReportView::read(&conn, report_id)
|
||||||
|
}).await??;
|
||||||
|
|
||||||
|
let user_id = user.id;
|
||||||
|
is_mod_or_admin(context.pool(), user_id, report.community_id).await?;
|
||||||
|
|
||||||
|
let resolved = data.resolved;
|
||||||
|
let resolve_fun = move |conn: &'_ _| {
|
||||||
|
if resolved {
|
||||||
|
CommentReport::resolve(conn, report_id.clone(), user_id)
|
||||||
|
} else {
|
||||||
|
CommentReport::unresolve(conn, report_id.clone())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if blocking(context.pool(),resolve_fun).await?.is_err() {
|
||||||
|
return Err(APIError::err("couldnt_resolve_report").into())
|
||||||
|
};
|
||||||
|
|
||||||
|
let report_id = data.report_id;
|
||||||
|
let res = ResolveCommentReportResponse {
|
||||||
|
report_id,
|
||||||
|
resolved,
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO this needs to use a SendModRoomMessage
|
||||||
|
// context.chat_server().do_send(SendUserRoomMessage {
|
||||||
|
// op: UserOperation::ResolveCommentReport,
|
||||||
|
// response: res.clone(),
|
||||||
|
// recipient_id: user.id,
|
||||||
|
// websocket_id,
|
||||||
|
// });
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait(?Send)]
|
||||||
|
impl Perform for ListCommentReports {
|
||||||
|
type Response = ListCommentReportsResponse;
|
||||||
|
|
||||||
|
async fn perform(
|
||||||
|
&self,
|
||||||
|
context: &Data<LemmyContext>,
|
||||||
|
websocket_id: Option<ConnectionId>,
|
||||||
|
) -> Result<ListCommentReportsResponse, LemmyError> {
|
||||||
|
let data: &ListCommentReports = &self;
|
||||||
|
let user = get_user_from_jwt(&data.auth, context.pool()).await?;
|
||||||
|
|
||||||
|
let user_id = user.id;
|
||||||
|
let community_id = data.community;
|
||||||
|
let community_ids = collect_moderated_communities(user_id, community_id, context.pool()).await?;
|
||||||
|
|
||||||
|
let page = data.page;
|
||||||
|
let limit = data.limit;
|
||||||
|
let comments = blocking(context.pool(), move |conn| {
|
||||||
|
CommentReportQueryBuilder::create(conn)
|
||||||
|
.community_ids(community_ids)
|
||||||
|
.page(page)
|
||||||
|
.limit(limit)
|
||||||
|
.list()
|
||||||
|
})
|
||||||
|
.await??;
|
||||||
|
|
||||||
|
let res = ListCommentReportsResponse { comments };
|
||||||
|
|
||||||
|
context.chat_server().do_send(SendUserRoomMessage {
|
||||||
|
op: UserOperation::ListCommentReports,
|
||||||
|
response: res.clone(),
|
||||||
|
recipient_id: user.id,
|
||||||
|
websocket_id,
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,14 +1,14 @@
|
||||||
use crate::claims::Claims;
|
use crate::claims::Claims;
|
||||||
use actix_web::{web, web::Data};
|
use actix_web::{web, web::Data};
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
community::Community,
|
community::{Community, CommunityModerator},
|
||||||
community_view::CommunityUserBanView,
|
community_view::CommunityUserBanView,
|
||||||
post::Post,
|
post::Post,
|
||||||
user::User_,
|
user::User_,
|
||||||
Crud,
|
Crud,
|
||||||
DbPool,
|
DbPool,
|
||||||
};
|
};
|
||||||
use lemmy_structs::{blocking, comment::*, community::*, post::*, report::*, site::*, user::*};
|
use lemmy_structs::{blocking, comment::*, community::*, post::*, site::*, user::*};
|
||||||
use lemmy_utils::{settings::Settings, APIError, ConnectionId, LemmyError};
|
use lemmy_utils::{settings::Settings, APIError, ConnectionId, LemmyError};
|
||||||
use lemmy_websocket::{serialize_websocket_message, LemmyContext, UserOperation};
|
use lemmy_websocket::{serialize_websocket_message, LemmyContext, UserOperation};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
@ -19,7 +19,6 @@ pub mod claims;
|
||||||
pub mod comment;
|
pub mod comment;
|
||||||
pub mod community;
|
pub mod community;
|
||||||
pub mod post;
|
pub mod post;
|
||||||
pub mod report;
|
|
||||||
pub mod site;
|
pub mod site;
|
||||||
pub mod user;
|
pub mod user;
|
||||||
pub mod version;
|
pub mod version;
|
||||||
|
@ -101,6 +100,23 @@ pub(in crate) async fn check_community_ban(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(in crate) async fn collect_moderated_communities(
|
||||||
|
user_id: i32,
|
||||||
|
community_id: Option<i32>,
|
||||||
|
pool: &DbPool,
|
||||||
|
) -> Result<Vec<i32>, LemmyError> {
|
||||||
|
if let Some(community_id) = community_id {
|
||||||
|
// if the user provides a community_id, just check for mod/admin privileges
|
||||||
|
is_mod_or_admin(pool, user_id, community_id).await?;
|
||||||
|
Ok(vec![community_id])
|
||||||
|
} else {
|
||||||
|
let ids = blocking(pool, move |conn: &'_ _| {
|
||||||
|
CommunityModerator::get_user_moderated_communities(conn, user_id)
|
||||||
|
}).await??;
|
||||||
|
Ok(ids)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(in crate) fn check_optional_url(item: &Option<Option<String>>) -> Result<(), LemmyError> {
|
pub(in crate) fn check_optional_url(item: &Option<Option<String>>) -> Result<(), LemmyError> {
|
||||||
if let Some(Some(item)) = &item {
|
if let Some(Some(item)) = &item {
|
||||||
if Url::parse(item).is_err() {
|
if Url::parse(item).is_err() {
|
||||||
|
@ -182,6 +198,9 @@ pub async fn match_websocket_operation(
|
||||||
UserOperation::SaveUserSettings => {
|
UserOperation::SaveUserSettings => {
|
||||||
do_websocket_operation::<SaveUserSettings>(context, id, op, data).await
|
do_websocket_operation::<SaveUserSettings>(context, id, op, data).await
|
||||||
}
|
}
|
||||||
|
UserOperation::GetReportCount => {
|
||||||
|
do_websocket_operation::<GetReportCount>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
|
||||||
// Private Message ops
|
// Private Message ops
|
||||||
UserOperation::CreatePrivateMessage => {
|
UserOperation::CreatePrivateMessage => {
|
||||||
|
@ -267,6 +286,15 @@ pub async fn match_websocket_operation(
|
||||||
do_websocket_operation::<CreatePostLike>(context, id, op, data).await
|
do_websocket_operation::<CreatePostLike>(context, id, op, data).await
|
||||||
}
|
}
|
||||||
UserOperation::SavePost => do_websocket_operation::<SavePost>(context, id, op, data).await,
|
UserOperation::SavePost => do_websocket_operation::<SavePost>(context, id, op, data).await,
|
||||||
|
UserOperation::CreatePostReport => {
|
||||||
|
do_websocket_operation::<CreatePostReport>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::ListPostReports => {
|
||||||
|
do_websocket_operation::<ListPostReports>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
UserOperation::ResolvePostReport => {
|
||||||
|
do_websocket_operation::<ResolvePostReport>(context, id, op, data).await
|
||||||
|
}
|
||||||
|
|
||||||
// Comment ops
|
// Comment ops
|
||||||
UserOperation::CreateComment => {
|
UserOperation::CreateComment => {
|
||||||
|
@ -293,19 +321,14 @@ pub async fn match_websocket_operation(
|
||||||
UserOperation::CreateCommentLike => {
|
UserOperation::CreateCommentLike => {
|
||||||
do_websocket_operation::<CreateCommentLike>(context, id, op, data).await
|
do_websocket_operation::<CreateCommentLike>(context, id, op, data).await
|
||||||
}
|
}
|
||||||
|
UserOperation::CreateCommentReport => {
|
||||||
// report ops
|
do_websocket_operation::<CreateCommentReport>(context, id, op, data).await
|
||||||
UserOperation::CreateReport => {
|
|
||||||
do_websocket_operation::<CreateReport>(context, id, op, data).await
|
|
||||||
}
|
}
|
||||||
UserOperation::ListReports => {
|
UserOperation::ListCommentReports => {
|
||||||
do_websocket_operation::<ListReports>(context, id, op, data).await
|
do_websocket_operation::<ListCommentReports>(context, id, op, data).await
|
||||||
}
|
}
|
||||||
UserOperation::ResolveReport => {
|
UserOperation::ResolveCommentReport => {
|
||||||
do_websocket_operation::<ResolveReport>(context, id, op, data).await
|
do_websocket_operation::<ResolveCommentReport>(context, id, op, data).await
|
||||||
}
|
|
||||||
UserOperation::GetReportCount => {
|
|
||||||
do_websocket_operation::<GetReportCount>(context, id, op, data).await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ use crate::{
|
||||||
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};
|
||||||
|
@ -14,6 +15,7 @@ use lemmy_db::{
|
||||||
moderator::*,
|
moderator::*,
|
||||||
naive_now,
|
naive_now,
|
||||||
post::*,
|
post::*,
|
||||||
|
post_report::*,
|
||||||
post_view::*,
|
post_view::*,
|
||||||
site_view::*,
|
site_view::*,
|
||||||
Crud,
|
Crud,
|
||||||
|
@ -21,6 +23,7 @@ use lemmy_db::{
|
||||||
ListingType,
|
ListingType,
|
||||||
Saveable,
|
Saveable,
|
||||||
SortType,
|
SortType,
|
||||||
|
Reportable,
|
||||||
};
|
};
|
||||||
use lemmy_structs::{blocking, post::*};
|
use lemmy_structs::{blocking, post::*};
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
|
@ -32,7 +35,7 @@ use lemmy_utils::{
|
||||||
LemmyError,
|
LemmyError,
|
||||||
};
|
};
|
||||||
use lemmy_websocket::{
|
use lemmy_websocket::{
|
||||||
messages::{GetPostUsersOnline, JoinPostRoom, SendPost},
|
messages::{GetPostUsersOnline, JoinPostRoom, SendPost, SendUserRoomMessage},
|
||||||
LemmyContext,
|
LemmyContext,
|
||||||
UserOperation,
|
UserOperation,
|
||||||
};
|
};
|
||||||
|
@ -741,3 +744,154 @@ impl Perform for PostJoin {
|
||||||
Ok(PostJoinResponse { joined: true })
|
Ok(PostJoinResponse { joined: true })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait(?Send)]
|
||||||
|
impl Perform for CreatePostReport {
|
||||||
|
type Response = CreatePostReportResponse;
|
||||||
|
|
||||||
|
async fn perform(
|
||||||
|
&self,
|
||||||
|
context: &Data<LemmyContext>,
|
||||||
|
_websocket_id: Option<ConnectionId>,
|
||||||
|
) -> Result<CreatePostReportResponse, LemmyError> {
|
||||||
|
let data: &CreatePostReport = &self;
|
||||||
|
let user = get_user_from_jwt(&data.auth, context.pool()).await?;
|
||||||
|
|
||||||
|
// check size of report and check for whitespace
|
||||||
|
let reason = data.reason.trim();
|
||||||
|
if reason.is_empty() {
|
||||||
|
return Err(APIError::err("report_reason_required").into());
|
||||||
|
}
|
||||||
|
if reason.len() > 1000 {
|
||||||
|
return Err(APIError::err("report_too_long").into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let user_id = user.id;
|
||||||
|
let post_id = data.post_id;
|
||||||
|
let post = blocking(context.pool(), move |conn| {
|
||||||
|
PostView::read(&conn, post_id, None)
|
||||||
|
}).await??;
|
||||||
|
|
||||||
|
check_community_ban(user_id, post.community_id, context.pool()).await?;
|
||||||
|
|
||||||
|
let report_form = PostReportForm {
|
||||||
|
creator_id: user_id,
|
||||||
|
post_id,
|
||||||
|
post_name: post.name,
|
||||||
|
post_url: post.url,
|
||||||
|
post_body: post.body,
|
||||||
|
reason: data.reason.to_owned(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let _report = match blocking(context.pool(), move |conn| {
|
||||||
|
PostReport::report(conn, &report_form)
|
||||||
|
}).await? {
|
||||||
|
Ok(report) => report,
|
||||||
|
Err(_e) => return Err(APIError::err("couldnt_create_report").into())
|
||||||
|
};
|
||||||
|
|
||||||
|
// to build on this, the user should get a success response, however
|
||||||
|
// mods should get a different response with more details
|
||||||
|
let res = CreatePostReportResponse { success: true };
|
||||||
|
|
||||||
|
// TODO this needs to use a SendModRoomMessage
|
||||||
|
// context.chat_server().do_send(SendUserRoomMessage {
|
||||||
|
// op: UserOperation::CreateReport,
|
||||||
|
// response: res.clone(),
|
||||||
|
// recipient_id: user.id,
|
||||||
|
// websocket_id,
|
||||||
|
// });
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait(?Send)]
|
||||||
|
impl Perform for ResolvePostReport {
|
||||||
|
type Response = ResolvePostReportResponse;
|
||||||
|
|
||||||
|
async fn perform(
|
||||||
|
&self,
|
||||||
|
context: &Data<LemmyContext>,
|
||||||
|
_websocket_id: Option<ConnectionId>,
|
||||||
|
) -> Result<ResolvePostReportResponse, LemmyError> {
|
||||||
|
let data: &ResolvePostReport = &self;
|
||||||
|
let user = get_user_from_jwt(&data.auth, context.pool()).await?;
|
||||||
|
|
||||||
|
let report_id = data.report_id;
|
||||||
|
let report = blocking(context.pool(), move |conn| {
|
||||||
|
PostReportView::read(&conn, report_id)
|
||||||
|
}).await??;
|
||||||
|
|
||||||
|
let user_id = user.id;
|
||||||
|
is_mod_or_admin(context.pool(), user_id, report.community_id).await?;
|
||||||
|
|
||||||
|
let resolved = data.resolved;
|
||||||
|
let resolve_fun = move |conn: &'_ _| {
|
||||||
|
if resolved {
|
||||||
|
PostReport::resolve(conn, report_id.clone(), user_id)
|
||||||
|
} else {
|
||||||
|
PostReport::unresolve(conn, report_id.clone())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let res = ResolvePostReportResponse {
|
||||||
|
report_id,
|
||||||
|
resolved: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
if blocking(context.pool(),resolve_fun).await?.is_err() {
|
||||||
|
return Err(APIError::err("couldnt_resolve_report").into())
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO this needs to use a SendModRoomMessage
|
||||||
|
// context.chat_server().do_send(SendUserRoomMessage {
|
||||||
|
// op: UserOperation::ResolvePostReport,
|
||||||
|
// response: res.clone(),
|
||||||
|
// recipient_id: user.id,
|
||||||
|
// websocket_id,
|
||||||
|
// });
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait(?Send)]
|
||||||
|
impl Perform for ListPostReports {
|
||||||
|
type Response = ListPostReportsResponse;
|
||||||
|
|
||||||
|
async fn perform(
|
||||||
|
&self,
|
||||||
|
context: &Data<LemmyContext>,
|
||||||
|
websocket_id: Option<ConnectionId>,
|
||||||
|
) -> Result<ListPostReportsResponse, LemmyError> {
|
||||||
|
let data: &ListPostReports = &self;
|
||||||
|
let user = get_user_from_jwt(&data.auth, context.pool()).await?;
|
||||||
|
|
||||||
|
let user_id = user.id;
|
||||||
|
let community_id = data.community;
|
||||||
|
let community_ids = collect_moderated_communities(user_id, community_id, context.pool()).await?;
|
||||||
|
|
||||||
|
let page = data.page;
|
||||||
|
let limit = data.limit;
|
||||||
|
let posts = blocking(context.pool(), move |conn| {
|
||||||
|
PostReportQueryBuilder::create(conn)
|
||||||
|
.community_ids(community_ids)
|
||||||
|
.page(page)
|
||||||
|
.limit(limit)
|
||||||
|
.list()
|
||||||
|
})
|
||||||
|
.await??;
|
||||||
|
|
||||||
|
let res = ListPostReportsResponse { posts };
|
||||||
|
|
||||||
|
context.chat_server().do_send(SendUserRoomMessage {
|
||||||
|
op: UserOperation::ListPostReports,
|
||||||
|
response: res.clone(),
|
||||||
|
recipient_id: user.id,
|
||||||
|
websocket_id,
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,300 +0,0 @@
|
||||||
use actix_web::web::Data;
|
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
use lemmy_db::{comment_report::*, comment_view::*, post_report::*, post_view::*, Reportable, ReportType,};
|
|
||||||
use lemmy_structs::{blocking, report::*};
|
|
||||||
use lemmy_utils::{APIError, ConnectionId, LemmyError};
|
|
||||||
use lemmy_websocket::{LemmyContext, UserOperation, messages::SendUserRoomMessage};
|
|
||||||
|
|
||||||
use crate::{check_community_ban, get_user_from_jwt, is_mod_or_admin, Perform};
|
|
||||||
|
|
||||||
const MAX_REPORT_LEN: usize = 1000;
|
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
|
||||||
impl Perform for CreateReport {
|
|
||||||
type Response = CreateReportResponse;
|
|
||||||
|
|
||||||
async fn perform(
|
|
||||||
&self,
|
|
||||||
context: &Data<LemmyContext>,
|
|
||||||
websocket_id: Option<ConnectionId>,
|
|
||||||
) -> Result<CreateReportResponse, LemmyError> {
|
|
||||||
let data: &CreateReport = &self;
|
|
||||||
let user = get_user_from_jwt(&data.auth, context.pool()).await?;
|
|
||||||
|
|
||||||
// check size of report and check for whitespace
|
|
||||||
let reason = data.reason.clone();
|
|
||||||
if reason.trim().is_empty() {
|
|
||||||
return Err(APIError::err("report_reason_required").into());
|
|
||||||
}
|
|
||||||
if reason.len() > MAX_REPORT_LEN {
|
|
||||||
return Err(APIError::err("report_too_long").into());
|
|
||||||
}
|
|
||||||
|
|
||||||
let report_type = ReportType::from_str(&data.report_type)?;
|
|
||||||
let user_id = user.id;
|
|
||||||
match report_type {
|
|
||||||
ReportType::Comment => { create_comment_report(context, data, user_id).await?; }
|
|
||||||
ReportType::Post => { create_post_report(context, data, user_id).await?; }
|
|
||||||
}
|
|
||||||
|
|
||||||
// to build on this, the user should get a success response, however
|
|
||||||
// mods should get a different response with more details
|
|
||||||
let res = CreateReportResponse { success: true };
|
|
||||||
|
|
||||||
context.chat_server().do_send(SendUserRoomMessage {
|
|
||||||
op: UserOperation::CreateReport,
|
|
||||||
response: res.clone(),
|
|
||||||
recipient_id: user.id,
|
|
||||||
websocket_id,
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
|
||||||
impl Perform for GetReportCount {
|
|
||||||
type Response = GetReportCountResponse;
|
|
||||||
|
|
||||||
async fn perform(
|
|
||||||
&self,
|
|
||||||
context: &Data<LemmyContext>,
|
|
||||||
websocket_id: Option<ConnectionId>,
|
|
||||||
) -> Result<GetReportCountResponse, LemmyError> {
|
|
||||||
let data: &GetReportCount = &self;
|
|
||||||
let user = get_user_from_jwt(&data.auth, context.pool()).await?;
|
|
||||||
let community_id = data.community;
|
|
||||||
|
|
||||||
// Check for mod/admin privileges
|
|
||||||
is_mod_or_admin(context.pool(), user.id, community_id).await?;
|
|
||||||
|
|
||||||
let comment_reports = blocking(context.pool(), move |conn| {
|
|
||||||
CommentReportQueryBuilder::create(conn)
|
|
||||||
.community_id(community_id)
|
|
||||||
.resolved(false)
|
|
||||||
.count()
|
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
let post_reports = blocking(context.pool(), move |conn| {
|
|
||||||
PostReportQueryBuilder::create(conn)
|
|
||||||
.community_id(community_id)
|
|
||||||
.resolved(false)
|
|
||||||
.count()
|
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
|
|
||||||
let res = GetReportCountResponse {
|
|
||||||
community: community_id,
|
|
||||||
comment_reports,
|
|
||||||
post_reports,
|
|
||||||
};
|
|
||||||
|
|
||||||
context.chat_server().do_send(SendUserRoomMessage {
|
|
||||||
op: UserOperation::ListReports,
|
|
||||||
response: res.clone(),
|
|
||||||
recipient_id: user.id,
|
|
||||||
websocket_id,
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
|
||||||
impl Perform for ListReports {
|
|
||||||
type Response = ListReportsResponse;
|
|
||||||
|
|
||||||
async fn perform(
|
|
||||||
&self,
|
|
||||||
context: &Data<LemmyContext>,
|
|
||||||
websocket_id: Option<ConnectionId>,
|
|
||||||
) -> Result<ListReportsResponse, LemmyError> {
|
|
||||||
let data: &ListReports = &self;
|
|
||||||
let user = get_user_from_jwt(&data.auth, context.pool()).await?;
|
|
||||||
let community_id = data.community;
|
|
||||||
|
|
||||||
// Check for mod/admin privileges
|
|
||||||
is_mod_or_admin(context.pool(), user.id, community_id).await?;
|
|
||||||
|
|
||||||
let page = data.page;
|
|
||||||
let limit = data.limit;
|
|
||||||
let comments = blocking(context.pool(), move |conn| {
|
|
||||||
CommentReportQueryBuilder::create(conn)
|
|
||||||
.community_id(community_id)
|
|
||||||
.page(page)
|
|
||||||
.limit(limit)
|
|
||||||
.list()
|
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
|
|
||||||
let posts = blocking(context.pool(), move |conn| {
|
|
||||||
PostReportQueryBuilder::create(conn)
|
|
||||||
.community_id(community_id)
|
|
||||||
.page(page)
|
|
||||||
.limit(limit)
|
|
||||||
.list()
|
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
|
|
||||||
let res = ListReportsResponse { comments, posts };
|
|
||||||
|
|
||||||
context.chat_server().do_send(SendUserRoomMessage {
|
|
||||||
op: UserOperation::ListReports,
|
|
||||||
response: res.clone(),
|
|
||||||
recipient_id: user.id,
|
|
||||||
websocket_id,
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
|
||||||
impl Perform for ResolveReport {
|
|
||||||
type Response = ResolveReportResponse;
|
|
||||||
|
|
||||||
async fn perform(
|
|
||||||
&self,
|
|
||||||
context: &Data<LemmyContext>,
|
|
||||||
websocket_id: Option<ConnectionId>,
|
|
||||||
) -> Result<ResolveReportResponse, LemmyError> {
|
|
||||||
let data: &ResolveReport = &self;
|
|
||||||
let user = get_user_from_jwt(&data.auth, context.pool()).await?;
|
|
||||||
|
|
||||||
let report_type = ReportType::from_str(&data.report_type)?;
|
|
||||||
let user_id = user.id;
|
|
||||||
match report_type {
|
|
||||||
ReportType::Comment => { resolve_comment_report(context, data, user_id).await?; }
|
|
||||||
ReportType::Post => { resolve_post_report(context, data, user_id).await?; }
|
|
||||||
}
|
|
||||||
|
|
||||||
let report_id = data.report_id;
|
|
||||||
let res = ResolveReportResponse {
|
|
||||||
report_type: data.report_type.to_owned(),
|
|
||||||
report_id,
|
|
||||||
resolved: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
context.chat_server().do_send(SendUserRoomMessage {
|
|
||||||
op: UserOperation::ResolveReport,
|
|
||||||
response: res.clone(),
|
|
||||||
recipient_id: user.id,
|
|
||||||
websocket_id,
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn create_comment_report(
|
|
||||||
context: &Data<LemmyContext>,
|
|
||||||
data: &CreateReport,
|
|
||||||
user_id: i32,
|
|
||||||
) -> Result<(), LemmyError> {
|
|
||||||
let comment_id = data.entity_id;
|
|
||||||
let comment = blocking(context.pool(), move |conn| {
|
|
||||||
CommentView::read(&conn, comment_id, None)
|
|
||||||
}).await??;
|
|
||||||
|
|
||||||
check_community_ban(user_id, comment.community_id, context.pool()).await?;
|
|
||||||
|
|
||||||
let report_form = CommentReportForm {
|
|
||||||
creator_id: user_id,
|
|
||||||
comment_id,
|
|
||||||
comment_text: comment.content,
|
|
||||||
reason: data.reason.to_owned(),
|
|
||||||
};
|
|
||||||
|
|
||||||
return match blocking(context.pool(), move |conn| {
|
|
||||||
CommentReport::report(conn, &report_form)
|
|
||||||
}).await? {
|
|
||||||
Ok(_) => Ok(()),
|
|
||||||
Err(_e) => Err(APIError::err("couldnt_create_report").into())
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn create_post_report(
|
|
||||||
context: &Data<LemmyContext>,
|
|
||||||
data: &CreateReport,
|
|
||||||
user_id: i32,
|
|
||||||
) -> Result<(), LemmyError> {
|
|
||||||
let post_id = data.entity_id;
|
|
||||||
let post = blocking(context.pool(), move |conn| {
|
|
||||||
PostView::read(&conn, post_id, None)
|
|
||||||
}).await??;
|
|
||||||
|
|
||||||
check_community_ban(user_id, post.community_id, context.pool()).await?;
|
|
||||||
|
|
||||||
let report_form = PostReportForm {
|
|
||||||
creator_id: user_id,
|
|
||||||
post_id,
|
|
||||||
post_name: post.name,
|
|
||||||
post_url: post.url,
|
|
||||||
post_body: post.body,
|
|
||||||
reason: data.reason.to_owned(),
|
|
||||||
};
|
|
||||||
|
|
||||||
return match blocking(context.pool(), move |conn| {
|
|
||||||
PostReport::report(conn, &report_form)
|
|
||||||
}).await? {
|
|
||||||
Ok(_) => Ok(()),
|
|
||||||
Err(_e) => Err(APIError::err("couldnt_create_report").into())
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn resolve_comment_report(
|
|
||||||
context: &Data<LemmyContext>,
|
|
||||||
data: &ResolveReport,
|
|
||||||
user_id: i32,
|
|
||||||
) -> Result<(), LemmyError> {
|
|
||||||
let report_id = data.report_id;
|
|
||||||
let report = blocking(context.pool(), move |conn| {
|
|
||||||
CommentReportView::read(&conn, report_id)
|
|
||||||
}).await??;
|
|
||||||
|
|
||||||
is_mod_or_admin(context.pool(), user_id, report.community_id).await?;
|
|
||||||
|
|
||||||
let resolved = data.resolved;
|
|
||||||
let resolve_fun = move |conn: &'_ _| {
|
|
||||||
if resolved {
|
|
||||||
CommentReport::resolve(conn, report_id.clone(), user_id)
|
|
||||||
} else {
|
|
||||||
CommentReport::unresolve(conn, report_id.clone())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if blocking(context.pool(),resolve_fun).await?.is_err() {
|
|
||||||
return Err(APIError::err("couldnt_resolve_report").into())
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn resolve_post_report(
|
|
||||||
context: &Data<LemmyContext>,
|
|
||||||
data: &ResolveReport,
|
|
||||||
user_id: i32,
|
|
||||||
) -> Result<(), LemmyError> {
|
|
||||||
let report_id = data.report_id;
|
|
||||||
let report = blocking(context.pool(), move |conn| {
|
|
||||||
PostReportView::read(&conn, report_id)
|
|
||||||
}).await??;
|
|
||||||
|
|
||||||
is_mod_or_admin(context.pool(), user_id, report.community_id).await?;
|
|
||||||
|
|
||||||
let resolved = data.resolved;
|
|
||||||
let resolve_fun = move |conn: &'_ _| {
|
|
||||||
if resolved {
|
|
||||||
PostReport::resolve(conn, report_id.clone(), user_id)
|
|
||||||
} else {
|
|
||||||
PostReport::unresolve(conn, report_id.clone())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if blocking(context.pool(),resolve_fun).await?.is_err() {
|
|
||||||
return Err(APIError::err("couldnt_resolve_report").into())
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
|
@ -6,6 +6,7 @@ use crate::{
|
||||||
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;
|
||||||
|
@ -15,6 +16,7 @@ use chrono::Duration;
|
||||||
use lemmy_apub::ApubObjectType;
|
use lemmy_apub::ApubObjectType;
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
comment::*,
|
comment::*,
|
||||||
|
comment_report::CommentReportView,
|
||||||
comment_view::*,
|
comment_view::*,
|
||||||
community::*,
|
community::*,
|
||||||
community_view::*,
|
community_view::*,
|
||||||
|
@ -23,6 +25,7 @@ use lemmy_db::{
|
||||||
naive_now,
|
naive_now,
|
||||||
password_reset_request::*,
|
password_reset_request::*,
|
||||||
post::*,
|
post::*,
|
||||||
|
post_report::PostReportView,
|
||||||
post_view::*,
|
post_view::*,
|
||||||
private_message::*,
|
private_message::*,
|
||||||
private_message_view::*,
|
private_message_view::*,
|
||||||
|
@ -1294,3 +1297,54 @@ impl Perform for UserJoin {
|
||||||
Ok(UserJoinResponse { joined: true })
|
Ok(UserJoinResponse { joined: true })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait(?Send)]
|
||||||
|
impl Perform for GetReportCount {
|
||||||
|
type Response = GetReportCountResponse;
|
||||||
|
|
||||||
|
async fn perform(
|
||||||
|
&self,
|
||||||
|
context: &Data<LemmyContext>,
|
||||||
|
websocket_id: Option<ConnectionId>,
|
||||||
|
) -> Result<GetReportCountResponse, LemmyError> {
|
||||||
|
let data: &GetReportCount = &self;
|
||||||
|
let user = get_user_from_jwt(&data.auth, context.pool()).await?;
|
||||||
|
|
||||||
|
let user_id = user.id;
|
||||||
|
let community_id = data.community;
|
||||||
|
let community_ids = collect_moderated_communities(user_id, community_id, context.pool()).await?;
|
||||||
|
|
||||||
|
let res = {
|
||||||
|
if community_ids.is_empty() {
|
||||||
|
GetReportCountResponse {
|
||||||
|
community: None,
|
||||||
|
comment_reports: 0,
|
||||||
|
post_reports: 0,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let ids = community_ids.clone();
|
||||||
|
let comment_reports = blocking(context.pool(), move |conn|
|
||||||
|
CommentReportView::get_report_count(conn, &ids)).await??;
|
||||||
|
|
||||||
|
let ids = community_ids.clone();
|
||||||
|
let post_reports = blocking(context.pool(), move |conn|
|
||||||
|
PostReportView::get_report_count(conn, &ids)).await??;
|
||||||
|
|
||||||
|
GetReportCountResponse {
|
||||||
|
community: data.community,
|
||||||
|
comment_reports,
|
||||||
|
post_reports,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
context.chat_server().do_send(SendUserRoomMessage {
|
||||||
|
op: UserOperation::GetReportCount,
|
||||||
|
response: res.clone(),
|
||||||
|
recipient_id: user.id,
|
||||||
|
websocket_id,
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ 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 {
|
||||||
|
@ -100,7 +100,7 @@ pub struct CommentReportView {
|
||||||
pub struct CommentReportQueryBuilder<'a> {
|
pub struct CommentReportQueryBuilder<'a> {
|
||||||
conn: &'a PgConnection,
|
conn: &'a PgConnection,
|
||||||
query: comment_report_view::BoxedQuery<'a, Pg>,
|
query: comment_report_view::BoxedQuery<'a, Pg>,
|
||||||
for_community_id: Option<i32>,
|
for_community_ids: Option<Vec<i32>>,
|
||||||
page: Option<i64>,
|
page: Option<i64>,
|
||||||
limit: Option<i64>,
|
limit: Option<i64>,
|
||||||
resolved: Option<bool>,
|
resolved: Option<bool>,
|
||||||
|
@ -113,6 +113,14 @@ impl CommentReportView {
|
||||||
.find(report_id)
|
.find(report_id)
|
||||||
.first::<Self>(conn)
|
.first::<Self>(conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_report_count(conn: &PgConnection, community_ids: &Vec<i32>) -> Result<i32, Error> {
|
||||||
|
use super::comment_report::comment_report_view::dsl::*;
|
||||||
|
comment_report_view
|
||||||
|
.filter(resolved.eq(false).and(community_id.eq_any(community_ids)))
|
||||||
|
.select(sql::<sql_types::Integer>("COUNT(*)"))
|
||||||
|
.first::<i32>(conn)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CommentReportQueryBuilder<'a> {
|
impl<'a> CommentReportQueryBuilder<'a> {
|
||||||
|
@ -124,15 +132,15 @@ impl<'a> CommentReportQueryBuilder<'a> {
|
||||||
CommentReportQueryBuilder {
|
CommentReportQueryBuilder {
|
||||||
conn,
|
conn,
|
||||||
query,
|
query,
|
||||||
for_community_id: None,
|
for_community_ids: None,
|
||||||
page: None,
|
page: None,
|
||||||
limit: None,
|
limit: None,
|
||||||
resolved: Some(false),
|
resolved: Some(false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn community_id<T: MaybeOptional<i32>>(mut self, community_id: T) -> Self {
|
pub fn community_ids<T: MaybeOptional<Vec<i32>>>(mut self, community_ids: T) -> Self {
|
||||||
self.for_community_id = community_id.get_optional();
|
self.for_community_ids = community_ids.get_optional();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,8 +164,8 @@ impl<'a> CommentReportQueryBuilder<'a> {
|
||||||
|
|
||||||
let mut query = self.query;
|
let mut query = self.query;
|
||||||
|
|
||||||
if let Some(comm_id) = self.for_community_id {
|
if let Some(comm_ids) = self.for_community_ids {
|
||||||
query = query.filter(community_id.eq(comm_id));
|
query = query.filter(community_id.eq_any(comm_ids));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(resolved_flag) = self.resolved {
|
if let Some(resolved_flag) = self.resolved {
|
||||||
|
@ -172,21 +180,4 @@ impl<'a> CommentReportQueryBuilder<'a> {
|
||||||
.offset(offset)
|
.offset(offset)
|
||||||
.load::<CommentReportView>(self.conn)
|
.load::<CommentReportView>(self.conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn count(self) -> Result<usize, Error> {
|
|
||||||
use super::comment_report::comment_report_view::dsl::*;
|
|
||||||
let mut query = self.query;
|
|
||||||
|
|
||||||
if let Some(comm_id) = self.for_community_id {
|
|
||||||
query = query.filter(community_id.eq(comm_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(resolved_flag) = self.resolved {
|
|
||||||
query = query.filter(resolved.eq(resolved_flag));
|
|
||||||
}
|
|
||||||
|
|
||||||
query.execute(self.conn)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -224,6 +224,14 @@ impl CommunityModerator {
|
||||||
use crate::schema::community_moderator::dsl::*;
|
use crate::schema::community_moderator::dsl::*;
|
||||||
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> {
|
||||||
|
use crate::schema::community_moderator::dsl::*;
|
||||||
|
community_moderator
|
||||||
|
.filter(user_id.eq(for_user_id))
|
||||||
|
.select(community_id)
|
||||||
|
.load::<i32>(conn)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
|
#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
|
||||||
|
|
|
@ -173,12 +173,6 @@ pub enum SearchType {
|
||||||
Url,
|
Url,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(EnumString, ToString, Debug, Serialize, Deserialize)]
|
|
||||||
pub enum ReportType {
|
|
||||||
Comment,
|
|
||||||
Post,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fuzzy_search(q: &str) -> String {
|
pub fn fuzzy_search(q: &str) -> String {
|
||||||
let replaced = q.replace(" ", "%");
|
let replaced = q.replace(" ", "%");
|
||||||
format!("%{}%", replaced)
|
format!("%{}%", replaced)
|
||||||
|
|
|
@ -110,12 +110,20 @@ impl PostReportView {
|
||||||
.find(report_id)
|
.find(report_id)
|
||||||
.first::<Self>(conn)
|
.first::<Self>(conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_report_count(conn: &PgConnection, community_ids: &Vec<i32>) -> Result<i32, Error> {
|
||||||
|
use super::post_report::post_report_view::dsl::*;
|
||||||
|
post_report_view
|
||||||
|
.filter(resolved.eq(false).and(community_id.eq_any(community_ids)))
|
||||||
|
.select(sql::<sql_types::Integer>("COUNT(*)"))
|
||||||
|
.first::<i32>(conn)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PostReportQueryBuilder<'a> {
|
pub struct PostReportQueryBuilder<'a> {
|
||||||
conn: &'a PgConnection,
|
conn: &'a PgConnection,
|
||||||
query: post_report_view::BoxedQuery<'a, Pg>,
|
query: post_report_view::BoxedQuery<'a, Pg>,
|
||||||
for_community_id: Option<i32>,
|
for_community_ids: Option<Vec<i32>>,
|
||||||
page: Option<i64>,
|
page: Option<i64>,
|
||||||
limit: Option<i64>,
|
limit: Option<i64>,
|
||||||
resolved: Option<bool>,
|
resolved: Option<bool>,
|
||||||
|
@ -130,15 +138,15 @@ impl<'a> PostReportQueryBuilder<'a> {
|
||||||
PostReportQueryBuilder {
|
PostReportQueryBuilder {
|
||||||
conn,
|
conn,
|
||||||
query,
|
query,
|
||||||
for_community_id: None,
|
for_community_ids: None,
|
||||||
page: None,
|
page: None,
|
||||||
limit: None,
|
limit: None,
|
||||||
resolved: Some(false),
|
resolved: Some(false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn community_id<T: MaybeOptional<i32>>(mut self, community_id: T) -> Self {
|
pub fn community_ids<T: MaybeOptional<Vec<i32>>>(mut self, community_ids: T) -> Self {
|
||||||
self.for_community_id = community_id.get_optional();
|
self.for_community_ids = community_ids.get_optional();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,8 +170,8 @@ impl<'a> PostReportQueryBuilder<'a> {
|
||||||
|
|
||||||
let mut query = self.query;
|
let mut query = self.query;
|
||||||
|
|
||||||
if let Some(comm_id) = self.for_community_id {
|
if let Some(comm_ids) = self.for_community_ids {
|
||||||
query = query.filter(community_id.eq(comm_id));
|
query = query.filter(community_id.eq_any(comm_ids));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(resolved_flag) = self.resolved {
|
if let Some(resolved_flag) = self.resolved {
|
||||||
|
@ -178,19 +186,4 @@ impl<'a> PostReportQueryBuilder<'a> {
|
||||||
.offset(offset)
|
.offset(offset)
|
||||||
.load::<PostReportView>(self.conn)
|
.load::<PostReportView>(self.conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn count(self) -> Result<usize, Error> {
|
|
||||||
use super::post_report::post_report_view::dsl::*;
|
|
||||||
let mut query = self.query;
|
|
||||||
|
|
||||||
if let Some(comm_id) = self.for_community_id {
|
|
||||||
query = query.filter(community_id.eq(comm_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(resolved_flag) = self.resolved {
|
|
||||||
query = query.filter(resolved.eq(resolved_flag));
|
|
||||||
}
|
|
||||||
|
|
||||||
query.execute(self.conn)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
use lemmy_db::comment_view::CommentView;
|
use lemmy_db::{
|
||||||
|
comment_view::CommentView,
|
||||||
|
comment_report::CommentReportView,
|
||||||
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
@ -76,3 +79,41 @@ pub struct GetComments {
|
||||||
pub struct GetCommentsResponse {
|
pub struct GetCommentsResponse {
|
||||||
pub comments: Vec<CommentView>,
|
pub comments: Vec<CommentView>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct CreateCommentReport {
|
||||||
|
pub comment_id: i32,
|
||||||
|
pub reason: String,
|
||||||
|
pub auth: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
|
pub struct CreateCommentReportResponse {
|
||||||
|
pub success: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct ResolveCommentReport {
|
||||||
|
pub report_id: i32,
|
||||||
|
pub resolved: bool,
|
||||||
|
pub auth: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
pub struct ResolveCommentReportResponse {
|
||||||
|
pub report_id: i32,
|
||||||
|
pub resolved: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct ListCommentReports {
|
||||||
|
pub page: Option<i64>,
|
||||||
|
pub limit: Option<i64>,
|
||||||
|
pub community: Option<i32>,
|
||||||
|
pub auth: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
pub struct ListCommentReportsResponse {
|
||||||
|
pub comments: Vec<CommentReportView>,
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
pub mod comment;
|
pub mod comment;
|
||||||
pub mod community;
|
pub mod community;
|
||||||
pub mod post;
|
pub mod post;
|
||||||
pub mod report;
|
|
||||||
pub mod site;
|
pub mod site;
|
||||||
pub mod user;
|
pub mod user;
|
||||||
pub mod websocket;
|
pub mod websocket;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use lemmy_db::{
|
use lemmy_db::{
|
||||||
comment_view::CommentView,
|
comment_view::CommentView,
|
||||||
community_view::{CommunityModeratorView, CommunityView},
|
community_view::{CommunityModeratorView, CommunityView},
|
||||||
|
post_report::PostReportView,
|
||||||
post_view::PostView,
|
post_view::PostView,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -113,3 +114,41 @@ pub struct PostJoin {
|
||||||
pub struct PostJoinResponse {
|
pub struct PostJoinResponse {
|
||||||
pub joined: bool,
|
pub joined: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct CreatePostReport {
|
||||||
|
pub post_id: i32,
|
||||||
|
pub reason: String,
|
||||||
|
pub auth: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
|
pub struct CreatePostReportResponse {
|
||||||
|
pub success: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct ResolvePostReport {
|
||||||
|
pub report_id: i32,
|
||||||
|
pub resolved: bool,
|
||||||
|
pub auth: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
pub struct ResolvePostReportResponse {
|
||||||
|
pub report_id: i32,
|
||||||
|
pub resolved: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct ListPostReports {
|
||||||
|
pub page: Option<i64>,
|
||||||
|
pub limit: Option<i64>,
|
||||||
|
pub community: Option<i32>,
|
||||||
|
pub auth: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
pub struct ListPostReportsResponse {
|
||||||
|
pub posts: Vec<PostReportView>,
|
||||||
|
}
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
use lemmy_db::{comment_report::CommentReportView, post_report::PostReportView};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
pub struct CreateReport {
|
|
||||||
pub report_type: String,
|
|
||||||
pub entity_id: i32,
|
|
||||||
pub reason: String,
|
|
||||||
pub auth: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
|
||||||
pub struct CreateReportResponse {
|
|
||||||
pub success: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
|
||||||
pub struct ListReports {
|
|
||||||
pub page: Option<i64>,
|
|
||||||
pub limit: Option<i64>,
|
|
||||||
pub community: i32,
|
|
||||||
pub auth: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
|
||||||
pub struct ListReportsResponse {
|
|
||||||
pub posts: Vec<PostReportView>,
|
|
||||||
pub comments: Vec<CommentReportView>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
|
||||||
pub struct GetReportCount {
|
|
||||||
pub community: i32,
|
|
||||||
pub auth: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
|
||||||
pub struct GetReportCountResponse {
|
|
||||||
pub community: i32,
|
|
||||||
pub comment_reports: usize,
|
|
||||||
pub post_reports: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
|
||||||
pub struct ResolveReport {
|
|
||||||
pub report_type: String,
|
|
||||||
pub report_id: i32,
|
|
||||||
pub resolved: bool,
|
|
||||||
pub auth: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
|
||||||
pub struct ResolveReportResponse {
|
|
||||||
pub report_type: String,
|
|
||||||
pub report_id: i32,
|
|
||||||
pub resolved: bool,
|
|
||||||
}
|
|
|
@ -237,3 +237,16 @@ pub struct UserJoin {
|
||||||
pub struct UserJoinResponse {
|
pub struct UserJoinResponse {
|
||||||
pub joined: bool,
|
pub joined: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct GetReportCount {
|
||||||
|
pub community: Option<i32>,
|
||||||
|
pub auth: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
pub struct GetReportCountResponse {
|
||||||
|
pub community: Option<i32>,
|
||||||
|
pub comment_reports: i32,
|
||||||
|
pub post_reports: i32,
|
||||||
|
}
|
||||||
|
|
|
@ -97,6 +97,9 @@ pub enum UserOperation {
|
||||||
MarkCommentAsRead,
|
MarkCommentAsRead,
|
||||||
SaveComment,
|
SaveComment,
|
||||||
CreateCommentLike,
|
CreateCommentLike,
|
||||||
|
CreateCommentReport,
|
||||||
|
ResolveCommentReport,
|
||||||
|
ListCommentReports,
|
||||||
GetPosts,
|
GetPosts,
|
||||||
CreatePostLike,
|
CreatePostLike,
|
||||||
EditPost,
|
EditPost,
|
||||||
|
@ -105,9 +108,9 @@ pub enum UserOperation {
|
||||||
LockPost,
|
LockPost,
|
||||||
StickyPost,
|
StickyPost,
|
||||||
SavePost,
|
SavePost,
|
||||||
CreateReport,
|
CreatePostReport,
|
||||||
ResolveReport,
|
ResolvePostReport,
|
||||||
ListReports,
|
ListPostReports,
|
||||||
GetReportCount,
|
GetReportCount,
|
||||||
EditCommunity,
|
EditCommunity,
|
||||||
DeleteCommunity,
|
DeleteCommunity,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use actix_web::{error::ErrorBadRequest, *};
|
use actix_web::{error::ErrorBadRequest, *};
|
||||||
use lemmy_api::Perform;
|
use lemmy_api::Perform;
|
||||||
use lemmy_rate_limit::RateLimit;
|
use lemmy_rate_limit::RateLimit;
|
||||||
use lemmy_structs::{comment::*, community::*, post::*, report::*, site::*, user::*};
|
use lemmy_structs::{comment::*, community::*, post::*, site::*, user::*};
|
||||||
use lemmy_websocket::LemmyContext;
|
use lemmy_websocket::LemmyContext;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) {
|
||||||
.route("/transfer", web::post().to(route_post::<TransferCommunity>))
|
.route("/transfer", web::post().to(route_post::<TransferCommunity>))
|
||||||
.route("/ban_user", web::post().to(route_post::<BanFromCommunity>))
|
.route("/ban_user", web::post().to(route_post::<BanFromCommunity>))
|
||||||
.route("/mod", web::post().to(route_post::<AddModToCommunity>))
|
.route("/mod", web::post().to(route_post::<AddModToCommunity>))
|
||||||
.route("/join", web::post().to(route_post::<CommunityJoin>))
|
.route("/join", web::post().to(route_post::<CommunityJoin>)),
|
||||||
)
|
)
|
||||||
// Post
|
// Post
|
||||||
.service(
|
.service(
|
||||||
|
@ -80,6 +80,9 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) {
|
||||||
.route("/like", web::post().to(route_post::<CreatePostLike>))
|
.route("/like", web::post().to(route_post::<CreatePostLike>))
|
||||||
.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/resolve", web::put().to(route_post::<ResolvePostReport>))
|
||||||
|
.route("/report/list", web::get().to(route_get::<ListPostReports>))
|
||||||
)
|
)
|
||||||
// Comment
|
// Comment
|
||||||
.service(
|
.service(
|
||||||
|
@ -96,6 +99,9 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) {
|
||||||
.route("/like", web::post().to(route_post::<CreateCommentLike>))
|
.route("/like", web::post().to(route_post::<CreateCommentLike>))
|
||||||
.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/resolve", web::put().to(route_post::<ResolveCommentReport>))
|
||||||
|
.route("/report/list", web::get().to(route_get::<ListCommentReports>))
|
||||||
)
|
)
|
||||||
// Private Message
|
// Private Message
|
||||||
.service(
|
.service(
|
||||||
|
@ -163,6 +169,10 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) {
|
||||||
.route(
|
.route(
|
||||||
"/save_user_settings",
|
"/save_user_settings",
|
||||||
web::put().to(route_post::<SaveUserSettings>),
|
web::put().to(route_post::<SaveUserSettings>),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/report_count",
|
||||||
|
web::get().to(route_get::<GetReportCount>)
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
// Admin Actions
|
// Admin Actions
|
||||||
|
@ -170,15 +180,6 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) {
|
||||||
web::resource("/admin/add")
|
web::resource("/admin/add")
|
||||||
.wrap(rate_limit.message())
|
.wrap(rate_limit.message())
|
||||||
.route(web::post().to(route_post::<AddAdmin>)),
|
.route(web::post().to(route_post::<AddAdmin>)),
|
||||||
)
|
|
||||||
// Reports
|
|
||||||
.service(
|
|
||||||
web::scope("/report")
|
|
||||||
.wrap(rate_limit.message())
|
|
||||||
.route("", web::get().to(route_get::<GetReportCount>))
|
|
||||||
.route("",web::post().to(route_post::<CreateReport>))
|
|
||||||
.route("/resolve",web::put().to(route_post::<ResolveReport>))
|
|
||||||
.route("/list", web::get().to(route_get::<ListReports>))
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue