From 366d9d1e2edfc612f7870a0309040e25f3f181f2 Mon Sep 17 00:00:00 2001 From: Nutomic Date: Tue, 5 Sep 2023 11:33:46 +0200 Subject: [PATCH] Get rid of remaining Perform/SendActivity traits (fixes #3670) (#3926) * Get rid of remaining Perform/SendActivity traits (fixes #3670) * fix api tests * ci --- crates/api/src/community/transfer.rs | 130 ++++--- crates/api/src/lib.rs | 10 +- crates/api/src/local_user/add_admin.rs | 60 ++-- crates/api/src/local_user/block.rs | 80 +++-- crates/api/src/local_user/change_password.rs | 84 +++-- .../local_user/change_password_after_reset.rs | 59 ++-- crates/api/src/local_user/get_captcha.rs | 71 ++-- crates/api/src/local_user/list_banned.rs | 24 +- crates/api/src/local_user/login.rs | 125 ++++--- .../local_user/notifications/list_mentions.rs | 57 ++-- .../local_user/notifications/list_replies.rs | 54 ++- .../local_user/notifications/mark_all_read.rs | 46 ++- .../notifications/mark_mention_read.rs | 67 ++-- .../local_user/notifications/unread_count.rs | 38 +-- crates/api/src/local_user/report_count.rs | 59 ++-- crates/api/src/local_user/reset_password.rs | 54 ++- crates/api/src/local_user/save_settings.rs | 286 ++++++++-------- crates/api/src/local_user/verify_email.rs | 43 ++- crates/api/src/post/get_link_metadata.rs | 24 +- crates/api/src/post/mark_read.rs | 45 ++- crates/api/src/post/save.rs | 60 ++-- crates/api/src/post_report/list.rs | 47 ++- crates/api/src/post_report/resolve.rs | 52 ++- crates/api/src/private_message/mark_read.rs | 70 ++-- crates/api/src/private_message/mod.rs | 2 +- .../api/src/private_message_report/create.rs | 82 +++-- crates/api/src/private_message_report/list.rs | 45 ++- crates/api/src/private_message_report/mod.rs | 6 +- .../api/src/private_message_report/resolve.rs | 53 ++- crates/api/src/site/federated_instances.rs | 28 +- crates/api/src/site/leave_admin.rs | 110 +++--- crates/api/src/site/mod.rs | 10 +- crates/api/src/site/mod_log.rs | 297 ++++++++-------- crates/api/src/site/purge/comment.rs | 52 ++- crates/api/src/site/purge/community.rs | 70 ++-- crates/api/src/site/purge/mod.rs | 8 +- crates/api/src/site/purge/person.rs | 70 ++-- crates/api/src/site/purge/post.rs | 74 ++-- .../site/registration_applications/approve.rs | 78 ++--- .../site/registration_applications/list.rs | 52 ++- .../src/site/registration_applications/mod.rs | 6 +- .../registration_applications/unread_count.rs | 35 +- crates/api_common/README.md | 2 +- crates/api_common/src/person.rs | 9 - crates/api_common/src/site.rs | 9 - crates/apub/src/activities/mod.rs | 1 - crates/apub/src/activities/unfederated.rs | 320 ------------------ crates/apub/src/lib.rs | 13 - src/api_routes_http.rs | 277 ++++++--------- 49 files changed, 1373 insertions(+), 1981 deletions(-) delete mode 100644 crates/apub/src/activities/unfederated.rs diff --git a/crates/api/src/community/transfer.rs b/crates/api/src/community/transfer.rs index 351389941..1dc5a96e0 100644 --- a/crates/api/src/community/transfer.rs +++ b/crates/api/src/community/transfer.rs @@ -1,5 +1,4 @@ -use crate::Perform; -use actix_web::web::Data; +use actix_web::web::{Data, Json}; use anyhow::Context; use lemmy_api_common::{ community::{GetCommunityResponse, TransferCommunity}, @@ -21,84 +20,77 @@ use lemmy_utils::{ // TODO: we dont do anything for federation here, it should be updated the next time the community // gets fetched. i hope we can get rid of the community creator role soon. -#[async_trait::async_trait(?Send)] -impl Perform for TransferCommunity { - type Response = GetCommunityResponse; +#[tracing::instrument(skip(context))] +pub async fn transfer_community( + 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: &TransferCommunity = self; - let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; + // Fetch the community mods + let community_id = data.community_id; + let mut community_mods = + CommunityModeratorView::for_community(&mut context.pool(), community_id).await?; - // Fetch the community mods - let community_id = data.community_id; - let mut community_mods = - CommunityModeratorView::for_community(&mut context.pool(), community_id).await?; + // Make sure transferrer is either the top community mod, or an admin + if !(is_top_mod(&local_user_view, &community_mods).is_ok() || is_admin(&local_user_view).is_ok()) + { + Err(LemmyErrorType::NotAnAdmin)? + } - // Make sure transferrer is either the top community mod, or an admin - if !(is_top_mod(&local_user_view, &community_mods).is_ok() - || is_admin(&local_user_view).is_ok()) - { - Err(LemmyErrorType::NotAnAdmin)? - } + // You have to re-do the community_moderator table, reordering it. + // Add the transferee to the top + let creator_index = community_mods + .iter() + .position(|r| r.moderator.id == data.person_id) + .context(location_info!())?; + let creator_person = community_mods.remove(creator_index); + community_mods.insert(0, creator_person); - // You have to re-do the community_moderator table, reordering it. - // Add the transferee to the top - let creator_index = community_mods - .iter() - .position(|r| r.moderator.id == data.person_id) - .context(location_info!())?; - let creator_person = community_mods.remove(creator_index); - community_mods.insert(0, creator_person); + // Delete all the mods + let community_id = data.community_id; - // Delete all the mods - let community_id = data.community_id; + CommunityModerator::delete_for_community(&mut context.pool(), community_id).await?; - CommunityModerator::delete_for_community(&mut context.pool(), community_id).await?; - - // TODO: this should probably be a bulk operation - // Re-add the mods, in the new order - for cmod in &community_mods { - let community_moderator_form = CommunityModeratorForm { - community_id: cmod.community.id, - person_id: cmod.moderator.id, - }; - - CommunityModerator::join(&mut context.pool(), &community_moderator_form) - .await - .with_lemmy_type(LemmyErrorType::CommunityModeratorAlreadyExists)?; - } - - // Mod tables - let form = ModTransferCommunityForm { - mod_person_id: local_user_view.person.id, - other_person_id: data.person_id, - community_id: data.community_id, + // TODO: this should probably be a bulk operation + // Re-add the mods, in the new order + for cmod in &community_mods { + let community_moderator_form = CommunityModeratorForm { + community_id: cmod.community.id, + person_id: cmod.moderator.id, }; - ModTransferCommunity::create(&mut context.pool(), &form).await?; + CommunityModerator::join(&mut context.pool(), &community_moderator_form) + .await + .with_lemmy_type(LemmyErrorType::CommunityModeratorAlreadyExists)?; + } - let community_id = data.community_id; - let person_id = local_user_view.person.id; - let community_view = - CommunityView::read(&mut context.pool(), community_id, Some(person_id), false) - .await - .with_lemmy_type(LemmyErrorType::CouldntFindCommunity)?; + // Mod tables + let form = ModTransferCommunityForm { + mod_person_id: local_user_view.person.id, + other_person_id: data.person_id, + community_id: data.community_id, + }; - let community_id = data.community_id; - let moderators = CommunityModeratorView::for_community(&mut context.pool(), community_id) + ModTransferCommunity::create(&mut context.pool(), &form).await?; + + let community_id = data.community_id; + let person_id = local_user_view.person.id; + let community_view = + CommunityView::read(&mut context.pool(), community_id, Some(person_id), false) .await .with_lemmy_type(LemmyErrorType::CouldntFindCommunity)?; - // Return the jwt - Ok(GetCommunityResponse { - community_view, - site: None, - moderators, - discussion_languages: vec![], - }) - } + let community_id = data.community_id; + let moderators = CommunityModeratorView::for_community(&mut context.pool(), community_id) + .await + .with_lemmy_type(LemmyErrorType::CouldntFindCommunity)?; + + // Return the jwt + Ok(Json(GetCommunityResponse { + community_view, + site: None, + moderators, + discussion_languages: vec![], + })) } diff --git a/crates/api/src/lib.rs b/crates/api/src/lib.rs index 8a45b41c9..65c8d0551 100644 --- a/crates/api/src/lib.rs +++ b/crates/api/src/lib.rs @@ -1,7 +1,6 @@ -use actix_web::web::Data; use base64::{engine::general_purpose::STANDARD_NO_PAD as base64, Engine}; use captcha::Captcha; -use lemmy_api_common::{context::LemmyContext, utils::local_site_to_slur_regex}; +use lemmy_api_common::utils::local_site_to_slur_regex; use lemmy_db_schema::source::local_site::LocalSite; use lemmy_utils::{ error::{LemmyError, LemmyErrorExt, LemmyErrorType}, @@ -20,13 +19,6 @@ pub mod private_message_report; pub mod site; pub mod sitemap; -#[async_trait::async_trait(?Send)] -pub trait Perform { - type Response: serde::ser::Serialize + Send + Clone + Sync; - - async fn perform(&self, context: &Data) -> Result; -} - /// Converts the captcha to a base64 encoded wav audio file pub(crate) fn captcha_as_wav_base64(captcha: &Captcha) -> Result { let letters = captcha.as_wav(); diff --git a/crates/api/src/local_user/add_admin.rs b/crates/api/src/local_user/add_admin.rs index 6800b75a5..adcd0c940 100644 --- a/crates/api/src/local_user/add_admin.rs +++ b/crates/api/src/local_user/add_admin.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::{AddAdmin, AddAdminResponse}, @@ -15,40 +14,37 @@ use lemmy_db_schema::{ use lemmy_db_views_actor::structs::PersonView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; -#[async_trait::async_trait(?Send)] -impl Perform for AddAdmin { - type Response = AddAdminResponse; +#[tracing::instrument(skip(context))] +pub async fn add_admin( + 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: &AddAdmin = self; - let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; + // Make sure user is an admin + is_admin(&local_user_view)?; - // Make sure user is an admin - is_admin(&local_user_view)?; + let added_admin = LocalUser::update( + &mut context.pool(), + data.local_user_id, + &LocalUserUpdateForm { + admin: Some(data.added), + ..Default::default() + }, + ) + .await + .with_lemmy_type(LemmyErrorType::CouldntUpdateUser)?; - let added_admin = LocalUser::update( - &mut context.pool(), - data.local_user_id, - &LocalUserUpdateForm { - admin: Some(data.added), - ..Default::default() - }, - ) - .await - .with_lemmy_type(LemmyErrorType::CouldntUpdateUser)?; + // Mod tables + let form = ModAddForm { + mod_person_id: local_user_view.person.id, + other_person_id: added_admin.person_id, + removed: Some(!data.added), + }; - // Mod tables - let form = ModAddForm { - mod_person_id: local_user_view.person.id, - other_person_id: added_admin.person_id, - removed: Some(!data.added), - }; + ModAdd::create(&mut context.pool(), &form).await?; - ModAdd::create(&mut context.pool(), &form).await?; + let admins = PersonView::admins(&mut context.pool()).await?; - let admins = PersonView::admins(&mut context.pool()).await?; - - Ok(AddAdminResponse { admins }) - } + Ok(Json(AddAdminResponse { admins })) } diff --git a/crates/api/src/local_user/block.rs b/crates/api/src/local_user/block.rs index 3d7acd4ba..77a23aef3 100644 --- a/crates/api/src/local_user/block.rs +++ b/crates/api/src/local_user/block.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::{BlockPerson, BlockPersonResponse}, @@ -13,47 +12,44 @@ use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::structs::PersonView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; -#[async_trait::async_trait(?Send)] -impl Perform for BlockPerson { - type Response = BlockPersonResponse; +#[tracing::instrument(skip(context))] +pub async fn block_person( + 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: &BlockPerson = self; - let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; + let target_id = data.person_id; + let person_id = local_user_view.person.id; - let target_id = data.person_id; - let person_id = local_user_view.person.id; - - // Don't let a person block themselves - if target_id == person_id { - Err(LemmyErrorType::CantBlockYourself)? - } - - let person_block_form = PersonBlockForm { - person_id, - target_id, - }; - - let target_user = LocalUserView::read_person(&mut context.pool(), target_id).await; - if target_user.map(|t| t.local_user.admin) == Ok(true) { - Err(LemmyErrorType::CantBlockAdmin)? - } - - if data.block { - PersonBlock::block(&mut context.pool(), &person_block_form) - .await - .with_lemmy_type(LemmyErrorType::PersonBlockAlreadyExists)?; - } else { - PersonBlock::unblock(&mut context.pool(), &person_block_form) - .await - .with_lemmy_type(LemmyErrorType::PersonBlockAlreadyExists)?; - } - - let person_view = PersonView::read(&mut context.pool(), target_id).await?; - Ok(BlockPersonResponse { - person_view, - blocked: data.block, - }) + // Don't let a person block themselves + if target_id == person_id { + Err(LemmyErrorType::CantBlockYourself)? } + + let person_block_form = PersonBlockForm { + person_id, + target_id, + }; + + let target_user = LocalUserView::read_person(&mut context.pool(), target_id).await; + if target_user.map(|t| t.local_user.admin) == Ok(true) { + Err(LemmyErrorType::CantBlockAdmin)? + } + + if data.block { + PersonBlock::block(&mut context.pool(), &person_block_form) + .await + .with_lemmy_type(LemmyErrorType::PersonBlockAlreadyExists)?; + } else { + PersonBlock::unblock(&mut context.pool(), &person_block_form) + .await + .with_lemmy_type(LemmyErrorType::PersonBlockAlreadyExists)?; + } + + let person_view = PersonView::read(&mut context.pool(), target_id).await?; + Ok(Json(BlockPersonResponse { + person_view, + blocked: data.block, + })) } diff --git a/crates/api/src/local_user/change_password.rs b/crates/api/src/local_user/change_password.rs index fa5797514..532c8ed7c 100644 --- a/crates/api/src/local_user/change_password.rs +++ b/crates/api/src/local_user/change_password.rs @@ -1,5 +1,4 @@ -use crate::Perform; -use actix_web::web::Data; +use actix_web::web::{Data, Json}; use bcrypt::verify; use lemmy_api_common::{ context::LemmyContext, @@ -12,49 +11,46 @@ use lemmy_utils::{ error::{LemmyError, LemmyErrorType}, }; -#[async_trait::async_trait(?Send)] -impl Perform for ChangePassword { - type Response = LoginResponse; +#[tracing::instrument(skip(context))] +pub async fn change_password( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(data.auth.as_ref(), &context).await?; - #[tracing::instrument(skip(self, context))] - async fn perform(&self, context: &Data) -> Result { - let data: &ChangePassword = self; - let local_user_view = local_user_view_from_jwt(data.auth.as_ref(), context).await?; + password_length_check(&data.new_password)?; - password_length_check(&data.new_password)?; - - // Make sure passwords match - if data.new_password != data.new_password_verify { - Err(LemmyErrorType::PasswordsDoNotMatch)? - } - - // Check the old password - let valid: bool = verify( - &data.old_password, - &local_user_view.local_user.password_encrypted, - ) - .unwrap_or(false); - if !valid { - Err(LemmyErrorType::IncorrectLogin)? - } - - let local_user_id = local_user_view.local_user.id; - let new_password = data.new_password.clone(); - let updated_local_user = - LocalUser::update_password(&mut context.pool(), local_user_id, &new_password).await?; - - // Return the jwt - Ok(LoginResponse { - jwt: Some( - Claims::jwt( - updated_local_user.id.0, - &context.secret().jwt_secret, - &context.settings().hostname, - )? - .into(), - ), - verify_email_sent: false, - registration_created: false, - }) + // Make sure passwords match + if data.new_password != data.new_password_verify { + Err(LemmyErrorType::PasswordsDoNotMatch)? } + + // Check the old password + let valid: bool = verify( + &data.old_password, + &local_user_view.local_user.password_encrypted, + ) + .unwrap_or(false); + if !valid { + Err(LemmyErrorType::IncorrectLogin)? + } + + let local_user_id = local_user_view.local_user.id; + let new_password = data.new_password.clone(); + let updated_local_user = + LocalUser::update_password(&mut context.pool(), local_user_id, &new_password).await?; + + // Return the jwt + Ok(Json(LoginResponse { + jwt: Some( + Claims::jwt( + updated_local_user.id.0, + &context.secret().jwt_secret, + &context.settings().hostname, + )? + .into(), + ), + verify_email_sent: false, + registration_created: false, + })) } diff --git a/crates/api/src/local_user/change_password_after_reset.rs b/crates/api/src/local_user/change_password_after_reset.rs index f89d5f78f..1bb501dd6 100644 --- a/crates/api/src/local_user/change_password_after_reset.rs +++ b/crates/api/src/local_user/change_password_after_reset.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::{LoginResponse, PasswordChangeAfterReset}, @@ -11,37 +10,33 @@ use lemmy_db_schema::source::{ }; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; -#[async_trait::async_trait(?Send)] -impl Perform for PasswordChangeAfterReset { - type Response = LoginResponse; +#[tracing::instrument(skip(context))] +pub async fn change_password_after_reset( + data: Json, + context: Data, +) -> Result, LemmyError> { + // Fetch the user_id from the token + let token = data.token.clone(); + let local_user_id = PasswordResetRequest::read_from_token(&mut context.pool(), &token) + .await + .map(|p| p.local_user_id)?; - #[tracing::instrument(skip(self, context))] - async fn perform(&self, context: &Data) -> Result { - let data: &PasswordChangeAfterReset = self; + password_length_check(&data.password)?; - // Fetch the user_id from the token - let token = data.token.clone(); - let local_user_id = PasswordResetRequest::read_from_token(&mut context.pool(), &token) - .await - .map(|p| p.local_user_id)?; - - password_length_check(&data.password)?; - - // Make sure passwords match - if data.password != data.password_verify { - Err(LemmyErrorType::PasswordsDoNotMatch)? - } - - // Update the user with the new password - let password = data.password.clone(); - LocalUser::update_password(&mut context.pool(), local_user_id, &password) - .await - .with_lemmy_type(LemmyErrorType::CouldntUpdateUser)?; - - Ok(LoginResponse { - jwt: None, - verify_email_sent: false, - registration_created: false, - }) + // Make sure passwords match + if data.password != data.password_verify { + Err(LemmyErrorType::PasswordsDoNotMatch)? } + + // Update the user with the new password + let password = data.password.clone(); + LocalUser::update_password(&mut context.pool(), local_user_id, &password) + .await + .with_lemmy_type(LemmyErrorType::CouldntUpdateUser)?; + + Ok(Json(LoginResponse { + jwt: None, + verify_email_sent: false, + registration_created: false, + })) } diff --git a/crates/api/src/local_user/get_captcha.rs b/crates/api/src/local_user/get_captcha.rs index 5f1079ef2..5d692aa0c 100644 --- a/crates/api/src/local_user/get_captcha.rs +++ b/crates/api/src/local_user/get_captcha.rs @@ -1,9 +1,9 @@ -use crate::{captcha_as_wav_base64, Perform}; -use actix_web::web::Data; +use crate::captcha_as_wav_base64; +use actix_web::web::{Data, Json}; use captcha::{gen, Difficulty}; use lemmy_api_common::{ context::LemmyContext, - person::{CaptchaResponse, GetCaptcha, GetCaptchaResponse}, + person::{CaptchaResponse, GetCaptchaResponse}, }; use lemmy_db_schema::source::{ captcha_answer::{CaptchaAnswer, CaptchaAnswerForm}, @@ -11,40 +11,37 @@ use lemmy_db_schema::source::{ }; use lemmy_utils::error::LemmyError; -#[async_trait::async_trait(?Send)] -impl Perform for GetCaptcha { - type Response = GetCaptchaResponse; +#[tracing::instrument(skip(context))] +pub async fn get_captcha( + context: Data, +) -> Result, LemmyError> { + let local_site = LocalSite::read(&mut context.pool()).await?; - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let local_site = LocalSite::read(&mut context.pool()).await?; - - if !local_site.captcha_enabled { - return Ok(GetCaptchaResponse { ok: None }); - } - - let captcha = gen(match local_site.captcha_difficulty.as_str() { - "easy" => Difficulty::Easy, - "hard" => Difficulty::Hard, - _ => Difficulty::Medium, - }); - - let answer = captcha.chars_as_string(); - - let png = captcha.as_base64().expect("failed to generate captcha"); - - let wav = captcha_as_wav_base64(&captcha)?; - - let captcha_form: CaptchaAnswerForm = CaptchaAnswerForm { answer }; - // Stores the captcha item in the db - let captcha = CaptchaAnswer::insert(&mut context.pool(), &captcha_form).await?; - - Ok(GetCaptchaResponse { - ok: Some(CaptchaResponse { - png, - wav, - uuid: captcha.uuid.to_string(), - }), - }) + if !local_site.captcha_enabled { + return Ok(Json(GetCaptchaResponse { ok: None })); } + + let captcha = gen(match local_site.captcha_difficulty.as_str() { + "easy" => Difficulty::Easy, + "hard" => Difficulty::Hard, + _ => Difficulty::Medium, + }); + + let answer = captcha.chars_as_string(); + + let png = captcha.as_base64().expect("failed to generate captcha"); + + let wav = captcha_as_wav_base64(&captcha)?; + + let captcha_form: CaptchaAnswerForm = CaptchaAnswerForm { answer }; + // Stores the captcha item in the db + let captcha = CaptchaAnswer::insert(&mut context.pool(), &captcha_form).await?; + + Ok(Json(GetCaptchaResponse { + ok: Some(CaptchaResponse { + png, + wav, + uuid: captcha.uuid.to_string(), + }), + })) } diff --git a/crates/api/src/local_user/list_banned.rs b/crates/api/src/local_user/list_banned.rs index 9391a4bbf..c4c0a98ae 100644 --- a/crates/api/src/local_user/list_banned.rs +++ b/crates/api/src/local_user/list_banned.rs @@ -1,5 +1,4 @@ -use crate::Perform; -use actix_web::web::Data; +use actix_web::web::{Data, Json, Query}; use lemmy_api_common::{ context::LemmyContext, person::{BannedPersonsResponse, GetBannedPersons}, @@ -8,19 +7,16 @@ use lemmy_api_common::{ use lemmy_db_views_actor::structs::PersonView; use lemmy_utils::error::LemmyError; -#[async_trait::async_trait(?Send)] -impl Perform for GetBannedPersons { - type Response = BannedPersonsResponse; +pub async fn list_banned_users( + data: Query, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - async fn perform(&self, context: &Data) -> Result { - let data: &GetBannedPersons = self; - let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; + // Make sure user is an admin + is_admin(&local_user_view)?; - // Make sure user is an admin - is_admin(&local_user_view)?; + let banned = PersonView::banned(&mut context.pool()).await?; - let banned = PersonView::banned(&mut context.pool()).await?; - - Ok(Self::Response { banned }) - } + Ok(Json(BannedPersonsResponse { banned })) } diff --git a/crates/api/src/local_user/login.rs b/crates/api/src/local_user/login.rs index 9b71f74c3..915aff939 100644 --- a/crates/api/src/local_user/login.rs +++ b/crates/api/src/local_user/login.rs @@ -1,5 +1,4 @@ -use crate::Perform; -use actix_web::web::Data; +use actix_web::web::{Data, Json}; use bcrypt::verify; use lemmy_api_common::{ context::LemmyContext, @@ -13,70 +12,66 @@ use lemmy_utils::{ utils::validation::check_totp_2fa_valid, }; -#[async_trait::async_trait(?Send)] -impl Perform for Login { - type Response = LoginResponse; +#[tracing::instrument(skip(context))] +pub async fn login( + data: Json, + context: Data, +) -> Result, LemmyError> { + let site_view = SiteView::read_local(&mut context.pool()).await?; - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data: &Login = self; + // Fetch that username / email + let username_or_email = data.username_or_email.clone(); + let local_user_view = + LocalUserView::find_by_email_or_name(&mut context.pool(), &username_or_email) + .await + .with_lemmy_type(LemmyErrorType::IncorrectLogin)?; - let site_view = SiteView::read_local(&mut context.pool()).await?; - - // Fetch that username / email - let username_or_email = data.username_or_email.clone(); - let local_user_view = - LocalUserView::find_by_email_or_name(&mut context.pool(), &username_or_email) - .await - .with_lemmy_type(LemmyErrorType::IncorrectLogin)?; - - // Verify the password - let valid: bool = verify( - &data.password, - &local_user_view.local_user.password_encrypted, - ) - .unwrap_or(false); - if !valid { - Err(LemmyErrorType::IncorrectLogin)? - } - check_user_valid( - local_user_view.person.banned, - local_user_view.person.ban_expires, - local_user_view.person.deleted, - )?; - - // Check if the user's email is verified if email verification is turned on - // However, skip checking verification if the user is an admin - if !local_user_view.local_user.admin - && site_view.local_site.require_email_verification - && !local_user_view.local_user.email_verified - { - Err(LemmyErrorType::EmailNotVerified)? - } - - check_registration_application(&local_user_view, &site_view.local_site, &mut context.pool()) - .await?; - - // Check the totp - check_totp_2fa_valid( - &local_user_view.local_user.totp_2fa_secret, - &data.totp_2fa_token, - &site_view.site.name, - &local_user_view.person.name, - )?; - - // Return the jwt - Ok(LoginResponse { - jwt: Some( - Claims::jwt( - local_user_view.local_user.id.0, - &context.secret().jwt_secret, - &context.settings().hostname, - )? - .into(), - ), - verify_email_sent: false, - registration_created: false, - }) + // Verify the password + let valid: bool = verify( + &data.password, + &local_user_view.local_user.password_encrypted, + ) + .unwrap_or(false); + if !valid { + Err(LemmyErrorType::IncorrectLogin)? } + check_user_valid( + local_user_view.person.banned, + local_user_view.person.ban_expires, + local_user_view.person.deleted, + )?; + + // Check if the user's email is verified if email verification is turned on + // However, skip checking verification if the user is an admin + if !local_user_view.local_user.admin + && site_view.local_site.require_email_verification + && !local_user_view.local_user.email_verified + { + Err(LemmyErrorType::EmailNotVerified)? + } + + check_registration_application(&local_user_view, &site_view.local_site, &mut context.pool()) + .await?; + + // Check the totp + check_totp_2fa_valid( + &local_user_view.local_user.totp_2fa_secret, + &data.totp_2fa_token, + &site_view.site.name, + &local_user_view.person.name, + )?; + + // Return the jwt + Ok(Json(LoginResponse { + jwt: Some( + Claims::jwt( + local_user_view.local_user.id.0, + &context.secret().jwt_secret, + &context.settings().hostname, + )? + .into(), + ), + verify_email_sent: false, + registration_created: false, + })) } diff --git a/crates/api/src/local_user/notifications/list_mentions.rs b/crates/api/src/local_user/notifications/list_mentions.rs index 46b11f605..af32e31a8 100644 --- a/crates/api/src/local_user/notifications/list_mentions.rs +++ b/crates/api/src/local_user/notifications/list_mentions.rs @@ -1,5 +1,4 @@ -use crate::Perform; -use actix_web::web::Data; +use actix_web::web::{Data, Json, Query}; use lemmy_api_common::{ context::LemmyContext, person::{GetPersonMentions, GetPersonMentionsResponse}, @@ -8,37 +7,31 @@ use lemmy_api_common::{ use lemmy_db_views_actor::person_mention_view::PersonMentionQuery; use lemmy_utils::error::LemmyError; -#[async_trait::async_trait(?Send)] -impl Perform for GetPersonMentions { - type Response = GetPersonMentionsResponse; +#[tracing::instrument(skip(context))] +pub async fn list_mentions( + 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: &GetPersonMentions = self; - let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; + let sort = data.sort; + let page = data.page; + let limit = data.limit; + let unread_only = data.unread_only.unwrap_or_default(); + let person_id = Some(local_user_view.person.id); + let show_bot_accounts = local_user_view.local_user.show_bot_accounts; - let sort = data.sort; - let page = data.page; - let limit = data.limit; - let unread_only = data.unread_only.unwrap_or_default(); - let person_id = Some(local_user_view.person.id); - let show_bot_accounts = local_user_view.local_user.show_bot_accounts; - - let mentions = PersonMentionQuery { - recipient_id: person_id, - my_person_id: person_id, - sort, - unread_only, - show_bot_accounts, - page, - limit, - } - .list(&mut context.pool()) - .await?; - - Ok(GetPersonMentionsResponse { mentions }) + let mentions = PersonMentionQuery { + recipient_id: person_id, + my_person_id: person_id, + sort, + unread_only, + show_bot_accounts, + page, + limit, } + .list(&mut context.pool()) + .await?; + + Ok(Json(GetPersonMentionsResponse { mentions })) } diff --git a/crates/api/src/local_user/notifications/list_replies.rs b/crates/api/src/local_user/notifications/list_replies.rs index 370cd61b4..8a7658d72 100644 --- a/crates/api/src/local_user/notifications/list_replies.rs +++ b/crates/api/src/local_user/notifications/list_replies.rs @@ -1,5 +1,4 @@ -use crate::Perform; -use actix_web::web::Data; +use actix_web::web::{Data, Json, Query}; use lemmy_api_common::{ context::LemmyContext, person::{GetReplies, GetRepliesResponse}, @@ -8,34 +7,31 @@ use lemmy_api_common::{ use lemmy_db_views_actor::comment_reply_view::CommentReplyQuery; use lemmy_utils::error::LemmyError; -#[async_trait::async_trait(?Send)] -impl Perform for GetReplies { - type Response = GetRepliesResponse; +#[tracing::instrument(skip(context))] +pub async fn list_replies( + 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: &GetReplies = self; - let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; + let sort = data.sort; + let page = data.page; + let limit = data.limit; + let unread_only = data.unread_only.unwrap_or_default(); + let person_id = Some(local_user_view.person.id); + let show_bot_accounts = local_user_view.local_user.show_bot_accounts; - let sort = data.sort; - let page = data.page; - let limit = data.limit; - let unread_only = data.unread_only.unwrap_or_default(); - let person_id = Some(local_user_view.person.id); - let show_bot_accounts = local_user_view.local_user.show_bot_accounts; - - let replies = CommentReplyQuery { - recipient_id: person_id, - my_person_id: person_id, - sort, - unread_only, - show_bot_accounts, - page, - limit, - } - .list(&mut context.pool()) - .await?; - - Ok(GetRepliesResponse { replies }) + let replies = CommentReplyQuery { + recipient_id: person_id, + my_person_id: person_id, + sort, + unread_only, + show_bot_accounts, + page, + limit, } + .list(&mut context.pool()) + .await?; + + Ok(Json(GetRepliesResponse { replies })) } diff --git a/crates/api/src/local_user/notifications/mark_all_read.rs b/crates/api/src/local_user/notifications/mark_all_read.rs index d852263ef..a38b23c53 100644 --- a/crates/api/src/local_user/notifications/mark_all_read.rs +++ b/crates/api/src/local_user/notifications/mark_all_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::{GetRepliesResponse, MarkAllAsRead}, @@ -12,31 +11,28 @@ use lemmy_db_schema::source::{ }; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; -#[async_trait::async_trait(?Send)] -impl Perform for MarkAllAsRead { - type Response = GetRepliesResponse; +#[tracing::instrument(skip(context))] +pub async fn mark_all_notifications_read( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; + let person_id = local_user_view.person.id; - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data: &MarkAllAsRead = self; - let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; - let person_id = local_user_view.person.id; + // Mark all comment_replies as read + CommentReply::mark_all_as_read(&mut context.pool(), person_id) + .await + .with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?; - // Mark all comment_replies as read - CommentReply::mark_all_as_read(&mut context.pool(), person_id) - .await - .with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?; + // Mark all user mentions as read + PersonMention::mark_all_as_read(&mut context.pool(), person_id) + .await + .with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?; - // Mark all user mentions as read - PersonMention::mark_all_as_read(&mut context.pool(), person_id) - .await - .with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?; + // Mark all private_messages as read + PrivateMessage::mark_all_as_read(&mut context.pool(), person_id) + .await + .with_lemmy_type(LemmyErrorType::CouldntUpdatePrivateMessage)?; - // Mark all private_messages as read - PrivateMessage::mark_all_as_read(&mut context.pool(), person_id) - .await - .with_lemmy_type(LemmyErrorType::CouldntUpdatePrivateMessage)?; - - Ok(GetRepliesResponse { replies: vec![] }) - } + Ok(Json(GetRepliesResponse { replies: vec![] })) } diff --git a/crates/api/src/local_user/notifications/mark_mention_read.rs b/crates/api/src/local_user/notifications/mark_mention_read.rs index 95233213b..f4529015d 100644 --- a/crates/api/src/local_user/notifications/mark_mention_read.rs +++ b/crates/api/src/local_user/notifications/mark_mention_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::{MarkPersonMentionAsRead, PersonMentionResponse}, @@ -12,42 +11,36 @@ use lemmy_db_schema::{ use lemmy_db_views_actor::structs::PersonMentionView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; -#[async_trait::async_trait(?Send)] -impl Perform for MarkPersonMentionAsRead { - type Response = PersonMentionResponse; +#[tracing::instrument(skip(context))] +pub async fn mark_person_mention_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: &MarkPersonMentionAsRead = self; - let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; + let person_mention_id = data.person_mention_id; + let read_person_mention = PersonMention::read(&mut context.pool(), person_mention_id).await?; - let person_mention_id = data.person_mention_id; - let read_person_mention = PersonMention::read(&mut context.pool(), person_mention_id).await?; - - if local_user_view.person.id != read_person_mention.recipient_id { - Err(LemmyErrorType::CouldntUpdateComment)? - } - - let person_mention_id = read_person_mention.id; - let read = Some(data.read); - PersonMention::update( - &mut context.pool(), - person_mention_id, - &PersonMentionUpdateForm { read }, - ) - .await - .with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?; - - let person_mention_id = read_person_mention.id; - let person_id = local_user_view.person.id; - let person_mention_view = - PersonMentionView::read(&mut context.pool(), person_mention_id, Some(person_id)).await?; - - Ok(PersonMentionResponse { - person_mention_view, - }) + if local_user_view.person.id != read_person_mention.recipient_id { + Err(LemmyErrorType::CouldntUpdateComment)? } + + let person_mention_id = read_person_mention.id; + let read = Some(data.read); + PersonMention::update( + &mut context.pool(), + person_mention_id, + &PersonMentionUpdateForm { read }, + ) + .await + .with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?; + + let person_mention_id = read_person_mention.id; + let person_id = local_user_view.person.id; + let person_mention_view = + PersonMentionView::read(&mut context.pool(), person_mention_id, Some(person_id)).await?; + + Ok(Json(PersonMentionResponse { + person_mention_view, + })) } diff --git a/crates/api/src/local_user/notifications/unread_count.rs b/crates/api/src/local_user/notifications/unread_count.rs index 21622ddbf..0315609dd 100644 --- a/crates/api/src/local_user/notifications/unread_count.rs +++ b/crates/api/src/local_user/notifications/unread_count.rs @@ -1,5 +1,4 @@ -use crate::Perform; -use actix_web::web::Data; +use actix_web::web::{Data, Json, Query}; use lemmy_api_common::{ context::LemmyContext, person::{GetUnreadCount, GetUnreadCountResponse}, @@ -9,28 +8,25 @@ use lemmy_db_views::structs::PrivateMessageView; use lemmy_db_views_actor::structs::{CommentReplyView, PersonMentionView}; use lemmy_utils::error::LemmyError; -#[async_trait::async_trait(?Send)] -impl Perform for GetUnreadCount { - type Response = GetUnreadCountResponse; +#[tracing::instrument(skip(context))] +pub async fn unread_count( + 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 = self; - let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; + let person_id = local_user_view.person.id; - let person_id = local_user_view.person.id; + let replies = CommentReplyView::get_unread_replies(&mut context.pool(), person_id).await?; - let replies = CommentReplyView::get_unread_replies(&mut context.pool(), person_id).await?; + let mentions = PersonMentionView::get_unread_mentions(&mut context.pool(), person_id).await?; - let mentions = PersonMentionView::get_unread_mentions(&mut context.pool(), person_id).await?; + let private_messages = + PrivateMessageView::get_unread_messages(&mut context.pool(), person_id).await?; - let private_messages = - PrivateMessageView::get_unread_messages(&mut context.pool(), person_id).await?; - - Ok(Self::Response { - replies, - mentions, - private_messages, - }) - } + Ok(Json(GetUnreadCountResponse { + replies, + mentions, + private_messages, + })) } diff --git a/crates/api/src/local_user/report_count.rs b/crates/api/src/local_user/report_count.rs index 061372960..08be9c948 100644 --- a/crates/api/src/local_user/report_count.rs +++ b/crates/api/src/local_user/report_count.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::{GetReportCount, GetReportCountResponse}, @@ -8,40 +7,34 @@ use lemmy_api_common::{ use lemmy_db_views::structs::{CommentReportView, PostReportView, PrivateMessageReportView}; use lemmy_utils::error::LemmyError; -#[async_trait::async_trait(?Send)] -impl Perform for GetReportCount { - type Response = GetReportCountResponse; +#[tracing::instrument(skip(context))] +pub async fn report_count( + 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: &GetReportCount = self; - let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; + let person_id = local_user_view.person.id; + let admin = local_user_view.local_user.admin; + let community_id = data.community_id; - let person_id = local_user_view.person.id; - let admin = local_user_view.local_user.admin; - let community_id = data.community_id; + let comment_reports = + CommentReportView::get_report_count(&mut context.pool(), person_id, admin, community_id) + .await?; - let comment_reports = - CommentReportView::get_report_count(&mut context.pool(), person_id, admin, community_id) - .await?; + let post_reports = + PostReportView::get_report_count(&mut context.pool(), person_id, admin, community_id).await?; - let post_reports = - PostReportView::get_report_count(&mut context.pool(), person_id, admin, community_id).await?; + let private_message_reports = if admin && community_id.is_none() { + Some(PrivateMessageReportView::get_report_count(&mut context.pool()).await?) + } else { + None + }; - let private_message_reports = if admin && community_id.is_none() { - Some(PrivateMessageReportView::get_report_count(&mut context.pool()).await?) - } else { - None - }; - - Ok(GetReportCountResponse { - community_id, - comment_reports, - post_reports, - private_message_reports, - }) - } + Ok(Json(GetReportCountResponse { + community_id, + comment_reports, + post_reports, + private_message_reports, + })) } diff --git a/crates/api/src/local_user/reset_password.rs b/crates/api/src/local_user/reset_password.rs index 6f45a8ffd..6bdb6f8ef 100644 --- a/crates/api/src/local_user/reset_password.rs +++ b/crates/api/src/local_user/reset_password.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::{PasswordReset, PasswordResetResponse}, @@ -9,35 +8,28 @@ use lemmy_db_schema::source::password_reset_request::PasswordResetRequest; use lemmy_db_views::structs::LocalUserView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; -#[async_trait::async_trait(?Send)] -impl Perform for PasswordReset { - type Response = PasswordResetResponse; +#[tracing::instrument(skip(context))] +pub async fn reset_password( + data: Json, + context: Data, +) -> Result, LemmyError> { + // Fetch that email + let email = data.email.to_lowercase(); + let local_user_view = LocalUserView::find_by_email(&mut context.pool(), &email) + .await + .with_lemmy_type(LemmyErrorType::IncorrectLogin)?; - #[tracing::instrument(skip(self, context))] - async fn perform( - &self, - context: &Data, - ) -> Result { - let data: &PasswordReset = self; - - // Fetch that email - let email = data.email.to_lowercase(); - let local_user_view = LocalUserView::find_by_email(&mut context.pool(), &email) - .await - .with_lemmy_type(LemmyErrorType::IncorrectLogin)?; - - // Check for too many attempts (to limit potential abuse) - let recent_resets_count = PasswordResetRequest::get_recent_password_resets_count( - &mut context.pool(), - local_user_view.local_user.id, - ) - .await?; - if recent_resets_count >= 3 { - Err(LemmyErrorType::PasswordResetLimitReached)? - } - - // Email the pure token to the user. - send_password_reset_email(&local_user_view, &mut context.pool(), context.settings()).await?; - Ok(PasswordResetResponse {}) + // Check for too many attempts (to limit potential abuse) + let recent_resets_count = PasswordResetRequest::get_recent_password_resets_count( + &mut context.pool(), + local_user_view.local_user.id, + ) + .await?; + if recent_resets_count >= 3 { + Err(LemmyErrorType::PasswordResetLimitReached)? } + + // Email the pure token to the user. + send_password_reset_email(&local_user_view, &mut context.pool(), context.settings()).await?; + Ok(Json(PasswordResetResponse {})) } diff --git a/crates/api/src/local_user/save_settings.rs b/crates/api/src/local_user/save_settings.rs index 40328ff31..c45c69f7f 100644 --- a/crates/api/src/local_user/save_settings.rs +++ b/crates/api/src/local_user/save_settings.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::{LoginResponse, SaveUserSettings}, @@ -27,152 +26,149 @@ use lemmy_utils::{ }, }; -#[async_trait::async_trait(?Send)] -impl Perform for SaveUserSettings { - type Response = LoginResponse; +#[tracing::instrument(skip(context))] +pub async fn save_user_settings( + 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?; - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let data: &SaveUserSettings = 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 bio = sanitize_html_opt(&data.bio); + let display_name = sanitize_html_opt(&data.display_name); - let bio = sanitize_html_opt(&data.bio); - let display_name = sanitize_html_opt(&data.display_name); + let avatar = diesel_option_overwrite_to_url(&data.avatar)?; + let banner = diesel_option_overwrite_to_url(&data.banner)?; + let bio = diesel_option_overwrite(bio); + let display_name = diesel_option_overwrite(display_name); + let matrix_user_id = diesel_option_overwrite(data.matrix_user_id.clone()); + let email_deref = data.email.as_deref().map(str::to_lowercase); + let email = diesel_option_overwrite(email_deref.clone()); - let avatar = diesel_option_overwrite_to_url(&data.avatar)?; - let banner = diesel_option_overwrite_to_url(&data.banner)?; - let bio = diesel_option_overwrite(bio); - let display_name = diesel_option_overwrite(display_name); - let matrix_user_id = diesel_option_overwrite(data.matrix_user_id.clone()); - let email_deref = data.email.as_deref().map(str::to_lowercase); - let email = diesel_option_overwrite(email_deref.clone()); - - if let Some(Some(email)) = &email { - let previous_email = local_user_view.local_user.email.clone().unwrap_or_default(); - // Only send the verification email if there was an email change - if previous_email.ne(email) { - send_verification_email( - &local_user_view, - email, - &mut context.pool(), - context.settings(), - ) - .await?; - } + if let Some(Some(email)) = &email { + let previous_email = local_user_view.local_user.email.clone().unwrap_or_default(); + // Only send the verification email if there was an email change + if previous_email.ne(email) { + send_verification_email( + &local_user_view, + email, + &mut context.pool(), + context.settings(), + ) + .await?; } - - // When the site requires email, make sure email is not Some(None). IE, an overwrite to a None value - if let Some(email) = &email { - if email.is_none() && site_view.local_site.require_email_verification { - Err(LemmyErrorType::EmailRequired)? - } - } - - if let Some(Some(bio)) = &bio { - is_valid_bio_field(bio)?; - } - - if let Some(Some(display_name)) = &display_name { - is_valid_display_name( - display_name.trim(), - site_view.local_site.actor_name_max_length as usize, - )?; - } - - if let Some(Some(matrix_user_id)) = &matrix_user_id { - is_valid_matrix_id(matrix_user_id)?; - } - - let local_user_id = local_user_view.local_user.id; - let person_id = local_user_view.person.id; - let default_listing_type = data.default_listing_type; - let default_sort_type = data.default_sort_type; - let theme = sanitize_html_opt(&data.theme); - - let person_form = PersonUpdateForm { - display_name, - bio, - matrix_user_id, - bot_account: data.bot_account, - avatar, - banner, - ..Default::default() - }; - - Person::update(&mut context.pool(), person_id, &person_form) - .await - .with_lemmy_type(LemmyErrorType::UserAlreadyExists)?; - - if let Some(discussion_languages) = data.discussion_languages.clone() { - LocalUserLanguage::update(&mut context.pool(), discussion_languages, local_user_id).await?; - } - - // If generate_totp is Some(false), this will clear it out from the database. - let (totp_2fa_secret, totp_2fa_url) = if let Some(generate) = data.generate_totp_2fa { - if generate { - let secret = generate_totp_2fa_secret(); - let url = - build_totp_2fa(&site_view.site.name, &local_user_view.person.name, &secret)?.get_url(); - (Some(Some(secret)), Some(Some(url))) - } else { - (Some(None), Some(None)) - } - } else { - (None, None) - }; - - let local_user_form = LocalUserUpdateForm { - email, - show_avatars: data.show_avatars, - show_read_posts: data.show_read_posts, - show_new_post_notifs: data.show_new_post_notifs, - send_notifications_to_email: data.send_notifications_to_email, - show_nsfw: data.show_nsfw, - blur_nsfw: data.blur_nsfw, - auto_expand: data.auto_expand, - show_bot_accounts: data.show_bot_accounts, - show_scores: data.show_scores, - default_sort_type, - default_listing_type, - theme, - interface_language: data.interface_language.clone(), - totp_2fa_secret, - totp_2fa_url, - open_links_in_new_tab: data.open_links_in_new_tab, - infinite_scroll_enabled: data.infinite_scroll_enabled, - ..Default::default() - }; - - let local_user_res = - LocalUser::update(&mut context.pool(), local_user_id, &local_user_form).await; - let updated_local_user = match local_user_res { - Ok(u) => u, - Err(e) => { - let err_type = if e.to_string() - == "duplicate key value violates unique constraint \"local_user_email_key\"" - { - LemmyErrorType::EmailAlreadyExists - } else { - LemmyErrorType::UserAlreadyExists - }; - - return Err(e).with_lemmy_type(err_type); - } - }; - - // Return the jwt - Ok(LoginResponse { - jwt: Some( - Claims::jwt( - updated_local_user.id.0, - &context.secret().jwt_secret, - &context.settings().hostname, - )? - .into(), - ), - verify_email_sent: false, - registration_created: false, - }) } + + // When the site requires email, make sure email is not Some(None). IE, an overwrite to a None value + if let Some(email) = &email { + if email.is_none() && site_view.local_site.require_email_verification { + Err(LemmyErrorType::EmailRequired)? + } + } + + if let Some(Some(bio)) = &bio { + is_valid_bio_field(bio)?; + } + + if let Some(Some(display_name)) = &display_name { + is_valid_display_name( + display_name.trim(), + site_view.local_site.actor_name_max_length as usize, + )?; + } + + if let Some(Some(matrix_user_id)) = &matrix_user_id { + is_valid_matrix_id(matrix_user_id)?; + } + + let local_user_id = local_user_view.local_user.id; + let person_id = local_user_view.person.id; + let default_listing_type = data.default_listing_type; + let default_sort_type = data.default_sort_type; + let theme = sanitize_html_opt(&data.theme); + + let person_form = PersonUpdateForm { + display_name, + bio, + matrix_user_id, + bot_account: data.bot_account, + avatar, + banner, + ..Default::default() + }; + + Person::update(&mut context.pool(), person_id, &person_form) + .await + .with_lemmy_type(LemmyErrorType::UserAlreadyExists)?; + + if let Some(discussion_languages) = data.discussion_languages.clone() { + LocalUserLanguage::update(&mut context.pool(), discussion_languages, local_user_id).await?; + } + + // If generate_totp is Some(false), this will clear it out from the database. + let (totp_2fa_secret, totp_2fa_url) = if let Some(generate) = data.generate_totp_2fa { + if generate { + let secret = generate_totp_2fa_secret(); + let url = + build_totp_2fa(&site_view.site.name, &local_user_view.person.name, &secret)?.get_url(); + (Some(Some(secret)), Some(Some(url))) + } else { + (Some(None), Some(None)) + } + } else { + (None, None) + }; + + let local_user_form = LocalUserUpdateForm { + email, + show_avatars: data.show_avatars, + show_read_posts: data.show_read_posts, + show_new_post_notifs: data.show_new_post_notifs, + send_notifications_to_email: data.send_notifications_to_email, + show_nsfw: data.show_nsfw, + blur_nsfw: data.blur_nsfw, + auto_expand: data.auto_expand, + show_bot_accounts: data.show_bot_accounts, + show_scores: data.show_scores, + default_sort_type, + default_listing_type, + theme, + interface_language: data.interface_language.clone(), + totp_2fa_secret, + totp_2fa_url, + open_links_in_new_tab: data.open_links_in_new_tab, + infinite_scroll_enabled: data.infinite_scroll_enabled, + ..Default::default() + }; + + let local_user_res = + LocalUser::update(&mut context.pool(), local_user_id, &local_user_form).await; + let updated_local_user = match local_user_res { + Ok(u) => u, + Err(e) => { + let err_type = if e.to_string() + == "duplicate key value violates unique constraint \"local_user_email_key\"" + { + LemmyErrorType::EmailAlreadyExists + } else { + LemmyErrorType::UserAlreadyExists + }; + + return Err(e).with_lemmy_type(err_type); + } + }; + + // Return the jwt + Ok(Json(LoginResponse { + jwt: Some( + Claims::jwt( + updated_local_user.id.0, + &context.secret().jwt_secret, + &context.settings().hostname, + )? + .into(), + ), + verify_email_sent: false, + registration_created: false, + })) } diff --git a/crates/api/src/local_user/verify_email.rs b/crates/api/src/local_user/verify_email.rs index a15743ea4..6226e5041 100644 --- a/crates/api/src/local_user/verify_email.rs +++ b/crates/api/src/local_user/verify_email.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::{VerifyEmail, VerifyEmailResponse}, @@ -13,29 +12,27 @@ use lemmy_db_schema::{ }; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; -#[async_trait::async_trait(?Send)] -impl Perform for VerifyEmail { - type Response = VerifyEmailResponse; +pub async fn verify_email( + data: Json, + context: Data, +) -> Result, LemmyError> { + let token = data.token.clone(); + let verification = EmailVerification::read_for_token(&mut context.pool(), &token) + .await + .with_lemmy_type(LemmyErrorType::TokenNotFound)?; - async fn perform(&self, context: &Data) -> Result { - let token = self.token.clone(); - let verification = EmailVerification::read_for_token(&mut context.pool(), &token) - .await - .with_lemmy_type(LemmyErrorType::TokenNotFound)?; + let form = LocalUserUpdateForm { + // necessary in case this is a new signup + email_verified: Some(true), + // necessary in case email of an existing user was changed + email: Some(Some(verification.email)), + ..Default::default() + }; + let local_user_id = verification.local_user_id; - let form = LocalUserUpdateForm { - // necessary in case this is a new signup - email_verified: Some(true), - // necessary in case email of an existing user was changed - email: Some(Some(verification.email)), - ..Default::default() - }; - let local_user_id = verification.local_user_id; + LocalUser::update(&mut context.pool(), local_user_id, &form).await?; - LocalUser::update(&mut context.pool(), local_user_id, &form).await?; + EmailVerification::delete_old_tokens_for_local_user(&mut context.pool(), local_user_id).await?; - EmailVerification::delete_old_tokens_for_local_user(&mut context.pool(), local_user_id).await?; - - Ok(VerifyEmailResponse {}) - } + Ok(Json(VerifyEmailResponse {})) } diff --git a/crates/api/src/post/get_link_metadata.rs b/crates/api/src/post/get_link_metadata.rs index a67ea3f6f..7ab6e9a92 100644 --- a/crates/api/src/post/get_link_metadata.rs +++ b/crates/api/src/post/get_link_metadata.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, post::{GetSiteMetadata, GetSiteMetadataResponse}, @@ -7,19 +6,12 @@ use lemmy_api_common::{ }; use lemmy_utils::error::LemmyError; -#[async_trait::async_trait(?Send)] -impl Perform for GetSiteMetadata { - type Response = GetSiteMetadataResponse; +#[tracing::instrument(skip(context))] +pub async fn get_link_metadata( + data: Json, + context: Data, +) -> Result, LemmyError> { + let metadata = fetch_site_metadata(context.client(), &data.url).await?; - #[tracing::instrument(skip(context))] - async fn perform( - &self, - context: &Data, - ) -> Result { - let data: &Self = self; - - let metadata = fetch_site_metadata(context.client(), &data.url).await?; - - Ok(GetSiteMetadataResponse { metadata }) - } + Ok(Json(GetSiteMetadataResponse { metadata })) } diff --git a/crates/api/src/post/mark_read.rs b/crates/api/src/post/mark_read.rs index 99f539a92..ecb1b3448 100644 --- a/crates/api/src/post/mark_read.rs +++ b/crates/api/src/post/mark_read.rs @@ -1,35 +1,32 @@ -use crate::Perform; -use actix_web::web::Data; +use actix_web::web::{Data, Json}; use lemmy_api_common::{ context::LemmyContext, post::{MarkPostAsRead, PostResponse}, - utils::{local_user_view_from_jwt, mark_post_as_read, mark_post_as_unread}, + utils, + utils::local_user_view_from_jwt, }; use lemmy_db_views::structs::PostView; use lemmy_utils::error::LemmyError; -#[async_trait::async_trait(?Send)] -impl Perform for MarkPostAsRead { - type Response = PostResponse; +#[tracing::instrument(skip(context))] +pub async fn mark_post_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 post_id = data.post_id; + let person_id = local_user_view.person.id; - let post_id = data.post_id; - let person_id = local_user_view.person.id; - - // Mark the post as read / unread - if data.read { - mark_post_as_read(person_id, post_id, &mut context.pool()).await?; - } else { - mark_post_as_unread(person_id, post_id, &mut context.pool()).await?; - } - - // Fetch it - let post_view = PostView::read(&mut context.pool(), post_id, Some(person_id), false).await?; - - Ok(Self::Response { post_view }) + // Mark the post as read / unread + if data.read { + utils::mark_post_as_read(person_id, post_id, &mut context.pool()).await?; + } else { + utils::mark_post_as_unread(person_id, post_id, &mut context.pool()).await?; } + + // Fetch it + let post_view = PostView::read(&mut context.pool(), post_id, Some(person_id), false).await?; + + Ok(Json(PostResponse { post_view })) } diff --git a/crates/api/src/post/save.rs b/crates/api/src/post/save.rs index d9965dc75..ddad6ede4 100644 --- a/crates/api/src/post/save.rs +++ b/crates/api/src/post/save.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, post::{PostResponse, SavePost}, @@ -12,37 +11,34 @@ use lemmy_db_schema::{ use lemmy_db_views::structs::PostView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; -#[async_trait::async_trait(?Send)] -impl Perform for SavePost { - type Response = PostResponse; +#[tracing::instrument(skip(context))] +pub async fn save_post( + 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: &SavePost = self; - let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; + let post_saved_form = PostSavedForm { + post_id: data.post_id, + person_id: local_user_view.person.id, + }; - let post_saved_form = PostSavedForm { - post_id: data.post_id, - person_id: local_user_view.person.id, - }; - - if data.save { - PostSaved::save(&mut context.pool(), &post_saved_form) - .await - .with_lemmy_type(LemmyErrorType::CouldntSavePost)?; - } else { - PostSaved::unsave(&mut context.pool(), &post_saved_form) - .await - .with_lemmy_type(LemmyErrorType::CouldntSavePost)?; - } - - let post_id = data.post_id; - let person_id = local_user_view.person.id; - let post_view = PostView::read(&mut context.pool(), post_id, Some(person_id), false).await?; - - // Mark the post as read - mark_post_as_read(person_id, post_id, &mut context.pool()).await?; - - Ok(PostResponse { post_view }) + if data.save { + PostSaved::save(&mut context.pool(), &post_saved_form) + .await + .with_lemmy_type(LemmyErrorType::CouldntSavePost)?; + } else { + PostSaved::unsave(&mut context.pool(), &post_saved_form) + .await + .with_lemmy_type(LemmyErrorType::CouldntSavePost)?; } + + let post_id = data.post_id; + let person_id = local_user_view.person.id; + let post_view = PostView::read(&mut context.pool(), post_id, Some(person_id), false).await?; + + // Mark the post as read + mark_post_as_read(person_id, post_id, &mut context.pool()).await?; + + Ok(Json(PostResponse { post_view })) } diff --git a/crates/api/src/post_report/list.rs b/crates/api/src/post_report/list.rs index 01a59aa84..e6509fe00 100644 --- a/crates/api/src/post_report/list.rs +++ b/crates/api/src/post_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::{ context::LemmyContext, post::{ListPostReports, ListPostReportsResponse}, @@ -10,32 +9,26 @@ use lemmy_utils::error::LemmyError; /// Lists post reports for a community if an id is supplied /// or returns all post reports for communities a user moderates -#[async_trait::async_trait(?Send)] -impl Perform for ListPostReports { - type Response = ListPostReportsResponse; +#[tracing::instrument(skip(context))] +pub async fn list_post_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: &ListPostReports = 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.unwrap_or_default(); - let community_id = data.community_id; - let unresolved_only = data.unresolved_only.unwrap_or_default(); - - let page = data.page; - let limit = data.limit; - let post_reports = PostReportQuery { - community_id, - unresolved_only, - page, - limit, - } - .list(&mut context.pool(), &local_user_view) - .await?; - - Ok(ListPostReportsResponse { post_reports }) + let page = data.page; + let limit = data.limit; + let post_reports = PostReportQuery { + community_id, + unresolved_only, + page, + limit, } + .list(&mut context.pool(), &local_user_view) + .await?; + + Ok(Json(ListPostReportsResponse { post_reports })) } diff --git a/crates/api/src/post_report/resolve.rs b/crates/api/src/post_report/resolve.rs index 7500a53b5..94e841e08 100644 --- a/crates/api/src/post_report/resolve.rs +++ b/crates/api/src/post_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::{ context::LemmyContext, post::{PostReportResponse, ResolvePostReport}, @@ -10,34 +9,31 @@ use lemmy_db_views::structs::PostReportView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; /// Resolves or unresolves a post report and notifies the moderators of the community -#[async_trait::async_trait(?Send)] -impl Perform for ResolvePostReport { - type Response = PostReportResponse; +#[tracing::instrument(skip(context))] +pub async fn resolve_post_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: &ResolvePostReport = 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 = PostReportView::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 = PostReportView::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 { - PostReport::resolve(&mut context.pool(), report_id, person_id) - .await - .with_lemmy_type(LemmyErrorType::CouldntResolveReport)?; - } else { - PostReport::unresolve(&mut context.pool(), report_id, person_id) - .await - .with_lemmy_type(LemmyErrorType::CouldntResolveReport)?; - } - - let post_report_view = PostReportView::read(&mut context.pool(), report_id, person_id).await?; - - Ok(PostReportResponse { post_report_view }) + if data.resolved { + PostReport::resolve(&mut context.pool(), report_id, person_id) + .await + .with_lemmy_type(LemmyErrorType::CouldntResolveReport)?; + } else { + PostReport::unresolve(&mut context.pool(), report_id, person_id) + .await + .with_lemmy_type(LemmyErrorType::CouldntResolveReport)?; } + + let post_report_view = PostReportView::read(&mut context.pool(), report_id, person_id).await?; + + Ok(Json(PostReportResponse { post_report_view })) } diff --git a/crates/api/src/private_message/mark_read.rs b/crates/api/src/private_message/mark_read.rs index e88ced04f..6b6f7a51d 100644 --- a/crates/api/src/private_message/mark_read.rs +++ b/crates/api/src/private_message/mark_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, private_message::{MarkPrivateMessageAsRead, PrivateMessageResponse}, @@ -12,43 +11,36 @@ use lemmy_db_schema::{ use lemmy_db_views::structs::PrivateMessageView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; -#[async_trait::async_trait(?Send)] -impl Perform for MarkPrivateMessageAsRead { - type Response = PrivateMessageResponse; +#[tracing::instrument(skip(context))] +pub async fn mark_pm_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: &MarkPrivateMessageAsRead = self; - let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; - - // Checking permissions - let private_message_id = data.private_message_id; - let orig_private_message = - PrivateMessage::read(&mut context.pool(), private_message_id).await?; - if local_user_view.person.id != orig_private_message.recipient_id { - Err(LemmyErrorType::CouldntUpdatePrivateMessage)? - } - - // Doing the update - let private_message_id = data.private_message_id; - let read = data.read; - PrivateMessage::update( - &mut context.pool(), - private_message_id, - &PrivateMessageUpdateForm { - read: Some(read), - ..Default::default() - }, - ) - .await - .with_lemmy_type(LemmyErrorType::CouldntUpdatePrivateMessage)?; - - let view = PrivateMessageView::read(&mut context.pool(), private_message_id).await?; - Ok(PrivateMessageResponse { - private_message_view: view, - }) + // Checking permissions + let private_message_id = data.private_message_id; + let orig_private_message = PrivateMessage::read(&mut context.pool(), private_message_id).await?; + if local_user_view.person.id != orig_private_message.recipient_id { + Err(LemmyErrorType::CouldntUpdatePrivateMessage)? } + + // Doing the update + let private_message_id = data.private_message_id; + let read = data.read; + PrivateMessage::update( + &mut context.pool(), + private_message_id, + &PrivateMessageUpdateForm { + read: Some(read), + ..Default::default() + }, + ) + .await + .with_lemmy_type(LemmyErrorType::CouldntUpdatePrivateMessage)?; + + let view = PrivateMessageView::read(&mut context.pool(), private_message_id).await?; + Ok(Json(PrivateMessageResponse { + private_message_view: view, + })) } diff --git a/crates/api/src/private_message/mod.rs b/crates/api/src/private_message/mod.rs index ce8c6245c..f680957df 100644 --- a/crates/api/src/private_message/mod.rs +++ b/crates/api/src/private_message/mod.rs @@ -1 +1 @@ -mod mark_read; +pub mod mark_read; diff --git a/crates/api/src/private_message_report/create.rs b/crates/api/src/private_message_report/create.rs index 4ca1d7cd6..e1479d3c3 100644 --- a/crates/api/src/private_message_report/create.rs +++ b/crates/api/src/private_message_report/create.rs @@ -1,5 +1,5 @@ -use crate::{check_report_reason, Perform}; -use actix_web::web::Data; +use crate::check_report_reason; +use actix_web::web::{Data, Json}; use lemmy_api_common::{ context::LemmyContext, private_message::{CreatePrivateMessageReport, PrivateMessageReportResponse}, @@ -16,51 +16,49 @@ use lemmy_db_schema::{ use lemmy_db_views::structs::PrivateMessageReportView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; -#[async_trait::async_trait(?Send)] -impl Perform for CreatePrivateMessageReport { - type Response = PrivateMessageReportResponse; +#[tracing::instrument(skip(context))] +pub async fn create_pm_report( + 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?; - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let local_user_view = local_user_view_from_jwt(&self.auth, context).await?; - let local_site = LocalSite::read(&mut context.pool()).await?; + let reason = sanitize_html(data.reason.trim()); + check_report_reason(&reason, &local_site)?; - let reason = sanitize_html(self.reason.trim()); - check_report_reason(&reason, &local_site)?; + let person_id = local_user_view.person.id; + let private_message_id = data.private_message_id; + let private_message = PrivateMessage::read(&mut context.pool(), private_message_id).await?; - let person_id = local_user_view.person.id; - let private_message_id = self.private_message_id; - let private_message = PrivateMessage::read(&mut context.pool(), private_message_id).await?; + let report_form = PrivateMessageReportForm { + creator_id: person_id, + private_message_id, + original_pm_text: private_message.content, + reason: reason.clone(), + }; - let report_form = PrivateMessageReportForm { - creator_id: person_id, - private_message_id, - original_pm_text: private_message.content, - reason: reason.clone(), - }; + let report = PrivateMessageReport::report(&mut context.pool(), &report_form) + .await + .with_lemmy_type(LemmyErrorType::CouldntCreateReport)?; - let report = PrivateMessageReport::report(&mut context.pool(), &report_form) - .await - .with_lemmy_type(LemmyErrorType::CouldntCreateReport)?; + let private_message_report_view = + PrivateMessageReportView::read(&mut context.pool(), report.id).await?; - let private_message_report_view = - PrivateMessageReportView::read(&mut context.pool(), report.id).await?; - - // Email the admins - if local_site.reports_email_admins { - send_new_report_email_to_admins( - &private_message_report_view.creator.name, - &private_message_report_view.private_message_creator.name, - &mut context.pool(), - context.settings(), - ) - .await?; - } - - // TODO: consider federating this - - Ok(PrivateMessageReportResponse { - private_message_report_view, - }) + // Email the admins + if local_site.reports_email_admins { + send_new_report_email_to_admins( + &private_message_report_view.creator.name, + &private_message_report_view.private_message_creator.name, + &mut context.pool(), + context.settings(), + ) + .await?; } + + // TODO: consider federating this + + Ok(Json(PrivateMessageReportResponse { + private_message_report_view, + })) } diff --git a/crates/api/src/private_message_report/list.rs b/crates/api/src/private_message_report/list.rs index c476b1f45..21e0cab21 100644 --- a/crates/api/src/private_message_report/list.rs +++ b/crates/api/src/private_message_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::{ context::LemmyContext, private_message::{ListPrivateMessageReports, ListPrivateMessageReportsResponse}, @@ -8,29 +7,27 @@ use lemmy_api_common::{ use lemmy_db_views::private_message_report_view::PrivateMessageReportQuery; use lemmy_utils::error::LemmyError; -#[async_trait::async_trait(?Send)] -impl Perform for ListPrivateMessageReports { - type Response = ListPrivateMessageReportsResponse; +#[tracing::instrument(skip(context))] +pub async fn list_pm_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 local_user_view = local_user_view_from_jwt(&self.auth, context).await?; + is_admin(&local_user_view)?; - is_admin(&local_user_view)?; - - let unresolved_only = self.unresolved_only.unwrap_or_default(); - let page = self.page; - let limit = self.limit; - let private_message_reports = PrivateMessageReportQuery { - unresolved_only, - page, - limit, - } - .list(&mut context.pool()) - .await?; - - Ok(ListPrivateMessageReportsResponse { - private_message_reports, - }) + let unresolved_only = data.unresolved_only.unwrap_or_default(); + let page = data.page; + let limit = data.limit; + let private_message_reports = PrivateMessageReportQuery { + unresolved_only, + page, + limit, } + .list(&mut context.pool()) + .await?; + + Ok(Json(ListPrivateMessageReportsResponse { + private_message_reports, + })) } diff --git a/crates/api/src/private_message_report/mod.rs b/crates/api/src/private_message_report/mod.rs index 375fde4c3..3bb1a9b46 100644 --- a/crates/api/src/private_message_report/mod.rs +++ b/crates/api/src/private_message_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/private_message_report/resolve.rs b/crates/api/src/private_message_report/resolve.rs index be346bb23..7f3f0647a 100644 --- a/crates/api/src/private_message_report/resolve.rs +++ b/crates/api/src/private_message_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::{ context::LemmyContext, private_message::{PrivateMessageReportResponse, ResolvePrivateMessageReport}, @@ -9,33 +8,31 @@ use lemmy_db_schema::{source::private_message_report::PrivateMessageReport, trai use lemmy_db_views::structs::PrivateMessageReportView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; -#[async_trait::async_trait(?Send)] -impl Perform for ResolvePrivateMessageReport { - type Response = PrivateMessageReportResponse; +#[tracing::instrument(skip(context))] +pub async fn resolve_pm_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 local_user_view = local_user_view_from_jwt(&self.auth, context).await?; + is_admin(&local_user_view)?; - is_admin(&local_user_view)?; - - let report_id = self.report_id; - let person_id = local_user_view.person.id; - if self.resolved { - PrivateMessageReport::resolve(&mut context.pool(), report_id, person_id) - .await - .with_lemmy_type(LemmyErrorType::CouldntResolveReport)?; - } else { - PrivateMessageReport::unresolve(&mut context.pool(), report_id, person_id) - .await - .with_lemmy_type(LemmyErrorType::CouldntResolveReport)?; - } - - let private_message_report_view = - PrivateMessageReportView::read(&mut context.pool(), report_id).await?; - - Ok(PrivateMessageReportResponse { - private_message_report_view, - }) + let report_id = data.report_id; + let person_id = local_user_view.person.id; + if data.resolved { + PrivateMessageReport::resolve(&mut context.pool(), report_id, person_id) + .await + .with_lemmy_type(LemmyErrorType::CouldntResolveReport)?; + } else { + PrivateMessageReport::unresolve(&mut context.pool(), report_id, person_id) + .await + .with_lemmy_type(LemmyErrorType::CouldntResolveReport)?; } + + let private_message_report_view = + PrivateMessageReportView::read(&mut context.pool(), report_id).await?; + + Ok(Json(PrivateMessageReportResponse { + private_message_report_view, + })) } diff --git a/crates/api/src/site/federated_instances.rs b/crates/api/src/site/federated_instances.rs index 43383e067..8f224b2eb 100644 --- a/crates/api/src/site/federated_instances.rs +++ b/crates/api/src/site/federated_instances.rs @@ -1,25 +1,21 @@ -use crate::Perform; -use actix_web::web::Data; +use actix_web::web::{Data, Json}; use lemmy_api_common::{ context::LemmyContext, - site::{GetFederatedInstances, GetFederatedInstancesResponse}, + site::GetFederatedInstancesResponse, utils::build_federated_instances, }; use lemmy_db_views::structs::SiteView; use lemmy_utils::error::LemmyError; -#[async_trait::async_trait(?Send)] -impl Perform for GetFederatedInstances { - type Response = GetFederatedInstancesResponse; +#[tracing::instrument(skip(context))] +pub async fn get_federated_instances( + context: Data, +) -> Result, LemmyError> { + let site_view = SiteView::read_local(&mut context.pool()).await?; + let federated_instances = + build_federated_instances(&site_view.local_site, &mut context.pool()).await?; - #[tracing::instrument(skip(context))] - async fn perform(&self, context: &Data) -> Result { - let site_view = SiteView::read_local(&mut context.pool()).await?; - let federated_instances = - build_federated_instances(&site_view.local_site, &mut context.pool()).await?; - - Ok(Self::Response { - federated_instances, - }) - } + Ok(Json(GetFederatedInstancesResponse { + federated_instances, + })) } diff --git a/crates/api/src/site/leave_admin.rs b/crates/api/src/site/leave_admin.rs index 432e3eb14..24b7184ae 100644 --- a/crates/api/src/site/leave_admin.rs +++ b/crates/api/src/site/leave_admin.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, site::{GetSiteResponse, LeaveAdmin}, @@ -22,62 +21,59 @@ use lemmy_utils::{ version, }; -#[async_trait::async_trait(?Send)] -impl Perform for LeaveAdmin { - type Response = GetSiteResponse; +#[tracing::instrument(skip(context))] +pub async fn leave_admin( + 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: &LeaveAdmin = self; - let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; + is_admin(&local_user_view)?; - is_admin(&local_user_view)?; - - // Make sure there isn't just one admin (so if one leaves, there will still be one left) - let admins = PersonView::admins(&mut context.pool()).await?; - if admins.len() == 1 { - Err(LemmyErrorType::CannotLeaveAdmin)? - } - - LocalUser::update( - &mut context.pool(), - local_user_view.local_user.id, - &LocalUserUpdateForm { - admin: Some(false), - ..Default::default() - }, - ) - .await?; - - // Mod tables - let person_id = local_user_view.person.id; - let form = ModAddForm { - mod_person_id: person_id, - other_person_id: person_id, - removed: Some(true), - }; - - ModAdd::create(&mut context.pool(), &form).await?; - - // Reread site and admins - let site_view = SiteView::read_local(&mut context.pool()).await?; - let admins = PersonView::admins(&mut context.pool()).await?; - - 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: None, - all_languages, - discussion_languages, - taglines, - custom_emojis, - }) + // Make sure there isn't just one admin (so if one leaves, there will still be one left) + let admins = PersonView::admins(&mut context.pool()).await?; + if admins.len() == 1 { + Err(LemmyErrorType::CannotLeaveAdmin)? } + + LocalUser::update( + &mut context.pool(), + local_user_view.local_user.id, + &LocalUserUpdateForm { + admin: Some(false), + ..Default::default() + }, + ) + .await?; + + // Mod tables + let person_id = local_user_view.person.id; + let form = ModAddForm { + mod_person_id: person_id, + other_person_id: person_id, + removed: Some(true), + }; + + ModAdd::create(&mut context.pool(), &form).await?; + + // Reread site and admins + let site_view = SiteView::read_local(&mut context.pool()).await?; + let admins = PersonView::admins(&mut context.pool()).await?; + + 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: None, + all_languages, + discussion_languages, + taglines, + custom_emojis, + })) } diff --git a/crates/api/src/site/mod.rs b/crates/api/src/site/mod.rs index c23839c94..85c20e272 100644 --- a/crates/api/src/site/mod.rs +++ b/crates/api/src/site/mod.rs @@ -1,5 +1,5 @@ -mod federated_instances; -mod leave_admin; -mod mod_log; -mod purge; -mod registration_applications; +pub mod federated_instances; +pub mod leave_admin; +pub mod mod_log; +pub mod purge; +pub mod registration_applications; diff --git a/crates/api/src/site/mod_log.rs b/crates/api/src/site/mod_log.rs index a06689804..6743469b7 100644 --- a/crates/api/src/site/mod_log.rs +++ b/crates/api/src/site/mod_log.rs @@ -1,5 +1,4 @@ -use crate::Perform; -use actix_web::web::Data; +use actix_web::web::{Data, Json, Query}; use lemmy_api_common::{ context::LemmyContext, site::{GetModlog, GetModlogResponse}, @@ -31,167 +30,161 @@ use lemmy_db_views_moderator::structs::{ use lemmy_utils::error::LemmyError; use ModlogActionType::*; -#[async_trait::async_trait(?Send)] -impl Perform for GetModlog { - type Response = GetModlogResponse; +#[tracing::instrument(skip(context))] +pub async fn get_mod_log( + 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: &GetModlog = self; + check_private_instance(&local_user_view, &local_site)?; - 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 type_ = data.type_.unwrap_or(All); + let community_id = data.community_id; - check_private_instance(&local_user_view, &local_site)?; + let (local_person_id, is_admin) = match local_user_view { + Some(s) => (s.person.id, is_admin(&s).is_ok()), + None => (PersonId(-1), false), + }; + let community_id_value = match community_id { + Some(s) => s, + None => CommunityId(-1), + }; + let is_mod_of_community = data.community_id.is_some() + && is_mod_or_admin(&mut context.pool(), local_person_id, community_id_value) + .await + .is_ok(); + let hide_modlog_names = local_site.hide_modlog_mod_names && !is_mod_of_community && !is_admin; - let type_ = data.type_.unwrap_or(All); - let community_id = data.community_id; + let mod_person_id = if hide_modlog_names { + None + } else { + data.mod_person_id + }; + let other_person_id = data.other_person_id; + let params = ModlogListParams { + community_id, + mod_person_id, + other_person_id, + page: data.page, + limit: data.limit, + hide_modlog_names, + }; + let removed_posts = match type_ { + All | ModRemovePost => ModRemovePostView::list(&mut context.pool(), params).await?, + _ => Default::default(), + }; - let (local_person_id, is_admin) = match local_user_view { - Some(s) => (s.person.id, is_admin(&s).is_ok()), - None => (PersonId(-1), false), - }; - let community_id_value = match community_id { - Some(s) => s, - None => CommunityId(-1), - }; - let is_mod_of_community = data.community_id.is_some() - && is_mod_or_admin(&mut context.pool(), local_person_id, community_id_value) - .await - .is_ok(); - let hide_modlog_names = local_site.hide_modlog_mod_names && !is_mod_of_community && !is_admin; + let locked_posts = match type_ { + All | ModLockPost => ModLockPostView::list(&mut context.pool(), params).await?, + _ => Default::default(), + }; - let mod_person_id = if hide_modlog_names { - None - } else { - data.mod_person_id - }; - let other_person_id = data.other_person_id; - let params = ModlogListParams { - community_id, - mod_person_id, - other_person_id, - page: data.page, - limit: data.limit, - hide_modlog_names, - }; - let removed_posts = match type_ { - All | ModRemovePost => ModRemovePostView::list(&mut context.pool(), params).await?, - _ => Default::default(), - }; + let featured_posts = match type_ { + All | ModFeaturePost => ModFeaturePostView::list(&mut context.pool(), params).await?, + _ => Default::default(), + }; - let locked_posts = match type_ { - All | ModLockPost => ModLockPostView::list(&mut context.pool(), params).await?, - _ => Default::default(), - }; + let removed_comments = match type_ { + All | ModRemoveComment => ModRemoveCommentView::list(&mut context.pool(), params).await?, + _ => Default::default(), + }; - let featured_posts = match type_ { - All | ModFeaturePost => ModFeaturePostView::list(&mut context.pool(), params).await?, - _ => Default::default(), - }; + let banned_from_community = match type_ { + All | ModBanFromCommunity => ModBanFromCommunityView::list(&mut context.pool(), params).await?, + _ => Default::default(), + }; - let removed_comments = match type_ { - All | ModRemoveComment => ModRemoveCommentView::list(&mut context.pool(), params).await?, - _ => Default::default(), - }; + let added_to_community = match type_ { + All | ModAddCommunity => ModAddCommunityView::list(&mut context.pool(), params).await?, + _ => Default::default(), + }; - let banned_from_community = match type_ { - All | ModBanFromCommunity => { - ModBanFromCommunityView::list(&mut context.pool(), params).await? - } - _ => Default::default(), - }; + let transferred_to_community = match type_ { + All | ModTransferCommunity => { + ModTransferCommunityView::list(&mut context.pool(), params).await? + } + _ => Default::default(), + }; - let added_to_community = match type_ { - All | ModAddCommunity => ModAddCommunityView::list(&mut context.pool(), params).await?, - _ => Default::default(), - }; + let hidden_communities = match type_ { + All | ModHideCommunity if other_person_id.is_none() => { + ModHideCommunityView::list(&mut context.pool(), params).await? + } + _ => Default::default(), + }; - let transferred_to_community = match type_ { - All | ModTransferCommunity => { - ModTransferCommunityView::list(&mut context.pool(), params).await? - } - _ => Default::default(), - }; + // These arrays are only for the full modlog, when a community isn't given + let ( + banned, + added, + removed_communities, + admin_purged_persons, + admin_purged_communities, + admin_purged_posts, + admin_purged_comments, + ) = if data.community_id.is_none() { + ( + match type_ { + All | ModBan => ModBanView::list(&mut context.pool(), params).await?, + _ => Default::default(), + }, + match type_ { + All | ModAdd => ModAddView::list(&mut context.pool(), params).await?, + _ => Default::default(), + }, + match type_ { + All | ModRemoveCommunity if other_person_id.is_none() => { + ModRemoveCommunityView::list(&mut context.pool(), params).await? + } + _ => Default::default(), + }, + match type_ { + All | AdminPurgePerson if other_person_id.is_none() => { + AdminPurgePersonView::list(&mut context.pool(), params).await? + } + _ => Default::default(), + }, + match type_ { + All | AdminPurgeCommunity if other_person_id.is_none() => { + AdminPurgeCommunityView::list(&mut context.pool(), params).await? + } + _ => Default::default(), + }, + match type_ { + All | AdminPurgePost if other_person_id.is_none() => { + AdminPurgePostView::list(&mut context.pool(), params).await? + } + _ => Default::default(), + }, + match type_ { + All | AdminPurgeComment if other_person_id.is_none() => { + AdminPurgeCommentView::list(&mut context.pool(), params).await? + } + _ => Default::default(), + }, + ) + } else { + Default::default() + }; - let hidden_communities = match type_ { - All | ModHideCommunity if other_person_id.is_none() => { - ModHideCommunityView::list(&mut context.pool(), params).await? - } - _ => Default::default(), - }; - - // These arrays are only for the full modlog, when a community isn't given - let ( - banned, - added, - removed_communities, - admin_purged_persons, - admin_purged_communities, - admin_purged_posts, - admin_purged_comments, - ) = if data.community_id.is_none() { - ( - match type_ { - All | ModBan => ModBanView::list(&mut context.pool(), params).await?, - _ => Default::default(), - }, - match type_ { - All | ModAdd => ModAddView::list(&mut context.pool(), params).await?, - _ => Default::default(), - }, - match type_ { - All | ModRemoveCommunity if other_person_id.is_none() => { - ModRemoveCommunityView::list(&mut context.pool(), params).await? - } - _ => Default::default(), - }, - match type_ { - All | AdminPurgePerson if other_person_id.is_none() => { - AdminPurgePersonView::list(&mut context.pool(), params).await? - } - _ => Default::default(), - }, - match type_ { - All | AdminPurgeCommunity if other_person_id.is_none() => { - AdminPurgeCommunityView::list(&mut context.pool(), params).await? - } - _ => Default::default(), - }, - match type_ { - All | AdminPurgePost if other_person_id.is_none() => { - AdminPurgePostView::list(&mut context.pool(), params).await? - } - _ => Default::default(), - }, - match type_ { - All | AdminPurgeComment if other_person_id.is_none() => { - AdminPurgeCommentView::list(&mut context.pool(), params).await? - } - _ => Default::default(), - }, - ) - } else { - Default::default() - }; - - // Return the jwt - Ok(GetModlogResponse { - removed_posts, - locked_posts, - featured_posts, - removed_comments, - removed_communities, - banned_from_community, - banned, - added_to_community, - added, - transferred_to_community, - admin_purged_persons, - admin_purged_communities, - admin_purged_posts, - admin_purged_comments, - hidden_communities, - }) - } + // Return the jwt + Ok(Json(GetModlogResponse { + removed_posts, + locked_posts, + featured_posts, + removed_comments, + removed_communities, + banned_from_community, + banned, + added_to_community, + added, + transferred_to_community, + admin_purged_persons, + admin_purged_communities, + admin_purged_posts, + admin_purged_comments, + hidden_communities, + })) } diff --git a/crates/api/src/site/purge/comment.rs b/crates/api/src/site/purge/comment.rs index bfaf9cbb0..391be98d7 100644 --- a/crates/api/src/site/purge/comment.rs +++ b/crates/api/src/site/purge/comment.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, site::{PurgeComment, PurgeItemResponse}, @@ -14,39 +13,36 @@ use lemmy_db_schema::{ }; use lemmy_utils::error::LemmyError; -#[async_trait::async_trait(?Send)] -impl Perform for PurgeComment { - type Response = PurgeItemResponse; +#[tracing::instrument(skip(context))] +pub async fn purge_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: &Self = self; - let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; + // Only let admin purge an item + is_admin(&local_user_view)?; - // Only let admin purge an item - is_admin(&local_user_view)?; + let comment_id = data.comment_id; - let comment_id = data.comment_id; + // Read the comment to get the post_id + let comment = Comment::read(&mut context.pool(), comment_id).await?; - // Read the comment to get the post_id - let comment = Comment::read(&mut context.pool(), comment_id).await?; + let post_id = comment.post_id; - let post_id = comment.post_id; + // TODO read comments for pictrs images and purge them - // TODO read comments for pictrs images and purge them + Comment::delete(&mut context.pool(), comment_id).await?; - Comment::delete(&mut context.pool(), comment_id).await?; + // Mod tables + let reason = sanitize_html_opt(&data.reason); + let form = AdminPurgeCommentForm { + admin_person_id: local_user_view.person.id, + reason, + post_id, + }; - // Mod tables - let reason = sanitize_html_opt(&data.reason); - let form = AdminPurgeCommentForm { - admin_person_id: local_user_view.person.id, - reason, - post_id, - }; + AdminPurgeComment::create(&mut context.pool(), &form).await?; - AdminPurgeComment::create(&mut context.pool(), &form).await?; - - Ok(PurgeItemResponse { success: true }) - } + Ok(Json(PurgeItemResponse { success: true })) } diff --git a/crates/api/src/site/purge/community.rs b/crates/api/src/site/purge/community.rs index 7c59fd76b..60c1142c3 100644 --- a/crates/api/src/site/purge/community.rs +++ b/crates/api/src/site/purge/community.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, request::purge_image_from_pictrs, @@ -15,44 +14,41 @@ use lemmy_db_schema::{ }; use lemmy_utils::error::LemmyError; -#[async_trait::async_trait(?Send)] -impl Perform for PurgeCommunity { - type Response = PurgeItemResponse; +#[tracing::instrument(skip(context))] +pub async fn purge_community( + 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 = self; - let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; + // Only let admin purge an item + is_admin(&local_user_view)?; - // Only let admin purge an item - is_admin(&local_user_view)?; + let community_id = data.community_id; - let community_id = data.community_id; + // Read the community to get its images + let community = Community::read(&mut context.pool(), community_id).await?; - // Read the community to get its images - let community = Community::read(&mut context.pool(), community_id).await?; - - if let Some(banner) = community.banner { - purge_image_from_pictrs(&banner, context).await.ok(); - } - - if let Some(icon) = community.icon { - purge_image_from_pictrs(&icon, context).await.ok(); - } - - purge_image_posts_for_community(community_id, context).await?; - - Community::delete(&mut context.pool(), community_id).await?; - - // Mod tables - let reason = sanitize_html_opt(&data.reason); - let form = AdminPurgeCommunityForm { - admin_person_id: local_user_view.person.id, - reason, - }; - - AdminPurgeCommunity::create(&mut context.pool(), &form).await?; - - Ok(PurgeItemResponse { success: true }) + if let Some(banner) = community.banner { + purge_image_from_pictrs(&banner, &context).await.ok(); } + + if let Some(icon) = community.icon { + purge_image_from_pictrs(&icon, &context).await.ok(); + } + + purge_image_posts_for_community(community_id, &context).await?; + + Community::delete(&mut context.pool(), community_id).await?; + + // Mod tables + let reason = sanitize_html_opt(&data.reason); + let form = AdminPurgeCommunityForm { + admin_person_id: local_user_view.person.id, + reason, + }; + + AdminPurgeCommunity::create(&mut context.pool(), &form).await?; + + Ok(Json(PurgeItemResponse { success: true })) } diff --git a/crates/api/src/site/purge/mod.rs b/crates/api/src/site/purge/mod.rs index aa00ba6eb..8165e3714 100644 --- a/crates/api/src/site/purge/mod.rs +++ b/crates/api/src/site/purge/mod.rs @@ -1,4 +1,4 @@ -mod comment; -mod community; -mod person; -mod post; +pub mod comment; +pub mod community; +pub mod person; +pub mod post; diff --git a/crates/api/src/site/purge/person.rs b/crates/api/src/site/purge/person.rs index 1100a0db9..3c6797118 100644 --- a/crates/api/src/site/purge/person.rs +++ b/crates/api/src/site/purge/person.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, request::purge_image_from_pictrs, @@ -15,43 +14,40 @@ use lemmy_db_schema::{ }; use lemmy_utils::error::LemmyError; -#[async_trait::async_trait(?Send)] -impl Perform for PurgePerson { - type Response = PurgeItemResponse; +#[tracing::instrument(skip(context))] +pub async fn purge_person( + 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 = self; - let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; + // Only let admin purge an item + is_admin(&local_user_view)?; - // Only let admin purge an item - is_admin(&local_user_view)?; + // Read the person to get their images + let person_id = data.person_id; + let person = Person::read(&mut context.pool(), person_id).await?; - // Read the person to get their images - let person_id = data.person_id; - let person = Person::read(&mut context.pool(), person_id).await?; - - if let Some(banner) = person.banner { - purge_image_from_pictrs(&banner, context).await.ok(); - } - - if let Some(avatar) = person.avatar { - purge_image_from_pictrs(&avatar, context).await.ok(); - } - - purge_image_posts_for_person(person_id, context).await?; - - Person::delete(&mut context.pool(), person_id).await?; - - // Mod tables - let reason = sanitize_html_opt(&data.reason); - let form = AdminPurgePersonForm { - admin_person_id: local_user_view.person.id, - reason, - }; - - AdminPurgePerson::create(&mut context.pool(), &form).await?; - - Ok(PurgeItemResponse { success: true }) + if let Some(banner) = person.banner { + purge_image_from_pictrs(&banner, &context).await.ok(); } + + if let Some(avatar) = person.avatar { + purge_image_from_pictrs(&avatar, &context).await.ok(); + } + + purge_image_posts_for_person(person_id, &context).await?; + + Person::delete(&mut context.pool(), person_id).await?; + + // Mod tables + let reason = sanitize_html_opt(&data.reason); + let form = AdminPurgePersonForm { + admin_person_id: local_user_view.person.id, + reason, + }; + + AdminPurgePerson::create(&mut context.pool(), &form).await?; + + Ok(Json(PurgeItemResponse { success: true })) } diff --git a/crates/api/src/site/purge/post.rs b/crates/api/src/site/purge/post.rs index b267f3518..a6e6c1825 100644 --- a/crates/api/src/site/purge/post.rs +++ b/crates/api/src/site/purge/post.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, request::purge_image_from_pictrs, @@ -15,46 +14,43 @@ use lemmy_db_schema::{ }; use lemmy_utils::error::LemmyError; -#[async_trait::async_trait(?Send)] -impl Perform for PurgePost { - type Response = PurgeItemResponse; +#[tracing::instrument(skip(context))] +pub async fn purge_post( + 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 = self; - let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; + // Only let admin purge an item + is_admin(&local_user_view)?; - // Only let admin purge an item - is_admin(&local_user_view)?; + let post_id = data.post_id; - let post_id = data.post_id; + // Read the post to get the community_id + let post = Post::read(&mut context.pool(), post_id).await?; - // Read the post to get the community_id - let post = Post::read(&mut context.pool(), post_id).await?; - - // Purge image - if let Some(url) = post.url { - purge_image_from_pictrs(&url, context).await.ok(); - } - // Purge thumbnail - if let Some(thumbnail_url) = post.thumbnail_url { - purge_image_from_pictrs(&thumbnail_url, context).await.ok(); - } - - let community_id = post.community_id; - - Post::delete(&mut context.pool(), post_id).await?; - - // Mod tables - let reason = sanitize_html_opt(&data.reason); - let form = AdminPurgePostForm { - admin_person_id: local_user_view.person.id, - reason, - community_id, - }; - - AdminPurgePost::create(&mut context.pool(), &form).await?; - - Ok(PurgeItemResponse { success: true }) + // Purge image + if let Some(url) = post.url { + purge_image_from_pictrs(&url, &context).await.ok(); } + // Purge thumbnail + if let Some(thumbnail_url) = post.thumbnail_url { + purge_image_from_pictrs(&thumbnail_url, &context).await.ok(); + } + + let community_id = post.community_id; + + Post::delete(&mut context.pool(), post_id).await?; + + // Mod tables + let reason = sanitize_html_opt(&data.reason); + let form = AdminPurgePostForm { + admin_person_id: local_user_view.person.id, + reason, + community_id, + }; + + AdminPurgePost::create(&mut context.pool(), &form).await?; + + Ok(Json(PurgeItemResponse { success: true })) } diff --git a/crates/api/src/site/registration_applications/approve.rs b/crates/api/src/site/registration_applications/approve.rs index eb0fb0323..344fa82c8 100644 --- a/crates/api/src/site/registration_applications/approve.rs +++ b/crates/api/src/site/registration_applications/approve.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, site::{ApproveRegistrationApplication, RegistrationApplicationResponse}, @@ -16,53 +15,50 @@ use lemmy_db_schema::{ use lemmy_db_views::structs::{LocalUserView, RegistrationApplicationView}; use lemmy_utils::error::LemmyError; -#[async_trait::async_trait(?Send)] -impl Perform for ApproveRegistrationApplication { - type Response = RegistrationApplicationResponse; +pub async fn approve_registration_application( + data: Json, + context: Data, +) -> Result, LemmyError> { + let local_user_view = local_user_view_from_jwt(&data.auth, &context).await?; - async fn perform(&self, context: &Data) -> Result { - let data = self; - let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; + let app_id = data.id; - let app_id = data.id; + // Only let admins do this + is_admin(&local_user_view)?; - // Only let admins do this - is_admin(&local_user_view)?; + // Update the registration with reason, admin_id + let deny_reason = diesel_option_overwrite(data.deny_reason.clone()); + let app_form = RegistrationApplicationUpdateForm { + admin_id: Some(Some(local_user_view.person.id)), + deny_reason, + }; - // Update the registration with reason, admin_id - let deny_reason = diesel_option_overwrite(data.deny_reason.clone()); - let app_form = RegistrationApplicationUpdateForm { - admin_id: Some(Some(local_user_view.person.id)), - deny_reason, - }; + let registration_application = + RegistrationApplication::update(&mut context.pool(), app_id, &app_form).await?; - let registration_application = - RegistrationApplication::update(&mut context.pool(), app_id, &app_form).await?; + // Update the local_user row + let local_user_form = LocalUserUpdateForm { + accepted_application: Some(data.approve), + ..Default::default() + }; - // Update the local_user row - let local_user_form = LocalUserUpdateForm { - accepted_application: Some(data.approve), - ..Default::default() - }; + let approved_user_id = registration_application.local_user_id; + LocalUser::update(&mut context.pool(), approved_user_id, &local_user_form).await?; - let approved_user_id = registration_application.local_user_id; - LocalUser::update(&mut context.pool(), approved_user_id, &local_user_form).await?; + if data.approve { + let approved_local_user_view = + LocalUserView::read(&mut context.pool(), approved_user_id).await?; - if data.approve { - let approved_local_user_view = - LocalUserView::read(&mut context.pool(), approved_user_id).await?; - - if approved_local_user_view.local_user.email.is_some() { - send_application_approved_email(&approved_local_user_view, context.settings()).await?; - } + if approved_local_user_view.local_user.email.is_some() { + send_application_approved_email(&approved_local_user_view, context.settings()).await?; } - - // Read the view - let registration_application = - RegistrationApplicationView::read(&mut context.pool(), app_id).await?; - - Ok(Self::Response { - registration_application, - }) } + + // Read the view + let registration_application = + RegistrationApplicationView::read(&mut context.pool(), app_id).await?; + + Ok(Json(RegistrationApplicationResponse { + registration_application, + })) } diff --git a/crates/api/src/site/registration_applications/list.rs b/crates/api/src/site/registration_applications/list.rs index aeff9f97f..0690f50fb 100644 --- a/crates/api/src/site/registration_applications/list.rs +++ b/crates/api/src/site/registration_applications/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::{ context::LemmyContext, site::{ListRegistrationApplications, ListRegistrationApplicationsResponse}, @@ -10,34 +9,31 @@ use lemmy_db_views::registration_application_view::RegistrationApplicationQuery; use lemmy_utils::error::LemmyError; /// Lists registration applications, filterable by undenied only. -#[async_trait::async_trait(?Send)] -impl Perform for ListRegistrationApplications { - type Response = ListRegistrationApplicationsResponse; +pub async fn list_registration_applications( + data: Query, + 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?; - async fn perform(&self, context: &Data) -> Result { - let data = 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 + is_admin(&local_user_view)?; - // Make sure user is an admin - is_admin(&local_user_view)?; + let unread_only = data.unread_only.unwrap_or_default(); + let verified_email_only = local_site.require_email_verification; - let unread_only = data.unread_only.unwrap_or_default(); - let verified_email_only = local_site.require_email_verification; - - let page = data.page; - let limit = data.limit; - let registration_applications = RegistrationApplicationQuery { - unread_only, - verified_email_only, - page, - limit, - } - .list(&mut context.pool()) - .await?; - - Ok(Self::Response { - registration_applications, - }) + let page = data.page; + let limit = data.limit; + let registration_applications = RegistrationApplicationQuery { + unread_only, + verified_email_only, + page, + limit, } + .list(&mut context.pool()) + .await?; + + Ok(Json(ListRegistrationApplicationsResponse { + registration_applications, + })) } diff --git a/crates/api/src/site/registration_applications/mod.rs b/crates/api/src/site/registration_applications/mod.rs index 0d330ba88..e5082615a 100644 --- a/crates/api/src/site/registration_applications/mod.rs +++ b/crates/api/src/site/registration_applications/mod.rs @@ -1,3 +1,3 @@ -mod approve; -mod list; -mod unread_count; +pub mod approve; +pub mod list; +pub mod unread_count; diff --git a/crates/api/src/site/registration_applications/unread_count.rs b/crates/api/src/site/registration_applications/unread_count.rs index 593e93ffb..49929c070 100644 --- a/crates/api/src/site/registration_applications/unread_count.rs +++ b/crates/api/src/site/registration_applications/unread_count.rs @@ -1,5 +1,4 @@ -use crate::Perform; -use actix_web::web::Data; +use actix_web::web::{Data, Json, Query}; use lemmy_api_common::{ context::LemmyContext, site::{GetUnreadRegistrationApplicationCount, GetUnreadRegistrationApplicationCountResponse}, @@ -9,26 +8,22 @@ use lemmy_db_schema::source::local_site::LocalSite; use lemmy_db_views::structs::RegistrationApplicationView; use lemmy_utils::error::LemmyError; -#[async_trait::async_trait(?Send)] -impl Perform for GetUnreadRegistrationApplicationCount { - type Response = GetUnreadRegistrationApplicationCountResponse; +pub async fn get_unread_registration_application_count( + data: Query, + 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?; - async fn perform(&self, context: &Data) -> Result { - let data = self; - let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; - let local_site = LocalSite::read(&mut context.pool()).await?; + // Only let admins do this + is_admin(&local_user_view)?; - // Only let admins do this - is_admin(&local_user_view)?; + let verified_email_only = local_site.require_email_verification; - let verified_email_only = local_site.require_email_verification; + let registration_applications = + RegistrationApplicationView::get_unread_count(&mut context.pool(), verified_email_only).await?; - let registration_applications = - RegistrationApplicationView::get_unread_count(&mut context.pool(), verified_email_only) - .await?; - - Ok(Self::Response { - registration_applications, - }) - } + Ok(Json(GetUnreadRegistrationApplicationCountResponse { + registration_applications, + })) } diff --git a/crates/api_common/README.md b/crates/api_common/README.md index f6a16c53c..b4e7ad63b 100644 --- a/crates/api_common/README.md +++ b/crates/api_common/README.md @@ -19,7 +19,7 @@ Here is an example using [reqwest](https://crates.io/crates/reqwest): print!("{:?}", &json); ``` -As you can see, each API endpoint needs a parameter type ( GetPosts), path (/post/list) and response type (GetPostsResponse). You can find the paths and parameter types from [this file](https://github.com/LemmyNet/lemmy/blob/main/src/api_routes_http.rs). For the response types you need to look through the crates [lemmy_api](https://github.com/LemmyNet/lemmy/tree/main/crates/api/src) and [lemmy_api_crud](https://github.com/LemmyNet/lemmy/tree/main/crates/api_crud/src) for the place where Perform/PerformCrud is implemented for the parameter type. The response type is specified as a type parameter on the trait. +As you can see, each API endpoint needs a parameter type ( GetPosts), path (/post/list) and response type (GetPostsResponse). You can find the paths and handler methods from [this file](https://github.com/LemmyNet/lemmy/blob/main/src/api_routes_http.rs). The parameter type and response type are defined on each handler method. For a real example of a Lemmy API client, look at [lemmyBB](https://github.com/LemmyNet/lemmyBB/tree/main/src/api). diff --git a/crates/api_common/src/person.rs b/crates/api_common/src/person.rs index 695486a5a..45574d0f2 100644 --- a/crates/api_common/src/person.rs +++ b/crates/api_common/src/person.rs @@ -51,15 +51,6 @@ pub struct Register { pub answer: Option, } -#[skip_serializing_none] -#[derive(Debug, Serialize, Deserialize, Clone, Default)] -#[cfg_attr(feature = "full", derive(TS))] -#[cfg_attr(feature = "full", ts(export))] -/// Fetches a Captcha item. -pub struct GetCaptcha { - pub auth: Option>, -} - #[skip_serializing_none] #[derive(Debug, Serialize, Deserialize, Clone)] #[cfg_attr(feature = "full", derive(TS))] diff --git a/crates/api_common/src/site.rs b/crates/api_common/src/site.rs index 35b6d77ec..0dc796ed8 100644 --- a/crates/api_common/src/site.rs +++ b/crates/api_common/src/site.rs @@ -301,15 +301,6 @@ pub struct GetSiteResponse { pub custom_emojis: Vec, } -#[skip_serializing_none] -#[derive(Debug, Serialize, Deserialize, Clone)] -#[cfg_attr(feature = "full", derive(TS))] -#[cfg_attr(feature = "full", ts(export))] -/// Fetches the federated instances for your site. -pub struct GetFederatedInstances { - pub auth: Option>, -} - #[skip_serializing_none] #[derive(Debug, Serialize, Deserialize, Clone)] #[cfg_attr(feature = "full", derive(TS))] diff --git a/crates/apub/src/activities/mod.rs b/crates/apub/src/activities/mod.rs index c6696725e..cddb5906b 100644 --- a/crates/apub/src/activities/mod.rs +++ b/crates/apub/src/activities/mod.rs @@ -65,7 +65,6 @@ pub mod community; pub mod create_or_update; pub mod deletion; pub mod following; -pub mod unfederated; pub mod voting; /// Amount of time that the list of dead instances is cached. This is only updated once a day, diff --git a/crates/apub/src/activities/unfederated.rs b/crates/apub/src/activities/unfederated.rs deleted file mode 100644 index 24ff9b686..000000000 --- a/crates/apub/src/activities/unfederated.rs +++ /dev/null @@ -1,320 +0,0 @@ -use crate::SendActivity; -use lemmy_api_common::{ - comment::{ - CommentReportResponse, - CommentResponse, - DistinguishComment, - GetComment, - ListCommentReports, - ListCommentReportsResponse, - ResolveCommentReport, - SaveComment, - }, - community::{ - CommunityResponse, - CreateCommunity, - GetCommunityResponse, - ListCommunities, - ListCommunitiesResponse, - TransferCommunity, - }, - custom_emoji::{ - CreateCustomEmoji, - CustomEmojiResponse, - DeleteCustomEmoji, - DeleteCustomEmojiResponse, - EditCustomEmoji, - }, - person::{ - AddAdmin, - AddAdminResponse, - BannedPersonsResponse, - BlockPerson, - BlockPersonResponse, - ChangePassword, - CommentReplyResponse, - GetBannedPersons, - GetCaptcha, - GetCaptchaResponse, - GetPersonMentions, - GetPersonMentionsResponse, - GetReplies, - GetRepliesResponse, - GetReportCount, - GetReportCountResponse, - GetUnreadCount, - GetUnreadCountResponse, - Login, - LoginResponse, - MarkAllAsRead, - MarkCommentReplyAsRead, - MarkPersonMentionAsRead, - PasswordChangeAfterReset, - PasswordReset, - PasswordResetResponse, - PersonMentionResponse, - Register, - SaveUserSettings, - VerifyEmail, - VerifyEmailResponse, - }, - post::{ - GetPost, - GetPostResponse, - GetSiteMetadata, - GetSiteMetadataResponse, - ListPostReports, - ListPostReportsResponse, - MarkPostAsRead, - PostReportResponse, - PostResponse, - ResolvePostReport, - SavePost, - }, - private_message::{ - CreatePrivateMessageReport, - GetPrivateMessages, - ListPrivateMessageReports, - ListPrivateMessageReportsResponse, - MarkPrivateMessageAsRead, - PrivateMessageReportResponse, - PrivateMessageResponse, - PrivateMessagesResponse, - ResolvePrivateMessageReport, - }, - site::{ - ApproveRegistrationApplication, - CreateSite, - EditSite, - GetFederatedInstances, - GetFederatedInstancesResponse, - GetModlog, - GetModlogResponse, - GetSite, - GetSiteResponse, - GetUnreadRegistrationApplicationCount, - GetUnreadRegistrationApplicationCountResponse, - LeaveAdmin, - ListRegistrationApplications, - ListRegistrationApplicationsResponse, - PurgeComment, - PurgeCommunity, - PurgeItemResponse, - PurgePerson, - PurgePost, - RegistrationApplicationResponse, - SiteResponse, - }, -}; - -impl SendActivity for Register { - type Response = LoginResponse; -} - -impl SendActivity for GetPrivateMessages { - type Response = PrivateMessagesResponse; -} - -impl SendActivity for CreateSite { - type Response = SiteResponse; -} - -impl SendActivity for EditSite { - type Response = SiteResponse; -} - -impl SendActivity for GetSite { - type Response = GetSiteResponse; -} - -impl SendActivity for ListCommunities { - type Response = ListCommunitiesResponse; -} - -impl SendActivity for CreateCommunity { - type Response = CommunityResponse; -} - -impl SendActivity for GetPost { - type Response = GetPostResponse; -} - -impl SendActivity for GetComment { - type Response = CommentResponse; -} - -impl SendActivity for Login { - type Response = LoginResponse; -} - -impl SendActivity for GetCaptcha { - type Response = GetCaptchaResponse; -} - -impl SendActivity for GetReplies { - type Response = GetRepliesResponse; -} - -impl SendActivity for AddAdmin { - type Response = AddAdminResponse; -} - -impl SendActivity for GetUnreadRegistrationApplicationCount { - type Response = GetUnreadRegistrationApplicationCountResponse; -} - -impl SendActivity for ListRegistrationApplications { - type Response = ListRegistrationApplicationsResponse; -} - -impl SendActivity for ApproveRegistrationApplication { - type Response = RegistrationApplicationResponse; -} - -impl SendActivity for GetBannedPersons { - type Response = BannedPersonsResponse; -} - -impl SendActivity for BlockPerson { - type Response = BlockPersonResponse; -} - -impl SendActivity for GetPersonMentions { - type Response = GetPersonMentionsResponse; -} - -impl SendActivity for MarkPersonMentionAsRead { - type Response = PersonMentionResponse; -} - -impl SendActivity for MarkCommentReplyAsRead { - type Response = CommentReplyResponse; -} - -impl SendActivity for MarkAllAsRead { - type Response = GetRepliesResponse; -} - -impl SendActivity for PasswordReset { - type Response = PasswordResetResponse; -} - -impl SendActivity for PasswordChangeAfterReset { - type Response = LoginResponse; -} - -impl SendActivity for SaveUserSettings { - type Response = LoginResponse; -} - -impl SendActivity for ChangePassword { - type Response = LoginResponse; -} - -impl SendActivity for GetReportCount { - type Response = GetReportCountResponse; -} - -impl SendActivity for GetUnreadCount { - type Response = GetUnreadCountResponse; -} - -impl SendActivity for VerifyEmail { - type Response = VerifyEmailResponse; -} - -impl SendActivity for MarkPrivateMessageAsRead { - type Response = PrivateMessageResponse; -} - -impl SendActivity for CreatePrivateMessageReport { - type Response = PrivateMessageReportResponse; -} - -impl SendActivity for ResolvePrivateMessageReport { - type Response = PrivateMessageReportResponse; -} - -impl SendActivity for ListPrivateMessageReports { - type Response = ListPrivateMessageReportsResponse; -} - -impl SendActivity for GetModlog { - type Response = GetModlogResponse; -} - -impl SendActivity for PurgePerson { - type Response = PurgeItemResponse; -} - -impl SendActivity for PurgeCommunity { - type Response = PurgeItemResponse; -} - -impl SendActivity for PurgePost { - type Response = PurgeItemResponse; -} - -impl SendActivity for PurgeComment { - type Response = PurgeItemResponse; -} - -impl SendActivity for TransferCommunity { - type Response = GetCommunityResponse; -} - -impl SendActivity for LeaveAdmin { - type Response = GetSiteResponse; -} - -impl SendActivity for MarkPostAsRead { - type Response = PostResponse; -} - -impl SendActivity for SavePost { - type Response = PostResponse; -} - -impl SendActivity for ListPostReports { - type Response = ListPostReportsResponse; -} - -impl SendActivity for ResolvePostReport { - type Response = PostReportResponse; -} - -impl SendActivity for GetSiteMetadata { - type Response = GetSiteMetadataResponse; -} - -impl SendActivity for SaveComment { - type Response = CommentResponse; -} - -impl SendActivity for DistinguishComment { - type Response = CommentResponse; -} - -impl SendActivity for ListCommentReports { - type Response = ListCommentReportsResponse; -} - -impl SendActivity for ResolveCommentReport { - type Response = CommentReportResponse; -} - -impl SendActivity for CreateCustomEmoji { - type Response = CustomEmojiResponse; -} - -impl SendActivity for EditCustomEmoji { - type Response = CustomEmojiResponse; -} - -impl SendActivity for DeleteCustomEmoji { - type Response = DeleteCustomEmojiResponse; -} - -impl SendActivity for GetFederatedInstances { - type Response = GetFederatedInstancesResponse; -} diff --git a/crates/apub/src/lib.rs b/crates/apub/src/lib.rs index 23a61b613..7ebe68223 100644 --- a/crates/apub/src/lib.rs +++ b/crates/apub/src/lib.rs @@ -194,16 +194,3 @@ async fn insert_received_activity( ReceivedActivity::create(&mut data.pool(), &ap_id.clone().into()).await?; Ok(()) } - -#[async_trait::async_trait] -pub trait SendActivity: Sync { - type Response: Sync + Send + Clone; - - async fn send_activity( - _request: &Self, - _response: &Self::Response, - _context: &Data, - ) -> Result<(), LemmyError> { - Ok(()) - } -} diff --git a/src/api_routes_http.rs b/src/api_routes_http.rs index 5c8360d0d..74003b8d8 100644 --- a/src/api_routes_http.rs +++ b/src/api_routes_http.rs @@ -1,4 +1,4 @@ -use actix_web::{guard, web, Error, HttpResponse, Result}; +use actix_web::{guard, web}; use lemmy_api::{ comment::{distinguish::distinguish_comment, like::like_comment, save::save_comment}, comment_report::{ @@ -12,53 +12,66 @@ use lemmy_api::{ block::block_community, follow::follow_community, hide::hide_community, + transfer::transfer_community, }, - local_user::{ban_person::ban_from_site, notifications::mark_reply_read::mark_reply_as_read}, - post::{feature::feature_post, like::like_post, lock::lock_post}, - post_report::create::create_post_report, - sitemap::get_sitemap, - Perform, -}; -use lemmy_api_common::{ - community::TransferCommunity, - context::LemmyContext, - person::{ - AddAdmin, - BlockPerson, - ChangePassword, - GetBannedPersons, - GetCaptcha, - GetPersonMentions, - GetReplies, - GetReportCount, - GetUnreadCount, - Login, - MarkAllAsRead, - MarkPersonMentionAsRead, - PasswordChangeAfterReset, - PasswordReset, - SaveUserSettings, - VerifyEmail, + local_user::{ + add_admin::add_admin, + ban_person::ban_from_site, + block::block_person, + change_password::change_password, + change_password_after_reset::change_password_after_reset, + get_captcha::get_captcha, + list_banned::list_banned_users, + login::login, + notifications::{ + list_mentions::list_mentions, + list_replies::list_replies, + mark_all_read::mark_all_notifications_read, + mark_mention_read::mark_person_mention_as_read, + mark_reply_read::mark_reply_as_read, + unread_count::unread_count, + }, + report_count::report_count, + reset_password::reset_password, + save_settings::save_user_settings, + verify_email::verify_email, }, - post::{GetSiteMetadata, ListPostReports, MarkPostAsRead, ResolvePostReport, SavePost}, - private_message::{ - CreatePrivateMessageReport, - ListPrivateMessageReports, - MarkPrivateMessageAsRead, - ResolvePrivateMessageReport, + post::{ + feature::feature_post, + get_link_metadata::get_link_metadata, + like::like_post, + lock::lock_post, + mark_read::mark_post_as_read, + save::save_post, + }, + post_report::{ + create::create_post_report, + list::list_post_reports, + resolve::resolve_post_report, + }, + private_message::mark_read::mark_pm_as_read, + private_message_report::{ + create::create_pm_report, + list::list_pm_reports, + resolve::resolve_pm_report, }, site::{ - ApproveRegistrationApplication, - GetFederatedInstances, - GetModlog, - GetUnreadRegistrationApplicationCount, - LeaveAdmin, - ListRegistrationApplications, - PurgeComment, - PurgeCommunity, - PurgePerson, - PurgePost, + federated_instances::get_federated_instances, + leave_admin::leave_admin, + mod_log::get_mod_log, + purge::{ + comment::purge_comment, + community::purge_community, + person::purge_person, + post::purge_post, + }, + registration_applications::{ + approve::approve_registration_application, + list::list_registration_applications, + unread_count::get_unread_registration_application_count, + }, }, + sitemap::get_sitemap, }; use lemmy_api_crud::{ comment::{ @@ -96,19 +109,15 @@ use lemmy_api_crud::{ site::{create::create_site, read::get_site, update::update_site}, user::{create::register, delete::delete_account}, }; -use lemmy_apub::{ - api::{ - list_comments::list_comments, - list_posts::list_posts, - read_community::get_community, - read_person::read_person, - resolve_object::resolve_object, - search::search, - }, - SendActivity, +use lemmy_apub::api::{ + list_comments::list_comments, + list_posts::list_posts, + read_community::get_community, + read_person::read_person, + resolve_object::resolve_object, + search::search, }; -use lemmy_utils::{rate_limit::RateLimitCell, spawn_try_task, SYNCHRONOUS_FEDERATION}; -use serde::Deserialize; +use lemmy_utils::rate_limit::RateLimitCell; pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) { cfg.service( @@ -125,7 +134,7 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) { .service( web::resource("/modlog") .wrap(rate_limit.message()) - .route(web::get().to(route_get::)), + .route(web::get().to(get_mod_log)), ) .service( web::resource("/search") @@ -156,14 +165,14 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) { .route("/delete", web::post().to(delete_community)) // Mod Actions .route("/remove", web::post().to(remove_community)) - .route("/transfer", web::post().to(route_post::)) + .route("/transfer", web::post().to(transfer_community)) .route("/ban_user", web::post().to(ban_from_community)) .route("/mod", web::post().to(add_mod_to_community)), ) .service( web::scope("/federated_instances") .wrap(rate_limit.message()) - .route("", web::get().to(route_get::)), + .route("", web::get().to(get_federated_instances)), ) // Post .service( @@ -180,25 +189,16 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) { .route("", web::put().to(update_post)) .route("/delete", web::post().to(delete_post)) .route("/remove", web::post().to(remove_post)) - .route( - "/mark_as_read", - web::post().to(route_post::), - ) + .route("/mark_as_read", web::post().to(mark_post_as_read)) .route("/lock", web::post().to(lock_post)) .route("/feature", web::post().to(feature_post)) .route("/list", web::get().to(list_posts)) .route("/like", web::post().to(like_post)) - .route("/save", web::put().to(route_post::)) + .route("/save", web::put().to(save_post)) .route("/report", web::post().to(create_post_report)) - .route( - "/report/resolve", - web::put().to(route_post::), - ) - .route("/report/list", web::get().to(route_get::)) - .route( - "/site_metadata", - web::get().to(route_get::), - ), + .route("/report/resolve", web::put().to(resolve_post_report)) + .route("/report/list", web::get().to(list_post_reports)) + .route("/site_metadata", web::get().to(get_link_metadata)), ) // Comment .service( @@ -232,22 +232,10 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) { .route("", web::post().to(create_private_message)) .route("", web::put().to(update_private_message)) .route("/delete", web::post().to(delete_private_message)) - .route( - "/mark_as_read", - web::post().to(route_post::), - ) - .route( - "/report", - web::post().to(route_post::), - ) - .route( - "/report/resolve", - web::put().to(route_post::), - ) - .route( - "/report/list", - web::get().to(route_get::), - ), + .route("/mark_as_read", web::post().to(mark_pm_as_read)) + .route("/report", web::post().to(create_pm_report)) + .route("/report/resolve", web::put().to(resolve_pm_report)) + .route("/report/list", web::get().to(list_pm_reports)), ) // User .service( @@ -262,75 +250,66 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) { // Handle captcha separately web::resource("/user/get_captcha") .wrap(rate_limit.post()) - .route(web::get().to(route_get::)), + .route(web::get().to(get_captcha)), ) // User actions .service( web::scope("/user") .wrap(rate_limit.message()) .route("", web::get().to(read_person)) - .route("/mention", web::get().to(route_get::)) + .route("/mention", web::get().to(list_mentions)) .route( "/mention/mark_as_read", - web::post().to(route_post::), + web::post().to(mark_person_mention_as_read), ) - .route("/replies", web::get().to(route_get::)) + .route("/replies", web::get().to(list_replies)) // Admin action. I don't like that it's in /user .route("/ban", web::post().to(ban_from_site)) - .route("/banned", web::get().to(route_get::)) - .route("/block", web::post().to(route_post::)) + .route("/banned", web::get().to(list_banned_users)) + .route("/block", web::post().to(block_person)) // Account actions. I don't like that they're in /user maybe /accounts - .route("/login", web::post().to(route_post::)) + .route("/login", web::post().to(login)) .route("/delete_account", web::post().to(delete_account)) - .route( - "/password_reset", - web::post().to(route_post::), - ) + .route("/password_reset", web::post().to(reset_password)) .route( "/password_change", - web::post().to(route_post::), + web::post().to(change_password_after_reset), ) // mark_all_as_read feels off being in this section as well .route( "/mark_all_as_read", - web::post().to(route_post::), + web::post().to(mark_all_notifications_read), ) - .route( - "/save_user_settings", - web::put().to(route_post::), - ) - .route( - "/change_password", - web::put().to(route_post::), - ) - .route("/report_count", web::get().to(route_get::)) - .route("/unread_count", web::get().to(route_get::)) - .route("/verify_email", web::post().to(route_post::)) - .route("/leave_admin", web::post().to(route_post::)), + .route("/save_user_settings", web::put().to(save_user_settings)) + .route("/change_password", web::put().to(change_password)) + .route("/report_count", web::get().to(report_count)) + .route("/unread_count", web::get().to(unread_count)) + .route("/verify_email", web::post().to(verify_email)) + .route("/leave_admin", web::post().to(leave_admin)), ) // Admin Actions .service( web::scope("/admin") .wrap(rate_limit.message()) - .route("/add", web::post().to(route_post::)) + .route("/add", web::post().to(add_admin)) .route( "/registration_application/count", - web::get().to(route_get::), + web::get().to(get_unread_registration_application_count), ) .route( "/registration_application/list", - web::get().to(route_get::), + web::get().to(list_registration_applications), ) .route( "/registration_application/approve", - web::put().to(route_post::), + web::put().to(approve_registration_application), ) .service( web::scope("/purge") - .route("/person", web::post().to(route_post::)) - .route("/community", web::post().to(route_post::)) - .route("/post", web::post().to(route_post::)) - .route("/comment", web::post().to(route_post::)), + .route("/person", web::post().to(purge_person)) + .route("/community", web::post().to(purge_community)) + .route("/post", web::post().to(purge_post)) + .route("/comment", web::post().to(purge_comment)), ), ) .service( @@ -347,59 +326,3 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimitCell) { .route("", web::get().to(get_sitemap)), ); } - -async fn perform<'a, Data>( - data: Data, - context: web::Data, - apub_data: activitypub_federation::config::Data, -) -> Result -where - Data: Perform - + SendActivity::Response> - + Clone - + Deserialize<'a> - + Send - + 'static, -{ - let res = data.perform(&context).await?; - let res_clone = res.clone(); - let fed_task = async move { SendActivity::send_activity(&data, &res_clone, &apub_data).await }; - if *SYNCHRONOUS_FEDERATION { - fed_task.await?; - } else { - spawn_try_task(fed_task); - } - Ok(HttpResponse::Ok().json(&res)) -} - -async fn route_get<'a, Data>( - data: web::Query, - context: web::Data, - apub_data: activitypub_federation::config::Data, -) -> Result -where - Data: Perform - + SendActivity::Response> - + Clone - + Deserialize<'a> - + Send - + 'static, -{ - perform::(data.0, context, apub_data).await -} - -async fn route_post<'a, Data>( - data: web::Json, - context: web::Data, - apub_data: activitypub_federation::config::Data, -) -> Result -where - Data: Perform - + SendActivity::Response> - + Clone - + Deserialize<'a> - + Send - + 'static, -{ - perform::(data.0, context, apub_data).await -}