diff --git a/Cargo.lock b/Cargo.lock index 5e879b8a2..f7e91c129 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1759,6 +1759,7 @@ dependencies = [ "strum_macros", "thiserror", "tokio", + "tracing", "url", "uuid", ] diff --git a/crates/api/Cargo.toml b/crates/api/Cargo.toml index 96b47f464..c2bc77faa 100644 --- a/crates/api/Cargo.toml +++ b/crates/api/Cargo.toml @@ -48,5 +48,6 @@ async-trait = "0.1.51" captcha = "0.0.8" anyhow = "1.0.44" thiserror = "1.0.29" +tracing = "0.1.29" background-jobs = "0.11.0" reqwest = { version = "0.11.4", features = ["json"] } diff --git a/crates/api/src/comment.rs b/crates/api/src/comment.rs index e673d4979..5ee360a7d 100644 --- a/crates/api/src/comment.rs +++ b/crates/api/src/comment.rs @@ -23,7 +23,7 @@ use lemmy_db_schema::{ traits::{Likeable, Saveable}, }; use lemmy_db_views::{comment_view::CommentView, local_user_view::LocalUserView}; -use lemmy_utils::{ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{ConnectionId, LemmyError}; use lemmy_websocket::{send::send_comment_ws_message, LemmyContext, UserOperation}; use crate::Perform; @@ -32,6 +32,7 @@ use crate::Perform; impl Perform for MarkCommentAsRead { type Response = CommentResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -56,7 +57,7 @@ impl Perform for MarkCommentAsRead { // Verify that only the recipient can mark as read if local_user_view.person.id != orig_comment.get_recipient_id() { - return Err(ApiError::err_plain("no_comment_edit_allowed").into()); + return Err(LemmyError::from_message("no_comment_edit_allowed".into())); } // Do the mark as read @@ -65,7 +66,8 @@ impl Perform for MarkCommentAsRead { Comment::update_read(conn, comment_id, read) }) .await? - .map_err(|_| ApiError::err_plain("couldnt_update_comment"))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_comment".into()))?; // Refetch it let comment_id = data.comment_id; @@ -89,6 +91,7 @@ impl Perform for MarkCommentAsRead { impl Perform for SaveComment { type Response = CommentResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -107,12 +110,14 @@ impl Perform for SaveComment { let save_comment = move |conn: &'_ _| CommentSaved::save(conn, &comment_saved_form); blocking(context.pool(), save_comment) .await? - .map_err(|e| ApiError::err("couldnt_save_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_save_comment".into()))?; } else { let unsave_comment = move |conn: &'_ _| CommentSaved::unsave(conn, &comment_saved_form); blocking(context.pool(), unsave_comment) .await? - .map_err(|e| ApiError::err("couldnt_save_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_save_comment".into()))?; } let comment_id = data.comment_id; @@ -134,6 +139,7 @@ impl Perform for SaveComment { impl Perform for CreateCommentLike { type Response = CommentResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -201,7 +207,8 @@ impl Perform for CreateCommentLike { let like = move |conn: &'_ _| CommentLike::like(conn, &like_form2); blocking(context.pool(), like) .await? - .map_err(|e| ApiError::err("couldnt_like_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_like_comment".into()))?; Vote::send( &object, diff --git a/crates/api/src/comment_report.rs b/crates/api/src/comment_report.rs index f1bf7023c..1c8d11106 100644 --- a/crates/api/src/comment_report.rs +++ b/crates/api/src/comment_report.rs @@ -14,7 +14,7 @@ use lemmy_db_views::{ comment_report_view::{CommentReportQueryBuilder, CommentReportView}, comment_view::CommentView, }; -use lemmy_utils::{ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{ConnectionId, LemmyError}; use lemmy_websocket::{messages::SendModRoomMessage, LemmyContext, UserOperation}; /// Creates a comment report and notifies the moderators of the community @@ -22,6 +22,7 @@ use lemmy_websocket::{messages::SendModRoomMessage, LemmyContext, UserOperation} impl Perform for CreateCommentReport { type Response = CommentReportResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -34,10 +35,10 @@ impl Perform for CreateCommentReport { // check size of report and check for whitespace let reason = data.reason.trim(); if reason.is_empty() { - return Err(ApiError::err_plain("report_reason_required").into()); + return Err(LemmyError::from_message("report_reason_required".into())); } if reason.chars().count() > 1000 { - return Err(ApiError::err_plain("report_too_long").into()); + return Err(LemmyError::from_message("report_too_long".into())); } let person_id = local_user_view.person.id; @@ -60,7 +61,8 @@ impl Perform for CreateCommentReport { CommentReport::report(conn, &report_form) }) .await? - .map_err(|e| ApiError::err("couldnt_create_report", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_create_report".into()))?; let comment_report_view = blocking(context.pool(), move |conn| { CommentReportView::read(conn, report.id, person_id) @@ -96,6 +98,7 @@ impl Perform for CreateCommentReport { impl Perform for ResolveCommentReport { type Response = CommentReportResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -126,7 +129,8 @@ impl Perform for ResolveCommentReport { blocking(context.pool(), resolve_fun) .await? - .map_err(|e| ApiError::err("couldnt_resolve_report", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_resolve_report".into()))?; let report_id = data.report_id; let comment_report_view = blocking(context.pool(), move |conn| { @@ -155,6 +159,7 @@ impl Perform for ResolveCommentReport { impl Perform for ListCommentReports { type Response = ListCommentReportsResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, diff --git a/crates/api/src/community.rs b/crates/api/src/community.rs index b47a4ec60..4877ddb51 100644 --- a/crates/api/src/community.rs +++ b/crates/api/src/community.rs @@ -54,13 +54,14 @@ use lemmy_db_views_actor::{ community_view::CommunityView, person_view::PersonViewSafe, }; -use lemmy_utils::{location_info, utils::naive_from_unix, ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{location_info, utils::naive_from_unix, ConnectionId, LemmyError}; use lemmy_websocket::{messages::SendCommunityRoomMessage, LemmyContext, UserOperation}; #[async_trait::async_trait(?Send)] impl Perform for FollowCommunity { type Response = CommunityResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -90,13 +91,15 @@ impl Perform for FollowCommunity { let follow = move |conn: &'_ _| CommunityFollower::follow(conn, &community_follower_form); blocking(context.pool(), follow) .await? - .map_err(|e| ApiError::err("community_follower_already_exists", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("community_follower_already_exists".into()))?; } else { let unfollow = move |conn: &'_ _| CommunityFollower::unfollow(conn, &community_follower_form); blocking(context.pool(), unfollow) .await? - .map_err(|e| ApiError::err("community_follower_already_exists", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("community_follower_already_exists".into()))?; } } else if data.follow { // Dont actually add to the community followers here, because you need @@ -109,7 +112,8 @@ impl Perform for FollowCommunity { let unfollow = move |conn: &'_ _| CommunityFollower::unfollow(conn, &community_follower_form); blocking(context.pool(), unfollow) .await? - .map_err(|e| ApiError::err("community_follower_already_exists", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("community_follower_already_exists".into()))?; } let community_id = data.community_id; @@ -134,6 +138,7 @@ impl Perform for FollowCommunity { impl Perform for BlockCommunity { type Response = BlockCommunityResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -154,7 +159,8 @@ impl Perform for BlockCommunity { let block = move |conn: &'_ _| CommunityBlock::block(conn, &community_block_form); blocking(context.pool(), block) .await? - .map_err(|e| ApiError::err("community_block_already_exists", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("community_block_already_exists".into()))?; // Also, unfollow the community, and send a federated unfollow let community_follower_form = CommunityFollowerForm { @@ -176,7 +182,8 @@ impl Perform for BlockCommunity { let unblock = move |conn: &'_ _| CommunityBlock::unblock(conn, &community_block_form); blocking(context.pool(), unblock) .await? - .map_err(|e| ApiError::err("community_block_already_exists", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("community_block_already_exists".into()))?; } let community_view = blocking(context.pool(), move |conn| { @@ -195,6 +202,7 @@ impl Perform for BlockCommunity { impl Perform for BanFromCommunity { type Response = BanFromCommunityResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -230,7 +238,8 @@ impl Perform for BanFromCommunity { let ban = move |conn: &'_ _| CommunityPersonBan::ban(conn, &community_user_ban_form); blocking(context.pool(), ban) .await? - .map_err(|e| ApiError::err("community_user_already_banned", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("community_user_already_banned".into()))?; // Also unsubscribe them from the community, if they are subscribed let community_follower_form = CommunityFollowerForm { @@ -255,7 +264,8 @@ impl Perform for BanFromCommunity { let unban = move |conn: &'_ _| CommunityPersonBan::unban(conn, &community_user_ban_form); blocking(context.pool(), unban) .await? - .map_err(|e| ApiError::err("community_user_already_banned", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("community_user_already_banned".into()))?; UndoBlockUserFromCommunity::send( &community, &banned_person, @@ -336,6 +346,7 @@ impl Perform for BanFromCommunity { impl Perform for AddModToCommunity { type Response = AddModToCommunityResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -359,12 +370,14 @@ impl Perform for AddModToCommunity { let join = move |conn: &'_ _| CommunityModerator::join(conn, &community_moderator_form); blocking(context.pool(), join) .await? - .map_err(|e| ApiError::err("community_moderator_already_exists", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("community_moderator_already_exists".into()))?; } else { let leave = move |conn: &'_ _| CommunityModerator::leave(conn, &community_moderator_form); blocking(context.pool(), leave) .await? - .map_err(|e| ApiError::err("community_moderator_already_exists", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("community_moderator_already_exists".into()))?; } // Mod tables @@ -434,6 +447,7 @@ impl Perform for AddModToCommunity { impl Perform for TransferCommunity { type Response = GetCommunityResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -472,7 +486,7 @@ impl Perform for TransferCommunity { .map(|a| a.person.id) .any(|x| x == local_user_view.person.id) { - return Err(ApiError::err_plain("not_an_admin").into()); + return Err(LemmyError::from_message("not_an_admin".into())); } // You have to re-do the community_moderator table, reordering it. @@ -502,7 +516,8 @@ impl Perform for TransferCommunity { let join = move |conn: &'_ _| CommunityModerator::join(conn, &community_moderator_form); blocking(context.pool(), join) .await? - .map_err(|e| ApiError::err("community_moderator_already_exists", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("community_moderator_already_exists".into()))?; } // Mod tables @@ -523,14 +538,16 @@ impl Perform for TransferCommunity { CommunityView::read(conn, community_id, Some(person_id)) }) .await? - .map_err(|e| ApiError::err("couldnt_find_community", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_find_community".into()))?; let community_id = data.community_id; let moderators = blocking(context.pool(), move |conn| { CommunityModeratorView::for_community(conn, community_id) }) .await? - .map_err(|e| ApiError::err("couldnt_find_community", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_find_community".into()))?; // Return the jwt Ok(GetCommunityResponse { diff --git a/crates/api/src/local_user.rs b/crates/api/src/local_user.rs index 6f63d14b1..22d788e92 100644 --- a/crates/api/src/local_user.rs +++ b/crates/api/src/local_user.rs @@ -49,7 +49,6 @@ use lemmy_utils::{ email::send_email, location_info, utils::{generate_random_string, is_valid_display_name, is_valid_matrix_id, naive_from_unix}, - ApiError, ConnectionId, LemmyError, }; @@ -63,6 +62,7 @@ use lemmy_websocket::{ impl Perform for Login { type Response = LoginResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -76,7 +76,8 @@ impl Perform for Login { LocalUserView::find_by_email_or_name(conn, &username_or_email) }) .await? - .map_err(|e| ApiError::err("couldnt_find_that_username_or_email", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_find_that_username_or_email".into()))?; // Verify the password let valid: bool = verify( @@ -85,7 +86,7 @@ impl Perform for Login { ) .unwrap_or(false); if !valid { - return Err(ApiError::err_plain("password_incorrect").into()); + return Err(LemmyError::from_message("password_incorrect".into())); } // Return the jwt @@ -103,6 +104,7 @@ impl Perform for Login { impl Perform for GetCaptcha { type Response = GetCaptchaResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -148,6 +150,7 @@ impl Perform for GetCaptcha { impl Perform for SaveUserSettings { type Response = LoginResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -167,7 +170,7 @@ impl Perform for SaveUserSettings { if let Some(Some(bio)) = &bio { if bio.chars().count() > 300 { - return Err(ApiError::err_plain("bio_length_overflow").into()); + return Err(LemmyError::from_message("bio_length_overflow".into())); } } @@ -176,13 +179,13 @@ impl Perform for SaveUserSettings { display_name.trim(), context.settings().actor_name_max_length, ) { - return Err(ApiError::err_plain("invalid_username").into()); + return Err(LemmyError::from_message("invalid_username".into())); } } if let Some(Some(matrix_user_id)) = &matrix_user_id { if !is_valid_matrix_id(matrix_user_id) { - return Err(ApiError::err_plain("invalid_matrix_id").into()); + return Err(LemmyError::from_message("invalid_matrix_id".into())); } } @@ -219,7 +222,8 @@ impl Perform for SaveUserSettings { Person::update(conn, person_id, &person_form) }) .await? - .map_err(|e| ApiError::err("user_already_exists", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("user_already_exists".into()))?; let local_user_form = LocalUserForm { person_id, @@ -253,7 +257,7 @@ impl Perform for SaveUserSettings { "user_already_exists" }; - return Err(ApiError::err(err_type, e).into()); + return Err(LemmyError::from(e).with_message(err_type.into())); } }; @@ -272,6 +276,7 @@ impl Perform for SaveUserSettings { impl Perform for ChangePassword { type Response = LoginResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -285,7 +290,7 @@ impl Perform for ChangePassword { // Make sure passwords match if data.new_password != data.new_password_verify { - return Err(ApiError::err_plain("passwords_dont_match").into()); + return Err(LemmyError::from_message("passwords_dont_match".into())); } // Check the old password @@ -295,7 +300,7 @@ impl Perform for ChangePassword { ) .unwrap_or(false); if !valid { - return Err(ApiError::err_plain("password_incorrect").into()); + return Err(LemmyError::from_message("password_incorrect".into())); } let local_user_id = local_user_view.local_user.id; @@ -320,6 +325,7 @@ impl Perform for ChangePassword { impl Perform for AddAdmin { type Response = AddAdminResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -338,7 +344,8 @@ impl Perform for AddAdmin { Person::add_admin(conn, added_person_id, added) }) .await? - .map_err(|e| ApiError::err("couldnt_update_user", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_user".into()))?; // Mod tables let form = ModAddForm { @@ -378,6 +385,7 @@ impl Perform for AddAdmin { impl Perform for BanPerson { type Response = BanPersonResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -395,7 +403,8 @@ impl Perform for BanPerson { let ban_person = move |conn: &'_ _| Person::ban_person(conn, banned_person_id, ban); blocking(context.pool(), ban_person) .await? - .map_err(|e| ApiError::err("couldnt_update_user", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_user".into()))?; // Remove their data if that's desired if data.remove_data.unwrap_or(false) { @@ -471,6 +480,7 @@ impl Perform for BanPerson { impl Perform for BlockPerson { type Response = BlockPersonResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -485,7 +495,7 @@ impl Perform for BlockPerson { // Don't let a person block themselves if target_id == person_id { - return Err(ApiError::err_plain("cant_block_yourself").into()); + return Err(LemmyError::from_message("cant_block_yourself".into())); } let person_block_form = PersonBlockForm { @@ -497,12 +507,14 @@ impl Perform for BlockPerson { let block = move |conn: &'_ _| PersonBlock::block(conn, &person_block_form); blocking(context.pool(), block) .await? - .map_err(|e| ApiError::err("person_block_already_exists", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("person_block_already_exists".into()))?; } else { let unblock = move |conn: &'_ _| PersonBlock::unblock(conn, &person_block_form); blocking(context.pool(), unblock) .await? - .map_err(|e| ApiError::err("person_block_already_exists", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("person_block_already_exists".into()))?; } // TODO does any federated stuff need to be done here? @@ -525,6 +537,7 @@ impl Perform for BlockPerson { impl Perform for GetReplies { type Response = GetRepliesResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -563,6 +576,7 @@ impl Perform for GetReplies { impl Perform for GetPersonMentions { type Response = GetPersonMentionsResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -598,6 +612,7 @@ impl Perform for GetPersonMentions { impl Perform for MarkPersonMentionAsRead { type Response = PersonMentionResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -614,7 +629,7 @@ impl Perform for MarkPersonMentionAsRead { .await??; if local_user_view.person.id != read_person_mention.recipient_id { - return Err(ApiError::err_plain("couldnt_update_comment").into()); + return Err(LemmyError::from_message("couldnt_update_comment".into())); } let person_mention_id = read_person_mention.id; @@ -623,7 +638,8 @@ impl Perform for MarkPersonMentionAsRead { move |conn: &'_ _| PersonMention::update_read(conn, person_mention_id, read); blocking(context.pool(), update_mention) .await? - .map_err(|e| ApiError::err("couldnt_update_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_comment".into()))?; let person_mention_id = read_person_mention.id; let person_id = local_user_view.person.id; @@ -642,6 +658,7 @@ impl Perform for MarkPersonMentionAsRead { impl Perform for MarkAllAsRead { type Response = GetRepliesResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -671,7 +688,8 @@ impl Perform for MarkAllAsRead { let mark_as_read = move |conn: &'_ _| Comment::update_read(conn, reply_id, true); blocking(context.pool(), mark_as_read) .await? - .map_err(|e| ApiError::err("couldnt_update_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_comment".into()))?; } // Mark all user mentions as read @@ -679,13 +697,15 @@ impl Perform for MarkAllAsRead { move |conn: &'_ _| PersonMention::mark_all_as_read(conn, person_id); blocking(context.pool(), update_person_mentions) .await? - .map_err(|e| ApiError::err("couldnt_update_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_comment".into()))?; // Mark all private_messages as read let update_pm = move |conn: &'_ _| PrivateMessage::mark_all_as_read(conn, person_id); blocking(context.pool(), update_pm) .await? - .map_err(|e| ApiError::err("couldnt_update_private_message", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_private_message".into()))?; Ok(GetRepliesResponse { replies: vec![] }) } @@ -695,6 +715,7 @@ impl Perform for MarkAllAsRead { impl Perform for PasswordReset { type Response = PasswordResetResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -708,7 +729,8 @@ impl Perform for PasswordReset { LocalUserView::find_by_email(conn, &email) }) .await? - .map_err(|e| ApiError::err("couldnt_find_that_username_or_email", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_find_that_username_or_email".into()))?; // Generate a random token let token = generate_random_string(); @@ -734,7 +756,8 @@ impl Perform for PasswordReset { html, &context.settings(), ) - .map_err(|e| ApiError::err("email_send_failed", e))?; + .map_err(LemmyError::from_message) + .map_err(|e| e.with_message("email_send_failed".into()))?; Ok(PasswordResetResponse {}) } @@ -744,6 +767,7 @@ impl Perform for PasswordReset { impl Perform for PasswordChange { type Response = LoginResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -762,7 +786,7 @@ impl Perform for PasswordChange { // Make sure passwords match if data.password != data.password_verify { - return Err(ApiError::err_plain("passwords_dont_match").into()); + return Err(LemmyError::from_message("passwords_dont_match".into())); } // Update the user with the new password @@ -771,7 +795,8 @@ impl Perform for PasswordChange { LocalUser::update_password(conn, local_user_id, &password) }) .await? - .map_err(|e| ApiError::err("couldnt_update_user", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_user".into()))?; // Return the jwt Ok(LoginResponse { @@ -788,6 +813,7 @@ impl Perform for PasswordChange { impl Perform for GetReportCount { type Response = GetReportCountResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -825,6 +851,7 @@ impl Perform for GetReportCount { impl Perform for GetUnreadCount { type Response = GetUnreadCountResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, diff --git a/crates/api/src/post.rs b/crates/api/src/post.rs index 60a580b84..ef2a97cc2 100644 --- a/crates/api/src/post.rs +++ b/crates/api/src/post.rs @@ -29,7 +29,7 @@ use lemmy_db_schema::{ traits::{Crud, Likeable, Saveable}, }; use lemmy_db_views::post_view::PostView; -use lemmy_utils::{request::fetch_site_metadata, ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{request::fetch_site_metadata, ConnectionId, LemmyError}; use lemmy_websocket::{send::send_post_ws_message, LemmyContext, UserOperation}; use std::convert::TryInto; @@ -37,6 +37,7 @@ use std::convert::TryInto; impl Perform for CreatePostLike { type Response = PostResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -83,7 +84,8 @@ impl Perform for CreatePostLike { let like = move |conn: &'_ _| PostLike::like(conn, &like_form2); blocking(context.pool(), like) .await? - .map_err(|e| ApiError::err("couldnt_like_post", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_like_post".into()))?; Vote::send( &object, @@ -123,6 +125,7 @@ impl Perform for CreatePostLike { impl Perform for MarkPostAsRead { type Response = PostResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -158,6 +161,7 @@ impl Perform for MarkPostAsRead { impl Perform for LockPost { type Response = PostResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -227,6 +231,7 @@ impl Perform for LockPost { impl Perform for StickyPost { type Response = PostResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -300,6 +305,7 @@ impl Perform for StickyPost { impl Perform for SavePost { type Response = PostResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -318,12 +324,14 @@ impl Perform for SavePost { let save = move |conn: &'_ _| PostSaved::save(conn, &post_saved_form); blocking(context.pool(), save) .await? - .map_err(|e| ApiError::err("couldnt_save_post", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_save_post".into()))?; } else { let unsave = move |conn: &'_ _| PostSaved::unsave(conn, &post_saved_form); blocking(context.pool(), unsave) .await? - .map_err(|e| ApiError::err("couldnt_save_post", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_save_post".into()))?; } let post_id = data.post_id; @@ -344,6 +352,7 @@ impl Perform for SavePost { impl Perform for GetSiteMetadata { type Response = GetSiteMetadataResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, diff --git a/crates/api/src/post_report.rs b/crates/api/src/post_report.rs index 0e47f592d..c87b11e1e 100644 --- a/crates/api/src/post_report.rs +++ b/crates/api/src/post_report.rs @@ -23,7 +23,7 @@ use lemmy_db_views::{ post_report_view::{PostReportQueryBuilder, PostReportView}, post_view::PostView, }; -use lemmy_utils::{ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{ConnectionId, LemmyError}; use lemmy_websocket::{messages::SendModRoomMessage, LemmyContext, UserOperation}; /// Creates a post report and notifies the moderators of the community @@ -31,6 +31,7 @@ use lemmy_websocket::{messages::SendModRoomMessage, LemmyContext, UserOperation} impl Perform for CreatePostReport { type Response = PostReportResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -43,10 +44,10 @@ impl Perform for CreatePostReport { // check size of report and check for whitespace let reason = data.reason.trim(); if reason.is_empty() { - return Err(ApiError::err_plain("report_reason_required").into()); + return Err(LemmyError::from_message("report_reason_required".into())); } if reason.chars().count() > 1000 { - return Err(ApiError::err_plain("report_too_long").into()); + return Err(LemmyError::from_message("report_too_long".into())); } let person_id = local_user_view.person.id; @@ -71,7 +72,8 @@ impl Perform for CreatePostReport { PostReport::report(conn, &report_form) }) .await? - .map_err(|e| ApiError::err("couldnt_create_report", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_create_report".into()))?; let post_report_view = blocking(context.pool(), move |conn| { PostReportView::read(conn, report.id, person_id) @@ -105,6 +107,7 @@ impl Perform for CreatePostReport { impl Perform for ResolvePostReport { type Response = PostReportResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -135,7 +138,8 @@ impl Perform for ResolvePostReport { blocking(context.pool(), resolve_fun) .await? - .map_err(|e| ApiError::err("couldnt_resolve_report", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_resolve_report".into()))?; let post_report_view = blocking(context.pool(), move |conn| { PostReportView::read(conn, report_id, person_id) @@ -161,6 +165,7 @@ impl Perform for ResolvePostReport { impl Perform for ListPostReports { type Response = ListPostReportsResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, diff --git a/crates/api/src/private_message.rs b/crates/api/src/private_message.rs index 1c80f44f4..b87639fc1 100644 --- a/crates/api/src/private_message.rs +++ b/crates/api/src/private_message.rs @@ -6,13 +6,14 @@ use lemmy_api_common::{ person::{MarkPrivateMessageAsRead, PrivateMessageResponse}, }; use lemmy_db_schema::{source::private_message::PrivateMessage, traits::Crud}; -use lemmy_utils::{ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{ConnectionId, LemmyError}; use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperation}; #[async_trait::async_trait(?Send)] impl Perform for MarkPrivateMessageAsRead { type Response = PrivateMessageResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -29,7 +30,9 @@ impl Perform for MarkPrivateMessageAsRead { }) .await??; if local_user_view.person.id != orig_private_message.recipient_id { - return Err(ApiError::err_plain("couldnt_update_private_message").into()); + return Err(LemmyError::from_message( + "couldnt_update_private_message".into(), + )); } // Doing the update @@ -39,7 +42,8 @@ impl Perform for MarkPrivateMessageAsRead { PrivateMessage::update_read(conn, private_message_id, read) }) .await? - .map_err(|e| ApiError::err("couldnt_update_private_message", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_private_message".into()))?; // No need to send an apub update let op = UserOperation::MarkPrivateMessageAsRead; diff --git a/crates/api/src/site.rs b/crates/api/src/site.rs index be9dc5da1..1de1a6679 100644 --- a/crates/api/src/site.rs +++ b/crates/api/src/site.rs @@ -49,20 +49,14 @@ use lemmy_db_views_moderator::{ mod_sticky_post_view::ModStickyPostView, mod_transfer_community_view::ModTransferCommunityView, }; -use lemmy_utils::{ - location_info, - settings::structs::Settings, - version, - ApiError, - ConnectionId, - LemmyError, -}; +use lemmy_utils::{location_info, settings::structs::Settings, version, ConnectionId, LemmyError}; use lemmy_websocket::LemmyContext; #[async_trait::async_trait(?Send)] impl Perform for GetModlog { type Response = GetModlogResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -143,6 +137,7 @@ impl Perform for GetModlog { impl Perform for Search { type Response = SearchResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -383,6 +378,7 @@ impl Perform for Search { impl Perform for ResolveObject { type Response = ResolveObjectResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -392,10 +388,12 @@ impl Perform for ResolveObject { get_local_user_view_from_jwt_opt(&self.auth, context.pool(), context.secret()).await?; let res = search_by_apub_id(&self.q, context) .await - .map_err(|e| ApiError::err("couldnt_find_object", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_find_object".into()))?; convert_response(res, local_user_view.map(|l| l.person.id), context.pool()) .await - .map_err(|e| ApiError::err("couldnt_find_object", e).into()) + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_find_object".into())) } } @@ -442,6 +440,7 @@ async fn convert_response( impl Perform for TransferSite { type Response = GetSiteResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -457,14 +456,15 @@ impl Perform for TransferSite { // Make sure user is the creator if read_site.creator_id != local_user_view.person.id { - return Err(ApiError::err_plain("not_an_admin").into()); + return Err(LemmyError::from_message("not_an_admin".into())); } let new_creator_id = data.person_id; let transfer_site = move |conn: &'_ _| Site::transfer(conn, new_creator_id); blocking(context.pool(), transfer_site) .await? - .map_err(|e| ApiError::err("couldnt_update_site", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_site".into()))?; // Mod tables let form = ModAddForm { @@ -509,6 +509,7 @@ impl Perform for TransferSite { impl Perform for GetSiteConfig { type Response = GetSiteConfigResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -531,6 +532,7 @@ impl Perform for GetSiteConfig { impl Perform for SaveSiteConfig { type Response = GetSiteConfigResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -545,7 +547,8 @@ impl Perform for SaveSiteConfig { // Make sure docker doesn't have :ro at the end of the volume, so its not a read-only filesystem let config_hjson = Settings::save_config_file(&data.config_hjson) - .map_err(|e| ApiError::err("couldnt_update_site", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_site".into()))?; Ok(GetSiteConfigResponse { config_hjson }) } diff --git a/crates/api/src/websocket.rs b/crates/api/src/websocket.rs index fa03e4ecf..c908d09b1 100644 --- a/crates/api/src/websocket.rs +++ b/crates/api/src/websocket.rs @@ -11,6 +11,7 @@ use lemmy_websocket::{ impl Perform for UserJoin { type Response = UserJoinResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -35,6 +36,7 @@ impl Perform for UserJoin { impl Perform for CommunityJoin { type Response = CommunityJoinResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -57,6 +59,7 @@ impl Perform for CommunityJoin { impl Perform for ModJoin { type Response = ModJoinResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -79,6 +82,7 @@ impl Perform for ModJoin { impl Perform for PostJoin { type Response = PostJoinResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, diff --git a/crates/api_common/src/lib.rs b/crates/api_common/src/lib.rs index f5b6ebad2..384f8ca7d 100644 --- a/crates/api_common/src/lib.rs +++ b/crates/api_common/src/lib.rs @@ -23,7 +23,7 @@ use lemmy_db_views_actor::{ community_person_ban_view::CommunityPersonBanView, community_view::CommunityView, }; -use lemmy_utils::{claims::Claims, settings::structs::FederationConfig, ApiError, LemmyError}; +use lemmy_utils::{claims::Claims, settings::structs::FederationConfig, LemmyError}; use url::Url; pub async fn blocking(pool: &DbPool, f: F) -> Result @@ -52,14 +52,14 @@ pub async fn is_mod_or_admin( }) .await?; if !is_mod_or_admin { - return Err(ApiError::err_plain("not_a_mod_or_admin").into()); + return Err(LemmyError::from_message("not_a_mod_or_admin".into())); } Ok(()) } pub fn is_admin(local_user_view: &LocalUserView) -> Result<(), LemmyError> { if !local_user_view.person.admin { - return Err(ApiError::err_plain("not_an_admin").into()); + return Err(LemmyError::from_message("not_an_admin".into())); } Ok(()) } @@ -67,7 +67,8 @@ pub fn is_admin(local_user_view: &LocalUserView) -> Result<(), LemmyError> { pub async fn get_post(post_id: PostId, pool: &DbPool) -> Result { blocking(pool, move |conn| Post::read(conn, post_id)) .await? - .map_err(|_| ApiError::err_plain("couldnt_find_post").into()) + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_find_post".into())) } pub async fn mark_post_as_read( @@ -81,7 +82,8 @@ pub async fn mark_post_as_read( PostRead::mark_as_read(conn, &post_read_form) }) .await? - .map_err(|e| ApiError::err("couldnt_mark_post_as_read", e).into()) + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_mark_post_as_read".into())) } pub async fn mark_post_as_unread( @@ -95,7 +97,8 @@ pub async fn mark_post_as_unread( PostRead::mark_as_unread(conn, &post_read_form) }) .await? - .map_err(|e| ApiError::err("couldnt_mark_post_as_read", e).into()) + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_mark_post_as_read".into())) } pub async fn get_local_user_view_from_jwt( @@ -104,19 +107,20 @@ pub async fn get_local_user_view_from_jwt( secret: &Secret, ) -> Result { let claims = Claims::decode(jwt, &secret.jwt_secret) - .map_err(|e| ApiError::err("not_logged_in", e))? + .map_err(LemmyError::from) + .map_err(|e| e.with_message("not_logged_in".into()))? .claims; let local_user_id = LocalUserId(claims.sub); let local_user_view = blocking(pool, move |conn| LocalUserView::read(conn, local_user_id)).await??; // Check for a site ban if local_user_view.person.banned { - return Err(ApiError::err_plain("site_ban").into()); + return Err(LemmyError::from_message("site_ban".into())); } // Check for user deletion if local_user_view.person.deleted { - return Err(ApiError::err_plain("deleted").into()); + return Err(LemmyError::from_message("deleted".into())); } check_validator_time(&local_user_view.local_user.validator_time, &claims)?; @@ -131,7 +135,7 @@ pub fn check_validator_time( ) -> Result<(), LemmyError> { let user_validation_time = validator_time.timestamp(); if user_validation_time > claims.iat { - Err(ApiError::err_plain("not_logged_in").into()) + Err(LemmyError::from_message("not_logged_in".into())) } else { Ok(()) } @@ -154,7 +158,8 @@ pub async fn get_local_user_settings_view_from_jwt( secret: &Secret, ) -> Result { let claims = Claims::decode(jwt, &secret.jwt_secret) - .map_err(|e| ApiError::err("not_logged_in", e))? + .map_err(LemmyError::from) + .map_err(|e| e.with_message("not_logged_in".into()))? .claims; let local_user_id = LocalUserId(claims.sub); let local_user_view = blocking(pool, move |conn| { @@ -163,7 +168,7 @@ pub async fn get_local_user_settings_view_from_jwt( .await??; // Check for a site ban if local_user_view.person.banned { - return Err(ApiError::err_plain("site_ban").into()); + return Err(LemmyError::from_message("site_ban".into())); } check_validator_time(&local_user_view.local_user.validator_time, &claims)?; @@ -192,7 +197,7 @@ pub async fn check_community_ban( let is_banned = move |conn: &'_ _| CommunityPersonBanView::get(conn, person_id, community_id).is_ok(); if blocking(pool, is_banned).await? { - Err(ApiError::err_plain("community_ban").into()) + Err(LemmyError::from_message("community_ban".into())) } else { Ok(()) } @@ -204,9 +209,10 @@ pub async fn check_community_deleted_or_removed( ) -> Result<(), LemmyError> { let community = blocking(pool, move |conn| Community::read(conn, community_id)) .await? - .map_err(|e| ApiError::err("couldnt_find_community", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_find_community".into()))?; if community.deleted || community.removed { - Err(ApiError::err_plain("deleted").into()) + Err(LemmyError::from_message("deleted".into())) } else { Ok(()) } @@ -214,7 +220,7 @@ pub async fn check_community_deleted_or_removed( pub fn check_post_deleted_or_removed(post: &Post) -> Result<(), LemmyError> { if post.deleted || post.removed { - Err(ApiError::err_plain("deleted").into()) + Err(LemmyError::from_message("deleted".into())) } else { Ok(()) } @@ -227,7 +233,7 @@ pub async fn check_person_block( ) -> Result<(), LemmyError> { let is_blocked = move |conn: &'_ _| PersonBlock::read(conn, potential_blocker_id, my_id).is_ok(); if blocking(pool, is_blocked).await? { - Err(ApiError::err_plain("person_block").into()) + Err(LemmyError::from_message("person_block".into())) } else { Ok(()) } @@ -237,7 +243,7 @@ pub async fn check_downvotes_enabled(score: i16, pool: &DbPool) -> Result<(), Le if score == -1 { let site = blocking(pool, Site::read_simple).await??; if !site.enable_downvotes { - return Err(ApiError::err_plain("downvotes_disabled").into()); + return Err(LemmyError::from_message("downvotes_disabled".into())); } } Ok(()) @@ -288,7 +294,7 @@ pub async fn build_federated_instances( /// Checks the password length pub fn password_length_check(pass: &str) -> Result<(), LemmyError> { if !(10..=60).contains(&pass.len()) { - Err(ApiError::err_plain("invalid_password").into()) + Err(LemmyError::from_message("invalid_password".into())) } else { Ok(()) } @@ -297,7 +303,9 @@ pub fn password_length_check(pass: &str) -> Result<(), LemmyError> { /// Checks the site description length pub fn site_description_length_check(description: &str) -> Result<(), LemmyError> { if description.len() > 150 { - Err(ApiError::err_plain("site_description_length_overflow").into()) + Err(LemmyError::from_message( + "site_description_length_overflow".into(), + )) } else { Ok(()) } @@ -306,7 +314,7 @@ pub fn site_description_length_check(description: &str) -> Result<(), LemmyError /// Checks for a honeypot. If this field is filled, fail the rest of the function pub fn honeypot_check(honeypot: &Option) -> Result<(), LemmyError> { if honeypot.is_some() { - Err(ApiError::err_plain("honeypot_fail").into()) + Err(LemmyError::from_message("honeypot_fail".into())) } else { Ok(()) } diff --git a/crates/api_crud/src/comment/create.rs b/crates/api_crud/src/comment/create.rs index 09163aef4..e4583d504 100644 --- a/crates/api_crud/src/comment/create.rs +++ b/crates/api_crud/src/comment/create.rs @@ -31,7 +31,6 @@ use lemmy_db_schema::{ use lemmy_db_views::comment_view::CommentView; use lemmy_utils::{ utils::{remove_slurs, scrape_text_for_mentions}, - ApiError, ConnectionId, LemmyError, }; @@ -45,6 +44,7 @@ use lemmy_websocket::{ impl PerformCrud for CreateComment { type Response = CommentResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -70,7 +70,7 @@ impl PerformCrud for CreateComment { // Check if post is locked, no new comments if post.locked { - return Err(ApiError::err_plain("locked").into()); + return Err(LemmyError::from_message("locked".into())); } // If there's a parent_id, check to make sure that comment is in that post @@ -78,13 +78,14 @@ impl PerformCrud for CreateComment { // Make sure the parent comment exists let parent = blocking(context.pool(), move |conn| Comment::read(conn, parent_id)) .await? - .map_err(|e| ApiError::err("couldnt_create_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_create_comment".into()))?; check_person_block(local_user_view.person.id, parent.creator_id, context.pool()).await?; // Strange issue where sometimes the post ID is incorrect if parent.post_id != post_id { - return Err(ApiError::err_plain("couldnt_create_comment").into()); + return Err(LemmyError::from_message("couldnt_create_comment".into())); } } @@ -102,7 +103,8 @@ impl PerformCrud for CreateComment { Comment::create(conn, &comment_form2) }) .await? - .map_err(|e| ApiError::err("couldnt_create_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_create_comment".into()))?; // Necessary to update the ap_id let inserted_comment_id = inserted_comment.id; @@ -118,7 +120,8 @@ impl PerformCrud for CreateComment { Ok(Comment::update_ap_id(conn, inserted_comment_id, apub_id)?) }) .await? - .map_err(|e| ApiError::err("couldnt_create_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_create_comment".into()))?; // Scan the comment for user mentions, add those rows let post_id = post.id; @@ -144,7 +147,8 @@ impl PerformCrud for CreateComment { let like = move |conn: &'_ _| CommentLike::like(conn, &like_form); blocking(context.pool(), like) .await? - .map_err(|e| ApiError::err("couldnt_like_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_like_comment".into()))?; let apub_comment: ApubComment = updated_comment.into(); CreateOrUpdateComment::send( @@ -179,7 +183,8 @@ impl PerformCrud for CreateComment { Comment::update_read(conn, comment_id, true) }) .await? - .map_err(|e| ApiError::err("couldnt_update_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_comment".into()))?; } // If its a reply, mark the parent as read if let Some(parent_id) = data.parent_id { @@ -192,7 +197,8 @@ impl PerformCrud for CreateComment { Comment::update_read(conn, parent_id, true) }) .await? - .map_err(|e| ApiError::err("couldnt_update_parent_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_parent_comment".into()))?; } // If the parent has PersonMentions mark them as read too let person_id = local_user_view.person.id; @@ -205,7 +211,8 @@ impl PerformCrud for CreateComment { PersonMention::update_read(conn, mention.id, true) }) .await? - .map_err(|e| ApiError::err("couldnt_update_person_mentions", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_person_mentions".into()))?; } } diff --git a/crates/api_crud/src/comment/delete.rs b/crates/api_crud/src/comment/delete.rs index 7e920882c..2a1a2c16e 100644 --- a/crates/api_crud/src/comment/delete.rs +++ b/crates/api_crud/src/comment/delete.rs @@ -18,7 +18,7 @@ use lemmy_db_schema::{ traits::Crud, }; use lemmy_db_views::comment_view::CommentView; -use lemmy_utils::{ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{ConnectionId, LemmyError}; use lemmy_websocket::{ send::{send_comment_ws_message, send_local_notifs}, LemmyContext, @@ -29,6 +29,7 @@ use lemmy_websocket::{ impl PerformCrud for DeleteComment { type Response = CommentResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -46,7 +47,7 @@ impl PerformCrud for DeleteComment { // Dont delete it if its already been deleted. if orig_comment.comment.deleted == data.deleted { - return Err(ApiError::err_plain("couldnt_update_comment").into()); + return Err(LemmyError::from_message("couldnt_update_comment".into())); } check_community_ban( @@ -58,7 +59,7 @@ impl PerformCrud for DeleteComment { // Verify that only the creator can delete if local_user_view.person.id != orig_comment.creator.id { - return Err(ApiError::err_plain("no_comment_edit_allowed").into()); + return Err(LemmyError::from_message("no_comment_edit_allowed".into())); } // Do the delete @@ -67,7 +68,8 @@ impl PerformCrud for DeleteComment { Comment::update_deleted(conn, comment_id, deleted) }) .await? - .map_err(|e| ApiError::err("couldnt_update_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_comment".into()))?; let post_id = updated_comment.post_id; let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; @@ -112,6 +114,7 @@ impl PerformCrud for DeleteComment { impl PerformCrud for RemoveComment { type Response = CommentResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -148,7 +151,8 @@ impl PerformCrud for RemoveComment { Comment::update_removed(conn, comment_id, removed) }) .await? - .map_err(|e| ApiError::err("couldnt_update_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_comment".into()))?; // Mod tables let form = ModRemoveCommentForm { diff --git a/crates/api_crud/src/comment/read.rs b/crates/api_crud/src/comment/read.rs index 4789b84fe..83b305982 100644 --- a/crates/api_crud/src/comment/read.rs +++ b/crates/api_crud/src/comment/read.rs @@ -13,13 +13,14 @@ use lemmy_db_schema::{ SortType, }; use lemmy_db_views::comment_view::{CommentQueryBuilder, CommentView}; -use lemmy_utils::{ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{ConnectionId, LemmyError}; use lemmy_websocket::LemmyContext; #[async_trait::async_trait(?Send)] impl PerformCrud for GetComment { type Response = CommentResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -35,7 +36,8 @@ impl PerformCrud for GetComment { CommentView::read(conn, id, person_id) }) .await? - .map_err(|e| ApiError::err("couldnt_find_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_find_comment".into()))?; Ok(Self::Response { comment_view, @@ -49,6 +51,7 @@ impl PerformCrud for GetComment { impl PerformCrud for GetComments { type Response = GetCommentsResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -91,7 +94,8 @@ impl PerformCrud for GetComments { .list() }) .await? - .map_err(|e| ApiError::err("couldnt_get_comments", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_get_comments".into()))?; // Blank out deleted or removed info for cv in comments diff --git a/crates/api_crud/src/comment/update.rs b/crates/api_crud/src/comment/update.rs index 7b2937922..71bff589a 100644 --- a/crates/api_crud/src/comment/update.rs +++ b/crates/api_crud/src/comment/update.rs @@ -16,7 +16,6 @@ use lemmy_db_schema::source::comment::Comment; use lemmy_db_views::comment_view::CommentView; use lemmy_utils::{ utils::{remove_slurs, scrape_text_for_mentions}, - ApiError, ConnectionId, LemmyError, }; @@ -32,6 +31,7 @@ use crate::PerformCrud; impl PerformCrud for EditComment { type Response = CommentResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -59,7 +59,7 @@ impl PerformCrud for EditComment { // Verify that only the creator can edit if local_user_view.person.id != orig_comment.creator.id { - return Err(ApiError::err_plain("no_comment_edit_allowed").into()); + return Err(LemmyError::from_message("no_comment_edit_allowed".into())); } // Do the update @@ -70,7 +70,8 @@ impl PerformCrud for EditComment { Comment::update_content(conn, comment_id, &content_slurs_removed) }) .await? - .map_err(|e| ApiError::err("couldnt_update_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_comment".into()))?; // Do the mentions / recipients let updated_comment_content = updated_comment.content.to_owned(); diff --git a/crates/api_crud/src/community/create.rs b/crates/api_crud/src/community/create.rs index 19c6fc6b5..003aaa6bc 100644 --- a/crates/api_crud/src/community/create.rs +++ b/crates/api_crud/src/community/create.rs @@ -34,7 +34,6 @@ use lemmy_db_views_actor::community_view::CommunityView; use lemmy_utils::{ apub::generate_actor_keypair, utils::{check_slurs, check_slurs_opt, is_valid_actor_name}, - ApiError, ConnectionId, LemmyError, }; @@ -44,6 +43,7 @@ use lemmy_websocket::LemmyContext; impl PerformCrud for CreateCommunity { type Response = CommunityResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -55,7 +55,9 @@ impl PerformCrud for CreateCommunity { let site = blocking(context.pool(), move |conn| Site::read(conn, 0)).await??; if site.community_creation_admin_only && is_admin(&local_user_view).is_err() { - return Err(ApiError::err_plain("only_admins_can_create_communities").into()); + return Err(LemmyError::from_message( + "only_admins_can_create_communities".into(), + )); } check_slurs(&data.name, &context.settings().slur_regex())?; @@ -63,7 +65,7 @@ impl PerformCrud for CreateCommunity { check_slurs_opt(&data.description, &context.settings().slur_regex())?; if !is_valid_actor_name(&data.name, context.settings().actor_name_max_length) { - return Err(ApiError::err_plain("invalid_community_name").into()); + return Err(LemmyError::from_message("invalid_community_name".into())); } // Double check for duplicate community actor_ids @@ -75,7 +77,7 @@ impl PerformCrud for CreateCommunity { let community_actor_id_wrapped = ObjectId::::new(community_actor_id.clone()); let community_dupe = community_actor_id_wrapped.dereference_local(context).await; if community_dupe.is_ok() { - return Err(ApiError::err_plain("community_already_exists").into()); + return Err(LemmyError::from_message("community_already_exists".into())); } // Check to make sure the icon and banners are urls @@ -105,7 +107,8 @@ impl PerformCrud for CreateCommunity { Community::create(conn, &community_form) }) .await? - .map_err(|e| ApiError::err("community_already_exists", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("community_already_exists".into()))?; // The community creator becomes a moderator let community_moderator_form = CommunityModeratorForm { @@ -115,7 +118,9 @@ impl PerformCrud for CreateCommunity { let join = move |conn: &'_ _| CommunityModerator::join(conn, &community_moderator_form); if blocking(context.pool(), join).await?.is_err() { - return Err(ApiError::err_plain("community_moderator_already_exists").into()); + return Err(LemmyError::from_message( + "community_moderator_already_exists".into(), + )); } // Follow your own community @@ -127,7 +132,9 @@ impl PerformCrud for CreateCommunity { let follow = move |conn: &'_ _| CommunityFollower::follow(conn, &community_follower_form); if blocking(context.pool(), follow).await?.is_err() { - return Err(ApiError::err_plain("community_follower_already_exists").into()); + return Err(LemmyError::from_message( + "community_follower_already_exists".into(), + )); } let person_id = local_user_view.person.id; diff --git a/crates/api_crud/src/community/delete.rs b/crates/api_crud/src/community/delete.rs index aec451926..5473e6062 100644 --- a/crates/api_crud/src/community/delete.rs +++ b/crates/api_crud/src/community/delete.rs @@ -10,13 +10,14 @@ use lemmy_db_schema::{ traits::Crud, }; use lemmy_db_views_actor::community_moderator_view::CommunityModeratorView; -use lemmy_utils::{utils::naive_from_unix, ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{utils::naive_from_unix, ConnectionId, LemmyError}; use lemmy_websocket::{send::send_community_ws_message, LemmyContext, UserOperationCrud}; #[async_trait::async_trait(?Send)] impl PerformCrud for DeleteCommunity { type Response = CommunityResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -35,7 +36,7 @@ impl PerformCrud for DeleteCommunity { // Make sure deleter is the top mod if local_user_view.person.id != community_mods[0].moderator.id { - return Err(ApiError::err_plain("no_community_edit_allowed").into()); + return Err(LemmyError::from_message("no_community_edit_allowed".into())); } // Do the delete @@ -45,7 +46,8 @@ impl PerformCrud for DeleteCommunity { Community::update_deleted(conn, community_id, deleted) }) .await? - .map_err(|e| ApiError::err("couldnt_update_community", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_community".into()))?; // Send apub messages send_apub_delete( @@ -72,6 +74,7 @@ impl PerformCrud for DeleteCommunity { impl PerformCrud for RemoveCommunity { type Response = CommunityResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -91,7 +94,8 @@ impl PerformCrud for RemoveCommunity { Community::update_removed(conn, community_id, removed) }) .await? - .map_err(|e| ApiError::err("couldnt_update_community", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_community".into()))?; // Mod tables let expires = data.expires.map(naive_from_unix); diff --git a/crates/api_crud/src/community/read.rs b/crates/api_crud/src/community/read.rs index 54f278510..c1ad2b37a 100644 --- a/crates/api_crud/src/community/read.rs +++ b/crates/api_crud/src/community/read.rs @@ -17,13 +17,14 @@ use lemmy_db_views_actor::{ community_moderator_view::CommunityModeratorView, community_view::{CommunityQueryBuilder, CommunityView}, }; -use lemmy_utils::{ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{ConnectionId, LemmyError}; use lemmy_websocket::{messages::GetCommunityUsersOnline, LemmyContext}; #[async_trait::async_trait(?Send)] impl PerformCrud for GetCommunity { type Response = GetCommunityResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -45,7 +46,8 @@ impl PerformCrud for GetCommunity { ObjectId::::new(community_actor_id) .dereference(context, &mut 0) .await - .map_err(|e| ApiError::err("couldnt_find_community", e))? + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_find_community".into()))? .id } }; @@ -54,7 +56,8 @@ impl PerformCrud for GetCommunity { CommunityView::read(conn, community_id, person_id) }) .await? - .map_err(|e| ApiError::err("couldnt_find_community", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_find_community".into()))?; // Blank out deleted or removed info for non-logged in users if person_id.is_none() && (community_view.community.deleted || community_view.community.removed) @@ -66,7 +69,8 @@ impl PerformCrud for GetCommunity { CommunityModeratorView::for_community(conn, community_id) }) .await? - .map_err(|e| ApiError::err("couldnt_find_community", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_find_community".into()))?; let online = context .chat_server() @@ -89,6 +93,7 @@ impl PerformCrud for GetCommunity { impl PerformCrud for ListCommunities { type Response = ListCommunitiesResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, diff --git a/crates/api_crud/src/community/update.rs b/crates/api_crud/src/community/update.rs index a4f877d62..125f7ed2c 100644 --- a/crates/api_crud/src/community/update.rs +++ b/crates/api_crud/src/community/update.rs @@ -14,13 +14,14 @@ use lemmy_db_schema::{ traits::Crud, }; use lemmy_db_views_actor::community_moderator_view::CommunityModeratorView; -use lemmy_utils::{utils::check_slurs_opt, ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{utils::check_slurs_opt, ConnectionId, LemmyError}; use lemmy_websocket::{send::send_community_ws_message, LemmyContext, UserOperationCrud}; #[async_trait::async_trait(?Send)] impl PerformCrud for EditCommunity { type Response = CommunityResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -41,7 +42,7 @@ impl PerformCrud for EditCommunity { }) .await??; if !mods.contains(&local_user_view.person.id) { - return Err(ApiError::err_plain("not_a_moderator").into()); + return Err(LemmyError::from_message("not_a_moderator".into())); } let community_id = data.community_id; @@ -70,7 +71,8 @@ impl PerformCrud for EditCommunity { Community::update(conn, community_id, &community_form) }) .await? - .map_err(|e| ApiError::err("couldnt_update_community", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_community".into()))?; UpdateCommunity::send( updated_community.into(), diff --git a/crates/api_crud/src/post/create.rs b/crates/api_crud/src/post/create.rs index a4a92f255..e30b17424 100644 --- a/crates/api_crud/src/post/create.rs +++ b/crates/api_crud/src/post/create.rs @@ -27,7 +27,6 @@ use lemmy_db_schema::{ use lemmy_utils::{ request::fetch_site_data, utils::{check_slurs, check_slurs_opt, clean_url_params, is_valid_post_title}, - ApiError, ConnectionId, LemmyError, }; @@ -40,6 +39,7 @@ use webmention::{Webmention, WebmentionError}; impl PerformCrud for CreatePost { type Response = PostResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -55,7 +55,7 @@ impl PerformCrud for CreatePost { honeypot_check(&data.honeypot)?; if !is_valid_post_title(&data.name) { - return Err(ApiError::err_plain("invalid_post_title").into()); + return Err(LemmyError::from_message("invalid_post_title".into())); } check_community_ban(local_user_view.person.id, data.community_id, context.pool()).await?; @@ -93,7 +93,7 @@ impl PerformCrud for CreatePost { "couldnt_create_post" }; - return Err(ApiError::err(err_type, e).into()); + return Err(LemmyError::from(e).with_message(err_type.into())); } }; @@ -108,7 +108,8 @@ impl PerformCrud for CreatePost { Ok(Post::update_ap_id(conn, inserted_post_id, apub_id)?) }) .await? - .map_err(|e| ApiError::err("couldnt_create_post", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_create_post".into()))?; // They like their own post by default let person_id = local_user_view.person.id; @@ -121,7 +122,7 @@ impl PerformCrud for CreatePost { let like = move |conn: &'_ _| PostLike::like(conn, &like_form); if blocking(context.pool(), like).await?.is_err() { - return Err(ApiError::err_plain("couldnt_like_post").into()); + return Err(LemmyError::from_message("couldnt_like_post".into())); } // Mark the post as read diff --git a/crates/api_crud/src/post/delete.rs b/crates/api_crud/src/post/delete.rs index a974feb12..20b7baac2 100644 --- a/crates/api_crud/src/post/delete.rs +++ b/crates/api_crud/src/post/delete.rs @@ -17,13 +17,14 @@ use lemmy_db_schema::{ }, traits::Crud, }; -use lemmy_utils::{ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{ConnectionId, LemmyError}; use lemmy_websocket::{send::send_post_ws_message, LemmyContext, UserOperationCrud}; #[async_trait::async_trait(?Send)] impl PerformCrud for DeletePost { type Response = PostResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -38,7 +39,7 @@ impl PerformCrud for DeletePost { // Dont delete it if its already been deleted. if orig_post.deleted == data.deleted { - return Err(ApiError::err_plain("couldnt_update_post").into()); + return Err(LemmyError::from_message("couldnt_update_post".into())); } check_community_ban( @@ -51,7 +52,7 @@ impl PerformCrud for DeletePost { // Verify that only the creator can delete if !Post::is_post_creator(local_user_view.person.id, orig_post.creator_id) { - return Err(ApiError::err_plain("no_post_edit_allowed").into()); + return Err(LemmyError::from_message("no_post_edit_allowed".into())); } // Update the post @@ -91,6 +92,7 @@ impl PerformCrud for DeletePost { impl PerformCrud for RemovePost { type Response = PostResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, diff --git a/crates/api_crud/src/post/read.rs b/crates/api_crud/src/post/read.rs index 720a18a4d..2095038b4 100644 --- a/crates/api_crud/src/post/read.rs +++ b/crates/api_crud/src/post/read.rs @@ -20,13 +20,14 @@ use lemmy_db_views_actor::{ community_moderator_view::CommunityModeratorView, community_view::CommunityView, }; -use lemmy_utils::{ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{ConnectionId, LemmyError}; use lemmy_websocket::{messages::GetPostUsersOnline, LemmyContext}; #[async_trait::async_trait(?Send)] impl PerformCrud for GetPost { type Response = GetPostResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -46,7 +47,8 @@ impl PerformCrud for GetPost { PostView::read(conn, id, person_id) }) .await? - .map_err(|e| ApiError::err("couldnt_find_post", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_find_post".into()))?; // Mark the post as read if let Some(person_id) = person_id { @@ -70,7 +72,8 @@ impl PerformCrud for GetPost { CommunityView::read(conn, community_id, person_id) }) .await? - .map_err(|e| ApiError::err("couldnt_find_community", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_find_community".into()))?; // Blank out deleted or removed info for non-logged in users if person_id.is_none() { @@ -115,6 +118,7 @@ impl PerformCrud for GetPost { impl PerformCrud for GetPosts { type Response = GetPostsResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -165,7 +169,8 @@ impl PerformCrud for GetPosts { .list() }) .await? - .map_err(|e| ApiError::err("couldnt_get_posts", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_get_posts".into()))?; // Blank out deleted or removed info for non-logged in users if person_id.is_none() { diff --git a/crates/api_crud/src/post/update.rs b/crates/api_crud/src/post/update.rs index 2cfc67d41..66d5f3fb1 100644 --- a/crates/api_crud/src/post/update.rs +++ b/crates/api_crud/src/post/update.rs @@ -19,7 +19,6 @@ use lemmy_db_schema::{ use lemmy_utils::{ request::fetch_site_data, utils::{check_slurs_opt, clean_url_params, is_valid_post_title}, - ApiError, ConnectionId, LemmyError, }; @@ -31,6 +30,7 @@ use crate::PerformCrud; impl PerformCrud for EditPost { type Response = PostResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -46,7 +46,7 @@ impl PerformCrud for EditPost { if let Some(name) = &data.name { if !is_valid_post_title(name) { - return Err(ApiError::err_plain("invalid_post_title").into()); + return Err(LemmyError::from_message("invalid_post_title".into())); } } @@ -63,7 +63,7 @@ impl PerformCrud for EditPost { // Verify that only the creator can edit if !Post::is_post_creator(local_user_view.person.id, orig_post.creator_id) { - return Err(ApiError::err_plain("no_post_edit_allowed").into()); + return Err(LemmyError::from_message("no_post_edit_allowed".into())); } // Fetch post links and Pictrs cached image @@ -103,7 +103,7 @@ impl PerformCrud for EditPost { "couldnt_update_post" }; - return Err(ApiError::err(err_type, e).into()); + return Err(LemmyError::from(e).with_message(err_type.into())); } }; diff --git a/crates/api_crud/src/private_message/create.rs b/crates/api_crud/src/private_message/create.rs index 0c6378269..f0f6578b6 100644 --- a/crates/api_crud/src/private_message/create.rs +++ b/crates/api_crud/src/private_message/create.rs @@ -19,7 +19,7 @@ use lemmy_db_schema::{ traits::Crud, }; use lemmy_db_views::local_user_view::LocalUserView; -use lemmy_utils::{utils::remove_slurs, ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{utils::remove_slurs, ConnectionId, LemmyError}; use lemmy_websocket::{ send::{send_email_to_user, send_pm_ws_message}, LemmyContext, @@ -30,6 +30,7 @@ use lemmy_websocket::{ impl PerformCrud for CreatePrivateMessage { type Response = PrivateMessageResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -58,7 +59,7 @@ impl PerformCrud for CreatePrivateMessage { { Ok(private_message) => private_message, Err(e) => { - return Err(ApiError::err("couldnt_create_private_message", e).into()); + return Err(LemmyError::from(e).with_message("couldnt_create_private_message".into())); } }; @@ -80,7 +81,8 @@ impl PerformCrud for CreatePrivateMessage { }, ) .await? - .map_err(|e| ApiError::err("couldnt_create_private_message", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_create_private_message".into()))?; CreateOrUpdatePrivateMessage::send( updated_private_message.into(), diff --git a/crates/api_crud/src/private_message/delete.rs b/crates/api_crud/src/private_message/delete.rs index 06bc22ede..2b328ac8c 100644 --- a/crates/api_crud/src/private_message/delete.rs +++ b/crates/api_crud/src/private_message/delete.rs @@ -13,13 +13,14 @@ use lemmy_db_schema::{ source::private_message::PrivateMessage, traits::{Crud, DeleteableOrRemoveable}, }; -use lemmy_utils::{ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{ConnectionId, LemmyError}; use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperationCrud}; #[async_trait::async_trait(?Send)] impl PerformCrud for DeletePrivateMessage { type Response = PrivateMessageResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -36,7 +37,9 @@ impl PerformCrud for DeletePrivateMessage { }) .await??; if local_user_view.person.id != orig_private_message.creator_id { - return Err(ApiError::err_plain("no_private_message_edit_allowed").into()); + return Err(LemmyError::from_message( + "no_private_message_edit_allowed".into(), + )); } // Doing the update @@ -46,7 +49,8 @@ impl PerformCrud for DeletePrivateMessage { PrivateMessage::update_deleted(conn, private_message_id, deleted) }) .await? - .map_err(|e| ApiError::err("couldnt_update_private_message", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_private_message".into()))?; // Send the apub update if data.deleted { diff --git a/crates/api_crud/src/private_message/read.rs b/crates/api_crud/src/private_message/read.rs index ae2dc203f..e130646c2 100644 --- a/crates/api_crud/src/private_message/read.rs +++ b/crates/api_crud/src/private_message/read.rs @@ -14,6 +14,7 @@ use lemmy_websocket::LemmyContext; impl PerformCrud for GetPrivateMessages { type Response = PrivateMessagesResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, diff --git a/crates/api_crud/src/private_message/update.rs b/crates/api_crud/src/private_message/update.rs index 95cc5cb34..dad82c6e5 100644 --- a/crates/api_crud/src/private_message/update.rs +++ b/crates/api_crud/src/private_message/update.rs @@ -10,13 +10,14 @@ use lemmy_apub::protocol::activities::{ CreateOrUpdateType, }; use lemmy_db_schema::{source::private_message::PrivateMessage, traits::Crud}; -use lemmy_utils::{utils::remove_slurs, ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{utils::remove_slurs, ConnectionId, LemmyError}; use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperationCrud}; #[async_trait::async_trait(?Send)] impl PerformCrud for EditPrivateMessage { type Response = PrivateMessageResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -33,7 +34,9 @@ impl PerformCrud for EditPrivateMessage { }) .await??; if local_user_view.person.id != orig_private_message.creator_id { - return Err(ApiError::err_plain("no_private_message_edit_allowed").into()); + return Err(LemmyError::from_message( + "no_private_message_edit_allowed".into(), + )); } // Doing the update @@ -43,7 +46,8 @@ impl PerformCrud for EditPrivateMessage { PrivateMessage::update_content(conn, private_message_id, &content_slurs_removed) }) .await? - .map_err(|e| ApiError::err("couldnt_update_private_message", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_private_message".into()))?; // Send the apub update CreateOrUpdatePrivateMessage::send( diff --git a/crates/api_crud/src/site/create.rs b/crates/api_crud/src/site/create.rs index 865ade77f..261110be8 100644 --- a/crates/api_crud/src/site/create.rs +++ b/crates/api_crud/src/site/create.rs @@ -16,7 +16,6 @@ use lemmy_db_schema::{ use lemmy_db_views::site_view::SiteView; use lemmy_utils::{ utils::{check_slurs, check_slurs_opt}, - ApiError, ConnectionId, LemmyError, }; @@ -26,6 +25,7 @@ use lemmy_websocket::LemmyContext; impl PerformCrud for CreateSite { type Response = SiteResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -35,7 +35,7 @@ impl PerformCrud for CreateSite { let read_site = Site::read_simple; if blocking(context.pool(), read_site).await?.is_ok() { - return Err(ApiError::err_plain("site_already_exists").into()); + return Err(LemmyError::from_message("site_already_exists".into())); }; let local_user_view = @@ -72,7 +72,7 @@ impl PerformCrud for CreateSite { let create_site = move |conn: &'_ _| Site::create(conn, &site_form); if blocking(context.pool(), create_site).await?.is_err() { - return Err(ApiError::err_plain("site_already_exists").into()); + return Err(LemmyError::from_message("site_already_exists".into())); } let site_view = blocking(context.pool(), SiteView::read).await??; diff --git a/crates/api_crud/src/site/read.rs b/crates/api_crud/src/site/read.rs index 837acc83c..7fd95f3d4 100644 --- a/crates/api_crud/src/site/read.rs +++ b/crates/api_crud/src/site/read.rs @@ -15,7 +15,7 @@ use lemmy_db_views_actor::{ person_block_view::PersonBlockView, person_view::PersonViewSafe, }; -use lemmy_utils::{version, ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{version, ConnectionId, LemmyError}; use lemmy_websocket::{messages::GetUsersOnline, LemmyContext}; use tracing::info; @@ -23,6 +23,7 @@ use tracing::info; impl PerformCrud for GetSite { type Response = GetSiteResponse; + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -100,27 +101,31 @@ impl PerformCrud for GetSite { CommunityFollowerView::for_person(conn, person_id) }) .await? - .map_err(|e| ApiError::err("system_err_login", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("system_err_login".into()))?; let person_id = local_user_view.person.id; let community_blocks = blocking(context.pool(), move |conn| { CommunityBlockView::for_person(conn, person_id) }) .await? - .map_err(|e| ApiError::err("system_err_login", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("system_err_login".into()))?; let person_id = local_user_view.person.id; let person_blocks = blocking(context.pool(), move |conn| { PersonBlockView::for_person(conn, person_id) }) .await? - .map_err(|e| ApiError::err("system_err_login", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("system_err_login".into()))?; let moderates = blocking(context.pool(), move |conn| { CommunityModeratorView::for_person(conn, person_id) }) .await? - .map_err(|e| ApiError::err("system_err_login", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("system_err_login".into()))?; Some(MyUserInfo { local_user_view, diff --git a/crates/api_crud/src/site/update.rs b/crates/api_crud/src/site/update.rs index b6f06e3ad..ea469aae9 100644 --- a/crates/api_crud/src/site/update.rs +++ b/crates/api_crud/src/site/update.rs @@ -15,12 +15,14 @@ use lemmy_db_schema::{ traits::Crud, }; use lemmy_db_views::site_view::SiteView; -use lemmy_utils::{utils::check_slurs_opt, ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{utils::check_slurs_opt, ConnectionId, LemmyError}; use lemmy_websocket::{messages::SendAllMessage, LemmyContext, UserOperationCrud}; #[async_trait::async_trait(?Send)] impl PerformCrud for EditSite { type Response = SiteResponse; + + #[tracing::instrument(skip(self, context, websocket_id))] async fn perform( &self, context: &Data, @@ -64,7 +66,8 @@ impl PerformCrud for EditSite { let update_site = move |conn: &'_ _| Site::update(conn, 1, &site_form); blocking(context.pool(), update_site) .await? - .map_err(|e| ApiError::err("couldnt_update_site", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_site".into()))?; let site_view = blocking(context.pool(), SiteView::read).await??; diff --git a/crates/api_crud/src/user/create.rs b/crates/api_crud/src/user/create.rs index 2ce2fa366..f8d4d1910 100644 --- a/crates/api_crud/src/user/create.rs +++ b/crates/api_crud/src/user/create.rs @@ -32,7 +32,6 @@ use lemmy_utils::{ apub::generate_actor_keypair, claims::Claims, utils::{check_slurs, is_valid_actor_name}, - ApiError, ConnectionId, LemmyError, }; @@ -42,6 +41,7 @@ use lemmy_websocket::{messages::CheckCaptcha, LemmyContext}; impl PerformCrud for Register { type Response = LoginResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -52,7 +52,7 @@ impl PerformCrud for Register { // Make sure site has open registration if let Ok(site) = blocking(context.pool(), Site::read_simple).await? { if !site.open_registration { - return Err(ApiError::err_plain("registration_closed").into()); + return Err(LemmyError::from_message("registration_closed".into())); } } @@ -61,7 +61,7 @@ impl PerformCrud for Register { // Make sure passwords match if data.password != data.password_verify { - return Err(ApiError::err_plain("passwords_dont_match").into()); + return Err(LemmyError::from_message("passwords_dont_match".into())); } // Check if there are admins. False if admins exist @@ -86,7 +86,7 @@ impl PerformCrud for Register { }) .await?; if !check { - return Err(ApiError::err_plain("captcha_incorrect").into()); + return Err(LemmyError::from_message("captcha_incorrect".into())); } } @@ -94,7 +94,7 @@ impl PerformCrud for Register { let actor_keypair = generate_actor_keypair()?; if !is_valid_actor_name(&data.username, context.settings().actor_name_max_length) { - return Err(ApiError::err_plain("invalid_username").into()); + return Err(LemmyError::from_message("invalid_username".into())); } let actor_id = generate_local_apub_endpoint( EndpointType::Person, @@ -121,7 +121,8 @@ impl PerformCrud for Register { Person::create(conn, &person_form) }) .await? - .map_err(|e| ApiError::err("user_already_exists", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("user_already_exists".into()))?; // Create the local user // TODO some of these could probably use the DB defaults @@ -163,7 +164,7 @@ impl PerformCrud for Register { }) .await??; - return Err(ApiError::err(err_type, e).into()); + return Err(LemmyError::from(e).with_message(err_type.into())); } }; @@ -213,7 +214,8 @@ impl PerformCrud for Register { let follow = move |conn: &'_ _| CommunityFollower::follow(conn, &community_follower_form); blocking(context.pool(), follow) .await? - .map_err(|e| ApiError::err("community_follower_already_exists", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("community_follower_already_exists".into()))?; // If its an admin, add them as a mod and follower to main if no_admins { @@ -225,7 +227,8 @@ impl PerformCrud for Register { let join = move |conn: &'_ _| CommunityModerator::join(conn, &community_moderator_form); blocking(context.pool(), join) .await? - .map_err(|e| ApiError::err("community_moderator_already_exists", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("community_moderator_already_exists".into()))?; } // Return the jwt diff --git a/crates/api_crud/src/user/delete.rs b/crates/api_crud/src/user/delete.rs index 28f42831e..7b2574b79 100644 --- a/crates/api_crud/src/user/delete.rs +++ b/crates/api_crud/src/user/delete.rs @@ -3,13 +3,14 @@ use actix_web::web::Data; use bcrypt::verify; use lemmy_api_common::{blocking, get_local_user_view_from_jwt, person::*}; use lemmy_db_schema::source::{comment::Comment, person::Person, post::Post}; -use lemmy_utils::{ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{ConnectionId, LemmyError}; use lemmy_websocket::LemmyContext; #[async_trait::async_trait(?Send)] impl PerformCrud for DeleteAccount { type Response = LoginResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -26,7 +27,7 @@ impl PerformCrud for DeleteAccount { ) .unwrap_or(false); if !valid { - return Err(ApiError::err_plain("password_incorrect").into()); + return Err(LemmyError::from_message("password_incorrect".into())); } // Comments @@ -34,13 +35,15 @@ impl PerformCrud for DeleteAccount { let permadelete = move |conn: &'_ _| Comment::permadelete_for_creator(conn, person_id); blocking(context.pool(), permadelete) .await? - .map_err(|e| ApiError::err("couldnt_update_comment", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_comment".into()))?; // Posts let permadelete = move |conn: &'_ _| Post::permadelete_for_creator(conn, person_id); blocking(context.pool(), permadelete) .await? - .map_err(|e| ApiError::err("couldnt_update_post", e))?; + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_update_post".into()))?; blocking(context.pool(), move |conn| { Person::delete_account(conn, person_id) diff --git a/crates/api_crud/src/user/read.rs b/crates/api_crud/src/user/read.rs index e20848605..7d74a17cb 100644 --- a/crates/api_crud/src/user/read.rs +++ b/crates/api_crud/src/user/read.rs @@ -13,13 +13,14 @@ use lemmy_db_views_actor::{ community_moderator_view::CommunityModeratorView, person_view::PersonViewSafe, }; -use lemmy_utils::{ApiError, ConnectionId, LemmyError}; +use lemmy_utils::{ConnectionId, LemmyError}; use lemmy_websocket::LemmyContext; #[async_trait::async_trait(?Send)] impl PerformCrud for GetPersonDetails { type Response = GetPersonDetailsResponse; + #[tracing::instrument(skip(self, context, _websocket_id))] async fn perform( &self, context: &Data, @@ -53,7 +54,8 @@ impl PerformCrud for GetPersonDetails { .dereference(context, &mut 0) .await; person - .map_err(|e| ApiError::err("couldnt_find_that_username_or_email", e))? + .map_err(LemmyError::from) + .map_err(|e| e.with_message("couldnt_find_that_username_or_email".into()))? .id } }; diff --git a/crates/db_schema/src/lib.rs b/crates/db_schema/src/lib.rs index ddff1375e..26175881d 100644 --- a/crates/db_schema/src/lib.rs +++ b/crates/db_schema/src/lib.rs @@ -21,7 +21,7 @@ pub type DbPool = diesel::r2d2::Pool) -> Option> { pub fn diesel_option_overwrite_to_url( opt: &Option, -) -> Result>, ApiError> { +) -> Result>, LemmyError> { match opt.as_ref().map(|s| s.as_str()) { // An empty string is an erase Some("") => Ok(Some(None)), Some(str_url) => match Url::parse(str_url) { Ok(url) => Ok(Some(Some(url.into()))), - Err(e) => Err(ApiError::err("invalid_url", e)), + Err(e) => Err(LemmyError::from(e).with_message("invalid_url".into())), }, None => Ok(None), } diff --git a/crates/utils/src/lib.rs b/crates/utils/src/lib.rs index 5eaff30e8..9b88a15ec 100644 --- a/crates/utils/src/lib.rs +++ b/crates/utils/src/lib.rs @@ -15,10 +15,9 @@ mod test; pub mod utils; pub mod version; +use actix_web::HttpResponse; use http::StatusCode; use std::{fmt, fmt::Display}; -use thiserror::Error; -use tracing::warn; use tracing_error::SpanTrace; pub type ConnectionId = usize; @@ -44,38 +43,42 @@ macro_rules! location_info { }; } -#[derive(Debug, Error)] -#[error("{{\"error\":\"{message}\"}}")] -pub struct ApiError { - message: String, -} - -impl ApiError { - pub fn err_plain(msg: &str) -> Self { - ApiError { - message: msg.to_string(), - } - } - pub fn err(msg: &str, original_error: E) -> Self { - warn!("{}", original_error); - ApiError { - message: msg.to_string(), - } - } +#[derive(serde::Serialize)] +struct ApiError { + error: String, } #[derive(Debug)] pub struct LemmyError { + pub message: Option, pub inner: anyhow::Error, pub context: SpanTrace, } +impl LemmyError { + pub fn from_message(message: String) -> Self { + let inner = anyhow::anyhow!("{}", message); + LemmyError { + message: Some(message), + inner, + context: SpanTrace::capture(), + } + } + pub fn with_message(self, message: String) -> Self { + LemmyError { + message: Some(message), + ..self + } + } +} + impl From for LemmyError where T: Into, { fn from(t: T) -> Self { LemmyError { + message: None, inner: t.into(), context: SpanTrace::capture(), } @@ -93,7 +96,19 @@ impl actix_web::error::ResponseError for LemmyError { fn status_code(&self) -> StatusCode { match self.inner.downcast_ref::() { Some(diesel::result::Error::NotFound) => StatusCode::NOT_FOUND, - _ => StatusCode::INTERNAL_SERVER_ERROR, + _ => StatusCode::BAD_REQUEST, + } + } + + fn error_response(&self) -> HttpResponse { + if let Some(message) = &self.message { + HttpResponse::build(self.status_code()).json(ApiError { + error: message.clone(), + }) + } else { + HttpResponse::build(self.status_code()) + .content_type("text/plain") + .body(self.inner.to_string()) } } } diff --git a/crates/utils/src/rate_limit/rate_limiter.rs b/crates/utils/src/rate_limit/rate_limiter.rs index 468199153..d10f5790c 100644 --- a/crates/utils/src/rate_limit/rate_limiter.rs +++ b/crates/utils/src/rate_limit/rate_limiter.rs @@ -1,4 +1,4 @@ -use crate::{ApiError, IpAddr, LemmyError}; +use crate::{IpAddr, LemmyError}; use std::{collections::HashMap, time::SystemTime}; use strum::IntoEnumIterator; use tracing::debug; @@ -79,18 +79,13 @@ impl RateLimiter { time_passed, rate_limit.allowance ); - Err( - ApiError { - message: format!( - "Too many requests. type: {}, IP: {}, {} per {} seconds", - type_.as_ref(), - ip, - rate, - per - ), - } - .into(), - ) + Err(LemmyError::from_message(format!( + "Too many requests. type: {}, IP: {}, {} per {} seconds", + type_.as_ref(), + ip, + rate, + per + ))) } else { if !check_only { rate_limit.allowance -= 1.0; diff --git a/crates/utils/src/utils.rs b/crates/utils/src/utils.rs index 1c33b4c59..36f838251 100644 --- a/crates/utils/src/utils.rs +++ b/crates/utils/src/utils.rs @@ -1,4 +1,4 @@ -use crate::{ApiError, IpAddr}; +use crate::{IpAddr, LemmyError}; use actix_web::dev::ConnectionInfo; use chrono::{DateTime, FixedOffset, NaiveDateTime}; use itertools::Itertools; @@ -60,15 +60,18 @@ pub(crate) fn slur_check<'a>( } } -pub fn check_slurs(text: &str, slur_regex: &Option) -> Result<(), ApiError> { +pub fn check_slurs(text: &str, slur_regex: &Option) -> Result<(), LemmyError> { if let Err(slurs) = slur_check(text, slur_regex) { - Err(ApiError::err_plain(&slurs_vec_to_str(slurs))) + Err(LemmyError::from_message(slurs_vec_to_str(slurs))) } else { Ok(()) } } -pub fn check_slurs_opt(text: &Option, slur_regex: &Option) -> Result<(), ApiError> { +pub fn check_slurs_opt( + text: &Option, + slur_regex: &Option, +) -> Result<(), LemmyError> { match text { Some(t) => check_slurs(t, slur_regex), None => Ok(()), diff --git a/crates/websocket/src/chat_server.rs b/crates/websocket/src/chat_server.rs index 2b58b2c1e..ab4d25bfb 100644 --- a/crates/websocket/src/chat_server.rs +++ b/crates/websocket/src/chat_server.rs @@ -22,7 +22,6 @@ use lemmy_utils::{ location_info, rate_limit::RateLimit, settings::structs::Settings, - ApiError, ConnectionId, IpAddr, LemmyError, @@ -477,7 +476,7 @@ impl ChatServer { let data = &json["data"].to_string(); let op = &json["op"] .as_str() - .ok_or_else(|| ApiError::err_plain("missing op"))?; + .ok_or_else(|| LemmyError::from_message("missing op".into()))?; if let Ok(user_operation_crud) = UserOperationCrud::from_str(op) { let fut = (message_handler_crud)(context, msg.id, user_operation_crud.clone(), data); diff --git a/src/api_routes.rs b/src/api_routes.rs index ae5fa40c1..3fbb7f053 100644 --- a/src/api_routes.rs +++ b/src/api_routes.rs @@ -1,4 +1,4 @@ -use actix_web::{error::ErrorBadRequest, *}; +use actix_web::*; use lemmy_api::Perform; use lemmy_api_common::{comment::*, community::*, person::*, post::*, site::*, websocket::*}; use lemmy_api_crud::PerformCrud; @@ -232,8 +232,7 @@ where let res = data .perform(&context, None) .await - .map(|json| HttpResponse::Ok().json(json)) - .map_err(ErrorBadRequest)?; + .map(|json| HttpResponse::Ok().json(json))?; Ok(res) } @@ -268,8 +267,7 @@ where let res = data .perform(&context, None) .await - .map(|json| HttpResponse::Ok().json(json)) - .map_err(ErrorBadRequest)?; + .map(|json| HttpResponse::Ok().json(json))?; Ok(res) }