mirror of
https://github.com/LemmyNet/lemmy.git
synced 2025-03-13 15:02:44 +00:00
Add community reports to API (#5435)
* add routes * implement some of api * fix use of check_report_reason * fix create_community_report * fix all compile errors * add field to reportcombined struct * add CommunityReportView::read test * import resolve_community_report * remove references to deleted table * resolve reports after remove
This commit is contained in:
parent
b8de9a518b
commit
08defa29fe
13 changed files with 225 additions and 2 deletions
71
crates/api/src/reports/community_report/create.rs
Normal file
71
crates/api/src/reports/community_report/create.rs
Normal file
|
@ -0,0 +1,71 @@
|
|||
use crate::check_report_reason;
|
||||
use actix_web::web::{Data, Json};
|
||||
use lemmy_api_common::{
|
||||
context::LemmyContext,
|
||||
reports::community::{CommunityReportResponse, CreateCommunityReport},
|
||||
utils::{send_new_report_email_to_admins, slur_regex},
|
||||
};
|
||||
use lemmy_db_schema::{
|
||||
source::{
|
||||
community::Community,
|
||||
community_report::{CommunityReport, CommunityReportForm},
|
||||
local_site::LocalSite,
|
||||
},
|
||||
traits::{Crud, Reportable},
|
||||
};
|
||||
use lemmy_db_views::structs::{CommunityReportView, LocalUserView};
|
||||
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult};
|
||||
|
||||
pub async fn create_community_report(
|
||||
data: Json<CreateCommunityReport>,
|
||||
context: Data<LemmyContext>,
|
||||
local_user_view: LocalUserView,
|
||||
) -> LemmyResult<Json<CommunityReportResponse>> {
|
||||
let reason = data.reason.trim().to_string();
|
||||
let slur_regex = slur_regex(&context).await?;
|
||||
check_report_reason(&reason, &slur_regex)?;
|
||||
|
||||
let person_id = local_user_view.person.id;
|
||||
let community_id = data.community_id;
|
||||
let community = Community::read(&mut context.pool(), community_id).await?;
|
||||
|
||||
let report_form = CommunityReportForm {
|
||||
creator_id: person_id,
|
||||
community_id,
|
||||
original_community_banner: community.banner,
|
||||
original_community_description: community.description,
|
||||
original_community_icon: community.icon,
|
||||
original_community_name: community.name,
|
||||
original_community_sidebar: community.sidebar,
|
||||
original_community_title: community.title,
|
||||
reason,
|
||||
};
|
||||
|
||||
let report = CommunityReport::report(&mut context.pool(), &report_form)
|
||||
.await
|
||||
.with_lemmy_type(LemmyErrorType::CouldntCreateReport)?;
|
||||
|
||||
let community_report_view =
|
||||
CommunityReportView::read(&mut context.pool(), report.id, person_id).await?;
|
||||
|
||||
// Email the admins
|
||||
let local_site = LocalSite::read(&mut context.pool()).await?;
|
||||
if local_site.reports_email_admins {
|
||||
send_new_report_email_to_admins(
|
||||
&community_report_view.creator.name,
|
||||
// The argument here is normally the reported content's creator, but a community doesn't have
|
||||
// a single person to be considered the creator or the person responsible for the bad thing,
|
||||
// so the community name is used instead
|
||||
&community_report_view.community.name,
|
||||
&mut context.pool(),
|
||||
context.settings(),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
// TODO: consider federating this
|
||||
|
||||
Ok(Json(CommunityReportResponse {
|
||||
community_report_view,
|
||||
}))
|
||||
}
|
2
crates/api/src/reports/community_report/mod.rs
Normal file
2
crates/api/src/reports/community_report/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
pub mod create;
|
||||
pub mod resolve;
|
36
crates/api/src/reports/community_report/resolve.rs
Normal file
36
crates/api/src/reports/community_report/resolve.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
use actix_web::web::{Data, Json};
|
||||
use lemmy_api_common::{
|
||||
context::LemmyContext,
|
||||
reports::community::{CommunityReportResponse, ResolveCommunityReport},
|
||||
utils::is_admin,
|
||||
};
|
||||
use lemmy_db_schema::{source::community_report::CommunityReport, traits::Reportable};
|
||||
use lemmy_db_views::structs::{CommunityReportView, LocalUserView};
|
||||
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult};
|
||||
|
||||
pub async fn resolve_community_report(
|
||||
data: Json<ResolveCommunityReport>,
|
||||
context: Data<LemmyContext>,
|
||||
local_user_view: LocalUserView,
|
||||
) -> LemmyResult<Json<CommunityReportResponse>> {
|
||||
is_admin(&local_user_view)?;
|
||||
|
||||
let report_id = data.report_id;
|
||||
let person_id = local_user_view.person.id;
|
||||
if data.resolved {
|
||||
CommunityReport::resolve(&mut context.pool(), report_id, person_id)
|
||||
.await
|
||||
.with_lemmy_type(LemmyErrorType::CouldntResolveReport)?;
|
||||
} else {
|
||||
CommunityReport::unresolve(&mut context.pool(), report_id, person_id)
|
||||
.await
|
||||
.with_lemmy_type(LemmyErrorType::CouldntResolveReport)?;
|
||||
}
|
||||
|
||||
let community_report_view =
|
||||
CommunityReportView::read(&mut context.pool(), report_id, person_id).await?;
|
||||
|
||||
Ok(Json(CommunityReportResponse {
|
||||
community_report_view,
|
||||
}))
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
pub mod comment_report;
|
||||
pub mod community_report;
|
||||
pub mod post_report;
|
||||
pub mod private_message_report;
|
||||
pub mod report_combined;
|
||||
|
|
31
crates/api_common/src/reports/community.rs
Normal file
31
crates/api_common/src/reports/community.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
use lemmy_db_schema::newtypes::{CommunityId, CommunityReportId};
|
||||
use lemmy_db_views::structs::CommunityReportView;
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[cfg(feature = "full")]
|
||||
use ts_rs::TS;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// Create a report for a community.
|
||||
pub struct CreateCommunityReport {
|
||||
pub community_id: CommunityId,
|
||||
pub reason: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// A community report response.
|
||||
pub struct CommunityReportResponse {
|
||||
pub community_report_view: CommunityReportView,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// Resolve a community report.
|
||||
pub struct ResolveCommunityReport {
|
||||
pub report_id: CommunityReportId,
|
||||
pub resolved: bool,
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
pub mod combined;
|
||||
pub mod comment;
|
||||
pub mod community;
|
||||
pub mod post;
|
||||
pub mod private_message;
|
||||
|
|
|
@ -10,9 +10,10 @@ use lemmy_api_common::{
|
|||
use lemmy_db_schema::{
|
||||
source::{
|
||||
community::{Community, CommunityUpdateForm},
|
||||
community_report::CommunityReport,
|
||||
mod_log::moderator::{ModRemoveCommunity, ModRemoveCommunityForm},
|
||||
},
|
||||
traits::Crud,
|
||||
traits::{Crud, Reportable},
|
||||
};
|
||||
use lemmy_db_views::structs::LocalUserView;
|
||||
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult};
|
||||
|
@ -48,6 +49,13 @@ pub async fn remove_community(
|
|||
.await
|
||||
.with_lemmy_type(LemmyErrorType::CouldntUpdateCommunity)?;
|
||||
|
||||
CommunityReport::resolve_all_for_object(
|
||||
&mut context.pool(),
|
||||
community_id,
|
||||
local_user_view.person.id,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Mod tables
|
||||
let form = ModRemoveCommunityForm {
|
||||
mod_person_id: local_user_view.person.id,
|
||||
|
|
|
@ -14,6 +14,7 @@ use lemmy_db_schema::{
|
|||
comment::{Comment, CommentUpdateForm},
|
||||
comment_report::CommentReport,
|
||||
community::{Community, CommunityUpdateForm},
|
||||
community_report::CommunityReport,
|
||||
mod_log::moderator::{
|
||||
ModRemoveComment,
|
||||
ModRemoveCommentForm,
|
||||
|
@ -116,6 +117,7 @@ pub(in crate::activities) async fn receive_remove_action(
|
|||
if community.local {
|
||||
Err(FederationError::OnlyLocalAdminCanRemoveCommunity)?
|
||||
}
|
||||
CommunityReport::resolve_all_for_object(&mut context.pool(), community.id, actor.id).await?;
|
||||
let form = ModRemoveCommunityForm {
|
||||
mod_person_id: actor.id,
|
||||
community_id: community.id,
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
use crate::newtypes::{CommentReportId, PostReportId, PrivateMessageReportId, ReportCombinedId};
|
||||
use crate::newtypes::{
|
||||
CommentReportId,
|
||||
CommunityReportId,
|
||||
PostReportId,
|
||||
PrivateMessageReportId,
|
||||
ReportCombinedId,
|
||||
};
|
||||
#[cfg(feature = "full")]
|
||||
use crate::schema::report_combined;
|
||||
use chrono::{DateTime, Utc};
|
||||
|
@ -20,4 +26,5 @@ pub struct ReportCombined {
|
|||
pub post_report_id: Option<PostReportId>,
|
||||
pub comment_report_id: Option<CommentReportId>,
|
||||
pub private_message_report_id: Option<PrivateMessageReportId>,
|
||||
pub community_report_id: Option<CommunityReportId>,
|
||||
}
|
||||
|
|
|
@ -511,6 +511,7 @@ mod tests {
|
|||
combined::report_combined_view::ReportCombinedQuery,
|
||||
structs::{
|
||||
CommentReportView,
|
||||
CommunityReportView,
|
||||
LocalUserView,
|
||||
PostReportView,
|
||||
ReportCombinedView,
|
||||
|
@ -1160,6 +1161,9 @@ mod tests {
|
|||
assert_eq!(community_report.reason, v.community_report.reason);
|
||||
assert_eq!(data.community.name, v.community.name);
|
||||
assert_eq!(data.community.title, v.community.title);
|
||||
let read_report =
|
||||
CommunityReportView::read(pool, community_report.id, data.admin_view.person.id).await?;
|
||||
assert_eq!(&read_report, v);
|
||||
} else {
|
||||
panic!("wrong type");
|
||||
}
|
||||
|
|
55
crates/db_views/src/reports/community_report_view.rs
Normal file
55
crates/db_views/src/reports/community_report_view.rs
Normal file
|
@ -0,0 +1,55 @@
|
|||
use crate::structs::CommunityReportView;
|
||||
use diesel::{
|
||||
result::Error,
|
||||
BoolExpressionMethods,
|
||||
ExpressionMethods,
|
||||
JoinOnDsl,
|
||||
NullableExpressionMethods,
|
||||
QueryDsl,
|
||||
};
|
||||
use diesel_async::RunQueryDsl;
|
||||
use lemmy_db_schema::{
|
||||
aliases,
|
||||
impls::community::community_follower_select_subscribed_type,
|
||||
newtypes::{CommunityReportId, PersonId},
|
||||
schema::{community, community_actions, community_report, person},
|
||||
utils::{get_conn, DbPool},
|
||||
};
|
||||
|
||||
impl CommunityReportView {
|
||||
/// returns the CommunityReportView for the provided report_id
|
||||
///
|
||||
/// * `report_id` - the report id to obtain
|
||||
pub async fn read(
|
||||
pool: &mut DbPool<'_>,
|
||||
report_id: CommunityReportId,
|
||||
my_person_id: PersonId,
|
||||
) -> Result<Self, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
|
||||
let community_actions_join = community_actions::table.on(
|
||||
community_actions::community_id
|
||||
.eq(community_report::community_id)
|
||||
.and(community_actions::person_id.eq(my_person_id)),
|
||||
);
|
||||
|
||||
community_report::table
|
||||
.find(report_id)
|
||||
.inner_join(community::table)
|
||||
.inner_join(person::table.on(community_report::creator_id.eq(person::id)))
|
||||
.left_join(
|
||||
aliases::person2
|
||||
.on(community_report::resolver_id.eq(aliases::person2.field(person::id).nullable())),
|
||||
)
|
||||
.left_join(community_actions_join)
|
||||
.select((
|
||||
community_report::all_columns,
|
||||
community::all_columns,
|
||||
person::all_columns,
|
||||
community_follower_select_subscribed_type(),
|
||||
aliases::person2.fields(person::all_columns.nullable()),
|
||||
))
|
||||
.first(conn)
|
||||
.await
|
||||
}
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
#[cfg(feature = "full")]
|
||||
pub mod comment_report_view;
|
||||
#[cfg(feature = "full")]
|
||||
pub mod community_report_view;
|
||||
#[cfg(feature = "full")]
|
||||
pub mod post_report_view;
|
||||
#[cfg(feature = "full")]
|
||||
pub mod private_message_report_view;
|
||||
|
|
|
@ -66,6 +66,7 @@ use lemmy_api::{
|
|||
private_message::mark_read::mark_pm_as_read,
|
||||
reports::{
|
||||
comment_report::{create::create_comment_report, resolve::resolve_comment_report},
|
||||
community_report::{create::create_community_report, resolve::resolve_community_report},
|
||||
post_report::{create::create_post_report, resolve::resolve_post_report},
|
||||
private_message_report::{create::create_pm_report, resolve::resolve_pm_report},
|
||||
report_combined::list::list_reports,
|
||||
|
@ -217,6 +218,8 @@ pub fn config(cfg: &mut ServiceConfig, rate_limit: &RateLimitCell) {
|
|||
.route("/hide", put().to(hide_community))
|
||||
.route("/list", get().to(list_communities))
|
||||
.route("/follow", post().to(follow_community))
|
||||
.route("/report", post().to(create_community_report))
|
||||
.route("/report/resolve", put().to(resolve_community_report))
|
||||
.route("/delete", post().to(delete_community))
|
||||
// Mod Actions
|
||||
.route("/remove", post().to(remove_community))
|
||||
|
|
Loading…
Reference in a new issue