From 37998b3398ed925a7640a9b67d1dc6ef871893a9 Mon Sep 17 00:00:00 2001 From: Nutomic Date: Fri, 28 Jul 2023 16:39:38 +0200 Subject: [PATCH] Rewrite some API handlers to remove Perform trait (#3735) * Rewrite some API handlers to remove Perform trait * Convert CreateComment * ci --- Cargo.lock | 1 + crates/api/Cargo.toml | 1 + crates/api/src/comment/distinguish.rs | 92 +++--- crates/api/src/comment/mod.rs | 6 +- crates/api/src/comment/save.rs | 60 ++-- crates/api/src/comment_report/list.rs | 47 ++- crates/api/src/comment_report/mod.rs | 6 +- crates/api/src/comment_report/resolve.rs | 61 ++-- crates/api/src/lib.rs | 18 +- crates/api/src/local_user/mod.rs | 26 +- .../notifications/mark_reply_read.rs | 59 ++-- .../api/src/local_user/notifications/mod.rs | 12 +- crates/api_common/src/build_response.rs | 2 +- crates/api_common/src/send_activity.rs | 3 +- crates/api_crud/src/comment/create.rs | 300 +++++++++--------- crates/api_crud/src/comment/delete.rs | 3 +- crates/api_crud/src/comment/mod.rs | 10 +- crates/api_crud/src/comment/read.rs | 27 +- crates/api_crud/src/comment/remove.rs | 3 +- crates/api_crud/src/comment/update.rs | 3 +- crates/api_crud/src/community/list.rs | 67 ++-- crates/api_crud/src/community/mod.rs | 10 +- crates/api_crud/src/lib.rs | 12 +- crates/api_crud/src/post/mod.rs | 8 +- crates/api_crud/src/post/read.rs | 179 +++++------ crates/api_crud/src/private_message/mod.rs | 8 +- crates/api_crud/src/private_message/read.rs | 61 ++-- crates/api_crud/src/site/create.rs | 208 ++++++------ crates/api_crud/src/site/mod.rs | 6 +- crates/api_crud/src/site/read.rs | 135 ++++---- crates/api_crud/src/site/update.rs | 264 ++++++++------- .../activities/create_or_update/comment.rs | 37 +-- crates/apub/src/activities/mod.rs | 25 +- crates/apub/src/api/read_community.rs | 2 +- crates/utils/translations | 2 +- src/api_routes_http.rs | 95 ++---- 36 files changed, 877 insertions(+), 982 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6ac601c0..bac96d5e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2573,6 +2573,7 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" name = "lemmy_api" version = "0.18.1" dependencies = [ + "activitypub_federation", "actix-web", "anyhow", "async-trait", diff --git a/crates/api/Cargo.toml b/crates/api/Cargo.toml index be3065e4..17f40d57 100644 --- a/crates/api/Cargo.toml +++ b/crates/api/Cargo.toml @@ -20,6 +20,7 @@ lemmy_db_views = { workspace = true, features = ["full"] } lemmy_db_views_moderator = { workspace = true, features = ["full"] } lemmy_db_views_actor = { workspace = true, features = ["full"] } lemmy_api_common = { workspace = true, features = ["full"] } +activitypub_federation = { workspace = true } bcrypt = { workspace = true } serde = { workspace = true } actix-web = { workspace = true } diff --git a/crates/api/src/comment/distinguish.rs b/crates/api/src/comment/distinguish.rs index 47c23d3d..540c19a3 100644 --- a/crates/api/src/comment/distinguish.rs +++ b/crates/api/src/comment/distinguish.rs @@ -1,5 +1,4 @@ -use crate::Perform; -use actix_web::web::Data; +use actix_web::web::{Data, Json}; use lemmy_api_common::{ comment::{CommentResponse, DistinguishComment}, context::LemmyContext, @@ -12,50 +11,47 @@ use lemmy_db_schema::{ use lemmy_db_views::structs::CommentView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; -#[async_trait::async_trait(?Send)] -impl Perform for DistinguishComment { - type Response = CommentResponse; - - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data: &DistinguishComment = self; - let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; - - let comment_id = data.comment_id; - let orig_comment = CommentView::read(&mut context.pool(), comment_id, None).await?; - - check_community_ban( - local_user_view.person.id, - orig_comment.community.id, - &mut context.pool(), - ) - .await?; - - // Verify that only a mod or admin can distinguish a comment - is_mod_or_admin( - &mut context.pool(), - local_user_view.person.id, - orig_comment.community.id, - ) - .await?; - - // Update the Comment - let comment_id = data.comment_id; - let form = CommentUpdateForm::builder() - .distinguished(Some(data.distinguished)) - .build(); - Comment::update(&mut context.pool(), comment_id, &form) - .await - .with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?; - - let comment_id = data.comment_id; - let person_id = local_user_view.person.id; - let comment_view = CommentView::read(&mut context.pool(), comment_id, Some(person_id)).await?; - - Ok(CommentResponse { - comment_view, - recipient_ids: Vec::new(), - form_id: None, - }) - } +#[tracing::instrument(skip(context))] +pub async fn distinguish_comment( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; + + let comment_id = data.comment_id; + let orig_comment = CommentView::read(&mut context.pool(), comment_id, None).await?; + + check_community_ban( + local_user_view.person.id, + orig_comment.community.id, + &mut context.pool(), + ) + .await?; + + // Verify that only a mod or admin can distinguish a comment + is_mod_or_admin( + &mut context.pool(), + local_user_view.person.id, + orig_comment.community.id, + ) + .await?; + + // Update the Comment + let comment_id = data.comment_id; + let form = CommentUpdateForm::builder() + .distinguished(Some(data.distinguished)) + .build(); + Comment::update(&mut context.pool(), comment_id, &form) + .await + .with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?; + + let comment_id = data.comment_id; + let person_id = local_user_view.person.id; + let comment_view = CommentView::read(&mut context.pool(), comment_id, Some(person_id)).await?; + + Ok(Json(CommentResponse { + comment_view, + recipient_ids: Vec::new(), + form_id: None, + })) } diff --git a/crates/api/src/comment/mod.rs b/crates/api/src/comment/mod.rs index 27584c36..8caeaf8b 100644 --- a/crates/api/src/comment/mod.rs +++ b/crates/api/src/comment/mod.rs @@ -1,3 +1,3 @@ -mod distinguish; -mod like; -mod save; +pub mod distinguish; +pub mod like; +pub mod save; diff --git a/crates/api/src/comment/save.rs b/crates/api/src/comment/save.rs index 7161c8e9..8c9d9055 100644 --- a/crates/api/src/comment/save.rs +++ b/crates/api/src/comment/save.rs @@ -1,5 +1,4 @@ -use crate::Perform; -use actix_web::web::Data; +use actix_web::web::{Data, Json}; use lemmy_api_common::{ comment::{CommentResponse, SaveComment}, context::LemmyContext, @@ -12,38 +11,35 @@ use lemmy_db_schema::{ use lemmy_db_views::structs::CommentView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; -#[async_trait::async_trait(?Send)] -impl Perform for SaveComment { - type Response = CommentResponse; +#[tracing::instrument(skip(context))] +pub async fn save_comment( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data: &SaveComment = self; - let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; + let comment_saved_form = CommentSavedForm { + comment_id: data.comment_id, + person_id: local_user_view.person.id, + }; - let comment_saved_form = CommentSavedForm { - comment_id: data.comment_id, - person_id: local_user_view.person.id, - }; - - if data.save { - CommentSaved::save(&mut context.pool(), &comment_saved_form) - .await - .with_lemmy_type(LemmyErrorType::CouldntSaveComment)?; - } else { - CommentSaved::unsave(&mut context.pool(), &comment_saved_form) - .await - .with_lemmy_type(LemmyErrorType::CouldntSaveComment)?; - } + if data.save { + CommentSaved::save(&mut context.pool(), &comment_saved_form) + .await + .with_lemmy_type(LemmyErrorType::CouldntSaveComment)?; + } else { + CommentSaved::unsave(&mut context.pool(), &comment_saved_form) + .await + .with_lemmy_type(LemmyErrorType::CouldntSaveComment)?; + } - let comment_id = data.comment_id; - let person_id = local_user_view.person.id; - let comment_view = CommentView::read(&mut context.pool(), comment_id, Some(person_id)).await?; + let comment_id = data.comment_id; + let person_id = local_user_view.person.id; + let comment_view = CommentView::read(&mut context.pool(), comment_id, Some(person_id)).await?; - Ok(CommentResponse { - comment_view, - recipient_ids: Vec::new(), - form_id: None, - }) - } + Ok(Json(CommentResponse { + comment_view, + recipient_ids: Vec::new(), + form_id: None, + })) } diff --git a/crates/api/src/comment_report/list.rs b/crates/api/src/comment_report/list.rs index b67ec333..0ca093c7 100644 --- a/crates/api/src/comment_report/list.rs +++ b/crates/api/src/comment_report/list.rs @@ -1,5 +1,4 @@ -use crate::Perform; -use actix_web::web::Data; +use actix_web::web::{Data, Json, Query}; use lemmy_api_common::{ comment::{ListCommentReports, ListCommentReportsResponse}, context::LemmyContext, @@ -10,32 +9,26 @@ use lemmy_utils::error::LemmyError; /// 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)] -impl Perform for ListCommentReports { - type Response = ListCommentReportsResponse; +#[tracing::instrument(skip(context))] +pub async fn list_comment_reports( + data: Query, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - #[tracing::instrument(skip(context))] - async fn perform( - &self, - context: &Data, - ) -> Result { - let data: &ListCommentReports = self; - let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; + let community_id = data.community_id; + let unresolved_only = data.unresolved_only; - let community_id = data.community_id; - let unresolved_only = data.unresolved_only; - - let page = data.page; - let limit = data.limit; - let comment_reports = CommentReportQuery { - community_id, - unresolved_only, - page, - limit, - } - .list(&mut context.pool(), &local_user_view.person) - .await?; - - Ok(ListCommentReportsResponse { comment_reports }) + let page = data.page; + let limit = data.limit; + let comment_reports = CommentReportQuery { + community_id, + unresolved_only, + page, + limit, } + .list(&mut context.pool(), &local_user_view.person) + .await?; + + Ok(Json(ListCommentReportsResponse { comment_reports })) } diff --git a/crates/api/src/comment_report/mod.rs b/crates/api/src/comment_report/mod.rs index 375fde4c..3bb1a9b4 100644 --- a/crates/api/src/comment_report/mod.rs +++ b/crates/api/src/comment_report/mod.rs @@ -1,3 +1,3 @@ -mod create; -mod list; -mod resolve; +pub mod create; +pub mod list; +pub mod resolve; diff --git a/crates/api/src/comment_report/resolve.rs b/crates/api/src/comment_report/resolve.rs index 11149527..8e03484e 100644 --- a/crates/api/src/comment_report/resolve.rs +++ b/crates/api/src/comment_report/resolve.rs @@ -1,5 +1,4 @@ -use crate::Perform; -use actix_web::web::Data; +use actix_web::web::{Data, Json}; use lemmy_api_common::{ comment::{CommentReportResponse, ResolveCommentReport}, context::LemmyContext, @@ -10,41 +9,35 @@ use lemmy_db_views::structs::CommentReportView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; /// Resolves or unresolves a comment report and notifies the moderators of the community -#[async_trait::async_trait(?Send)] -impl Perform for ResolveCommentReport { - type Response = CommentReportResponse; +#[tracing::instrument(skip(context))] +pub async fn resolve_comment_report( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - #[tracing::instrument(skip(context))] - async fn perform( - &self, - context: &Data, - ) -> Result { - let data: &ResolveCommentReport = self; - let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; + let report_id = data.report_id; + let person_id = local_user_view.person.id; + let report = CommentReportView::read(&mut context.pool(), report_id, person_id).await?; - let report_id = data.report_id; - let person_id = local_user_view.person.id; - let report = CommentReportView::read(&mut context.pool(), report_id, person_id).await?; + let person_id = local_user_view.person.id; + is_mod_or_admin(&mut context.pool(), person_id, report.community.id).await?; - let person_id = local_user_view.person.id; - is_mod_or_admin(&mut context.pool(), person_id, report.community.id).await?; - - if data.resolved { - CommentReport::resolve(&mut context.pool(), report_id, person_id) - .await - .with_lemmy_type(LemmyErrorType::CouldntResolveReport)?; - } else { - CommentReport::unresolve(&mut context.pool(), report_id, person_id) - .await - .with_lemmy_type(LemmyErrorType::CouldntResolveReport)?; - } + if data.resolved { + CommentReport::resolve(&mut context.pool(), report_id, person_id) + .await + .with_lemmy_type(LemmyErrorType::CouldntResolveReport)?; + } else { + CommentReport::unresolve(&mut context.pool(), report_id, person_id) + .await + .with_lemmy_type(LemmyErrorType::CouldntResolveReport)?; + } - let report_id = data.report_id; - let comment_report_view = - CommentReportView::read(&mut context.pool(), report_id, person_id).await?; + let report_id = data.report_id; + let comment_report_view = + CommentReportView::read(&mut context.pool(), report_id, person_id).await?; - Ok(CommentReportResponse { - comment_report_view, - }) - } + Ok(Json(CommentReportResponse { + comment_report_view, + })) } diff --git a/crates/api/src/lib.rs b/crates/api/src/lib.rs index b297f503..cc5fb8e8 100644 --- a/crates/api/src/lib.rs +++ b/crates/api/src/lib.rs @@ -9,15 +9,15 @@ use lemmy_utils::{ }; use std::io::Cursor; -mod comment; -mod comment_report; -mod community; -mod local_user; -mod post; -mod post_report; -mod private_message; -mod private_message_report; -mod site; +pub mod comment; +pub mod comment_report; +pub mod community; +pub mod local_user; +pub mod post; +pub mod post_report; +pub mod private_message; +pub mod private_message_report; +pub mod site; #[async_trait::async_trait(?Send)] pub trait Perform { diff --git a/crates/api/src/local_user/mod.rs b/crates/api/src/local_user/mod.rs index 3a92beda..806fa66a 100644 --- a/crates/api/src/local_user/mod.rs +++ b/crates/api/src/local_user/mod.rs @@ -1,13 +1,13 @@ -mod add_admin; -mod ban_person; -mod block; -mod change_password; -mod change_password_after_reset; -mod get_captcha; -mod list_banned; -mod login; -mod notifications; -mod report_count; -mod reset_password; -mod save_settings; -mod verify_email; +pub mod add_admin; +pub mod ban_person; +pub mod block; +pub mod change_password; +pub mod change_password_after_reset; +pub mod get_captcha; +pub mod list_banned; +pub mod login; +pub mod notifications; +pub mod report_count; +pub mod reset_password; +pub mod save_settings; +pub mod verify_email; diff --git a/crates/api/src/local_user/notifications/mark_reply_read.rs b/crates/api/src/local_user/notifications/mark_reply_read.rs index 4071a466..9ae9f525 100644 --- a/crates/api/src/local_user/notifications/mark_reply_read.rs +++ b/crates/api/src/local_user/notifications/mark_reply_read.rs @@ -1,5 +1,4 @@ -use crate::Perform; -use actix_web::web::Data; +use actix_web::web::{Data, Json}; use lemmy_api_common::{ context::LemmyContext, person::{CommentReplyResponse, MarkCommentReplyAsRead}, @@ -12,41 +11,35 @@ use lemmy_db_schema::{ use lemmy_db_views_actor::structs::CommentReplyView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; -#[async_trait::async_trait(?Send)] -impl Perform for MarkCommentReplyAsRead { - type Response = CommentReplyResponse; +#[tracing::instrument(skip(context))] +pub async fn mark_reply_as_read( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - #[tracing::instrument(skip(context))] - async fn perform( - &self, - context: &Data, - ) -> Result { - let data = self; - let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; + let comment_reply_id = data.comment_reply_id; + let read_comment_reply = CommentReply::read(&mut context.pool(), comment_reply_id).await?; - let comment_reply_id = data.comment_reply_id; - let read_comment_reply = CommentReply::read(&mut context.pool(), comment_reply_id).await?; - - if local_user_view.person.id != read_comment_reply.recipient_id { - return Err(LemmyErrorType::CouldntUpdateComment)?; - } + if local_user_view.person.id != read_comment_reply.recipient_id { + return Err(LemmyErrorType::CouldntUpdateComment)?; + } - let comment_reply_id = read_comment_reply.id; - let read = Some(data.read); + let comment_reply_id = read_comment_reply.id; + let read = Some(data.read); - CommentReply::update( - &mut context.pool(), - comment_reply_id, - &CommentReplyUpdateForm { read }, - ) - .await - .with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?; + CommentReply::update( + &mut context.pool(), + comment_reply_id, + &CommentReplyUpdateForm { read }, + ) + .await + .with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?; - let comment_reply_id = read_comment_reply.id; - let person_id = local_user_view.person.id; - let comment_reply_view = - CommentReplyView::read(&mut context.pool(), comment_reply_id, Some(person_id)).await?; + let comment_reply_id = read_comment_reply.id; + let person_id = local_user_view.person.id; + let comment_reply_view = + CommentReplyView::read(&mut context.pool(), comment_reply_id, Some(person_id)).await?; - Ok(CommentReplyResponse { comment_reply_view }) - } + Ok(Json(CommentReplyResponse { comment_reply_view })) } diff --git a/crates/api/src/local_user/notifications/mod.rs b/crates/api/src/local_user/notifications/mod.rs index ab98053f..35567afd 100644 --- a/crates/api/src/local_user/notifications/mod.rs +++ b/crates/api/src/local_user/notifications/mod.rs @@ -1,6 +1,6 @@ -mod list_mentions; -mod list_replies; -mod mark_all_read; -mod mark_mention_read; -mod mark_reply_read; -mod unread_count; +pub mod list_mentions; +pub mod list_replies; +pub mod mark_all_read; +pub mod mark_mention_read; +pub mod mark_reply_read; +pub mod unread_count; diff --git a/crates/api_common/src/build_response.rs b/crates/api_common/src/build_response.rs index 8a63f7ad..b8c02457 100644 --- a/crates/api_common/src/build_response.rs +++ b/crates/api_common/src/build_response.rs @@ -23,7 +23,7 @@ use lemmy_db_views_actor::structs::CommunityView; use lemmy_utils::{error::LemmyError, utils::mention::MentionData}; pub async fn build_comment_response( - context: &Data, + context: &LemmyContext, comment_id: CommentId, local_user_view: Option, form_id: Option, diff --git a/crates/api_common/src/send_activity.rs b/crates/api_common/src/send_activity.rs index 6c91258e..994aea2a 100644 --- a/crates/api_common/src/send_activity.rs +++ b/crates/api_common/src/send_activity.rs @@ -1,7 +1,7 @@ use crate::context::LemmyContext; use activitypub_federation::config::Data; use futures::future::BoxFuture; -use lemmy_db_schema::source::post::Post; +use lemmy_db_schema::source::{comment::Comment, post::Post}; use lemmy_utils::{error::LemmyResult, SYNCHRONOUS_FEDERATION}; use once_cell::sync::{Lazy, OnceCell}; use tokio::{ @@ -22,6 +22,7 @@ pub static MATCH_OUTGOING_ACTIVITIES: OnceCell = O #[derive(Debug)] pub enum SendActivityData { CreatePost(Post), + CreateComment(Comment), } // TODO: instead of static, move this into LemmyContext. make sure that stopping the process with diff --git a/crates/api_crud/src/comment/create.rs b/crates/api_crud/src/comment/create.rs index 4a7513a4..f334efe5 100644 --- a/crates/api_crud/src/comment/create.rs +++ b/crates/api_crud/src/comment/create.rs @@ -1,9 +1,10 @@ -use crate::PerformCrud; -use actix_web::web::Data; +use activitypub_federation::config::Data; +use actix_web::web::Json; use lemmy_api_common::{ build_response::{build_comment_response, send_local_notifs}, comment::{CommentResponse, CreateComment}, context::LemmyContext, + send_activity::{ActivityChannel, SendActivityData}, utils::{ check_community_ban, check_community_deleted_or_removed, @@ -35,169 +36,174 @@ use lemmy_utils::{ validation::is_valid_body_field, }, }; +use std::ops::Deref; const MAX_COMMENT_DEPTH_LIMIT: usize = 100; -#[async_trait::async_trait(?Send)] -impl PerformCrud for CreateComment { - type Response = CommentResponse; - - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data: &CreateComment = self; - let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; - let local_site = LocalSite::read(&mut context.pool()).await?; - - let content = remove_slurs( - &data.content.clone(), - &local_site_to_slur_regex(&local_site), - ); - is_valid_body_field(&Some(content.clone()), false)?; - let content = sanitize_html(&content); - - // Check for a community ban - let post_id = data.post_id; - let post = get_post(post_id, &mut context.pool()).await?; - let community_id = post.community_id; - - check_community_ban(local_user_view.person.id, community_id, &mut context.pool()).await?; - check_community_deleted_or_removed(community_id, &mut context.pool()).await?; - check_post_deleted_or_removed(&post)?; - - // Check if post is locked, no new comments - if post.locked { - return Err(LemmyErrorType::Locked)?; - } +#[tracing::instrument(skip(context))] +pub async fn create_comment( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; + let local_site = LocalSite::read(&mut context.pool()).await?; + + let content = remove_slurs( + &data.content.clone(), + &local_site_to_slur_regex(&local_site), + ); + is_valid_body_field(&Some(content.clone()), false)?; + let content = sanitize_html(&content); + + // Check for a community ban + let post_id = data.post_id; + let post = get_post(post_id, &mut context.pool()).await?; + let community_id = post.community_id; + + check_community_ban(local_user_view.person.id, community_id, &mut context.pool()).await?; + check_community_deleted_or_removed(community_id, &mut context.pool()).await?; + check_post_deleted_or_removed(&post)?; + + // Check if post is locked, no new comments + if post.locked { + return Err(LemmyErrorType::Locked)?; + } - // Fetch the parent, if it exists - let parent_opt = if let Some(parent_id) = data.parent_id { - Comment::read(&mut context.pool(), parent_id).await.ok() - } else { - None - }; - - // If there's a parent_id, check to make sure that comment is in that post - // Strange issue where sometimes the post ID of the parent comment is incorrect - if let Some(parent) = parent_opt.as_ref() { - if parent.post_id != post_id { - return Err(LemmyErrorType::CouldntCreateComment)?; - } - check_comment_depth(parent)?; + // Fetch the parent, if it exists + let parent_opt = if let Some(parent_id) = data.parent_id { + Comment::read(&mut context.pool(), parent_id).await.ok() + } else { + None + }; + + // If there's a parent_id, check to make sure that comment is in that post + // Strange issue where sometimes the post ID of the parent comment is incorrect + if let Some(parent) = parent_opt.as_ref() { + if parent.post_id != post_id { + return Err(LemmyErrorType::CouldntCreateComment)?; } + check_comment_depth(parent)?; + } - CommunityLanguage::is_allowed_community_language( - &mut context.pool(), - data.language_id, - community_id, - ) - .await?; - - // attempt to set default language if none was provided - let language_id = match data.language_id { - Some(lid) => Some(lid), - None => { - default_post_language( - &mut context.pool(), - community_id, - local_user_view.local_user.id, - ) - .await? - } - }; - - let comment_form = CommentInsertForm::builder() - .content(content.clone()) - .post_id(data.post_id) - .creator_id(local_user_view.person.id) - .language_id(language_id) - .build(); - - // Create the comment - let parent_path = parent_opt.clone().map(|t| t.path); - let inserted_comment = - Comment::create(&mut context.pool(), &comment_form, parent_path.as_ref()) - .await - .with_lemmy_type(LemmyErrorType::CouldntCreateComment)?; - - // Necessary to update the ap_id - let inserted_comment_id = inserted_comment.id; - let protocol_and_hostname = context.settings().get_protocol_and_hostname(); - - let apub_id = generate_local_apub_endpoint( - EndpointType::Comment, - &inserted_comment_id.to_string(), - &protocol_and_hostname, - )?; - let updated_comment = Comment::update( - &mut context.pool(), - inserted_comment_id, - &CommentUpdateForm::builder().ap_id(Some(apub_id)).build(), - ) + CommunityLanguage::is_allowed_community_language( + &mut context.pool(), + data.language_id, + community_id, + ) + .await?; + + // attempt to set default language if none was provided + let language_id = match data.language_id { + Some(lid) => Some(lid), + None => { + default_post_language( + &mut context.pool(), + community_id, + local_user_view.local_user.id, + ) + .await? + } + }; + + let comment_form = CommentInsertForm::builder() + .content(content.clone()) + .post_id(data.post_id) + .creator_id(local_user_view.person.id) + .language_id(language_id) + .build(); + + // Create the comment + let parent_path = parent_opt.clone().map(|t| t.path); + let inserted_comment = Comment::create(&mut context.pool(), &comment_form, parent_path.as_ref()) .await .with_lemmy_type(LemmyErrorType::CouldntCreateComment)?; - // Scan the comment for user mentions, add those rows - let mentions = scrape_text_for_mentions(&content); - let recipient_ids = send_local_notifs( - mentions, - &updated_comment, - &local_user_view.person, - &post, - true, - context, - ) - .await?; - - // You like your own comment by default - let like_form = CommentLikeForm { - comment_id: inserted_comment.id, - post_id: post.id, - person_id: local_user_view.person.id, - score: 1, - }; + // Necessary to update the ap_id + let inserted_comment_id = inserted_comment.id; + let protocol_and_hostname = context.settings().get_protocol_and_hostname(); + + let apub_id = generate_local_apub_endpoint( + EndpointType::Comment, + &inserted_comment_id.to_string(), + &protocol_and_hostname, + )?; + let updated_comment = Comment::update( + &mut context.pool(), + inserted_comment_id, + &CommentUpdateForm::builder().ap_id(Some(apub_id)).build(), + ) + .await + .with_lemmy_type(LemmyErrorType::CouldntCreateComment)?; + + // Scan the comment for user mentions, add those rows + let mentions = scrape_text_for_mentions(&content); + let recipient_ids = send_local_notifs( + mentions, + &updated_comment, + &local_user_view.person, + &post, + true, + &context, + ) + .await?; + + // You like your own comment by default + let like_form = CommentLikeForm { + comment_id: inserted_comment.id, + post_id: post.id, + person_id: local_user_view.person.id, + score: 1, + }; + + CommentLike::like(&mut context.pool(), &like_form) + .await + .with_lemmy_type(LemmyErrorType::CouldntLikeComment)?; + + ActivityChannel::submit_activity( + SendActivityData::CreateComment(updated_comment.clone()), + &context, + ) + .await?; + + // If its a reply, mark the parent as read + if let Some(parent) = parent_opt { + let parent_id = parent.id; + let comment_reply = CommentReply::read_by_comment(&mut context.pool(), parent_id).await; + if let Ok(reply) = comment_reply { + CommentReply::update( + &mut context.pool(), + reply.id, + &CommentReplyUpdateForm { read: Some(true) }, + ) + .await + .with_lemmy_type(LemmyErrorType::CouldntUpdateReplies)?; + } - CommentLike::like(&mut context.pool(), &like_form) + // If the parent has PersonMentions mark them as read too + let person_id = local_user_view.person.id; + let person_mention = + PersonMention::read_by_comment_and_person(&mut context.pool(), parent_id, person_id).await; + if let Ok(mention) = person_mention { + PersonMention::update( + &mut context.pool(), + mention.id, + &PersonMentionUpdateForm { read: Some(true) }, + ) .await - .with_lemmy_type(LemmyErrorType::CouldntLikeComment)?; - - // If its a reply, mark the parent as read - if let Some(parent) = parent_opt { - let parent_id = parent.id; - let comment_reply = CommentReply::read_by_comment(&mut context.pool(), parent_id).await; - if let Ok(reply) = comment_reply { - CommentReply::update( - &mut context.pool(), - reply.id, - &CommentReplyUpdateForm { read: Some(true) }, - ) - .await - .with_lemmy_type(LemmyErrorType::CouldntUpdateReplies)?; - } - - // If the parent has PersonMentions mark them as read too - let person_id = local_user_view.person.id; - let person_mention = - PersonMention::read_by_comment_and_person(&mut context.pool(), parent_id, person_id).await; - if let Ok(mention) = person_mention { - PersonMention::update( - &mut context.pool(), - mention.id, - &PersonMentionUpdateForm { read: Some(true) }, - ) - .await - .with_lemmy_type(LemmyErrorType::CouldntUpdatePersonMentions)?; - } + .with_lemmy_type(LemmyErrorType::CouldntUpdatePersonMentions)?; } + } + Ok(Json( build_comment_response( - context, + context.deref(), inserted_comment.id, Some(local_user_view), - self.form_id.clone(), + data.form_id.clone(), recipient_ids, ) - .await - } + .await?, + )) } pub fn check_comment_depth(comment: &Comment) -> Result<(), LemmyError> { diff --git a/crates/api_crud/src/comment/delete.rs b/crates/api_crud/src/comment/delete.rs index c42924de..eba7d1de 100644 --- a/crates/api_crud/src/comment/delete.rs +++ b/crates/api_crud/src/comment/delete.rs @@ -15,6 +15,7 @@ use lemmy_db_schema::{ }; use lemmy_db_views::structs::CommentView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use std::ops::Deref; #[async_trait::async_trait(?Send)] impl PerformCrud for DeleteComment { @@ -68,7 +69,7 @@ impl PerformCrud for DeleteComment { .await?; build_comment_response( - context, + context.deref(), updated_comment.id, Some(local_user_view), None, diff --git a/crates/api_crud/src/comment/mod.rs b/crates/api_crud/src/comment/mod.rs index d3d789a0..8bb842b7 100644 --- a/crates/api_crud/src/comment/mod.rs +++ b/crates/api_crud/src/comment/mod.rs @@ -1,5 +1,5 @@ -mod create; -mod delete; -mod read; -mod remove; -mod update; +pub mod create; +pub mod delete; +pub mod read; +pub mod remove; +pub mod update; diff --git a/crates/api_crud/src/comment/read.rs b/crates/api_crud/src/comment/read.rs index e6899fdc..1a794dc5 100644 --- a/crates/api_crud/src/comment/read.rs +++ b/crates/api_crud/src/comment/read.rs @@ -1,5 +1,4 @@ -use crate::PerformCrud; -use actix_web::web::Data; +use actix_web::web::{Data, Json, Query}; use lemmy_api_common::{ build_response::build_comment_response, comment::{CommentResponse, GetComment}, @@ -8,19 +7,19 @@ use lemmy_api_common::{ }; use lemmy_db_schema::source::local_site::LocalSite; use lemmy_utils::error::LemmyError; +use std::ops::Deref; -#[async_trait::async_trait(?Send)] -impl PerformCrud for GetComment { - type Response = CommentResponse; +#[tracing::instrument(skip(context))] +pub async fn get_comment( + data: Query, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt_opt(data.auth.as_ref(), &context).await; + let local_site = LocalSite::read(&mut context.pool()).await?; - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data = self; - let local_user_view = local_user_view_from_jwt_opt(data.auth.as_ref(), context).await; - let local_site = LocalSite::read(&mut context.pool()).await?; + check_private_instance(&local_user_view, &local_site)?; - check_private_instance(&local_user_view, &local_site)?; - - build_comment_response(context, data.id, local_user_view, None, vec![]).await - } + Ok(Json( + build_comment_response(context.deref(), data.id, local_user_view, None, vec![]).await?, + )) } diff --git a/crates/api_crud/src/comment/remove.rs b/crates/api_crud/src/comment/remove.rs index e87eb425..cfc3ccff 100644 --- a/crates/api_crud/src/comment/remove.rs +++ b/crates/api_crud/src/comment/remove.rs @@ -16,6 +16,7 @@ use lemmy_db_schema::{ }; use lemmy_db_views::structs::CommentView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use std::ops::Deref; #[async_trait::async_trait(?Send)] impl PerformCrud for RemoveComment { @@ -76,7 +77,7 @@ impl PerformCrud for RemoveComment { .await?; build_comment_response( - context, + context.deref(), updated_comment.id, Some(local_user_view), None, diff --git a/crates/api_crud/src/comment/update.rs b/crates/api_crud/src/comment/update.rs index 558965f6..5d4d75a3 100644 --- a/crates/api_crud/src/comment/update.rs +++ b/crates/api_crud/src/comment/update.rs @@ -29,6 +29,7 @@ use lemmy_utils::{ validation::is_valid_body_field, }, }; +use std::ops::Deref; #[async_trait::async_trait(?Send)] impl PerformCrud for EditComment { @@ -95,7 +96,7 @@ impl PerformCrud for EditComment { .await?; build_comment_response( - context, + context.deref(), updated_comment.id, Some(local_user_view), self.form_id.clone(), diff --git a/crates/api_crud/src/community/list.rs b/crates/api_crud/src/community/list.rs index bd818995..c8ce9e58 100644 --- a/crates/api_crud/src/community/list.rs +++ b/crates/api_crud/src/community/list.rs @@ -1,5 +1,4 @@ -use crate::PerformCrud; -use actix_web::web::Data; +use actix_web::web::{Data, Json, Query}; use lemmy_api_common::{ community::{ListCommunities, ListCommunitiesResponse}, context::LemmyContext, @@ -9,42 +8,36 @@ use lemmy_db_schema::source::local_site::LocalSite; use lemmy_db_views_actor::community_view::CommunityQuery; use lemmy_utils::error::LemmyError; -#[async_trait::async_trait(?Send)] -impl PerformCrud for ListCommunities { - type Response = ListCommunitiesResponse; +#[tracing::instrument(skip(context))] +pub async fn list_communities( + data: Query, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt_opt(data.auth.as_ref(), &context).await; + let local_site = LocalSite::read(&mut context.pool()).await?; + let is_admin = local_user_view.as_ref().map(|luv| is_admin(luv).is_ok()); - #[tracing::instrument(skip(context))] - async fn perform( - &self, - context: &Data, - ) -> Result { - let data: &ListCommunities = self; - let local_user_view = local_user_view_from_jwt_opt(data.auth.as_ref(), context).await; - let local_site = LocalSite::read(&mut context.pool()).await?; - let is_admin = local_user_view.as_ref().map(|luv| is_admin(luv).is_ok()); + check_private_instance(&local_user_view, &local_site)?; - check_private_instance(&local_user_view, &local_site)?; - - let sort = data.sort; - let listing_type = data.type_; - let show_nsfw = data.show_nsfw; - let page = data.page; - let limit = data.limit; - let local_user = local_user_view.map(|l| l.local_user); - let communities = CommunityQuery { - listing_type, - show_nsfw, - sort, - local_user: local_user.as_ref(), - page, - limit, - is_mod_or_admin: is_admin, - ..Default::default() - } - .list(&mut context.pool()) - .await?; - - // Return the jwt - Ok(ListCommunitiesResponse { communities }) + let sort = data.sort; + let listing_type = data.type_; + let show_nsfw = data.show_nsfw; + let page = data.page; + let limit = data.limit; + let local_user = local_user_view.map(|l| l.local_user); + let communities = CommunityQuery { + listing_type, + show_nsfw, + sort, + local_user: local_user.as_ref(), + page, + limit, + is_mod_or_admin: is_admin, + ..Default::default() } + .list(&mut context.pool()) + .await?; + + // Return the jwt + Ok(Json(ListCommunitiesResponse { communities })) } diff --git a/crates/api_crud/src/community/mod.rs b/crates/api_crud/src/community/mod.rs index 3fc74165..4bd02848 100644 --- a/crates/api_crud/src/community/mod.rs +++ b/crates/api_crud/src/community/mod.rs @@ -1,5 +1,5 @@ -mod create; -mod delete; -mod list; -mod remove; -mod update; +pub mod create; +pub mod delete; +pub mod list; +pub mod remove; +pub mod update; diff --git a/crates/api_crud/src/lib.rs b/crates/api_crud/src/lib.rs index e7934286..edd5c46f 100644 --- a/crates/api_crud/src/lib.rs +++ b/crates/api_crud/src/lib.rs @@ -2,13 +2,13 @@ use actix_web::web::Data; use lemmy_api_common::context::LemmyContext; use lemmy_utils::error::LemmyError; -mod comment; -mod community; -mod custom_emoji; +pub mod comment; +pub mod community; +pub mod custom_emoji; pub mod post; -mod private_message; -mod site; -mod user; +pub mod private_message; +pub mod site; +pub mod user; #[async_trait::async_trait(?Send)] pub trait PerformCrud { diff --git a/crates/api_crud/src/post/mod.rs b/crates/api_crud/src/post/mod.rs index 43795556..8bb842b7 100644 --- a/crates/api_crud/src/post/mod.rs +++ b/crates/api_crud/src/post/mod.rs @@ -1,5 +1,5 @@ pub mod create; -mod delete; -mod read; -mod remove; -mod update; +pub mod delete; +pub mod read; +pub mod remove; +pub mod update; diff --git a/crates/api_crud/src/post/read.rs b/crates/api_crud/src/post/read.rs index e668517d..efa0c87b 100644 --- a/crates/api_crud/src/post/read.rs +++ b/crates/api_crud/src/post/read.rs @@ -1,5 +1,4 @@ -use crate::PerformCrud; -use actix_web::web::Data; +use actix_web::web::{Data, Json, Query}; use lemmy_api_common::{ context::LemmyContext, post::{GetPost, GetPostResponse}, @@ -19,107 +18,103 @@ use lemmy_db_views::{post_view::PostQuery, structs::PostView}; use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView}; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; -#[async_trait::async_trait(?Send)] -impl PerformCrud for GetPost { - type Response = GetPostResponse; +#[tracing::instrument(skip(context))] +pub async fn get_post( + data: Query, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt_opt(data.auth.as_ref(), &context).await; + let local_site = LocalSite::read(&mut context.pool()).await?; - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data: &GetPost = self; - let local_user_view = local_user_view_from_jwt_opt(data.auth.as_ref(), context).await; - let local_site = LocalSite::read(&mut context.pool()).await?; + check_private_instance(&local_user_view, &local_site)?; - check_private_instance(&local_user_view, &local_site)?; + let person_id = local_user_view.as_ref().map(|u| u.person.id); - let person_id = local_user_view.as_ref().map(|u| u.person.id); + // I'd prefer fetching the post_view by a comment join, but it adds a lot of boilerplate + let post_id = if let Some(id) = data.id { + id + } else if let Some(comment_id) = data.comment_id { + Comment::read(&mut context.pool(), comment_id) + .await + .with_lemmy_type(LemmyErrorType::CouldntFindPost)? + .post_id + } else { + Err(LemmyErrorType::CouldntFindPost)? + }; - // I'd prefer fetching the post_view by a comment join, but it adds a lot of boilerplate - let post_id = if let Some(id) = data.id { - id - } else if let Some(comment_id) = data.comment_id { - Comment::read(&mut context.pool(), comment_id) - .await - .with_lemmy_type(LemmyErrorType::CouldntFindPost)? - .post_id - } else { - Err(LemmyErrorType::CouldntFindPost)? - }; + // Check to see if the person is a mod or admin, to show deleted / removed + let community_id = Post::read(&mut context.pool(), post_id).await?.community_id; + let is_mod_or_admin = is_mod_or_admin_opt( + &mut context.pool(), + local_user_view.as_ref(), + Some(community_id), + ) + .await + .is_ok(); - // Check to see if the person is a mod or admin, to show deleted / removed - let community_id = Post::read(&mut context.pool(), post_id).await?.community_id; - let is_mod_or_admin = is_mod_or_admin_opt( - &mut context.pool(), - local_user_view.as_ref(), - Some(community_id), - ) - .await - .is_ok(); + let post_view = PostView::read( + &mut context.pool(), + post_id, + person_id, + Some(is_mod_or_admin), + ) + .await + .with_lemmy_type(LemmyErrorType::CouldntFindPost)?; - let post_view = PostView::read( - &mut context.pool(), - post_id, - person_id, - Some(is_mod_or_admin), - ) - .await - .with_lemmy_type(LemmyErrorType::CouldntFindPost)?; + // Mark the post as read + let post_id = post_view.post.id; + if let Some(person_id) = person_id { + mark_post_as_read(person_id, post_id, &mut context.pool()).await?; + } - // Mark the post as read - let post_id = post_view.post.id; - if let Some(person_id) = person_id { - mark_post_as_read(person_id, post_id, &mut context.pool()).await?; - } + // Necessary for the sidebar subscribed + let community_view = CommunityView::read( + &mut context.pool(), + community_id, + person_id, + Some(is_mod_or_admin), + ) + .await + .with_lemmy_type(LemmyErrorType::CouldntFindCommunity)?; - // Necessary for the sidebar subscribed - let community_view = CommunityView::read( - &mut context.pool(), - community_id, + // Insert into PersonPostAggregates + // to update the read_comments count + if let Some(person_id) = person_id { + let read_comments = post_view.counts.comments; + let person_post_agg_form = PersonPostAggregatesForm { person_id, - Some(is_mod_or_admin), - ) - .await - .with_lemmy_type(LemmyErrorType::CouldntFindCommunity)?; - - // Insert into PersonPostAggregates - // to update the read_comments count - if let Some(person_id) = person_id { - let read_comments = post_view.counts.comments; - let person_post_agg_form = PersonPostAggregatesForm { - person_id, - post_id, - read_comments, - ..PersonPostAggregatesForm::default() - }; - PersonPostAggregates::upsert(&mut context.pool(), &person_post_agg_form) - .await - .with_lemmy_type(LemmyErrorType::CouldntFindPost)?; - } + post_id, + read_comments, + ..PersonPostAggregatesForm::default() + }; + PersonPostAggregates::upsert(&mut context.pool(), &person_post_agg_form) + .await + .with_lemmy_type(LemmyErrorType::CouldntFindPost)?; + } - let moderators = - CommunityModeratorView::for_community(&mut context.pool(), community_id).await?; + let moderators = CommunityModeratorView::for_community(&mut context.pool(), community_id).await?; - // Fetch the cross_posts - let cross_posts = if let Some(url) = &post_view.post.url { - let mut x_posts = PostQuery { - url_search: Some(url.inner().as_str().into()), - ..Default::default() - } - .list(&mut context.pool()) - .await?; + // Fetch the cross_posts + let cross_posts = if let Some(url) = &post_view.post.url { + let mut x_posts = PostQuery { + url_search: Some(url.inner().as_str().into()), + ..Default::default() + } + .list(&mut context.pool()) + .await?; - // Don't return this post as one of the cross_posts - x_posts.retain(|x| x.post.id != post_id); - x_posts - } else { - Vec::new() - }; + // Don't return this post as one of the cross_posts + x_posts.retain(|x| x.post.id != post_id); + x_posts + } else { + Vec::new() + }; - // Return the jwt - Ok(GetPostResponse { - post_view, - community_view, - moderators, - cross_posts, - }) - } + // Return the jwt + Ok(Json(GetPostResponse { + post_view, + community_view, + moderators, + cross_posts, + })) } diff --git a/crates/api_crud/src/private_message/mod.rs b/crates/api_crud/src/private_message/mod.rs index 71683237..ab7fa439 100644 --- a/crates/api_crud/src/private_message/mod.rs +++ b/crates/api_crud/src/private_message/mod.rs @@ -1,4 +1,4 @@ -mod create; -mod delete; -mod read; -mod update; +pub mod create; +pub mod delete; +pub mod read; +pub mod update; diff --git a/crates/api_crud/src/private_message/read.rs b/crates/api_crud/src/private_message/read.rs index 87d8ee66..ec4f5c10 100644 --- a/crates/api_crud/src/private_message/read.rs +++ b/crates/api_crud/src/private_message/read.rs @@ -1,5 +1,4 @@ -use crate::PerformCrud; -use actix_web::web::Data; +use actix_web::web::{Data, Json, Query}; use lemmy_api_common::{ context::LemmyContext, private_message::{GetPrivateMessages, PrivateMessagesResponse}, @@ -8,40 +7,34 @@ use lemmy_api_common::{ use lemmy_db_views::private_message_view::PrivateMessageQuery; use lemmy_utils::error::LemmyError; -#[async_trait::async_trait(?Send)] -impl PerformCrud for GetPrivateMessages { - type Response = PrivateMessagesResponse; +#[tracing::instrument(skip(context))] +pub async fn get_private_message( + data: Query, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(data.auth.as_ref(), &context).await?; + let person_id = local_user_view.person.id; - #[tracing::instrument(skip(self, context))] - async fn perform( - &self, - context: &Data, - ) -> Result { - let data: &GetPrivateMessages = self; - let local_user_view = local_user_view_from_jwt(data.auth.as_ref(), context).await?; - let person_id = local_user_view.person.id; + let page = data.page; + let limit = data.limit; + let unread_only = data.unread_only; + let mut messages = PrivateMessageQuery { + page, + limit, + unread_only, + } + .list(&mut context.pool(), person_id) + .await?; - let page = data.page; - let limit = data.limit; - let unread_only = data.unread_only; - let mut messages = PrivateMessageQuery { - page, - limit, - unread_only, + // Messages sent by ourselves should be marked as read. The `read` column in database is only + // for the recipient, and shouldnt be exposed to sender. + messages.iter_mut().for_each(|pmv| { + if pmv.creator.id == person_id { + pmv.private_message.read = true } - .list(&mut context.pool(), person_id) - .await?; - - // Messages sent by ourselves should be marked as read. The `read` column in database is only - // for the recipient, and shouldnt be exposed to sender. - messages.iter_mut().for_each(|pmv| { - if pmv.creator.id == person_id { - pmv.private_message.read = true - } - }); + }); - Ok(PrivateMessagesResponse { - private_messages: messages, - }) - } + Ok(Json(PrivateMessagesResponse { + private_messages: messages, + })) } diff --git a/crates/api_crud/src/site/create.rs b/crates/api_crud/src/site/create.rs index 98d111a1..59a57ff8 100644 --- a/crates/api_crud/src/site/create.rs +++ b/crates/api_crud/src/site/create.rs @@ -1,9 +1,6 @@ -use crate::{ - site::{application_question_check, site_default_post_listing_type_check}, - PerformCrud, -}; +use crate::site::{application_question_check, site_default_post_listing_type_check}; use activitypub_federation::http_signatures::generate_actor_keypair; -use actix_web::web::Data; +use actix_web::web::{Data, Json}; use lemmy_api_common::{ context::LemmyContext, site::{CreateSite, SiteResponse}, @@ -43,108 +40,105 @@ use lemmy_utils::{ }; use url::Url; -#[async_trait::async_trait(?Send)] -impl PerformCrud for CreateSite { - type Response = SiteResponse; - - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data: &CreateSite = self; - let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; - let local_site = LocalSite::read(&mut context.pool()).await?; - - // Make sure user is an admin; other types of users should not create site data... - is_admin(&local_user_view)?; - - validate_create_payload(&local_site, data)?; - - let actor_id: DbUrl = Url::parse(&context.settings().get_protocol_and_hostname())?.into(); - let inbox_url = Some(generate_site_inbox_url(&actor_id)?); - let keypair = generate_actor_keypair()?; - let name = sanitize_html(&data.name); - let sidebar = sanitize_html_opt(&data.sidebar); - let description = sanitize_html_opt(&data.description); - - let site_form = SiteUpdateForm::builder() - .name(Some(name)) - .sidebar(diesel_option_overwrite(sidebar)) - .description(diesel_option_overwrite(description)) - .icon(diesel_option_overwrite_to_url(&data.icon)?) - .banner(diesel_option_overwrite_to_url(&data.banner)?) - .actor_id(Some(actor_id)) - .last_refreshed_at(Some(naive_now())) - .inbox_url(inbox_url) - .private_key(Some(Some(keypair.private_key))) - .public_key(Some(keypair.public_key)) - .build(); - - let site_id = local_site.site_id; - - Site::update(&mut context.pool(), site_id, &site_form).await?; - - let application_question = sanitize_html_opt(&data.application_question); - let default_theme = sanitize_html_opt(&data.default_theme); - let legal_information = sanitize_html_opt(&data.legal_information); - - let local_site_form = LocalSiteUpdateForm::builder() - // Set the site setup to true - .site_setup(Some(true)) - .enable_downvotes(data.enable_downvotes) - .registration_mode(data.registration_mode) - .enable_nsfw(data.enable_nsfw) - .community_creation_admin_only(data.community_creation_admin_only) - .require_email_verification(data.require_email_verification) - .application_question(diesel_option_overwrite(application_question)) - .private_instance(data.private_instance) - .default_theme(default_theme) - .default_post_listing_type(data.default_post_listing_type) - .legal_information(diesel_option_overwrite(legal_information)) - .application_email_admins(data.application_email_admins) - .hide_modlog_mod_names(data.hide_modlog_mod_names) - .updated(Some(Some(naive_now()))) - .slur_filter_regex(diesel_option_overwrite(data.slur_filter_regex.clone())) - .actor_name_max_length(data.actor_name_max_length) - .federation_enabled(data.federation_enabled) - .captcha_enabled(data.captcha_enabled) - .captcha_difficulty(data.captcha_difficulty.clone()) - .build(); - - LocalSite::update(&mut context.pool(), &local_site_form).await?; - - let local_site_rate_limit_form = LocalSiteRateLimitUpdateForm::builder() - .message(data.rate_limit_message) - .message_per_second(data.rate_limit_message_per_second) - .post(data.rate_limit_post) - .post_per_second(data.rate_limit_post_per_second) - .register(data.rate_limit_register) - .register_per_second(data.rate_limit_register_per_second) - .image(data.rate_limit_image) - .image_per_second(data.rate_limit_image_per_second) - .comment(data.rate_limit_comment) - .comment_per_second(data.rate_limit_comment_per_second) - .search(data.rate_limit_search) - .search_per_second(data.rate_limit_search_per_second) - .build(); - - LocalSiteRateLimit::update(&mut context.pool(), &local_site_rate_limit_form).await?; - - let site_view = SiteView::read_local(&mut context.pool()).await?; - - let new_taglines = data.taglines.clone(); - let taglines = Tagline::replace(&mut context.pool(), local_site.id, new_taglines).await?; - - let rate_limit_config = - local_site_rate_limit_to_rate_limit_config(&site_view.local_site_rate_limit); - context - .settings_updated_channel() - .send(rate_limit_config) - .await?; - - Ok(SiteResponse { - site_view, - taglines, - }) - } +#[tracing::instrument(skip(context))] +pub async fn create_site( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; + let local_site = LocalSite::read(&mut context.pool()).await?; + + // Make sure user is an admin; other types of users should not create site data... + is_admin(&local_user_view)?; + + validate_create_payload(&local_site, &data)?; + + let actor_id: DbUrl = Url::parse(&context.settings().get_protocol_and_hostname())?.into(); + let inbox_url = Some(generate_site_inbox_url(&actor_id)?); + let keypair = generate_actor_keypair()?; + let name = sanitize_html(&data.name); + let sidebar = sanitize_html_opt(&data.sidebar); + let description = sanitize_html_opt(&data.description); + + let site_form = SiteUpdateForm::builder() + .name(Some(name)) + .sidebar(diesel_option_overwrite(sidebar)) + .description(diesel_option_overwrite(description)) + .icon(diesel_option_overwrite_to_url(&data.icon)?) + .banner(diesel_option_overwrite_to_url(&data.banner)?) + .actor_id(Some(actor_id)) + .last_refreshed_at(Some(naive_now())) + .inbox_url(inbox_url) + .private_key(Some(Some(keypair.private_key))) + .public_key(Some(keypair.public_key)) + .build(); + + let site_id = local_site.site_id; + + Site::update(&mut context.pool(), site_id, &site_form).await?; + + let application_question = sanitize_html_opt(&data.application_question); + let default_theme = sanitize_html_opt(&data.default_theme); + let legal_information = sanitize_html_opt(&data.legal_information); + + let local_site_form = LocalSiteUpdateForm::builder() + // Set the site setup to true + .site_setup(Some(true)) + .enable_downvotes(data.enable_downvotes) + .registration_mode(data.registration_mode) + .enable_nsfw(data.enable_nsfw) + .community_creation_admin_only(data.community_creation_admin_only) + .require_email_verification(data.require_email_verification) + .application_question(diesel_option_overwrite(application_question)) + .private_instance(data.private_instance) + .default_theme(default_theme) + .default_post_listing_type(data.default_post_listing_type) + .legal_information(diesel_option_overwrite(legal_information)) + .application_email_admins(data.application_email_admins) + .hide_modlog_mod_names(data.hide_modlog_mod_names) + .updated(Some(Some(naive_now()))) + .slur_filter_regex(diesel_option_overwrite(data.slur_filter_regex.clone())) + .actor_name_max_length(data.actor_name_max_length) + .federation_enabled(data.federation_enabled) + .captcha_enabled(data.captcha_enabled) + .captcha_difficulty(data.captcha_difficulty.clone()) + .build(); + + LocalSite::update(&mut context.pool(), &local_site_form).await?; + + let local_site_rate_limit_form = LocalSiteRateLimitUpdateForm::builder() + .message(data.rate_limit_message) + .message_per_second(data.rate_limit_message_per_second) + .post(data.rate_limit_post) + .post_per_second(data.rate_limit_post_per_second) + .register(data.rate_limit_register) + .register_per_second(data.rate_limit_register_per_second) + .image(data.rate_limit_image) + .image_per_second(data.rate_limit_image_per_second) + .comment(data.rate_limit_comment) + .comment_per_second(data.rate_limit_comment_per_second) + .search(data.rate_limit_search) + .search_per_second(data.rate_limit_search_per_second) + .build(); + + LocalSiteRateLimit::update(&mut context.pool(), &local_site_rate_limit_form).await?; + + let site_view = SiteView::read_local(&mut context.pool()).await?; + + let new_taglines = data.taglines.clone(); + let taglines = Tagline::replace(&mut context.pool(), local_site.id, new_taglines).await?; + + let rate_limit_config = + local_site_rate_limit_to_rate_limit_config(&site_view.local_site_rate_limit); + context + .settings_updated_channel() + .send(rate_limit_config) + .await?; + + Ok(Json(SiteResponse { + site_view, + taglines, + })) } fn validate_create_payload(local_site: &LocalSite, create_site: &CreateSite) -> LemmyResult<()> { diff --git a/crates/api_crud/src/site/mod.rs b/crates/api_crud/src/site/mod.rs index 652b9e65..e4911ba4 100644 --- a/crates/api_crud/src/site/mod.rs +++ b/crates/api_crud/src/site/mod.rs @@ -1,9 +1,9 @@ use lemmy_db_schema::{ListingType, RegistrationMode}; use lemmy_utils::error::{LemmyErrorType, LemmyResult}; -mod create; -mod read; -mod update; +pub mod create; +pub mod read; +pub mod update; /// Checks whether the default post listing type is valid for a site. pub fn site_default_post_listing_type_check( diff --git a/crates/api_crud/src/site/read.rs b/crates/api_crud/src/site/read.rs index e74eeefb..62d96492 100644 --- a/crates/api_crud/src/site/read.rs +++ b/crates/api_crud/src/site/read.rs @@ -1,5 +1,4 @@ -use crate::PerformCrud; -use actix_web::web::Data; +use actix_web::web::{Data, Json, Query}; use lemmy_api_common::{ context::LemmyContext, sensitive::Sensitive, @@ -28,76 +27,72 @@ use lemmy_utils::{ version, }; -#[async_trait::async_trait(?Send)] -impl PerformCrud for GetSite { - type Response = GetSiteResponse; - - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data: &GetSite = self; - - let site_view = SiteView::read_local(&mut context.pool()).await?; - - let admins = PersonView::admins(&mut context.pool()).await?; - - // Build the local user - let my_user = if let Some(local_user_view) = - local_user_settings_view_from_jwt_opt(data.auth.as_ref(), context).await - { - let person_id = local_user_view.person.id; - let local_user_id = local_user_view.local_user.id; - - let follows = CommunityFollowerView::for_person(&mut context.pool(), person_id) - .await - .with_lemmy_type(LemmyErrorType::SystemErrLogin)?; - - let person_id = local_user_view.person.id; - let community_blocks = CommunityBlockView::for_person(&mut context.pool(), person_id) - .await - .with_lemmy_type(LemmyErrorType::SystemErrLogin)?; - - let person_id = local_user_view.person.id; - let person_blocks = PersonBlockView::for_person(&mut context.pool(), person_id) - .await - .with_lemmy_type(LemmyErrorType::SystemErrLogin)?; - - let moderates = CommunityModeratorView::for_person(&mut context.pool(), person_id) - .await - .with_lemmy_type(LemmyErrorType::SystemErrLogin)?; - - let discussion_languages = LocalUserLanguage::read(&mut context.pool(), local_user_id) - .await - .with_lemmy_type(LemmyErrorType::SystemErrLogin)?; - - Some(MyUserInfo { - local_user_view, - follows, - moderates, - community_blocks, - person_blocks, - discussion_languages, - }) - } else { - None - }; - - let all_languages = Language::read_all(&mut context.pool()).await?; - let discussion_languages = SiteLanguage::read_local_raw(&mut context.pool()).await?; - let taglines = Tagline::get_all(&mut context.pool(), site_view.local_site.id).await?; - let custom_emojis = - CustomEmojiView::get_all(&mut context.pool(), site_view.local_site.id).await?; - - Ok(GetSiteResponse { - site_view, - admins, - version: version::VERSION.to_string(), - my_user, - all_languages, +#[tracing::instrument(skip(context))] +pub async fn get_site( + data: Query, + context: Data, +) -> Result, LemmyError> { + let site_view = SiteView::read_local(&mut context.pool()).await?; + + let admins = PersonView::admins(&mut context.pool()).await?; + + // Build the local user + let my_user = if let Some(local_user_view) = + local_user_settings_view_from_jwt_opt(data.auth.as_ref(), &context).await + { + let person_id = local_user_view.person.id; + let local_user_id = local_user_view.local_user.id; + + let follows = CommunityFollowerView::for_person(&mut context.pool(), person_id) + .await + .with_lemmy_type(LemmyErrorType::SystemErrLogin)?; + + let person_id = local_user_view.person.id; + let community_blocks = CommunityBlockView::for_person(&mut context.pool(), person_id) + .await + .with_lemmy_type(LemmyErrorType::SystemErrLogin)?; + + let person_id = local_user_view.person.id; + let person_blocks = PersonBlockView::for_person(&mut context.pool(), person_id) + .await + .with_lemmy_type(LemmyErrorType::SystemErrLogin)?; + + let moderates = CommunityModeratorView::for_person(&mut context.pool(), person_id) + .await + .with_lemmy_type(LemmyErrorType::SystemErrLogin)?; + + let discussion_languages = LocalUserLanguage::read(&mut context.pool(), local_user_id) + .await + .with_lemmy_type(LemmyErrorType::SystemErrLogin)?; + + Some(MyUserInfo { + local_user_view, + follows, + moderates, + community_blocks, + person_blocks, discussion_languages, - taglines, - custom_emojis, }) - } + } else { + None + }; + + let all_languages = Language::read_all(&mut context.pool()).await?; + let discussion_languages = SiteLanguage::read_local_raw(&mut context.pool()).await?; + let taglines = Tagline::get_all(&mut context.pool(), site_view.local_site.id).await?; + let custom_emojis = + CustomEmojiView::get_all(&mut context.pool(), site_view.local_site.id).await?; + + Ok(Json(GetSiteResponse { + site_view, + admins, + version: version::VERSION.to_string(), + my_user, + all_languages, + discussion_languages, + taglines, + custom_emojis, + })) } #[tracing::instrument(skip_all)] diff --git a/crates/api_crud/src/site/update.rs b/crates/api_crud/src/site/update.rs index 2b8ce4c0..f560c729 100644 --- a/crates/api_crud/src/site/update.rs +++ b/crates/api_crud/src/site/update.rs @@ -1,8 +1,5 @@ -use crate::{ - site::{application_question_check, site_default_post_listing_type_check}, - PerformCrud, -}; -use actix_web::web::Data; +use crate::site::{application_question_check, site_default_post_listing_type_check}; +use actix_web::web::{Data, Json}; use lemmy_api_common::{ context::LemmyContext, site::{EditSite, SiteResponse}, @@ -43,147 +40,142 @@ use lemmy_utils::{ }, }; -#[async_trait::async_trait(?Send)] -impl PerformCrud for EditSite { - type Response = SiteResponse; - - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data: &EditSite = self; - let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; - let site_view = SiteView::read_local(&mut context.pool()).await?; - let local_site = site_view.local_site; - let site = site_view.site; - - // Make sure user is an admin; other types of users should not update site data... - is_admin(&local_user_view)?; - - validate_update_payload(&local_site, data)?; +#[tracing::instrument(skip(context))] +pub async fn update_site( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; + let site_view = SiteView::read_local(&mut context.pool()).await?; + let local_site = site_view.local_site; + let site = site_view.site; - if let Some(discussion_languages) = data.discussion_languages.clone() { - SiteLanguage::update(&mut context.pool(), discussion_languages.clone(), &site).await?; - } + // Make sure user is an admin; other types of users should not update site data... + is_admin(&local_user_view)?; - let name = sanitize_html_opt(&data.name); - let sidebar = sanitize_html_opt(&data.sidebar); - let description = sanitize_html_opt(&data.description); + validate_update_payload(&local_site, &data)?; - let site_form = SiteUpdateForm::builder() - .name(name) - .sidebar(diesel_option_overwrite(sidebar)) - .description(diesel_option_overwrite(description)) - .icon(diesel_option_overwrite_to_url(&data.icon)?) - .banner(diesel_option_overwrite_to_url(&data.banner)?) - .updated(Some(Some(naive_now()))) - .build(); + if let Some(discussion_languages) = data.discussion_languages.clone() { + SiteLanguage::update(&mut context.pool(), discussion_languages.clone(), &site).await?; + } - Site::update(&mut context.pool(), site.id, &site_form) - .await - // Ignore errors for all these, so as to not throw errors if no update occurs - // Diesel will throw an error for empty update forms - .ok(); - - let application_question = sanitize_html_opt(&data.application_question); - let default_theme = sanitize_html_opt(&data.default_theme); - let legal_information = sanitize_html_opt(&data.legal_information); - - let local_site_form = LocalSiteUpdateForm::builder() - .enable_downvotes(data.enable_downvotes) - .registration_mode(data.registration_mode) - .enable_nsfw(data.enable_nsfw) - .community_creation_admin_only(data.community_creation_admin_only) - .require_email_verification(data.require_email_verification) - .application_question(diesel_option_overwrite(application_question)) - .private_instance(data.private_instance) - .default_theme(default_theme) - .default_post_listing_type(data.default_post_listing_type) - .legal_information(diesel_option_overwrite(legal_information)) - .application_email_admins(data.application_email_admins) - .hide_modlog_mod_names(data.hide_modlog_mod_names) - .updated(Some(Some(naive_now()))) - .slur_filter_regex(diesel_option_overwrite(data.slur_filter_regex.clone())) - .actor_name_max_length(data.actor_name_max_length) - .federation_enabled(data.federation_enabled) - .captcha_enabled(data.captcha_enabled) - .captcha_difficulty(data.captcha_difficulty.clone()) - .reports_email_admins(data.reports_email_admins) - .build(); - - let update_local_site = LocalSite::update(&mut context.pool(), &local_site_form) - .await - .ok(); - - let local_site_rate_limit_form = LocalSiteRateLimitUpdateForm::builder() - .message(data.rate_limit_message) - .message_per_second(data.rate_limit_message_per_second) - .post(data.rate_limit_post) - .post_per_second(data.rate_limit_post_per_second) - .register(data.rate_limit_register) - .register_per_second(data.rate_limit_register_per_second) - .image(data.rate_limit_image) - .image_per_second(data.rate_limit_image_per_second) - .comment(data.rate_limit_comment) - .comment_per_second(data.rate_limit_comment_per_second) - .search(data.rate_limit_search) - .search_per_second(data.rate_limit_search_per_second) - .build(); - - LocalSiteRateLimit::update(&mut context.pool(), &local_site_rate_limit_form) + let name = sanitize_html_opt(&data.name); + let sidebar = sanitize_html_opt(&data.sidebar); + let description = sanitize_html_opt(&data.description); + + let site_form = SiteUpdateForm::builder() + .name(name) + .sidebar(diesel_option_overwrite(sidebar)) + .description(diesel_option_overwrite(description)) + .icon(diesel_option_overwrite_to_url(&data.icon)?) + .banner(diesel_option_overwrite_to_url(&data.banner)?) + .updated(Some(Some(naive_now()))) + .build(); + + Site::update(&mut context.pool(), site.id, &site_form) + .await + // Ignore errors for all these, so as to not throw errors if no update occurs + // Diesel will throw an error for empty update forms + .ok(); + + let application_question = sanitize_html_opt(&data.application_question); + let default_theme = sanitize_html_opt(&data.default_theme); + let legal_information = sanitize_html_opt(&data.legal_information); + + let local_site_form = LocalSiteUpdateForm::builder() + .enable_downvotes(data.enable_downvotes) + .registration_mode(data.registration_mode) + .enable_nsfw(data.enable_nsfw) + .community_creation_admin_only(data.community_creation_admin_only) + .require_email_verification(data.require_email_verification) + .application_question(diesel_option_overwrite(application_question)) + .private_instance(data.private_instance) + .default_theme(default_theme) + .default_post_listing_type(data.default_post_listing_type) + .legal_information(diesel_option_overwrite(legal_information)) + .application_email_admins(data.application_email_admins) + .hide_modlog_mod_names(data.hide_modlog_mod_names) + .updated(Some(Some(naive_now()))) + .slur_filter_regex(diesel_option_overwrite(data.slur_filter_regex.clone())) + .actor_name_max_length(data.actor_name_max_length) + .federation_enabled(data.federation_enabled) + .captcha_enabled(data.captcha_enabled) + .captcha_difficulty(data.captcha_difficulty.clone()) + .reports_email_admins(data.reports_email_admins) + .build(); + + let update_local_site = LocalSite::update(&mut context.pool(), &local_site_form) + .await + .ok(); + + let local_site_rate_limit_form = LocalSiteRateLimitUpdateForm::builder() + .message(data.rate_limit_message) + .message_per_second(data.rate_limit_message_per_second) + .post(data.rate_limit_post) + .post_per_second(data.rate_limit_post_per_second) + .register(data.rate_limit_register) + .register_per_second(data.rate_limit_register_per_second) + .image(data.rate_limit_image) + .image_per_second(data.rate_limit_image_per_second) + .comment(data.rate_limit_comment) + .comment_per_second(data.rate_limit_comment_per_second) + .search(data.rate_limit_search) + .search_per_second(data.rate_limit_search_per_second) + .build(); + + LocalSiteRateLimit::update(&mut context.pool(), &local_site_rate_limit_form) + .await + .ok(); + + // Replace the blocked and allowed instances + let allowed = data.allowed_instances.clone(); + FederationAllowList::replace(&mut context.pool(), allowed).await?; + let blocked = data.blocked_instances.clone(); + FederationBlockList::replace(&mut context.pool(), blocked).await?; + + // TODO can't think of a better way to do this. + // If the server suddenly requires email verification, or required applications, no old users + // will be able to log in. It really only wants this to be a requirement for NEW signups. + // So if it was set from false, to true, you need to update all current users columns to be verified. + + let old_require_application = + local_site.registration_mode == RegistrationMode::RequireApplication; + let new_require_application = update_local_site + .as_ref() + .map(|ols| ols.registration_mode == RegistrationMode::RequireApplication) + .unwrap_or(false); + if !old_require_application && new_require_application { + LocalUser::set_all_users_registration_applications_accepted(&mut context.pool()) .await - .ok(); - - // Replace the blocked and allowed instances - let allowed = data.allowed_instances.clone(); - FederationAllowList::replace(&mut context.pool(), allowed).await?; - let blocked = data.blocked_instances.clone(); - FederationBlockList::replace(&mut context.pool(), blocked).await?; - - // TODO can't think of a better way to do this. - // If the server suddenly requires email verification, or required applications, no old users - // will be able to log in. It really only wants this to be a requirement for NEW signups. - // So if it was set from false, to true, you need to update all current users columns to be verified. - - let old_require_application = - local_site.registration_mode == RegistrationMode::RequireApplication; - let new_require_application = update_local_site - .as_ref() - .map(|ols| ols.registration_mode == RegistrationMode::RequireApplication) - .unwrap_or(false); - if !old_require_application && new_require_application { - LocalUser::set_all_users_registration_applications_accepted(&mut context.pool()) - .await - .with_lemmy_type(LemmyErrorType::CouldntSetAllRegistrationsAccepted)?; - } - - let new_require_email_verification = update_local_site - .as_ref() - .map(|ols| ols.require_email_verification) - .unwrap_or(false); - if !local_site.require_email_verification && new_require_email_verification { - LocalUser::set_all_users_email_verified(&mut context.pool()) - .await - .with_lemmy_type(LemmyErrorType::CouldntSetAllEmailVerified)?; - } + .with_lemmy_type(LemmyErrorType::CouldntSetAllRegistrationsAccepted)?; + } - let new_taglines = data.taglines.clone(); - let taglines = Tagline::replace(&mut context.pool(), local_site.id, new_taglines).await?; + let new_require_email_verification = update_local_site + .as_ref() + .map(|ols| ols.require_email_verification) + .unwrap_or(false); + if !local_site.require_email_verification && new_require_email_verification { + LocalUser::set_all_users_email_verified(&mut context.pool()) + .await + .with_lemmy_type(LemmyErrorType::CouldntSetAllEmailVerified)?; + } - let site_view = SiteView::read_local(&mut context.pool()).await?; + let new_taglines = data.taglines.clone(); + let taglines = Tagline::replace(&mut context.pool(), local_site.id, new_taglines).await?; - let rate_limit_config = - local_site_rate_limit_to_rate_limit_config(&site_view.local_site_rate_limit); - context - .settings_updated_channel() - .send(rate_limit_config) - .await?; + let site_view = SiteView::read_local(&mut context.pool()).await?; - let res = SiteResponse { - site_view, - taglines, - }; + let rate_limit_config = + local_site_rate_limit_to_rate_limit_config(&site_view.local_site_rate_limit); + context + .settings_updated_channel() + .send(rate_limit_config) + .await?; - Ok(res) - } + Ok(Json(SiteResponse { + site_view, + taglines, + })) } fn validate_update_payload(local_site: &LocalSite, edit_site: &EditSite) -> LemmyResult<()> { diff --git a/crates/apub/src/activities/create_or_update/comment.rs b/crates/apub/src/activities/create_or_update/comment.rs index 51b87ed2..fa235a7f 100644 --- a/crates/apub/src/activities/create_or_update/comment.rs +++ b/crates/apub/src/activities/create_or_update/comment.rs @@ -25,7 +25,7 @@ use activitypub_federation::{ }; use lemmy_api_common::{ build_response::send_local_notifs, - comment::{CommentResponse, CreateComment, EditComment}, + comment::{CommentResponse, EditComment}, context::LemmyContext, utils::{check_post_deleted_or_removed, is_mod_or_admin}, }; @@ -43,25 +43,6 @@ use lemmy_db_schema::{ use lemmy_utils::{error::LemmyError, utils::mention::scrape_text_for_mentions}; use url::Url; -#[async_trait::async_trait] -impl SendActivity for CreateComment { - type Response = CommentResponse; - - async fn send_activity( - _request: &Self, - response: &Self::Response, - context: &Data, - ) -> Result<(), LemmyError> { - CreateOrUpdateNote::send( - &response.comment_view.comment, - response.comment_view.creator.id, - CreateOrUpdateType::Create, - context, - ) - .await - } -} - #[async_trait::async_trait] impl SendActivity for EditComment { type Response = CommentResponse; @@ -72,10 +53,10 @@ impl SendActivity for EditComment { context: &Data, ) -> Result<(), LemmyError> { CreateOrUpdateNote::send( - &response.comment_view.comment, + response.comment_view.comment.clone(), response.comment_view.creator.id, CreateOrUpdateType::Update, - context, + context.reset_request_count(), ) .await } @@ -83,11 +64,11 @@ impl SendActivity for EditComment { impl CreateOrUpdateNote { #[tracing::instrument(skip(comment, person_id, kind, context))] - async fn send( - comment: &Comment, + pub(crate) async fn send( + comment: Comment, person_id: PersonId, kind: CreateOrUpdateType, - context: &Data, + context: Data, ) -> Result<(), LemmyError> { // TODO: might be helpful to add a comment method to retrieve community directly let post_id = comment.post_id; @@ -102,7 +83,7 @@ impl CreateOrUpdateNote { kind.clone(), &context.settings().get_protocol_and_hostname(), )?; - let note = ApubComment(comment.clone()).into_json(context).await?; + let note = ApubComment(comment).into_json(&context).await?; let create_or_update = CreateOrUpdateNote { actor: person.id().into(), @@ -130,12 +111,12 @@ impl CreateOrUpdateNote { .collect(); let mut inboxes = vec![]; for t in tagged_users { - let person = t.dereference(context).await?; + let person = t.dereference(&context).await?; inboxes.push(person.shared_inbox_or_inbox()); } let activity = AnnouncableActivities::CreateOrUpdateComment(create_or_update); - send_activity_in_community(activity, &person, &community, inboxes, false, context).await + send_activity_in_community(activity, &person, &community, inboxes, false, &context).await } } diff --git a/crates/apub/src/activities/mod.rs b/crates/apub/src/activities/mod.rs index 02ad0b6b..c7d19e37 100644 --- a/crates/apub/src/activities/mod.rs +++ b/crates/apub/src/activities/mod.rs @@ -1,6 +1,9 @@ use crate::{ objects::{community::ApubCommunity, person::ApubPerson}, - protocol::activities::{create_or_update::page::CreateOrUpdatePage, CreateOrUpdateType}, + protocol::activities::{ + create_or_update::{note::CreateOrUpdateNote, page::CreateOrUpdatePage}, + CreateOrUpdateType, + }, CONTEXT, }; use activitypub_federation::{ @@ -217,15 +220,17 @@ pub async fn match_outgoing_activities( data: SendActivityData, context: &Data, ) -> LemmyResult<()> { - let fed_task = match data { - SendActivityData::CreatePost(post) => { - let creator_id = post.creator_id; - CreateOrUpdatePage::send( - post, - creator_id, - CreateOrUpdateType::Create, - context.reset_request_count(), - ) + let context = context.reset_request_count(); + let fed_task = async { + match data { + SendActivityData::CreatePost(post) => { + let creator_id = post.creator_id; + CreateOrUpdatePage::send(post, creator_id, CreateOrUpdateType::Create, context).await + } + SendActivityData::CreateComment(comment) => { + let creator_id = comment.creator_id; + CreateOrUpdateNote::send(comment, creator_id, CreateOrUpdateType::Create, context).await + } } }; if *SYNCHRONOUS_FEDERATION { diff --git a/crates/apub/src/api/read_community.rs b/crates/apub/src/api/read_community.rs index 12e17dac..1bdfb88a 100644 --- a/crates/apub/src/api/read_community.rs +++ b/crates/apub/src/api/read_community.rs @@ -16,7 +16,7 @@ use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView}; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorExt2, LemmyErrorType}; #[tracing::instrument(skip(context))] -pub async fn read_community( +pub async fn get_community( data: Query, context: Data, ) -> Result, LemmyError> { diff --git a/crates/utils/translations b/crates/utils/translations index 713ceed9..1c42c579 160000 --- a/crates/utils/translations +++ b/crates/utils/translations @@ -1 +1 @@ -Subproject commit 713ceed9c7ef84deaa222e68361e670e0763cd83 +Subproject commit 1c42c579460871de7b4ea18e58dc25543b80d289 diff --git a/src/api_routes_http.rs b/src/api_routes_http.rs index bc4340e3..e372e340 100644 --- a/src/api_routes_http.rs +++ b/src/api_routes_http.rs @@ -1,19 +1,12 @@ use actix_web::{guard, web, Error, HttpResponse, Result}; -use lemmy_api::Perform; +use lemmy_api::{ + comment::{distinguish::distinguish_comment, save::save_comment}, + comment_report::{list::list_comment_reports, resolve::resolve_comment_report}, + local_user::notifications::mark_reply_read::mark_reply_as_read, + Perform, +}; use lemmy_api_common::{ - comment::{ - CreateComment, - CreateCommentLike, - CreateCommentReport, - DeleteComment, - DistinguishComment, - EditComment, - GetComment, - ListCommentReports, - RemoveComment, - ResolveCommentReport, - SaveComment, - }, + comment::{CreateCommentLike, CreateCommentReport, DeleteComment, EditComment, RemoveComment}, community::{ AddModToCommunity, BanFromCommunity, @@ -23,7 +16,6 @@ use lemmy_api_common::{ EditCommunity, FollowCommunity, HideCommunity, - ListCommunities, RemoveCommunity, TransferCommunity, }, @@ -43,7 +35,6 @@ use lemmy_api_common::{ GetUnreadCount, Login, MarkAllAsRead, - MarkCommentReplyAsRead, MarkPersonMentionAsRead, PasswordChangeAfterReset, PasswordReset, @@ -57,7 +48,6 @@ use lemmy_api_common::{ DeletePost, EditPost, FeaturePost, - GetPost, GetSiteMetadata, ListPostReports, LockPost, @@ -71,18 +61,14 @@ use lemmy_api_common::{ CreatePrivateMessageReport, DeletePrivateMessage, EditPrivateMessage, - GetPrivateMessages, ListPrivateMessageReports, MarkPrivateMessageAsRead, ResolvePrivateMessageReport, }, site::{ ApproveRegistrationApplication, - CreateSite, - EditSite, GetFederatedInstances, GetModlog, - GetSite, GetUnreadRegistrationApplicationCount, LeaveAdmin, ListRegistrationApplications, @@ -92,12 +78,19 @@ use lemmy_api_common::{ PurgePost, }, }; -use lemmy_api_crud::{post::create::create_post, PerformCrud}; +use lemmy_api_crud::{ + comment::{create::create_comment, read::get_comment}, + community::list::list_communities, + post::{create::create_post, read::get_post}, + private_message::read::get_private_message, + site::{create::create_site, read::get_site, update::update_site}, + PerformCrud, +}; use lemmy_apub::{ api::{ list_comments::list_comments, list_posts::list_posts, - read_community::read_community, + read_community::get_community, read_person::read_person, resolve_object::resolve_object, search::search, @@ -114,10 +107,10 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) { .service( web::scope("/site") .wrap(rate_limit.message()) - .route("", web::get().to(route_get_crud::)) + .route("", web::get().to(get_site)) // Admin Actions - .route("", web::post().to(route_post_crud::)) - .route("", web::put().to(route_post_crud::)), + .route("", web::post().to(create_site)) + .route("", web::put().to(update_site)), ) .service( web::resource("/modlog") @@ -144,10 +137,10 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) { .service( web::scope("/community") .wrap(rate_limit.message()) - .route("", web::get().to(read_community)) + .route("", web::get().to(get_community)) .route("", web::put().to(route_post_crud::)) .route("/hide", web::put().to(route_post::)) - .route("/list", web::get().to(route_get_crud::)) + .route("/list", web::get().to(list_communities)) .route("/follow", web::post().to(route_post::)) .route("/block", web::post().to(route_post::)) .route( @@ -179,7 +172,7 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) { .service( web::scope("/post") .wrap(rate_limit.message()) - .route("", web::get().to(route_get_crud::)) + .route("", web::get().to(get_post)) .route("", web::put().to(route_post_crud::)) .route("/delete", web::post().to(route_post_crud::)) .route("/remove", web::post().to(route_post_crud::)) @@ -209,41 +202,29 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) { web::resource("/comment") .guard(guard::Post()) .wrap(rate_limit.comment()) - .route(web::post().to(route_post_crud::)), + .route(web::post().to(create_comment)), ) .service( web::scope("/comment") .wrap(rate_limit.message()) - .route("", web::get().to(route_get_crud::)) + .route("", web::get().to(get_comment)) .route("", web::put().to(route_post_crud::)) .route("/delete", web::post().to(route_post_crud::)) .route("/remove", web::post().to(route_post_crud::)) - .route( - "/mark_as_read", - web::post().to(route_post::), - ) - .route( - "/distinguish", - web::post().to(route_post::), - ) + .route("/mark_as_read", web::post().to(mark_reply_as_read)) + .route("/distinguish", web::post().to(distinguish_comment)) .route("/like", web::post().to(route_post::)) - .route("/save", web::put().to(route_post::)) + .route("/save", web::put().to(save_comment)) .route("/list", web::get().to(list_comments)) .route("/report", web::post().to(route_post::)) - .route( - "/report/resolve", - web::put().to(route_post::), - ) - .route( - "/report/list", - web::get().to(route_get::), - ), + .route("/report/resolve", web::put().to(resolve_comment_report)) + .route("/report/list", web::get().to(list_comment_reports)), ) // Private Message .service( web::scope("/private_message") .wrap(rate_limit.message()) - .route("/list", web::get().to(route_get_crud::)) + .route("/list", web::get().to(get_private_message)) .route("", web::post().to(route_post_crud::)) .route("", web::put().to(route_post_crud::)) .route( @@ -447,22 +428,6 @@ where Ok(HttpResponse::Ok().json(&res)) } -async fn route_get_crud<'a, Data>( - data: web::Query, - context: web::Data, - apub_data: activitypub_federation::config::Data, -) -> Result -where - Data: PerformCrud - + SendActivity::Response> - + Clone - + Deserialize<'a> - + Send - + 'static, -{ - perform_crud::(data.0, context, apub_data).await -} - async fn route_post_crud<'a, Data>( data: web::Json, context: web::Data, -- 2.44.1