Don't drop error context when adding a message to errors (#1958)

* Respond directly with LemmyError

Instrument Perform implementations for more precise traces
Use ApiError to format JSON errors when messages are present
Keep SpanTrace output in LemmyError Display impl

* Hide SpanTrace debug output from LemmyError

* Don't log when entering spans, only when leaving

* Update actix-web

* Update actix-rt

* Add newline after error info in LemmyError Display impl

* Propogate span information to blocking operations

* Instrument apub functions

* Use skip_all for more instrument attributes, don't skip 'self' in some api actions

* Make message a static string

* Send proper JSON over websocket

* Add 'message' to LemmyError display if present

* Use a quieter root span builder, don't pretty-print logs

* Keep passwords and emails out of logs

* Re-enable logging Login

* Instrument feeds

* Emit our own errors

* Move error log after status code recording

* Make Sensitive generic over the inner type

* Remove line that logged secrets
This commit is contained in:
Riley 2021-12-06 08:54:47 -06:00 committed by GitHub
parent 4a541a25ab
commit 35cbae61bc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
101 changed files with 1127 additions and 531 deletions

28
Cargo.lock generated
View file

@ -69,9 +69,9 @@ dependencies = [
[[package]] [[package]]
name = "actix-http" name = "actix-http"
version = "3.0.0-beta.12" version = "3.0.0-beta.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afaeb3d3fcb06b775ac62f05d580aae4afe5a149513333a73f688fdf26c06639" checksum = "1bc3f9d97e32d75fae3ad7d955ac005eea3fd3ea60a89132768700911a60fd94"
dependencies = [ dependencies = [
"actix-codec", "actix-codec",
"actix-rt", "actix-rt",
@ -130,9 +130,9 @@ dependencies = [
[[package]] [[package]]
name = "actix-rt" name = "actix-rt"
version = "2.4.0" version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a0c218d0a17c120f10ee0c69c9f0c45d87319e8f66b1f065e8412b612fc3e24" checksum = "05c2f80ce8d0c990941c7a7a931f69fd0701b76d521f8d36298edf59cd3fbf1f"
dependencies = [ dependencies = [
"actix-macros", "actix-macros",
"futures-core", "futures-core",
@ -170,9 +170,9 @@ dependencies = [
[[package]] [[package]]
name = "actix-tls" name = "actix-tls"
version = "3.0.0-beta.8" version = "3.0.0-beta.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a563b0245222230c860c1b077ca7309179fff0f575b1914967c1ee385aa5da64" checksum = "53d4739910b49c77ea88308a9fbfae544524b34884161527f9978c0102052da0"
dependencies = [ dependencies = [
"actix-codec", "actix-codec",
"actix-rt", "actix-rt",
@ -182,6 +182,7 @@ dependencies = [
"futures-core", "futures-core",
"http", "http",
"log", "log",
"pin-project-lite",
"tokio-rustls", "tokio-rustls",
"tokio-util", "tokio-util",
"webpki-roots", "webpki-roots",
@ -199,9 +200,9 @@ dependencies = [
[[package]] [[package]]
name = "actix-web" name = "actix-web"
version = "4.0.0-beta.11" version = "4.0.0-beta.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e85aa9bb018d83a0db70f557ba0cde9c6170a5d1de4fede02e377f68c1ac5aa9" checksum = "e87cfc4efaad42f8a054e269d1b85046397ff4e8707e49128dea3f99a512a9d6"
dependencies = [ dependencies = [
"actix-codec", "actix-codec",
"actix-http", "actix-http",
@ -388,9 +389,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]] [[package]]
name = "awc" name = "awc"
version = "3.0.0-beta.10" version = "3.0.0-beta.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f122bed94dc044b13a991b292ff6a3cde4c3fba890a4e3dbbec0f2eedc607f0a" checksum = "f9f7d0c472987e454f41c3f4c7fa336ca139707ab255644b0480144c2060c800"
dependencies = [ dependencies = [
"actix-codec", "actix-codec",
"actix-http", "actix-http",
@ -1759,6 +1760,7 @@ dependencies = [
"strum_macros", "strum_macros",
"thiserror", "thiserror",
"tokio", "tokio",
"tracing",
"url", "url",
"uuid", "uuid",
] ]
@ -1777,6 +1779,7 @@ dependencies = [
"lemmy_utils", "lemmy_utils",
"serde", "serde",
"serde_json", "serde_json",
"tracing",
"url", "url",
] ]
@ -1982,6 +1985,7 @@ dependencies = [
"serde", "serde",
"sha2", "sha2",
"strum", "strum",
"tracing",
"url", "url",
] ]
@ -3998,9 +4002,9 @@ dependencies = [
[[package]] [[package]]
name = "tracing-actix-web" name = "tracing-actix-web"
version = "0.5.0-beta.2" version = "0.5.0-beta.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cac34827e06f78b69523b2fbe5b2dd4dfc75940b2ea5ba37e4fa2a25d4a0edf" checksum = "994e4a59135823bdca121a8d086e3fcc71741c8677b47fa95a6afdd15e8f646f"
dependencies = [ dependencies = [
"actix-web", "actix-web",
"pin-project", "pin-project",

View file

@ -50,7 +50,7 @@ serde = { version = "1.0.130", features = ["derive"] }
actix = "0.12.0" actix = "0.12.0"
actix-web = { version = "4.0.0-beta.9", default-features = false, features = ["rustls"] } actix-web = { version = "4.0.0-beta.9", default-features = false, features = ["rustls"] }
tracing = "0.1.29" tracing = "0.1.29"
tracing-actix-web = "0.5.0-beta.2" tracing-actix-web = { version = "0.5.0-beta.3", default-features = false }
tracing-error = "0.2.0" tracing-error = "0.2.0"
tracing-log = "0.1.2" tracing-log = "0.1.2"
tracing-subscriber = { version = "0.3.2", features = ["env-filter"] } tracing-subscriber = { version = "0.3.2", features = ["env-filter"] }

View file

@ -48,5 +48,6 @@ async-trait = "0.1.51"
captcha = "0.0.8" captcha = "0.0.8"
anyhow = "1.0.44" anyhow = "1.0.44"
thiserror = "1.0.29" thiserror = "1.0.29"
tracing = "0.1.29"
background-jobs = "0.11.0" background-jobs = "0.11.0"
reqwest = { version = "0.11.4", features = ["json"] } reqwest = { version = "0.11.4", features = ["json"] }

View file

@ -23,7 +23,7 @@ use lemmy_db_schema::{
traits::{Likeable, Saveable}, traits::{Likeable, Saveable},
}; };
use lemmy_db_views::{comment_view::CommentView, local_user_view::LocalUserView}; 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 lemmy_websocket::{send::send_comment_ws_message, LemmyContext, UserOperation};
use crate::Perform; use crate::Perform;
@ -32,6 +32,7 @@ use crate::Perform;
impl Perform for MarkCommentAsRead { impl Perform for MarkCommentAsRead {
type Response = CommentResponse; type Response = CommentResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -56,7 +57,7 @@ impl Perform for MarkCommentAsRead {
// Verify that only the recipient can mark as read // Verify that only the recipient can mark as read
if local_user_view.person.id != orig_comment.get_recipient_id() { 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"));
} }
// Do the mark as read // Do the mark as read
@ -65,7 +66,8 @@ impl Perform for MarkCommentAsRead {
Comment::update_read(conn, comment_id, read) Comment::update_read(conn, comment_id, read)
}) })
.await? .await?
.map_err(|_| ApiError::err_plain("couldnt_update_comment"))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_update_comment"))?;
// Refetch it // Refetch it
let comment_id = data.comment_id; let comment_id = data.comment_id;
@ -89,6 +91,7 @@ impl Perform for MarkCommentAsRead {
impl Perform for SaveComment { impl Perform for SaveComment {
type Response = CommentResponse; type Response = CommentResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -107,12 +110,14 @@ impl Perform for SaveComment {
let save_comment = move |conn: &'_ _| CommentSaved::save(conn, &comment_saved_form); let save_comment = move |conn: &'_ _| CommentSaved::save(conn, &comment_saved_form);
blocking(context.pool(), save_comment) blocking(context.pool(), save_comment)
.await? .await?
.map_err(|e| ApiError::err("couldnt_save_comment", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_save_comment"))?;
} else { } else {
let unsave_comment = move |conn: &'_ _| CommentSaved::unsave(conn, &comment_saved_form); let unsave_comment = move |conn: &'_ _| CommentSaved::unsave(conn, &comment_saved_form);
blocking(context.pool(), unsave_comment) blocking(context.pool(), unsave_comment)
.await? .await?
.map_err(|e| ApiError::err("couldnt_save_comment", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_save_comment"))?;
} }
let comment_id = data.comment_id; let comment_id = data.comment_id;
@ -134,6 +139,7 @@ impl Perform for SaveComment {
impl Perform for CreateCommentLike { impl Perform for CreateCommentLike {
type Response = CommentResponse; type Response = CommentResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -201,7 +207,8 @@ impl Perform for CreateCommentLike {
let like = move |conn: &'_ _| CommentLike::like(conn, &like_form2); let like = move |conn: &'_ _| CommentLike::like(conn, &like_form2);
blocking(context.pool(), like) blocking(context.pool(), like)
.await? .await?
.map_err(|e| ApiError::err("couldnt_like_comment", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_like_comment"))?;
Vote::send( Vote::send(
&object, &object,

View file

@ -14,7 +14,7 @@ use lemmy_db_views::{
comment_report_view::{CommentReportQueryBuilder, CommentReportView}, comment_report_view::{CommentReportQueryBuilder, CommentReportView},
comment_view::CommentView, comment_view::CommentView,
}; };
use lemmy_utils::{ApiError, ConnectionId, LemmyError}; use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::{messages::SendModRoomMessage, LemmyContext, UserOperation}; use lemmy_websocket::{messages::SendModRoomMessage, LemmyContext, UserOperation};
/// Creates a comment report and notifies the moderators of the community /// 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 { impl Perform for CreateCommentReport {
type Response = CommentReportResponse; type Response = CommentReportResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -34,10 +35,10 @@ impl Perform for CreateCommentReport {
// check size of report and check for whitespace // check size of report and check for whitespace
let reason = data.reason.trim(); let reason = data.reason.trim();
if reason.is_empty() { if reason.is_empty() {
return Err(ApiError::err_plain("report_reason_required").into()); return Err(LemmyError::from_message("report_reason_required"));
} }
if reason.chars().count() > 1000 { if reason.chars().count() > 1000 {
return Err(ApiError::err_plain("report_too_long").into()); return Err(LemmyError::from_message("report_too_long"));
} }
let person_id = local_user_view.person.id; let person_id = local_user_view.person.id;
@ -60,7 +61,8 @@ impl Perform for CreateCommentReport {
CommentReport::report(conn, &report_form) CommentReport::report(conn, &report_form)
}) })
.await? .await?
.map_err(|e| ApiError::err("couldnt_create_report", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_create_report"))?;
let comment_report_view = blocking(context.pool(), move |conn| { let comment_report_view = blocking(context.pool(), move |conn| {
CommentReportView::read(conn, report.id, person_id) CommentReportView::read(conn, report.id, person_id)
@ -96,6 +98,7 @@ impl Perform for CreateCommentReport {
impl Perform for ResolveCommentReport { impl Perform for ResolveCommentReport {
type Response = CommentReportResponse; type Response = CommentReportResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -126,7 +129,8 @@ impl Perform for ResolveCommentReport {
blocking(context.pool(), resolve_fun) blocking(context.pool(), resolve_fun)
.await? .await?
.map_err(|e| ApiError::err("couldnt_resolve_report", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_resolve_report"))?;
let report_id = data.report_id; let report_id = data.report_id;
let comment_report_view = blocking(context.pool(), move |conn| { let comment_report_view = blocking(context.pool(), move |conn| {
@ -155,6 +159,7 @@ impl Perform for ResolveCommentReport {
impl Perform for ListCommentReports { impl Perform for ListCommentReports {
type Response = ListCommentReportsResponse; type Response = ListCommentReportsResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,

View file

@ -54,13 +54,14 @@ use lemmy_db_views_actor::{
community_view::CommunityView, community_view::CommunityView,
person_view::PersonViewSafe, 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}; use lemmy_websocket::{messages::SendCommunityRoomMessage, LemmyContext, UserOperation};
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl Perform for FollowCommunity { impl Perform for FollowCommunity {
type Response = CommunityResponse; type Response = CommunityResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -90,13 +91,15 @@ impl Perform for FollowCommunity {
let follow = move |conn: &'_ _| CommunityFollower::follow(conn, &community_follower_form); let follow = move |conn: &'_ _| CommunityFollower::follow(conn, &community_follower_form);
blocking(context.pool(), follow) blocking(context.pool(), follow)
.await? .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"))?;
} else { } else {
let unfollow = let unfollow =
move |conn: &'_ _| CommunityFollower::unfollow(conn, &community_follower_form); move |conn: &'_ _| CommunityFollower::unfollow(conn, &community_follower_form);
blocking(context.pool(), unfollow) blocking(context.pool(), unfollow)
.await? .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"))?;
} }
} else if data.follow { } else if data.follow {
// Dont actually add to the community followers here, because you need // 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); let unfollow = move |conn: &'_ _| CommunityFollower::unfollow(conn, &community_follower_form);
blocking(context.pool(), unfollow) blocking(context.pool(), unfollow)
.await? .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"))?;
} }
let community_id = data.community_id; let community_id = data.community_id;
@ -134,6 +138,7 @@ impl Perform for FollowCommunity {
impl Perform for BlockCommunity { impl Perform for BlockCommunity {
type Response = BlockCommunityResponse; type Response = BlockCommunityResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -154,7 +159,8 @@ impl Perform for BlockCommunity {
let block = move |conn: &'_ _| CommunityBlock::block(conn, &community_block_form); let block = move |conn: &'_ _| CommunityBlock::block(conn, &community_block_form);
blocking(context.pool(), block) blocking(context.pool(), block)
.await? .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"))?;
// Also, unfollow the community, and send a federated unfollow // Also, unfollow the community, and send a federated unfollow
let community_follower_form = CommunityFollowerForm { let community_follower_form = CommunityFollowerForm {
@ -176,7 +182,8 @@ impl Perform for BlockCommunity {
let unblock = move |conn: &'_ _| CommunityBlock::unblock(conn, &community_block_form); let unblock = move |conn: &'_ _| CommunityBlock::unblock(conn, &community_block_form);
blocking(context.pool(), unblock) blocking(context.pool(), unblock)
.await? .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"))?;
} }
let community_view = blocking(context.pool(), move |conn| { let community_view = blocking(context.pool(), move |conn| {
@ -195,6 +202,7 @@ impl Perform for BlockCommunity {
impl Perform for BanFromCommunity { impl Perform for BanFromCommunity {
type Response = BanFromCommunityResponse; type Response = BanFromCommunityResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -230,7 +238,8 @@ impl Perform for BanFromCommunity {
let ban = move |conn: &'_ _| CommunityPersonBan::ban(conn, &community_user_ban_form); let ban = move |conn: &'_ _| CommunityPersonBan::ban(conn, &community_user_ban_form);
blocking(context.pool(), ban) blocking(context.pool(), ban)
.await? .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"))?;
// Also unsubscribe them from the community, if they are subscribed // Also unsubscribe them from the community, if they are subscribed
let community_follower_form = CommunityFollowerForm { let community_follower_form = CommunityFollowerForm {
@ -255,7 +264,8 @@ impl Perform for BanFromCommunity {
let unban = move |conn: &'_ _| CommunityPersonBan::unban(conn, &community_user_ban_form); let unban = move |conn: &'_ _| CommunityPersonBan::unban(conn, &community_user_ban_form);
blocking(context.pool(), unban) blocking(context.pool(), unban)
.await? .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"))?;
UndoBlockUserFromCommunity::send( UndoBlockUserFromCommunity::send(
&community, &community,
&banned_person, &banned_person,
@ -336,6 +346,7 @@ impl Perform for BanFromCommunity {
impl Perform for AddModToCommunity { impl Perform for AddModToCommunity {
type Response = AddModToCommunityResponse; type Response = AddModToCommunityResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -359,12 +370,14 @@ impl Perform for AddModToCommunity {
let join = move |conn: &'_ _| CommunityModerator::join(conn, &community_moderator_form); let join = move |conn: &'_ _| CommunityModerator::join(conn, &community_moderator_form);
blocking(context.pool(), join) blocking(context.pool(), join)
.await? .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"))?;
} else { } else {
let leave = move |conn: &'_ _| CommunityModerator::leave(conn, &community_moderator_form); let leave = move |conn: &'_ _| CommunityModerator::leave(conn, &community_moderator_form);
blocking(context.pool(), leave) blocking(context.pool(), leave)
.await? .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"))?;
} }
// Mod tables // Mod tables
@ -434,6 +447,7 @@ impl Perform for AddModToCommunity {
impl Perform for TransferCommunity { impl Perform for TransferCommunity {
type Response = GetCommunityResponse; type Response = GetCommunityResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -472,7 +486,7 @@ impl Perform for TransferCommunity {
.map(|a| a.person.id) .map(|a| a.person.id)
.any(|x| x == local_user_view.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"));
} }
// You have to re-do the community_moderator table, reordering it. // 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); let join = move |conn: &'_ _| CommunityModerator::join(conn, &community_moderator_form);
blocking(context.pool(), join) blocking(context.pool(), join)
.await? .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"))?;
} }
// Mod tables // Mod tables
@ -523,14 +538,16 @@ impl Perform for TransferCommunity {
CommunityView::read(conn, community_id, Some(person_id)) CommunityView::read(conn, community_id, Some(person_id))
}) })
.await? .await?
.map_err(|e| ApiError::err("couldnt_find_community", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_find_community"))?;
let community_id = data.community_id; let community_id = data.community_id;
let moderators = blocking(context.pool(), move |conn| { let moderators = blocking(context.pool(), move |conn| {
CommunityModeratorView::for_community(conn, community_id) CommunityModeratorView::for_community(conn, community_id)
}) })
.await? .await?
.map_err(|e| ApiError::err("couldnt_find_community", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_find_community"))?;
// Return the jwt // Return the jwt
Ok(GetCommunityResponse { Ok(GetCommunityResponse {

View file

@ -49,9 +49,9 @@ use lemmy_utils::{
email::send_email, email::send_email,
location_info, location_info,
utils::{generate_random_string, is_valid_display_name, is_valid_matrix_id, naive_from_unix}, utils::{generate_random_string, is_valid_display_name, is_valid_matrix_id, naive_from_unix},
ApiError,
ConnectionId, ConnectionId,
LemmyError, LemmyError,
Sensitive,
}; };
use lemmy_websocket::{ use lemmy_websocket::{
messages::{CaptchaItem, SendAllMessage}, messages::{CaptchaItem, SendAllMessage},
@ -63,6 +63,7 @@ use lemmy_websocket::{
impl Perform for Login { impl Perform for Login {
type Response = LoginResponse; type Response = LoginResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -76,7 +77,8 @@ impl Perform for Login {
LocalUserView::find_by_email_or_name(conn, &username_or_email) LocalUserView::find_by_email_or_name(conn, &username_or_email)
}) })
.await? .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"))?;
// Verify the password // Verify the password
let valid: bool = verify( let valid: bool = verify(
@ -85,7 +87,7 @@ impl Perform for Login {
) )
.unwrap_or(false); .unwrap_or(false);
if !valid { if !valid {
return Err(ApiError::err_plain("password_incorrect").into()); return Err(LemmyError::from_message("password_incorrect"));
} }
// Return the jwt // Return the jwt
@ -94,7 +96,8 @@ impl Perform for Login {
local_user_view.local_user.id.0, local_user_view.local_user.id.0,
&context.secret().jwt_secret, &context.secret().jwt_secret,
&context.settings().hostname, &context.settings().hostname,
)?, )?
.into(),
}) })
} }
} }
@ -103,6 +106,7 @@ impl Perform for Login {
impl Perform for GetCaptcha { impl Perform for GetCaptcha {
type Response = GetCaptchaResponse; type Response = GetCaptchaResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -148,6 +152,7 @@ impl Perform for GetCaptcha {
impl Perform for SaveUserSettings { impl Perform for SaveUserSettings {
type Response = LoginResponse; type Response = LoginResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -159,7 +164,7 @@ impl Perform for SaveUserSettings {
let avatar = diesel_option_overwrite_to_url(&data.avatar)?; let avatar = diesel_option_overwrite_to_url(&data.avatar)?;
let banner = diesel_option_overwrite_to_url(&data.banner)?; let banner = diesel_option_overwrite_to_url(&data.banner)?;
let email = diesel_option_overwrite(&data.email); let email = diesel_option_overwrite(&data.email.clone().map(Sensitive::into_inner));
let bio = diesel_option_overwrite(&data.bio); let bio = diesel_option_overwrite(&data.bio);
let display_name = diesel_option_overwrite(&data.display_name); let display_name = diesel_option_overwrite(&data.display_name);
let matrix_user_id = diesel_option_overwrite(&data.matrix_user_id); let matrix_user_id = diesel_option_overwrite(&data.matrix_user_id);
@ -167,7 +172,7 @@ impl Perform for SaveUserSettings {
if let Some(Some(bio)) = &bio { if let Some(Some(bio)) = &bio {
if bio.chars().count() > 300 { if bio.chars().count() > 300 {
return Err(ApiError::err_plain("bio_length_overflow").into()); return Err(LemmyError::from_message("bio_length_overflow"));
} }
} }
@ -176,13 +181,13 @@ impl Perform for SaveUserSettings {
display_name.trim(), display_name.trim(),
context.settings().actor_name_max_length, context.settings().actor_name_max_length,
) { ) {
return Err(ApiError::err_plain("invalid_username").into()); return Err(LemmyError::from_message("invalid_username"));
} }
} }
if let Some(Some(matrix_user_id)) = &matrix_user_id { if let Some(Some(matrix_user_id)) = &matrix_user_id {
if !is_valid_matrix_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"));
} }
} }
@ -219,7 +224,8 @@ impl Perform for SaveUserSettings {
Person::update(conn, person_id, &person_form) Person::update(conn, person_id, &person_form)
}) })
.await? .await?
.map_err(|e| ApiError::err("user_already_exists", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("user_already_exists"))?;
let local_user_form = LocalUserForm { let local_user_form = LocalUserForm {
person_id, person_id,
@ -253,7 +259,7 @@ impl Perform for SaveUserSettings {
"user_already_exists" "user_already_exists"
}; };
return Err(ApiError::err(err_type, e).into()); return Err(LemmyError::from(e).with_message(err_type));
} }
}; };
@ -263,7 +269,8 @@ impl Perform for SaveUserSettings {
updated_local_user.id.0, updated_local_user.id.0,
&context.secret().jwt_secret, &context.secret().jwt_secret,
&context.settings().hostname, &context.settings().hostname,
)?, )?
.into(),
}) })
} }
} }
@ -272,6 +279,7 @@ impl Perform for SaveUserSettings {
impl Perform for ChangePassword { impl Perform for ChangePassword {
type Response = LoginResponse; type Response = LoginResponse;
#[tracing::instrument(skip(self, context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -279,13 +287,13 @@ impl Perform for ChangePassword {
) -> Result<LoginResponse, LemmyError> { ) -> Result<LoginResponse, LemmyError> {
let data: &ChangePassword = self; let data: &ChangePassword = self;
let local_user_view = let local_user_view =
get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?; get_local_user_view_from_jwt(data.auth.as_ref(), context.pool(), context.secret()).await?;
password_length_check(&data.new_password)?; password_length_check(&data.new_password)?;
// Make sure passwords match // Make sure passwords match
if data.new_password != data.new_password_verify { 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"));
} }
// Check the old password // Check the old password
@ -295,7 +303,7 @@ impl Perform for ChangePassword {
) )
.unwrap_or(false); .unwrap_or(false);
if !valid { if !valid {
return Err(ApiError::err_plain("password_incorrect").into()); return Err(LemmyError::from_message("password_incorrect"));
} }
let local_user_id = local_user_view.local_user.id; let local_user_id = local_user_view.local_user.id;
@ -311,7 +319,8 @@ impl Perform for ChangePassword {
updated_local_user.id.0, updated_local_user.id.0,
&context.secret().jwt_secret, &context.secret().jwt_secret,
&context.settings().hostname, &context.settings().hostname,
)?, )?
.into(),
}) })
} }
} }
@ -320,6 +329,7 @@ impl Perform for ChangePassword {
impl Perform for AddAdmin { impl Perform for AddAdmin {
type Response = AddAdminResponse; type Response = AddAdminResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -338,7 +348,8 @@ impl Perform for AddAdmin {
Person::add_admin(conn, added_person_id, added) Person::add_admin(conn, added_person_id, added)
}) })
.await? .await?
.map_err(|e| ApiError::err("couldnt_update_user", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_update_user"))?;
// Mod tables // Mod tables
let form = ModAddForm { let form = ModAddForm {
@ -378,6 +389,7 @@ impl Perform for AddAdmin {
impl Perform for BanPerson { impl Perform for BanPerson {
type Response = BanPersonResponse; type Response = BanPersonResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -395,7 +407,8 @@ impl Perform for BanPerson {
let ban_person = move |conn: &'_ _| Person::ban_person(conn, banned_person_id, ban); let ban_person = move |conn: &'_ _| Person::ban_person(conn, banned_person_id, ban);
blocking(context.pool(), ban_person) blocking(context.pool(), ban_person)
.await? .await?
.map_err(|e| ApiError::err("couldnt_update_user", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_update_user"))?;
// Remove their data if that's desired // Remove their data if that's desired
if data.remove_data.unwrap_or(false) { if data.remove_data.unwrap_or(false) {
@ -471,6 +484,7 @@ impl Perform for BanPerson {
impl Perform for BlockPerson { impl Perform for BlockPerson {
type Response = BlockPersonResponse; type Response = BlockPersonResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -485,7 +499,7 @@ impl Perform for BlockPerson {
// Don't let a person block themselves // Don't let a person block themselves
if target_id == person_id { if target_id == person_id {
return Err(ApiError::err_plain("cant_block_yourself").into()); return Err(LemmyError::from_message("cant_block_yourself"));
} }
let person_block_form = PersonBlockForm { let person_block_form = PersonBlockForm {
@ -497,12 +511,14 @@ impl Perform for BlockPerson {
let block = move |conn: &'_ _| PersonBlock::block(conn, &person_block_form); let block = move |conn: &'_ _| PersonBlock::block(conn, &person_block_form);
blocking(context.pool(), block) blocking(context.pool(), block)
.await? .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"))?;
} else { } else {
let unblock = move |conn: &'_ _| PersonBlock::unblock(conn, &person_block_form); let unblock = move |conn: &'_ _| PersonBlock::unblock(conn, &person_block_form);
blocking(context.pool(), unblock) blocking(context.pool(), unblock)
.await? .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"))?;
} }
// TODO does any federated stuff need to be done here? // TODO does any federated stuff need to be done here?
@ -525,6 +541,7 @@ impl Perform for BlockPerson {
impl Perform for GetReplies { impl Perform for GetReplies {
type Response = GetRepliesResponse; type Response = GetRepliesResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -563,6 +580,7 @@ impl Perform for GetReplies {
impl Perform for GetPersonMentions { impl Perform for GetPersonMentions {
type Response = GetPersonMentionsResponse; type Response = GetPersonMentionsResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -598,6 +616,7 @@ impl Perform for GetPersonMentions {
impl Perform for MarkPersonMentionAsRead { impl Perform for MarkPersonMentionAsRead {
type Response = PersonMentionResponse; type Response = PersonMentionResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -614,7 +633,7 @@ impl Perform for MarkPersonMentionAsRead {
.await??; .await??;
if local_user_view.person.id != read_person_mention.recipient_id { 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"));
} }
let person_mention_id = read_person_mention.id; let person_mention_id = read_person_mention.id;
@ -623,7 +642,8 @@ impl Perform for MarkPersonMentionAsRead {
move |conn: &'_ _| PersonMention::update_read(conn, person_mention_id, read); move |conn: &'_ _| PersonMention::update_read(conn, person_mention_id, read);
blocking(context.pool(), update_mention) blocking(context.pool(), update_mention)
.await? .await?
.map_err(|e| ApiError::err("couldnt_update_comment", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_update_comment"))?;
let person_mention_id = read_person_mention.id; let person_mention_id = read_person_mention.id;
let person_id = local_user_view.person.id; let person_id = local_user_view.person.id;
@ -642,6 +662,7 @@ impl Perform for MarkPersonMentionAsRead {
impl Perform for MarkAllAsRead { impl Perform for MarkAllAsRead {
type Response = GetRepliesResponse; type Response = GetRepliesResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -671,7 +692,8 @@ impl Perform for MarkAllAsRead {
let mark_as_read = move |conn: &'_ _| Comment::update_read(conn, reply_id, true); let mark_as_read = move |conn: &'_ _| Comment::update_read(conn, reply_id, true);
blocking(context.pool(), mark_as_read) blocking(context.pool(), mark_as_read)
.await? .await?
.map_err(|e| ApiError::err("couldnt_update_comment", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_update_comment"))?;
} }
// Mark all user mentions as read // Mark all user mentions as read
@ -679,13 +701,15 @@ impl Perform for MarkAllAsRead {
move |conn: &'_ _| PersonMention::mark_all_as_read(conn, person_id); move |conn: &'_ _| PersonMention::mark_all_as_read(conn, person_id);
blocking(context.pool(), update_person_mentions) blocking(context.pool(), update_person_mentions)
.await? .await?
.map_err(|e| ApiError::err("couldnt_update_comment", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_update_comment"))?;
// Mark all private_messages as read // Mark all private_messages as read
let update_pm = move |conn: &'_ _| PrivateMessage::mark_all_as_read(conn, person_id); let update_pm = move |conn: &'_ _| PrivateMessage::mark_all_as_read(conn, person_id);
blocking(context.pool(), update_pm) blocking(context.pool(), update_pm)
.await? .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"))?;
Ok(GetRepliesResponse { replies: vec![] }) Ok(GetRepliesResponse { replies: vec![] })
} }
@ -695,6 +719,7 @@ impl Perform for MarkAllAsRead {
impl Perform for PasswordReset { impl Perform for PasswordReset {
type Response = PasswordResetResponse; type Response = PasswordResetResponse;
#[tracing::instrument(skip(self, context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -708,7 +733,8 @@ impl Perform for PasswordReset {
LocalUserView::find_by_email(conn, &email) LocalUserView::find_by_email(conn, &email)
}) })
.await? .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"))?;
// Generate a random token // Generate a random token
let token = generate_random_string(); let token = generate_random_string();
@ -734,7 +760,9 @@ impl Perform for PasswordReset {
html, html,
&context.settings(), &context.settings(),
) )
.map_err(|e| ApiError::err("email_send_failed", e))?; .map_err(|e| anyhow::anyhow!("{}", e))
.map_err(LemmyError::from)
.map_err(|e| e.with_message("email_send_failed"))?;
Ok(PasswordResetResponse {}) Ok(PasswordResetResponse {})
} }
@ -744,6 +772,7 @@ impl Perform for PasswordReset {
impl Perform for PasswordChange { impl Perform for PasswordChange {
type Response = LoginResponse; type Response = LoginResponse;
#[tracing::instrument(skip(self, context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -762,7 +791,7 @@ impl Perform for PasswordChange {
// Make sure passwords match // Make sure passwords match
if data.password != data.password_verify { if data.password != data.password_verify {
return Err(ApiError::err_plain("passwords_dont_match").into()); return Err(LemmyError::from_message("passwords_dont_match"));
} }
// Update the user with the new password // Update the user with the new password
@ -771,7 +800,8 @@ impl Perform for PasswordChange {
LocalUser::update_password(conn, local_user_id, &password) LocalUser::update_password(conn, local_user_id, &password)
}) })
.await? .await?
.map_err(|e| ApiError::err("couldnt_update_user", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_update_user"))?;
// Return the jwt // Return the jwt
Ok(LoginResponse { Ok(LoginResponse {
@ -779,7 +809,8 @@ impl Perform for PasswordChange {
updated_local_user.id.0, updated_local_user.id.0,
&context.secret().jwt_secret, &context.secret().jwt_secret,
&context.settings().hostname, &context.settings().hostname,
)?, )?
.into(),
}) })
} }
} }
@ -788,6 +819,7 @@ impl Perform for PasswordChange {
impl Perform for GetReportCount { impl Perform for GetReportCount {
type Response = GetReportCountResponse; type Response = GetReportCountResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -825,6 +857,7 @@ impl Perform for GetReportCount {
impl Perform for GetUnreadCount { impl Perform for GetUnreadCount {
type Response = GetUnreadCountResponse; type Response = GetUnreadCountResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,

View file

@ -29,7 +29,7 @@ use lemmy_db_schema::{
traits::{Crud, Likeable, Saveable}, traits::{Crud, Likeable, Saveable},
}; };
use lemmy_db_views::post_view::PostView; 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 lemmy_websocket::{send::send_post_ws_message, LemmyContext, UserOperation};
use std::convert::TryInto; use std::convert::TryInto;
@ -37,6 +37,7 @@ use std::convert::TryInto;
impl Perform for CreatePostLike { impl Perform for CreatePostLike {
type Response = PostResponse; type Response = PostResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -83,7 +84,8 @@ impl Perform for CreatePostLike {
let like = move |conn: &'_ _| PostLike::like(conn, &like_form2); let like = move |conn: &'_ _| PostLike::like(conn, &like_form2);
blocking(context.pool(), like) blocking(context.pool(), like)
.await? .await?
.map_err(|e| ApiError::err("couldnt_like_post", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_like_post"))?;
Vote::send( Vote::send(
&object, &object,
@ -123,6 +125,7 @@ impl Perform for CreatePostLike {
impl Perform for MarkPostAsRead { impl Perform for MarkPostAsRead {
type Response = PostResponse; type Response = PostResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -158,6 +161,7 @@ impl Perform for MarkPostAsRead {
impl Perform for LockPost { impl Perform for LockPost {
type Response = PostResponse; type Response = PostResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -227,6 +231,7 @@ impl Perform for LockPost {
impl Perform for StickyPost { impl Perform for StickyPost {
type Response = PostResponse; type Response = PostResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -300,6 +305,7 @@ impl Perform for StickyPost {
impl Perform for SavePost { impl Perform for SavePost {
type Response = PostResponse; type Response = PostResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -318,12 +324,14 @@ impl Perform for SavePost {
let save = move |conn: &'_ _| PostSaved::save(conn, &post_saved_form); let save = move |conn: &'_ _| PostSaved::save(conn, &post_saved_form);
blocking(context.pool(), save) blocking(context.pool(), save)
.await? .await?
.map_err(|e| ApiError::err("couldnt_save_post", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_save_post"))?;
} else { } else {
let unsave = move |conn: &'_ _| PostSaved::unsave(conn, &post_saved_form); let unsave = move |conn: &'_ _| PostSaved::unsave(conn, &post_saved_form);
blocking(context.pool(), unsave) blocking(context.pool(), unsave)
.await? .await?
.map_err(|e| ApiError::err("couldnt_save_post", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_save_post"))?;
} }
let post_id = data.post_id; let post_id = data.post_id;
@ -344,6 +352,7 @@ impl Perform for SavePost {
impl Perform for GetSiteMetadata { impl Perform for GetSiteMetadata {
type Response = GetSiteMetadataResponse; type Response = GetSiteMetadataResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,

View file

@ -23,7 +23,7 @@ use lemmy_db_views::{
post_report_view::{PostReportQueryBuilder, PostReportView}, post_report_view::{PostReportQueryBuilder, PostReportView},
post_view::PostView, post_view::PostView,
}; };
use lemmy_utils::{ApiError, ConnectionId, LemmyError}; use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::{messages::SendModRoomMessage, LemmyContext, UserOperation}; use lemmy_websocket::{messages::SendModRoomMessage, LemmyContext, UserOperation};
/// Creates a post report and notifies the moderators of the community /// 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 { impl Perform for CreatePostReport {
type Response = PostReportResponse; type Response = PostReportResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -43,10 +44,10 @@ impl Perform for CreatePostReport {
// check size of report and check for whitespace // check size of report and check for whitespace
let reason = data.reason.trim(); let reason = data.reason.trim();
if reason.is_empty() { if reason.is_empty() {
return Err(ApiError::err_plain("report_reason_required").into()); return Err(LemmyError::from_message("report_reason_required"));
} }
if reason.chars().count() > 1000 { if reason.chars().count() > 1000 {
return Err(ApiError::err_plain("report_too_long").into()); return Err(LemmyError::from_message("report_too_long"));
} }
let person_id = local_user_view.person.id; let person_id = local_user_view.person.id;
@ -71,7 +72,8 @@ impl Perform for CreatePostReport {
PostReport::report(conn, &report_form) PostReport::report(conn, &report_form)
}) })
.await? .await?
.map_err(|e| ApiError::err("couldnt_create_report", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_create_report"))?;
let post_report_view = blocking(context.pool(), move |conn| { let post_report_view = blocking(context.pool(), move |conn| {
PostReportView::read(conn, report.id, person_id) PostReportView::read(conn, report.id, person_id)
@ -105,6 +107,7 @@ impl Perform for CreatePostReport {
impl Perform for ResolvePostReport { impl Perform for ResolvePostReport {
type Response = PostReportResponse; type Response = PostReportResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -135,7 +138,8 @@ impl Perform for ResolvePostReport {
blocking(context.pool(), resolve_fun) blocking(context.pool(), resolve_fun)
.await? .await?
.map_err(|e| ApiError::err("couldnt_resolve_report", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_resolve_report"))?;
let post_report_view = blocking(context.pool(), move |conn| { let post_report_view = blocking(context.pool(), move |conn| {
PostReportView::read(conn, report_id, person_id) PostReportView::read(conn, report_id, person_id)
@ -161,6 +165,7 @@ impl Perform for ResolvePostReport {
impl Perform for ListPostReports { impl Perform for ListPostReports {
type Response = ListPostReportsResponse; type Response = ListPostReportsResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,

View file

@ -6,13 +6,14 @@ use lemmy_api_common::{
person::{MarkPrivateMessageAsRead, PrivateMessageResponse}, person::{MarkPrivateMessageAsRead, PrivateMessageResponse},
}; };
use lemmy_db_schema::{source::private_message::PrivateMessage, traits::Crud}; 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}; use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperation};
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl Perform for MarkPrivateMessageAsRead { impl Perform for MarkPrivateMessageAsRead {
type Response = PrivateMessageResponse; type Response = PrivateMessageResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -29,7 +30,7 @@ impl Perform for MarkPrivateMessageAsRead {
}) })
.await??; .await??;
if local_user_view.person.id != orig_private_message.recipient_id { 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"));
} }
// Doing the update // Doing the update
@ -39,7 +40,8 @@ impl Perform for MarkPrivateMessageAsRead {
PrivateMessage::update_read(conn, private_message_id, read) PrivateMessage::update_read(conn, private_message_id, read)
}) })
.await? .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"))?;
// No need to send an apub update // No need to send an apub update
let op = UserOperation::MarkPrivateMessageAsRead; let op = UserOperation::MarkPrivateMessageAsRead;

View file

@ -49,20 +49,14 @@ use lemmy_db_views_moderator::{
mod_sticky_post_view::ModStickyPostView, mod_sticky_post_view::ModStickyPostView,
mod_transfer_community_view::ModTransferCommunityView, mod_transfer_community_view::ModTransferCommunityView,
}; };
use lemmy_utils::{ use lemmy_utils::{location_info, settings::structs::Settings, version, ConnectionId, LemmyError};
location_info,
settings::structs::Settings,
version,
ApiError,
ConnectionId,
LemmyError,
};
use lemmy_websocket::LemmyContext; use lemmy_websocket::LemmyContext;
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl Perform for GetModlog { impl Perform for GetModlog {
type Response = GetModlogResponse; type Response = GetModlogResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -143,6 +137,7 @@ impl Perform for GetModlog {
impl Perform for Search { impl Perform for Search {
type Response = SearchResponse; type Response = SearchResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -151,7 +146,8 @@ impl Perform for Search {
let data: &Search = self; let data: &Search = self;
let local_user_view = let local_user_view =
get_local_user_view_from_jwt_opt(&data.auth, context.pool(), context.secret()).await?; get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret())
.await?;
let show_nsfw = local_user_view.as_ref().map(|t| t.local_user.show_nsfw); let show_nsfw = local_user_view.as_ref().map(|t| t.local_user.show_nsfw);
let show_bot_accounts = local_user_view let show_bot_accounts = local_user_view
@ -383,19 +379,23 @@ impl Perform for Search {
impl Perform for ResolveObject { impl Perform for ResolveObject {
type Response = ResolveObjectResponse; type Response = ResolveObjectResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
_websocket_id: Option<ConnectionId>, _websocket_id: Option<ConnectionId>,
) -> Result<ResolveObjectResponse, LemmyError> { ) -> Result<ResolveObjectResponse, LemmyError> {
let local_user_view = let local_user_view =
get_local_user_view_from_jwt_opt(&self.auth, context.pool(), context.secret()).await?; get_local_user_view_from_jwt_opt(self.auth.as_ref(), context.pool(), context.secret())
.await?;
let res = search_by_apub_id(&self.q, context) let res = search_by_apub_id(&self.q, context)
.await .await
.map_err(|e| ApiError::err("couldnt_find_object", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_find_object"))?;
convert_response(res, local_user_view.map(|l| l.person.id), context.pool()) convert_response(res, local_user_view.map(|l| l.person.id), context.pool())
.await .await
.map_err(|e| ApiError::err("couldnt_find_object", e).into()) .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_find_object"))
} }
} }
@ -442,6 +442,7 @@ async fn convert_response(
impl Perform for TransferSite { impl Perform for TransferSite {
type Response = GetSiteResponse; type Response = GetSiteResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -457,14 +458,15 @@ impl Perform for TransferSite {
// Make sure user is the creator // Make sure user is the creator
if read_site.creator_id != local_user_view.person.id { 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"));
} }
let new_creator_id = data.person_id; let new_creator_id = data.person_id;
let transfer_site = move |conn: &'_ _| Site::transfer(conn, new_creator_id); let transfer_site = move |conn: &'_ _| Site::transfer(conn, new_creator_id);
blocking(context.pool(), transfer_site) blocking(context.pool(), transfer_site)
.await? .await?
.map_err(|e| ApiError::err("couldnt_update_site", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_update_site"))?;
// Mod tables // Mod tables
let form = ModAddForm { let form = ModAddForm {
@ -509,6 +511,7 @@ impl Perform for TransferSite {
impl Perform for GetSiteConfig { impl Perform for GetSiteConfig {
type Response = GetSiteConfigResponse; type Response = GetSiteConfigResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -531,6 +534,7 @@ impl Perform for GetSiteConfig {
impl Perform for SaveSiteConfig { impl Perform for SaveSiteConfig {
type Response = GetSiteConfigResponse; type Response = GetSiteConfigResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -545,7 +549,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 // 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) 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"))?;
Ok(GetSiteConfigResponse { config_hjson }) Ok(GetSiteConfigResponse { config_hjson })
} }

View file

@ -11,6 +11,7 @@ use lemmy_websocket::{
impl Perform for UserJoin { impl Perform for UserJoin {
type Response = UserJoinResponse; type Response = UserJoinResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -35,6 +36,7 @@ impl Perform for UserJoin {
impl Perform for CommunityJoin { impl Perform for CommunityJoin {
type Response = CommunityJoinResponse; type Response = CommunityJoinResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -57,6 +59,7 @@ impl Perform for CommunityJoin {
impl Perform for ModJoin { impl Perform for ModJoin {
type Response = ModJoinResponse; type Response = ModJoinResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -79,6 +82,7 @@ impl Perform for ModJoin {
impl Perform for PostJoin { impl Perform for PostJoin {
type Response = PostJoinResponse; type Response = PostJoinResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,

View file

@ -23,4 +23,5 @@ diesel = "1.4.8"
actix-web = { version = "4.0.0-beta.9", default-features = false, features = ["cookies"] } actix-web = { version = "4.0.0-beta.9", default-features = false, features = ["cookies"] }
chrono = { version = "0.4.19", features = ["serde"] } chrono = { version = "0.4.19", features = ["serde"] }
serde_json = { version = "1.0.68", features = ["preserve_order"] } serde_json = { version = "1.0.68", features = ["preserve_order"] }
tracing = "0.1.29"
url = "2.2.2" url = "2.2.2"

View file

@ -1,74 +1,75 @@
use lemmy_db_schema::newtypes::{CommentId, CommentReportId, CommunityId, LocalUserId, PostId}; use lemmy_db_schema::newtypes::{CommentId, CommentReportId, CommunityId, LocalUserId, PostId};
use lemmy_db_views::{comment_report_view::CommentReportView, comment_view::CommentView}; use lemmy_db_views::{comment_report_view::CommentReportView, comment_view::CommentView};
use lemmy_utils::Sensitive;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct CreateComment { pub struct CreateComment {
pub content: String, pub content: String,
pub post_id: PostId, pub post_id: PostId,
pub parent_id: Option<CommentId>, pub parent_id: Option<CommentId>,
pub form_id: Option<String>, pub form_id: Option<String>,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct GetComment { pub struct GetComment {
pub id: CommentId, pub id: CommentId,
pub auth: Option<String>, pub auth: Option<Sensitive<String>>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct EditComment { pub struct EditComment {
pub content: String, pub content: String,
pub comment_id: CommentId, pub comment_id: CommentId,
pub form_id: Option<String>, pub form_id: Option<String>,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct DeleteComment { pub struct DeleteComment {
pub comment_id: CommentId, pub comment_id: CommentId,
pub deleted: bool, pub deleted: bool,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct RemoveComment { pub struct RemoveComment {
pub comment_id: CommentId, pub comment_id: CommentId,
pub removed: bool, pub removed: bool,
pub reason: Option<String>, pub reason: Option<String>,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct MarkCommentAsRead { pub struct MarkCommentAsRead {
pub comment_id: CommentId, pub comment_id: CommentId,
pub read: bool, pub read: bool,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct SaveComment { pub struct SaveComment {
pub comment_id: CommentId, pub comment_id: CommentId,
pub save: bool, pub save: bool,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct CommentResponse { pub struct CommentResponse {
pub comment_view: CommentView, pub comment_view: CommentView,
pub recipient_ids: Vec<LocalUserId>, pub recipient_ids: Vec<LocalUserId>,
pub form_id: Option<String>, // An optional front end ID, to tell which is coming back pub form_id: Option<String>, // An optional front end ID, to tell which is coming back
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct CreateCommentLike { pub struct CreateCommentLike {
pub comment_id: CommentId, pub comment_id: CommentId,
pub score: i16, pub score: i16,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct GetComments { pub struct GetComments {
pub type_: Option<String>, pub type_: Option<String>,
pub sort: Option<String>, pub sort: Option<String>,
@ -77,34 +78,34 @@ pub struct GetComments {
pub community_id: Option<CommunityId>, pub community_id: Option<CommunityId>,
pub community_name: Option<String>, pub community_name: Option<String>,
pub saved_only: Option<bool>, pub saved_only: Option<bool>,
pub auth: Option<String>, pub auth: Option<Sensitive<String>>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct GetCommentsResponse { pub struct GetCommentsResponse {
pub comments: Vec<CommentView>, pub comments: Vec<CommentView>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct CreateCommentReport { pub struct CreateCommentReport {
pub comment_id: CommentId, pub comment_id: CommentId,
pub reason: String, pub reason: String,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct CommentReportResponse { pub struct CommentReportResponse {
pub comment_report_view: CommentReportView, pub comment_report_view: CommentReportView,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct ResolveCommentReport { pub struct ResolveCommentReport {
pub report_id: CommentReportId, pub report_id: CommentReportId,
pub resolved: bool, pub resolved: bool,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct ListCommentReports { pub struct ListCommentReports {
pub page: Option<i64>, pub page: Option<i64>,
pub limit: Option<i64>, pub limit: Option<i64>,
@ -112,10 +113,10 @@ pub struct ListCommentReports {
pub unresolved_only: Option<bool>, pub unresolved_only: Option<bool>,
/// if no community is given, it returns reports for all communities moderated by the auth user /// if no community is given, it returns reports for all communities moderated by the auth user
pub community_id: Option<CommunityId>, pub community_id: Option<CommunityId>,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct ListCommentReportsResponse { pub struct ListCommentReportsResponse {
pub comment_reports: Vec<CommentReportView>, pub comment_reports: Vec<CommentReportView>,
} }

View file

@ -4,24 +4,25 @@ use lemmy_db_views_actor::{
community_view::CommunityView, community_view::CommunityView,
person_view::PersonViewSafe, person_view::PersonViewSafe,
}; };
use lemmy_utils::Sensitive;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct GetCommunity { pub struct GetCommunity {
pub id: Option<CommunityId>, pub id: Option<CommunityId>,
/// Example: star_trek , or star_trek@xyz.tld /// Example: star_trek , or star_trek@xyz.tld
pub name: Option<String>, pub name: Option<String>,
pub auth: Option<String>, pub auth: Option<Sensitive<String>>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct GetCommunityResponse { pub struct GetCommunityResponse {
pub community_view: CommunityView, pub community_view: CommunityView,
pub moderators: Vec<CommunityModeratorView>, pub moderators: Vec<CommunityModeratorView>,
pub online: usize, pub online: usize,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct CreateCommunity { pub struct CreateCommunity {
pub name: String, pub name: String,
pub title: String, pub title: String,
@ -29,10 +30,10 @@ pub struct CreateCommunity {
pub icon: Option<String>, pub icon: Option<String>,
pub banner: Option<String>, pub banner: Option<String>,
pub nsfw: Option<bool>, pub nsfw: Option<bool>,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct CommunityResponse { pub struct CommunityResponse {
pub community_view: CommunityView, pub community_view: CommunityView,
} }
@ -43,7 +44,7 @@ pub struct ListCommunities {
pub sort: Option<String>, pub sort: Option<String>,
pub page: Option<i64>, pub page: Option<i64>,
pub limit: Option<i64>, pub limit: Option<i64>,
pub auth: Option<String>, pub auth: Option<Sensitive<String>>,
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
@ -51,7 +52,7 @@ pub struct ListCommunitiesResponse {
pub communities: Vec<CommunityView>, pub communities: Vec<CommunityView>,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct BanFromCommunity { pub struct BanFromCommunity {
pub community_id: CommunityId, pub community_id: CommunityId,
pub person_id: PersonId, pub person_id: PersonId,
@ -59,29 +60,29 @@ pub struct BanFromCommunity {
pub remove_data: Option<bool>, pub remove_data: Option<bool>,
pub reason: Option<String>, pub reason: Option<String>,
pub expires: Option<i64>, pub expires: Option<i64>,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct BanFromCommunityResponse { pub struct BanFromCommunityResponse {
pub person_view: PersonViewSafe, pub person_view: PersonViewSafe,
pub banned: bool, pub banned: bool,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct AddModToCommunity { pub struct AddModToCommunity {
pub community_id: CommunityId, pub community_id: CommunityId,
pub person_id: PersonId, pub person_id: PersonId,
pub added: bool, pub added: bool,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct AddModToCommunityResponse { pub struct AddModToCommunityResponse {
pub moderators: Vec<CommunityModeratorView>, pub moderators: Vec<CommunityModeratorView>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct EditCommunity { pub struct EditCommunity {
pub community_id: CommunityId, pub community_id: CommunityId,
pub title: Option<String>, pub title: Option<String>,
@ -89,48 +90,48 @@ pub struct EditCommunity {
pub icon: Option<String>, pub icon: Option<String>,
pub banner: Option<String>, pub banner: Option<String>,
pub nsfw: Option<bool>, pub nsfw: Option<bool>,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct DeleteCommunity { pub struct DeleteCommunity {
pub community_id: CommunityId, pub community_id: CommunityId,
pub deleted: bool, pub deleted: bool,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct RemoveCommunity { pub struct RemoveCommunity {
pub community_id: CommunityId, pub community_id: CommunityId,
pub removed: bool, pub removed: bool,
pub reason: Option<String>, pub reason: Option<String>,
pub expires: Option<i64>, pub expires: Option<i64>,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct FollowCommunity { pub struct FollowCommunity {
pub community_id: CommunityId, pub community_id: CommunityId,
pub follow: bool, pub follow: bool,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct BlockCommunity { pub struct BlockCommunity {
pub community_id: CommunityId, pub community_id: CommunityId,
pub block: bool, pub block: bool,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct BlockCommunityResponse { pub struct BlockCommunityResponse {
pub community_view: CommunityView, pub community_view: CommunityView,
pub blocked: bool, pub blocked: bool,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct TransferCommunity { pub struct TransferCommunity {
pub community_id: CommunityId, pub community_id: CommunityId,
pub person_id: PersonId, pub person_id: PersonId,
pub auth: String, pub auth: Sensitive<String>,
} }

View file

@ -23,7 +23,7 @@ use lemmy_db_views_actor::{
community_person_ban_view::CommunityPersonBanView, community_person_ban_view::CommunityPersonBanView,
community_view::CommunityView, community_view::CommunityView,
}; };
use lemmy_utils::{claims::Claims, settings::structs::FederationConfig, ApiError, LemmyError}; use lemmy_utils::{claims::Claims, settings::structs::FederationConfig, LemmyError, Sensitive};
use url::Url; use url::Url;
pub async fn blocking<F, T>(pool: &DbPool, f: F) -> Result<T, LemmyError> pub async fn blocking<F, T>(pool: &DbPool, f: F) -> Result<T, LemmyError>
@ -32,9 +32,12 @@ where
T: Send + 'static, T: Send + 'static,
{ {
let pool = pool.clone(); let pool = pool.clone();
let blocking_span = tracing::info_span!("blocking operation");
let res = actix_web::web::block(move || { let res = actix_web::web::block(move || {
let entered = blocking_span.enter();
let conn = pool.get()?; let conn = pool.get()?;
let res = (f)(&conn); let res = (f)(&conn);
drop(entered);
Ok(res) as Result<T, LemmyError> Ok(res) as Result<T, LemmyError>
}) })
.await?; .await?;
@ -52,14 +55,14 @@ pub async fn is_mod_or_admin(
}) })
.await?; .await?;
if !is_mod_or_admin { 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"));
} }
Ok(()) Ok(())
} }
pub fn is_admin(local_user_view: &LocalUserView) -> Result<(), LemmyError> { pub fn is_admin(local_user_view: &LocalUserView) -> Result<(), LemmyError> {
if !local_user_view.person.admin { if !local_user_view.person.admin {
return Err(ApiError::err_plain("not_an_admin").into()); return Err(LemmyError::from_message("not_an_admin"));
} }
Ok(()) Ok(())
} }
@ -67,7 +70,8 @@ pub fn is_admin(local_user_view: &LocalUserView) -> Result<(), LemmyError> {
pub async fn get_post(post_id: PostId, pool: &DbPool) -> Result<Post, LemmyError> { pub async fn get_post(post_id: PostId, pool: &DbPool) -> Result<Post, LemmyError> {
blocking(pool, move |conn| Post::read(conn, post_id)) blocking(pool, move |conn| Post::read(conn, post_id))
.await? .await?
.map_err(|_| ApiError::err_plain("couldnt_find_post").into()) .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_find_post"))
} }
pub async fn mark_post_as_read( pub async fn mark_post_as_read(
@ -81,7 +85,8 @@ pub async fn mark_post_as_read(
PostRead::mark_as_read(conn, &post_read_form) PostRead::mark_as_read(conn, &post_read_form)
}) })
.await? .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"))
} }
pub async fn mark_post_as_unread( pub async fn mark_post_as_unread(
@ -95,7 +100,8 @@ pub async fn mark_post_as_unread(
PostRead::mark_as_unread(conn, &post_read_form) PostRead::mark_as_unread(conn, &post_read_form)
}) })
.await? .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"))
} }
pub async fn get_local_user_view_from_jwt( pub async fn get_local_user_view_from_jwt(
@ -104,19 +110,20 @@ pub async fn get_local_user_view_from_jwt(
secret: &Secret, secret: &Secret,
) -> Result<LocalUserView, LemmyError> { ) -> Result<LocalUserView, LemmyError> {
let claims = Claims::decode(jwt, &secret.jwt_secret) 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"))?
.claims; .claims;
let local_user_id = LocalUserId(claims.sub); let local_user_id = LocalUserId(claims.sub);
let local_user_view = let local_user_view =
blocking(pool, move |conn| LocalUserView::read(conn, local_user_id)).await??; blocking(pool, move |conn| LocalUserView::read(conn, local_user_id)).await??;
// Check for a site ban // Check for a site ban
if local_user_view.person.banned { if local_user_view.person.banned {
return Err(ApiError::err_plain("site_ban").into()); return Err(LemmyError::from_message("site_ban"));
} }
// Check for user deletion // Check for user deletion
if local_user_view.person.deleted { if local_user_view.person.deleted {
return Err(ApiError::err_plain("deleted").into()); return Err(LemmyError::from_message("deleted"));
} }
check_validator_time(&local_user_view.local_user.validator_time, &claims)?; check_validator_time(&local_user_view.local_user.validator_time, &claims)?;
@ -131,14 +138,14 @@ pub fn check_validator_time(
) -> Result<(), LemmyError> { ) -> Result<(), LemmyError> {
let user_validation_time = validator_time.timestamp(); let user_validation_time = validator_time.timestamp();
if user_validation_time > claims.iat { if user_validation_time > claims.iat {
Err(ApiError::err_plain("not_logged_in").into()) Err(LemmyError::from_message("not_logged_in"))
} else { } else {
Ok(()) Ok(())
} }
} }
pub async fn get_local_user_view_from_jwt_opt( pub async fn get_local_user_view_from_jwt_opt(
jwt: &Option<String>, jwt: Option<&Sensitive<String>>,
pool: &DbPool, pool: &DbPool,
secret: &Secret, secret: &Secret,
) -> Result<Option<LocalUserView>, LemmyError> { ) -> Result<Option<LocalUserView>, LemmyError> {
@ -149,12 +156,13 @@ pub async fn get_local_user_view_from_jwt_opt(
} }
pub async fn get_local_user_settings_view_from_jwt( pub async fn get_local_user_settings_view_from_jwt(
jwt: &str, jwt: &Sensitive<String>,
pool: &DbPool, pool: &DbPool,
secret: &Secret, secret: &Secret,
) -> Result<LocalUserSettingsView, LemmyError> { ) -> Result<LocalUserSettingsView, LemmyError> {
let claims = Claims::decode(jwt, &secret.jwt_secret) let claims = Claims::decode(jwt.as_ref(), &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"))?
.claims; .claims;
let local_user_id = LocalUserId(claims.sub); let local_user_id = LocalUserId(claims.sub);
let local_user_view = blocking(pool, move |conn| { let local_user_view = blocking(pool, move |conn| {
@ -163,7 +171,7 @@ pub async fn get_local_user_settings_view_from_jwt(
.await??; .await??;
// Check for a site ban // Check for a site ban
if local_user_view.person.banned { if local_user_view.person.banned {
return Err(ApiError::err_plain("site_ban").into()); return Err(LemmyError::from_message("site_ban"));
} }
check_validator_time(&local_user_view.local_user.validator_time, &claims)?; check_validator_time(&local_user_view.local_user.validator_time, &claims)?;
@ -172,7 +180,7 @@ pub async fn get_local_user_settings_view_from_jwt(
} }
pub async fn get_local_user_settings_view_from_jwt_opt( pub async fn get_local_user_settings_view_from_jwt_opt(
jwt: &Option<String>, jwt: Option<&Sensitive<String>>,
pool: &DbPool, pool: &DbPool,
secret: &Secret, secret: &Secret,
) -> Result<Option<LocalUserSettingsView>, LemmyError> { ) -> Result<Option<LocalUserSettingsView>, LemmyError> {
@ -192,7 +200,7 @@ pub async fn check_community_ban(
let is_banned = let is_banned =
move |conn: &'_ _| CommunityPersonBanView::get(conn, person_id, community_id).is_ok(); move |conn: &'_ _| CommunityPersonBanView::get(conn, person_id, community_id).is_ok();
if blocking(pool, is_banned).await? { if blocking(pool, is_banned).await? {
Err(ApiError::err_plain("community_ban").into()) Err(LemmyError::from_message("community_ban"))
} else { } else {
Ok(()) Ok(())
} }
@ -204,9 +212,10 @@ pub async fn check_community_deleted_or_removed(
) -> Result<(), LemmyError> { ) -> Result<(), LemmyError> {
let community = blocking(pool, move |conn| Community::read(conn, community_id)) let community = blocking(pool, move |conn| Community::read(conn, community_id))
.await? .await?
.map_err(|e| ApiError::err("couldnt_find_community", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_find_community"))?;
if community.deleted || community.removed { if community.deleted || community.removed {
Err(ApiError::err_plain("deleted").into()) Err(LemmyError::from_message("deleted"))
} else { } else {
Ok(()) Ok(())
} }
@ -214,7 +223,7 @@ pub async fn check_community_deleted_or_removed(
pub fn check_post_deleted_or_removed(post: &Post) -> Result<(), LemmyError> { pub fn check_post_deleted_or_removed(post: &Post) -> Result<(), LemmyError> {
if post.deleted || post.removed { if post.deleted || post.removed {
Err(ApiError::err_plain("deleted").into()) Err(LemmyError::from_message("deleted"))
} else { } else {
Ok(()) Ok(())
} }
@ -227,7 +236,7 @@ pub async fn check_person_block(
) -> Result<(), LemmyError> { ) -> Result<(), LemmyError> {
let is_blocked = move |conn: &'_ _| PersonBlock::read(conn, potential_blocker_id, my_id).is_ok(); let is_blocked = move |conn: &'_ _| PersonBlock::read(conn, potential_blocker_id, my_id).is_ok();
if blocking(pool, is_blocked).await? { if blocking(pool, is_blocked).await? {
Err(ApiError::err_plain("person_block").into()) Err(LemmyError::from_message("person_block"))
} else { } else {
Ok(()) Ok(())
} }
@ -237,7 +246,7 @@ pub async fn check_downvotes_enabled(score: i16, pool: &DbPool) -> Result<(), Le
if score == -1 { if score == -1 {
let site = blocking(pool, Site::read_simple).await??; let site = blocking(pool, Site::read_simple).await??;
if !site.enable_downvotes { if !site.enable_downvotes {
return Err(ApiError::err_plain("downvotes_disabled").into()); return Err(LemmyError::from_message("downvotes_disabled"));
} }
} }
Ok(()) Ok(())
@ -288,7 +297,7 @@ pub async fn build_federated_instances(
/// Checks the password length /// Checks the password length
pub fn password_length_check(pass: &str) -> Result<(), LemmyError> { pub fn password_length_check(pass: &str) -> Result<(), LemmyError> {
if !(10..=60).contains(&pass.len()) { if !(10..=60).contains(&pass.len()) {
Err(ApiError::err_plain("invalid_password").into()) Err(LemmyError::from_message("invalid_password"))
} else { } else {
Ok(()) Ok(())
} }
@ -297,7 +306,7 @@ pub fn password_length_check(pass: &str) -> Result<(), LemmyError> {
/// Checks the site description length /// Checks the site description length
pub fn site_description_length_check(description: &str) -> Result<(), LemmyError> { pub fn site_description_length_check(description: &str) -> Result<(), LemmyError> {
if description.len() > 150 { if description.len() > 150 {
Err(ApiError::err_plain("site_description_length_overflow").into()) Err(LemmyError::from_message("site_description_length_overflow"))
} else { } else {
Ok(()) Ok(())
} }
@ -306,7 +315,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 /// Checks for a honeypot. If this field is filled, fail the rest of the function
pub fn honeypot_check(honeypot: &Option<String>) -> Result<(), LemmyError> { pub fn honeypot_check(honeypot: &Option<String>) -> Result<(), LemmyError> {
if honeypot.is_some() { if honeypot.is_some() {
Err(ApiError::err_plain("honeypot_fail").into()) Err(LemmyError::from_message("honeypot_fail"))
} else { } else {
Ok(()) Ok(())
} }

View file

@ -8,43 +8,44 @@ use lemmy_db_views_actor::{
person_mention_view::PersonMentionView, person_mention_view::PersonMentionView,
person_view::PersonViewSafe, person_view::PersonViewSafe,
}; };
use lemmy_utils::Sensitive;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)] #[derive(Debug, Serialize, Deserialize)]
pub struct Login { pub struct Login {
pub username_or_email: String, pub username_or_email: Sensitive<String>,
pub password: String, pub password: Sensitive<String>,
} }
use lemmy_db_schema::newtypes::{CommunityId, PersonId, PersonMentionId, PrivateMessageId}; use lemmy_db_schema::newtypes::{CommunityId, PersonId, PersonMentionId, PrivateMessageId};
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct Register { pub struct Register {
pub username: String, pub username: String,
pub password: String, pub password: Sensitive<String>,
pub password_verify: String, pub password_verify: Sensitive<String>,
pub show_nsfw: bool, pub show_nsfw: bool,
pub email: Option<String>, pub email: Option<Sensitive<String>>,
pub captcha_uuid: Option<String>, pub captcha_uuid: Option<String>,
pub captcha_answer: Option<String>, pub captcha_answer: Option<String>,
pub honeypot: Option<String>, pub honeypot: Option<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct GetCaptcha {} pub struct GetCaptcha {}
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct GetCaptchaResponse { pub struct GetCaptchaResponse {
pub ok: Option<CaptchaResponse>, // Will be None if captchas are disabled pub ok: Option<CaptchaResponse>, // Will be None if captchas are disabled
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct CaptchaResponse { pub struct CaptchaResponse {
pub png: String, // A Base64 encoded png pub png: String, // A Base64 encoded png
pub wav: String, // A Base64 encoded wav audio pub wav: String, // A Base64 encoded wav audio
pub uuid: String, pub uuid: String,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct SaveUserSettings { pub struct SaveUserSettings {
pub show_nsfw: Option<bool>, pub show_nsfw: Option<bool>,
pub show_scores: Option<bool>, pub show_scores: Option<bool>,
@ -55,7 +56,7 @@ pub struct SaveUserSettings {
pub avatar: Option<String>, pub avatar: Option<String>,
pub banner: Option<String>, pub banner: Option<String>,
pub display_name: Option<String>, pub display_name: Option<String>,
pub email: Option<String>, pub email: Option<Sensitive<String>>,
pub bio: Option<String>, pub bio: Option<String>,
pub matrix_user_id: Option<String>, pub matrix_user_id: Option<String>,
pub show_avatars: Option<bool>, pub show_avatars: Option<bool>,
@ -64,23 +65,23 @@ pub struct SaveUserSettings {
pub show_bot_accounts: Option<bool>, pub show_bot_accounts: Option<bool>,
pub show_read_posts: Option<bool>, pub show_read_posts: Option<bool>,
pub show_new_post_notifs: Option<bool>, pub show_new_post_notifs: Option<bool>,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct ChangePassword { pub struct ChangePassword {
pub new_password: String, pub new_password: Sensitive<String>,
pub new_password_verify: String, pub new_password_verify: Sensitive<String>,
pub old_password: String, pub old_password: Sensitive<String>,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct LoginResponse { pub struct LoginResponse {
pub jwt: String, pub jwt: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct GetPersonDetails { pub struct GetPersonDetails {
pub person_id: Option<PersonId>, // One of these two are required pub person_id: Option<PersonId>, // One of these two are required
/// Example: dessalines , or dessalines@xyz.tld /// Example: dessalines , or dessalines@xyz.tld
@ -90,10 +91,10 @@ pub struct GetPersonDetails {
pub limit: Option<i64>, pub limit: Option<i64>,
pub community_id: Option<CommunityId>, pub community_id: Option<CommunityId>,
pub saved_only: Option<bool>, pub saved_only: Option<bool>,
pub auth: Option<String>, pub auth: Option<Sensitive<String>>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct GetPersonDetailsResponse { pub struct GetPersonDetailsResponse {
pub person_view: PersonViewSafe, pub person_view: PersonViewSafe,
pub comments: Vec<CommentView>, pub comments: Vec<CommentView>,
@ -101,178 +102,178 @@ pub struct GetPersonDetailsResponse {
pub moderates: Vec<CommunityModeratorView>, pub moderates: Vec<CommunityModeratorView>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct GetRepliesResponse { pub struct GetRepliesResponse {
pub replies: Vec<CommentView>, pub replies: Vec<CommentView>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct GetPersonMentionsResponse { pub struct GetPersonMentionsResponse {
pub mentions: Vec<PersonMentionView>, pub mentions: Vec<PersonMentionView>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct MarkAllAsRead { pub struct MarkAllAsRead {
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct AddAdmin { pub struct AddAdmin {
pub person_id: PersonId, pub person_id: PersonId,
pub added: bool, pub added: bool,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct AddAdminResponse { pub struct AddAdminResponse {
pub admins: Vec<PersonViewSafe>, pub admins: Vec<PersonViewSafe>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct BanPerson { pub struct BanPerson {
pub person_id: PersonId, pub person_id: PersonId,
pub ban: bool, pub ban: bool,
pub remove_data: Option<bool>, pub remove_data: Option<bool>,
pub reason: Option<String>, pub reason: Option<String>,
pub expires: Option<i64>, pub expires: Option<i64>,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct BanPersonResponse { pub struct BanPersonResponse {
pub person_view: PersonViewSafe, pub person_view: PersonViewSafe,
pub banned: bool, pub banned: bool,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct BlockPerson { pub struct BlockPerson {
pub person_id: PersonId, pub person_id: PersonId,
pub block: bool, pub block: bool,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct BlockPersonResponse { pub struct BlockPersonResponse {
pub person_view: PersonViewSafe, pub person_view: PersonViewSafe,
pub blocked: bool, pub blocked: bool,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct GetReplies { pub struct GetReplies {
pub sort: Option<String>, pub sort: Option<String>,
pub page: Option<i64>, pub page: Option<i64>,
pub limit: Option<i64>, pub limit: Option<i64>,
pub unread_only: Option<bool>, pub unread_only: Option<bool>,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct GetPersonMentions { pub struct GetPersonMentions {
pub sort: Option<String>, pub sort: Option<String>,
pub page: Option<i64>, pub page: Option<i64>,
pub limit: Option<i64>, pub limit: Option<i64>,
pub unread_only: Option<bool>, pub unread_only: Option<bool>,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct MarkPersonMentionAsRead { pub struct MarkPersonMentionAsRead {
pub person_mention_id: PersonMentionId, pub person_mention_id: PersonMentionId,
pub read: bool, pub read: bool,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct PersonMentionResponse { pub struct PersonMentionResponse {
pub person_mention_view: PersonMentionView, pub person_mention_view: PersonMentionView,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct DeleteAccount { pub struct DeleteAccount {
pub password: String, pub password: Sensitive<String>,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct PasswordReset { pub struct PasswordReset {
pub email: String, pub email: Sensitive<String>,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct PasswordResetResponse {} pub struct PasswordResetResponse {}
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct PasswordChange { pub struct PasswordChange {
pub token: String, pub token: Sensitive<String>,
pub password: String, pub password: Sensitive<String>,
pub password_verify: String, pub password_verify: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct CreatePrivateMessage { pub struct CreatePrivateMessage {
pub content: String, pub content: String,
pub recipient_id: PersonId, pub recipient_id: PersonId,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct EditPrivateMessage { pub struct EditPrivateMessage {
pub private_message_id: PrivateMessageId, pub private_message_id: PrivateMessageId,
pub content: String, pub content: String,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct DeletePrivateMessage { pub struct DeletePrivateMessage {
pub private_message_id: PrivateMessageId, pub private_message_id: PrivateMessageId,
pub deleted: bool, pub deleted: bool,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct MarkPrivateMessageAsRead { pub struct MarkPrivateMessageAsRead {
pub private_message_id: PrivateMessageId, pub private_message_id: PrivateMessageId,
pub read: bool, pub read: bool,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct GetPrivateMessages { pub struct GetPrivateMessages {
pub unread_only: Option<bool>, pub unread_only: Option<bool>,
pub page: Option<i64>, pub page: Option<i64>,
pub limit: Option<i64>, pub limit: Option<i64>,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct PrivateMessagesResponse { pub struct PrivateMessagesResponse {
pub private_messages: Vec<PrivateMessageView>, pub private_messages: Vec<PrivateMessageView>,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct PrivateMessageResponse { pub struct PrivateMessageResponse {
pub private_message_view: PrivateMessageView, pub private_message_view: PrivateMessageView,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct GetReportCount { pub struct GetReportCount {
pub community_id: Option<CommunityId>, pub community_id: Option<CommunityId>,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct GetReportCountResponse { pub struct GetReportCountResponse {
pub community_id: Option<CommunityId>, pub community_id: Option<CommunityId>,
pub comment_reports: i64, pub comment_reports: i64,
pub post_reports: i64, pub post_reports: i64,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct GetUnreadCount { pub struct GetUnreadCount {
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct GetUnreadCountResponse { pub struct GetUnreadCountResponse {
pub replies: i64, pub replies: i64,
pub mentions: i64, pub mentions: i64,

View file

@ -8,7 +8,7 @@ use lemmy_db_views_actor::{
community_moderator_view::CommunityModeratorView, community_moderator_view::CommunityModeratorView,
community_view::CommunityView, community_view::CommunityView,
}; };
use lemmy_utils::request::SiteMetadata; use lemmy_utils::{request::SiteMetadata, Sensitive};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use url::Url; use url::Url;
@ -20,21 +20,21 @@ pub struct CreatePost {
pub body: Option<String>, pub body: Option<String>,
pub honeypot: Option<String>, pub honeypot: Option<String>,
pub nsfw: Option<bool>, pub nsfw: Option<bool>,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct PostResponse { pub struct PostResponse {
pub post_view: PostView, pub post_view: PostView,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct GetPost { pub struct GetPost {
pub id: PostId, pub id: PostId,
pub auth: Option<String>, pub auth: Option<Sensitive<String>>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct GetPostResponse { pub struct GetPostResponse {
pub post_view: PostView, pub post_view: PostView,
pub community_view: CommunityView, pub community_view: CommunityView,
@ -52,7 +52,7 @@ pub struct GetPosts {
pub community_id: Option<CommunityId>, pub community_id: Option<CommunityId>,
pub community_name: Option<String>, pub community_name: Option<String>,
pub saved_only: Option<bool>, pub saved_only: Option<bool>,
pub auth: Option<String>, pub auth: Option<Sensitive<String>>,
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
@ -60,86 +60,86 @@ pub struct GetPostsResponse {
pub posts: Vec<PostView>, pub posts: Vec<PostView>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct CreatePostLike { pub struct CreatePostLike {
pub post_id: PostId, pub post_id: PostId,
pub score: i16, pub score: i16,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct EditPost { pub struct EditPost {
pub post_id: PostId, pub post_id: PostId,
pub name: Option<String>, pub name: Option<String>,
pub url: Option<Url>, pub url: Option<Url>,
pub body: Option<String>, pub body: Option<String>,
pub nsfw: Option<bool>, pub nsfw: Option<bool>,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct DeletePost { pub struct DeletePost {
pub post_id: PostId, pub post_id: PostId,
pub deleted: bool, pub deleted: bool,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct RemovePost { pub struct RemovePost {
pub post_id: PostId, pub post_id: PostId,
pub removed: bool, pub removed: bool,
pub reason: Option<String>, pub reason: Option<String>,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct MarkPostAsRead { pub struct MarkPostAsRead {
pub post_id: PostId, pub post_id: PostId,
pub read: bool, pub read: bool,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct LockPost { pub struct LockPost {
pub post_id: PostId, pub post_id: PostId,
pub locked: bool, pub locked: bool,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct StickyPost { pub struct StickyPost {
pub post_id: PostId, pub post_id: PostId,
pub stickied: bool, pub stickied: bool,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct SavePost { pub struct SavePost {
pub post_id: PostId, pub post_id: PostId,
pub save: bool, pub save: bool,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct CreatePostReport { pub struct CreatePostReport {
pub post_id: PostId, pub post_id: PostId,
pub reason: String, pub reason: String,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct PostReportResponse { pub struct PostReportResponse {
pub post_report_view: PostReportView, pub post_report_view: PostReportView,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct ResolvePostReport { pub struct ResolvePostReport {
pub report_id: PostReportId, pub report_id: PostReportId,
pub resolved: bool, pub resolved: bool,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct ListPostReports { pub struct ListPostReports {
pub page: Option<i64>, pub page: Option<i64>,
pub limit: Option<i64>, pub limit: Option<i64>,
@ -147,10 +147,10 @@ pub struct ListPostReports {
pub unresolved_only: Option<bool>, pub unresolved_only: Option<bool>,
/// if no community is given, it returns reports for all communities moderated by the auth user /// if no community is given, it returns reports for all communities moderated by the auth user
pub community_id: Option<CommunityId>, pub community_id: Option<CommunityId>,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct ListPostReportsResponse { pub struct ListPostReportsResponse {
pub post_reports: Vec<PostReportView>, pub post_reports: Vec<PostReportView>,
} }

View file

@ -25,6 +25,7 @@ use lemmy_db_views_moderator::{
mod_sticky_post_view::ModStickyPostView, mod_sticky_post_view::ModStickyPostView,
mod_transfer_community_view::ModTransferCommunityView, mod_transfer_community_view::ModTransferCommunityView,
}; };
use lemmy_utils::Sensitive;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
@ -38,7 +39,7 @@ pub struct Search {
pub listing_type: Option<String>, pub listing_type: Option<String>,
pub page: Option<i64>, pub page: Option<i64>,
pub limit: Option<i64>, pub limit: Option<i64>,
pub auth: Option<String>, pub auth: Option<Sensitive<String>>,
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
@ -53,10 +54,10 @@ pub struct SearchResponse {
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct ResolveObject { pub struct ResolveObject {
pub q: String, pub q: String,
pub auth: Option<String>, pub auth: Option<Sensitive<String>>,
} }
#[derive(Serialize, Deserialize, Default)] #[derive(Debug, Serialize, Deserialize, Default)]
pub struct ResolveObjectResponse { pub struct ResolveObjectResponse {
pub comment: Option<CommentView>, pub comment: Option<CommentView>,
pub post: Option<PostView>, pub post: Option<PostView>,
@ -64,7 +65,7 @@ pub struct ResolveObjectResponse {
pub person: Option<PersonViewSafe>, pub person: Option<PersonViewSafe>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct GetModlog { pub struct GetModlog {
pub mod_person_id: Option<PersonId>, pub mod_person_id: Option<PersonId>,
pub community_id: Option<CommunityId>, pub community_id: Option<CommunityId>,
@ -72,7 +73,7 @@ pub struct GetModlog {
pub limit: Option<i64>, pub limit: Option<i64>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct GetModlogResponse { pub struct GetModlogResponse {
pub removed_posts: Vec<ModRemovePostView>, pub removed_posts: Vec<ModRemovePostView>,
pub locked_posts: Vec<ModLockPostView>, pub locked_posts: Vec<ModLockPostView>,
@ -86,7 +87,7 @@ pub struct GetModlogResponse {
pub added: Vec<ModAddView>, pub added: Vec<ModAddView>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct CreateSite { pub struct CreateSite {
pub name: String, pub name: String,
pub sidebar: Option<String>, pub sidebar: Option<String>,
@ -97,10 +98,10 @@ pub struct CreateSite {
pub open_registration: Option<bool>, pub open_registration: Option<bool>,
pub enable_nsfw: Option<bool>, pub enable_nsfw: Option<bool>,
pub community_creation_admin_only: Option<bool>, pub community_creation_admin_only: Option<bool>,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct EditSite { pub struct EditSite {
pub name: Option<String>, pub name: Option<String>,
pub sidebar: Option<String>, pub sidebar: Option<String>,
@ -111,20 +112,20 @@ pub struct EditSite {
pub open_registration: Option<bool>, pub open_registration: Option<bool>,
pub enable_nsfw: Option<bool>, pub enable_nsfw: Option<bool>,
pub community_creation_admin_only: Option<bool>, pub community_creation_admin_only: Option<bool>,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct GetSite { pub struct GetSite {
pub auth: Option<String>, pub auth: Option<Sensitive<String>>,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct SiteResponse { pub struct SiteResponse {
pub site_view: SiteView, pub site_view: SiteView,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct GetSiteResponse { pub struct GetSiteResponse {
pub site_view: Option<SiteView>, // Because the site might not be set up yet pub site_view: Option<SiteView>, // Because the site might not be set up yet
pub admins: Vec<PersonViewSafe>, pub admins: Vec<PersonViewSafe>,
@ -135,7 +136,7 @@ pub struct GetSiteResponse {
pub federated_instances: Option<FederatedInstances>, // Federation may be disabled pub federated_instances: Option<FederatedInstances>, // Federation may be disabled
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct MyUserInfo { pub struct MyUserInfo {
pub local_user_view: LocalUserSettingsView, pub local_user_view: LocalUserSettingsView,
pub follows: Vec<CommunityFollowerView>, pub follows: Vec<CommunityFollowerView>,
@ -144,29 +145,29 @@ pub struct MyUserInfo {
pub person_blocks: Vec<PersonBlockView>, pub person_blocks: Vec<PersonBlockView>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct TransferSite { pub struct TransferSite {
pub person_id: PersonId, pub person_id: PersonId,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct GetSiteConfig { pub struct GetSiteConfig {
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct GetSiteConfigResponse { pub struct GetSiteConfigResponse {
pub config_hjson: String, pub config_hjson: String,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct SaveSiteConfig { pub struct SaveSiteConfig {
pub config_hjson: String, pub config_hjson: String,
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct FederatedInstances { pub struct FederatedInstances {
pub linked: Vec<String>, pub linked: Vec<String>,
pub allowed: Option<Vec<String>>, pub allowed: Option<Vec<String>>,

View file

@ -1,12 +1,13 @@
use lemmy_db_schema::newtypes::{CommunityId, PostId}; use lemmy_db_schema::newtypes::{CommunityId, PostId};
use lemmy_utils::Sensitive;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct UserJoin { pub struct UserJoin {
pub auth: String, pub auth: Sensitive<String>,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct UserJoinResponse { pub struct UserJoinResponse {
pub joined: bool, pub joined: bool,
} }
@ -16,7 +17,7 @@ pub struct CommunityJoin {
pub community_id: CommunityId, pub community_id: CommunityId,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct CommunityJoinResponse { pub struct CommunityJoinResponse {
pub joined: bool, pub joined: bool,
} }
@ -26,7 +27,7 @@ pub struct ModJoin {
pub community_id: CommunityId, pub community_id: CommunityId,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ModJoinResponse { pub struct ModJoinResponse {
pub joined: bool, pub joined: bool,
} }
@ -36,7 +37,7 @@ pub struct PostJoin {
pub post_id: PostId, pub post_id: PostId,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct PostJoinResponse { pub struct PostJoinResponse {
pub joined: bool, pub joined: bool,
} }

View file

@ -30,7 +30,6 @@ use lemmy_db_schema::{
use lemmy_db_views::comment_view::CommentView; use lemmy_db_views::comment_view::CommentView;
use lemmy_utils::{ use lemmy_utils::{
utils::{remove_slurs, scrape_text_for_mentions}, utils::{remove_slurs, scrape_text_for_mentions},
ApiError,
ConnectionId, ConnectionId,
LemmyError, LemmyError,
}; };
@ -44,6 +43,7 @@ use lemmy_websocket::{
impl PerformCrud for CreateComment { impl PerformCrud for CreateComment {
type Response = CommentResponse; type Response = CommentResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -67,7 +67,7 @@ impl PerformCrud for CreateComment {
// Check if post is locked, no new comments // Check if post is locked, no new comments
if post.locked { if post.locked {
return Err(ApiError::err_plain("locked").into()); return Err(LemmyError::from_message("locked"));
} }
// If there's a parent_id, check to make sure that comment is in that post // If there's a parent_id, check to make sure that comment is in that post
@ -75,11 +75,12 @@ impl PerformCrud for CreateComment {
// Make sure the parent comment exists // Make sure the parent comment exists
let parent = blocking(context.pool(), move |conn| Comment::read(conn, parent_id)) let parent = blocking(context.pool(), move |conn| Comment::read(conn, parent_id))
.await? .await?
.map_err(|e| ApiError::err("couldnt_create_comment", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_create_comment"))?;
// Strange issue where sometimes the post ID is incorrect // Strange issue where sometimes the post ID is incorrect
if parent.post_id != post_id { if parent.post_id != post_id {
return Err(ApiError::err_plain("couldnt_create_comment").into()); return Err(LemmyError::from_message("couldnt_create_comment"));
} }
} }
@ -97,7 +98,8 @@ impl PerformCrud for CreateComment {
Comment::create(conn, &comment_form2) Comment::create(conn, &comment_form2)
}) })
.await? .await?
.map_err(|e| ApiError::err("couldnt_create_comment", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_create_comment"))?;
// Necessary to update the ap_id // Necessary to update the ap_id
let inserted_comment_id = inserted_comment.id; let inserted_comment_id = inserted_comment.id;
@ -113,7 +115,8 @@ impl PerformCrud for CreateComment {
Ok(Comment::update_ap_id(conn, inserted_comment_id, apub_id)?) Ok(Comment::update_ap_id(conn, inserted_comment_id, apub_id)?)
}) })
.await? .await?
.map_err(|e| ApiError::err("couldnt_create_comment", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_create_comment"))?;
// Scan the comment for user mentions, add those rows // Scan the comment for user mentions, add those rows
let post_id = post.id; let post_id = post.id;
@ -139,7 +142,8 @@ impl PerformCrud for CreateComment {
let like = move |conn: &'_ _| CommentLike::like(conn, &like_form); let like = move |conn: &'_ _| CommentLike::like(conn, &like_form);
blocking(context.pool(), like) blocking(context.pool(), like)
.await? .await?
.map_err(|e| ApiError::err("couldnt_like_comment", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_like_comment"))?;
let apub_comment: ApubComment = updated_comment.into(); let apub_comment: ApubComment = updated_comment.into();
CreateOrUpdateComment::send( CreateOrUpdateComment::send(
@ -174,7 +178,8 @@ impl PerformCrud for CreateComment {
Comment::update_read(conn, comment_id, true) Comment::update_read(conn, comment_id, true)
}) })
.await? .await?
.map_err(|e| ApiError::err("couldnt_update_comment", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_update_comment"))?;
} }
// If its a reply, mark the parent as read // If its a reply, mark the parent as read
if let Some(parent_id) = data.parent_id { if let Some(parent_id) = data.parent_id {
@ -187,7 +192,8 @@ impl PerformCrud for CreateComment {
Comment::update_read(conn, parent_id, true) Comment::update_read(conn, parent_id, true)
}) })
.await? .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"))?;
} }
// If the parent has PersonMentions mark them as read too // If the parent has PersonMentions mark them as read too
let person_id = local_user_view.person.id; let person_id = local_user_view.person.id;
@ -200,7 +206,8 @@ impl PerformCrud for CreateComment {
PersonMention::update_read(conn, mention.id, true) PersonMention::update_read(conn, mention.id, true)
}) })
.await? .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"))?;
} }
} }

View file

@ -18,7 +18,7 @@ use lemmy_db_schema::{
traits::Crud, traits::Crud,
}; };
use lemmy_db_views::comment_view::CommentView; use lemmy_db_views::comment_view::CommentView;
use lemmy_utils::{ApiError, ConnectionId, LemmyError}; use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::{ use lemmy_websocket::{
send::{send_comment_ws_message, send_local_notifs}, send::{send_comment_ws_message, send_local_notifs},
LemmyContext, LemmyContext,
@ -29,6 +29,7 @@ use lemmy_websocket::{
impl PerformCrud for DeleteComment { impl PerformCrud for DeleteComment {
type Response = CommentResponse; type Response = CommentResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -46,7 +47,7 @@ impl PerformCrud for DeleteComment {
// Dont delete it if its already been deleted. // Dont delete it if its already been deleted.
if orig_comment.comment.deleted == data.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"));
} }
check_community_ban( check_community_ban(
@ -58,7 +59,7 @@ impl PerformCrud for DeleteComment {
// Verify that only the creator can delete // Verify that only the creator can delete
if local_user_view.person.id != orig_comment.creator.id { 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"));
} }
// Do the delete // Do the delete
@ -67,7 +68,8 @@ impl PerformCrud for DeleteComment {
Comment::update_deleted(conn, comment_id, deleted) Comment::update_deleted(conn, comment_id, deleted)
}) })
.await? .await?
.map_err(|e| ApiError::err("couldnt_update_comment", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_update_comment"))?;
let post_id = updated_comment.post_id; let post_id = updated_comment.post_id;
let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; 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 { impl PerformCrud for RemoveComment {
type Response = CommentResponse; type Response = CommentResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -148,7 +151,8 @@ impl PerformCrud for RemoveComment {
Comment::update_removed(conn, comment_id, removed) Comment::update_removed(conn, comment_id, removed)
}) })
.await? .await?
.map_err(|e| ApiError::err("couldnt_update_comment", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_update_comment"))?;
// Mod tables // Mod tables
let form = ModRemoveCommentForm { let form = ModRemoveCommentForm {

View file

@ -13,13 +13,14 @@ use lemmy_db_schema::{
SortType, SortType,
}; };
use lemmy_db_views::comment_view::{CommentQueryBuilder, CommentView}; use lemmy_db_views::comment_view::{CommentQueryBuilder, CommentView};
use lemmy_utils::{ApiError, ConnectionId, LemmyError}; use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext; use lemmy_websocket::LemmyContext;
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl PerformCrud for GetComment { impl PerformCrud for GetComment {
type Response = CommentResponse; type Response = CommentResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -27,7 +28,8 @@ impl PerformCrud for GetComment {
) -> Result<Self::Response, LemmyError> { ) -> Result<Self::Response, LemmyError> {
let data = self; let data = self;
let local_user_view = let local_user_view =
get_local_user_view_from_jwt_opt(&data.auth, context.pool(), context.secret()).await?; get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret())
.await?;
let person_id = local_user_view.map(|u| u.person.id); let person_id = local_user_view.map(|u| u.person.id);
let id = data.id; let id = data.id;
@ -35,7 +37,8 @@ impl PerformCrud for GetComment {
CommentView::read(conn, id, person_id) CommentView::read(conn, id, person_id)
}) })
.await? .await?
.map_err(|e| ApiError::err("couldnt_find_comment", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_find_comment"))?;
Ok(Self::Response { Ok(Self::Response {
comment_view, comment_view,
@ -49,6 +52,7 @@ impl PerformCrud for GetComment {
impl PerformCrud for GetComments { impl PerformCrud for GetComments {
type Response = GetCommentsResponse; type Response = GetCommentsResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -56,7 +60,8 @@ impl PerformCrud for GetComments {
) -> Result<GetCommentsResponse, LemmyError> { ) -> Result<GetCommentsResponse, LemmyError> {
let data: &GetComments = self; let data: &GetComments = self;
let local_user_view = let local_user_view =
get_local_user_view_from_jwt_opt(&data.auth, context.pool(), context.secret()).await?; get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret())
.await?;
let show_bot_accounts = local_user_view let show_bot_accounts = local_user_view
.as_ref() .as_ref()
@ -91,7 +96,8 @@ impl PerformCrud for GetComments {
.list() .list()
}) })
.await? .await?
.map_err(|e| ApiError::err("couldnt_get_comments", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_get_comments"))?;
// Blank out deleted or removed info // Blank out deleted or removed info
for cv in comments for cv in comments

View file

@ -16,7 +16,6 @@ use lemmy_db_schema::source::comment::Comment;
use lemmy_db_views::comment_view::CommentView; use lemmy_db_views::comment_view::CommentView;
use lemmy_utils::{ use lemmy_utils::{
utils::{remove_slurs, scrape_text_for_mentions}, utils::{remove_slurs, scrape_text_for_mentions},
ApiError,
ConnectionId, ConnectionId,
LemmyError, LemmyError,
}; };
@ -32,6 +31,7 @@ use crate::PerformCrud;
impl PerformCrud for EditComment { impl PerformCrud for EditComment {
type Response = CommentResponse; type Response = CommentResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -59,7 +59,7 @@ impl PerformCrud for EditComment {
// Verify that only the creator can edit // Verify that only the creator can edit
if local_user_view.person.id != orig_comment.creator.id { 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"));
} }
// Do the update // Do the update
@ -70,7 +70,8 @@ impl PerformCrud for EditComment {
Comment::update_content(conn, comment_id, &content_slurs_removed) Comment::update_content(conn, comment_id, &content_slurs_removed)
}) })
.await? .await?
.map_err(|e| ApiError::err("couldnt_update_comment", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_update_comment"))?;
// Do the mentions / recipients // Do the mentions / recipients
let updated_comment_content = updated_comment.content.to_owned(); let updated_comment_content = updated_comment.content.to_owned();

View file

@ -34,7 +34,6 @@ use lemmy_db_views_actor::community_view::CommunityView;
use lemmy_utils::{ use lemmy_utils::{
apub::generate_actor_keypair, apub::generate_actor_keypair,
utils::{check_slurs, check_slurs_opt, is_valid_actor_name}, utils::{check_slurs, check_slurs_opt, is_valid_actor_name},
ApiError,
ConnectionId, ConnectionId,
LemmyError, LemmyError,
}; };
@ -44,6 +43,7 @@ use lemmy_websocket::LemmyContext;
impl PerformCrud for CreateCommunity { impl PerformCrud for CreateCommunity {
type Response = CommunityResponse; type Response = CommunityResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -55,7 +55,9 @@ impl PerformCrud for CreateCommunity {
let site = blocking(context.pool(), move |conn| Site::read(conn, 0)).await??; 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() { 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",
));
} }
check_slurs(&data.name, &context.settings().slur_regex())?; 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())?; check_slurs_opt(&data.description, &context.settings().slur_regex())?;
if !is_valid_actor_name(&data.name, context.settings().actor_name_max_length) { 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"));
} }
// Double check for duplicate community actor_ids // Double check for duplicate community actor_ids
@ -75,7 +77,7 @@ impl PerformCrud for CreateCommunity {
let community_actor_id_wrapped = ObjectId::<ApubCommunity>::new(community_actor_id.clone()); let community_actor_id_wrapped = ObjectId::<ApubCommunity>::new(community_actor_id.clone());
let community_dupe = community_actor_id_wrapped.dereference_local(context).await; let community_dupe = community_actor_id_wrapped.dereference_local(context).await;
if community_dupe.is_ok() { if community_dupe.is_ok() {
return Err(ApiError::err_plain("community_already_exists").into()); return Err(LemmyError::from_message("community_already_exists"));
} }
// Check to make sure the icon and banners are urls // Check to make sure the icon and banners are urls
@ -105,7 +107,8 @@ impl PerformCrud for CreateCommunity {
Community::create(conn, &community_form) Community::create(conn, &community_form)
}) })
.await? .await?
.map_err(|e| ApiError::err("community_already_exists", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("community_already_exists"))?;
// The community creator becomes a moderator // The community creator becomes a moderator
let community_moderator_form = CommunityModeratorForm { let community_moderator_form = CommunityModeratorForm {
@ -115,7 +118,9 @@ impl PerformCrud for CreateCommunity {
let join = move |conn: &'_ _| CommunityModerator::join(conn, &community_moderator_form); let join = move |conn: &'_ _| CommunityModerator::join(conn, &community_moderator_form);
if blocking(context.pool(), join).await?.is_err() { 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",
));
} }
// Follow your own community // Follow your own community
@ -127,7 +132,9 @@ impl PerformCrud for CreateCommunity {
let follow = move |conn: &'_ _| CommunityFollower::follow(conn, &community_follower_form); let follow = move |conn: &'_ _| CommunityFollower::follow(conn, &community_follower_form);
if blocking(context.pool(), follow).await?.is_err() { 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",
));
} }
let person_id = local_user_view.person.id; let person_id = local_user_view.person.id;

View file

@ -10,13 +10,14 @@ use lemmy_db_schema::{
traits::Crud, traits::Crud,
}; };
use lemmy_db_views_actor::community_moderator_view::CommunityModeratorView; 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}; use lemmy_websocket::{send::send_community_ws_message, LemmyContext, UserOperationCrud};
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl PerformCrud for DeleteCommunity { impl PerformCrud for DeleteCommunity {
type Response = CommunityResponse; type Response = CommunityResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -35,7 +36,7 @@ impl PerformCrud for DeleteCommunity {
// Make sure deleter is the top mod // Make sure deleter is the top mod
if local_user_view.person.id != community_mods[0].moderator.id { 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"));
} }
// Do the delete // Do the delete
@ -45,7 +46,8 @@ impl PerformCrud for DeleteCommunity {
Community::update_deleted(conn, community_id, deleted) Community::update_deleted(conn, community_id, deleted)
}) })
.await? .await?
.map_err(|e| ApiError::err("couldnt_update_community", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_update_community"))?;
// Send apub messages // Send apub messages
send_apub_delete( send_apub_delete(
@ -72,6 +74,7 @@ impl PerformCrud for DeleteCommunity {
impl PerformCrud for RemoveCommunity { impl PerformCrud for RemoveCommunity {
type Response = CommunityResponse; type Response = CommunityResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -91,7 +94,8 @@ impl PerformCrud for RemoveCommunity {
Community::update_removed(conn, community_id, removed) Community::update_removed(conn, community_id, removed)
}) })
.await? .await?
.map_err(|e| ApiError::err("couldnt_update_community", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_update_community"))?;
// Mod tables // Mod tables
let expires = data.expires.map(naive_from_unix); let expires = data.expires.map(naive_from_unix);

View file

@ -17,13 +17,14 @@ use lemmy_db_views_actor::{
community_moderator_view::CommunityModeratorView, community_moderator_view::CommunityModeratorView,
community_view::{CommunityQueryBuilder, CommunityView}, community_view::{CommunityQueryBuilder, CommunityView},
}; };
use lemmy_utils::{ApiError, ConnectionId, LemmyError}; use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::{messages::GetCommunityUsersOnline, LemmyContext}; use lemmy_websocket::{messages::GetCommunityUsersOnline, LemmyContext};
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl PerformCrud for GetCommunity { impl PerformCrud for GetCommunity {
type Response = GetCommunityResponse; type Response = GetCommunityResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -31,7 +32,8 @@ impl PerformCrud for GetCommunity {
) -> Result<GetCommunityResponse, LemmyError> { ) -> Result<GetCommunityResponse, LemmyError> {
let data: &GetCommunity = self; let data: &GetCommunity = self;
let local_user_view = let local_user_view =
get_local_user_view_from_jwt_opt(&data.auth, context.pool(), context.secret()).await?; get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret())
.await?;
let person_id = local_user_view.map(|u| u.person.id); let person_id = local_user_view.map(|u| u.person.id);
let community_id = match data.id { let community_id = match data.id {
@ -45,7 +47,8 @@ impl PerformCrud for GetCommunity {
ObjectId::<ApubCommunity>::new(community_actor_id) ObjectId::<ApubCommunity>::new(community_actor_id)
.dereference(context, &mut 0) .dereference(context, &mut 0)
.await .await
.map_err(|e| ApiError::err("couldnt_find_community", e))? .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_find_community"))?
.id .id
} }
}; };
@ -54,7 +57,8 @@ impl PerformCrud for GetCommunity {
CommunityView::read(conn, community_id, person_id) CommunityView::read(conn, community_id, person_id)
}) })
.await? .await?
.map_err(|e| ApiError::err("couldnt_find_community", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_find_community"))?;
// Blank out deleted or removed info for non-logged in users // Blank out deleted or removed info for non-logged in users
if person_id.is_none() && (community_view.community.deleted || community_view.community.removed) if person_id.is_none() && (community_view.community.deleted || community_view.community.removed)
@ -66,7 +70,8 @@ impl PerformCrud for GetCommunity {
CommunityModeratorView::for_community(conn, community_id) CommunityModeratorView::for_community(conn, community_id)
}) })
.await? .await?
.map_err(|e| ApiError::err("couldnt_find_community", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_find_community"))?;
let online = context let online = context
.chat_server() .chat_server()
@ -89,6 +94,7 @@ impl PerformCrud for GetCommunity {
impl PerformCrud for ListCommunities { impl PerformCrud for ListCommunities {
type Response = ListCommunitiesResponse; type Response = ListCommunitiesResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -96,7 +102,8 @@ impl PerformCrud for ListCommunities {
) -> Result<ListCommunitiesResponse, LemmyError> { ) -> Result<ListCommunitiesResponse, LemmyError> {
let data: &ListCommunities = self; let data: &ListCommunities = self;
let local_user_view = let local_user_view =
get_local_user_view_from_jwt_opt(&data.auth, context.pool(), context.secret()).await?; get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret())
.await?;
let person_id = local_user_view.to_owned().map(|l| l.person.id); let person_id = local_user_view.to_owned().map(|l| l.person.id);

View file

@ -14,13 +14,14 @@ use lemmy_db_schema::{
traits::Crud, traits::Crud,
}; };
use lemmy_db_views_actor::community_moderator_view::CommunityModeratorView; 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}; use lemmy_websocket::{send::send_community_ws_message, LemmyContext, UserOperationCrud};
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl PerformCrud for EditCommunity { impl PerformCrud for EditCommunity {
type Response = CommunityResponse; type Response = CommunityResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -41,7 +42,7 @@ impl PerformCrud for EditCommunity {
}) })
.await??; .await??;
if !mods.contains(&local_user_view.person.id) { 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"));
} }
let community_id = data.community_id; let community_id = data.community_id;
@ -70,7 +71,8 @@ impl PerformCrud for EditCommunity {
Community::update(conn, community_id, &community_form) Community::update(conn, community_id, &community_form)
}) })
.await? .await?
.map_err(|e| ApiError::err("couldnt_update_community", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_update_community"))?;
UpdateCommunity::send( UpdateCommunity::send(
updated_community.into(), updated_community.into(),

View file

@ -27,7 +27,6 @@ use lemmy_db_schema::{
use lemmy_utils::{ use lemmy_utils::{
request::fetch_site_data, request::fetch_site_data,
utils::{check_slurs, check_slurs_opt, clean_url_params, is_valid_post_title}, utils::{check_slurs, check_slurs_opt, clean_url_params, is_valid_post_title},
ApiError,
ConnectionId, ConnectionId,
LemmyError, LemmyError,
}; };
@ -40,6 +39,7 @@ use webmention::{Webmention, WebmentionError};
impl PerformCrud for CreatePost { impl PerformCrud for CreatePost {
type Response = PostResponse; type Response = PostResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -55,7 +55,7 @@ impl PerformCrud for CreatePost {
honeypot_check(&data.honeypot)?; honeypot_check(&data.honeypot)?;
if !is_valid_post_title(&data.name) { if !is_valid_post_title(&data.name) {
return Err(ApiError::err_plain("invalid_post_title").into()); return Err(LemmyError::from_message("invalid_post_title"));
} }
check_community_ban(local_user_view.person.id, data.community_id, context.pool()).await?; 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" "couldnt_create_post"
}; };
return Err(ApiError::err(err_type, e).into()); return Err(LemmyError::from(e).with_message(err_type));
} }
}; };
@ -108,7 +108,8 @@ impl PerformCrud for CreatePost {
Ok(Post::update_ap_id(conn, inserted_post_id, apub_id)?) Ok(Post::update_ap_id(conn, inserted_post_id, apub_id)?)
}) })
.await? .await?
.map_err(|e| ApiError::err("couldnt_create_post", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_create_post"))?;
// They like their own post by default // They like their own post by default
let person_id = local_user_view.person.id; 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); let like = move |conn: &'_ _| PostLike::like(conn, &like_form);
if blocking(context.pool(), like).await?.is_err() { 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"));
} }
// Mark the post as read // Mark the post as read

View file

@ -17,13 +17,14 @@ use lemmy_db_schema::{
}, },
traits::Crud, traits::Crud,
}; };
use lemmy_utils::{ApiError, ConnectionId, LemmyError}; use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::{send::send_post_ws_message, LemmyContext, UserOperationCrud}; use lemmy_websocket::{send::send_post_ws_message, LemmyContext, UserOperationCrud};
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl PerformCrud for DeletePost { impl PerformCrud for DeletePost {
type Response = PostResponse; type Response = PostResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -38,7 +39,7 @@ impl PerformCrud for DeletePost {
// Dont delete it if its already been deleted. // Dont delete it if its already been deleted.
if orig_post.deleted == data.deleted { if orig_post.deleted == data.deleted {
return Err(ApiError::err_plain("couldnt_update_post").into()); return Err(LemmyError::from_message("couldnt_update_post"));
} }
check_community_ban( check_community_ban(
@ -51,7 +52,7 @@ impl PerformCrud for DeletePost {
// Verify that only the creator can delete // Verify that only the creator can delete
if !Post::is_post_creator(local_user_view.person.id, orig_post.creator_id) { 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"));
} }
// Update the post // Update the post
@ -91,6 +92,7 @@ impl PerformCrud for DeletePost {
impl PerformCrud for RemovePost { impl PerformCrud for RemovePost {
type Response = PostResponse; type Response = PostResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,

View file

@ -20,13 +20,14 @@ use lemmy_db_views_actor::{
community_moderator_view::CommunityModeratorView, community_moderator_view::CommunityModeratorView,
community_view::CommunityView, community_view::CommunityView,
}; };
use lemmy_utils::{ApiError, ConnectionId, LemmyError}; use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::{messages::GetPostUsersOnline, LemmyContext}; use lemmy_websocket::{messages::GetPostUsersOnline, LemmyContext};
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl PerformCrud for GetPost { impl PerformCrud for GetPost {
type Response = GetPostResponse; type Response = GetPostResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -34,7 +35,8 @@ impl PerformCrud for GetPost {
) -> Result<GetPostResponse, LemmyError> { ) -> Result<GetPostResponse, LemmyError> {
let data: &GetPost = self; let data: &GetPost = self;
let local_user_view = let local_user_view =
get_local_user_view_from_jwt_opt(&data.auth, context.pool(), context.secret()).await?; get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret())
.await?;
let show_bot_accounts = local_user_view let show_bot_accounts = local_user_view
.as_ref() .as_ref()
@ -46,7 +48,8 @@ impl PerformCrud for GetPost {
PostView::read(conn, id, person_id) PostView::read(conn, id, person_id)
}) })
.await? .await?
.map_err(|e| ApiError::err("couldnt_find_post", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_find_post"))?;
// Mark the post as read // Mark the post as read
if let Some(person_id) = person_id { if let Some(person_id) = person_id {
@ -70,7 +73,8 @@ impl PerformCrud for GetPost {
CommunityView::read(conn, community_id, person_id) CommunityView::read(conn, community_id, person_id)
}) })
.await? .await?
.map_err(|e| ApiError::err("couldnt_find_community", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_find_community"))?;
// Blank out deleted or removed info for non-logged in users // Blank out deleted or removed info for non-logged in users
if person_id.is_none() { if person_id.is_none() {
@ -115,6 +119,7 @@ impl PerformCrud for GetPost {
impl PerformCrud for GetPosts { impl PerformCrud for GetPosts {
type Response = GetPostsResponse; type Response = GetPostsResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -122,7 +127,8 @@ impl PerformCrud for GetPosts {
) -> Result<GetPostsResponse, LemmyError> { ) -> Result<GetPostsResponse, LemmyError> {
let data: &GetPosts = self; let data: &GetPosts = self;
let local_user_view = let local_user_view =
get_local_user_view_from_jwt_opt(&data.auth, context.pool(), context.secret()).await?; get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret())
.await?;
let person_id = local_user_view.to_owned().map(|l| l.person.id); let person_id = local_user_view.to_owned().map(|l| l.person.id);
@ -165,7 +171,8 @@ impl PerformCrud for GetPosts {
.list() .list()
}) })
.await? .await?
.map_err(|e| ApiError::err("couldnt_get_posts", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_get_posts"))?;
// Blank out deleted or removed info for non-logged in users // Blank out deleted or removed info for non-logged in users
if person_id.is_none() { if person_id.is_none() {

View file

@ -19,7 +19,6 @@ use lemmy_db_schema::{
use lemmy_utils::{ use lemmy_utils::{
request::fetch_site_data, request::fetch_site_data,
utils::{check_slurs_opt, clean_url_params, is_valid_post_title}, utils::{check_slurs_opt, clean_url_params, is_valid_post_title},
ApiError,
ConnectionId, ConnectionId,
LemmyError, LemmyError,
}; };
@ -31,6 +30,7 @@ use crate::PerformCrud;
impl PerformCrud for EditPost { impl PerformCrud for EditPost {
type Response = PostResponse; type Response = PostResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -46,7 +46,7 @@ impl PerformCrud for EditPost {
if let Some(name) = &data.name { if let Some(name) = &data.name {
if !is_valid_post_title(name) { if !is_valid_post_title(name) {
return Err(ApiError::err_plain("invalid_post_title").into()); return Err(LemmyError::from_message("invalid_post_title"));
} }
} }
@ -63,7 +63,7 @@ impl PerformCrud for EditPost {
// Verify that only the creator can edit // Verify that only the creator can edit
if !Post::is_post_creator(local_user_view.person.id, orig_post.creator_id) { 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"));
} }
// Fetch post links and Pictrs cached image // Fetch post links and Pictrs cached image
@ -103,7 +103,7 @@ impl PerformCrud for EditPost {
"couldnt_update_post" "couldnt_update_post"
}; };
return Err(ApiError::err(err_type, e).into()); return Err(LemmyError::from(e).with_message(err_type));
} }
}; };

View file

@ -19,7 +19,7 @@ use lemmy_db_schema::{
traits::Crud, traits::Crud,
}; };
use lemmy_db_views::local_user_view::LocalUserView; 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::{ use lemmy_websocket::{
send::{send_email_to_user, send_pm_ws_message}, send::{send_email_to_user, send_pm_ws_message},
LemmyContext, LemmyContext,
@ -30,6 +30,7 @@ use lemmy_websocket::{
impl PerformCrud for CreatePrivateMessage { impl PerformCrud for CreatePrivateMessage {
type Response = PrivateMessageResponse; type Response = PrivateMessageResponse;
#[tracing::instrument(skip(self, context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -58,7 +59,7 @@ impl PerformCrud for CreatePrivateMessage {
{ {
Ok(private_message) => private_message, Ok(private_message) => private_message,
Err(e) => { Err(e) => {
return Err(ApiError::err("couldnt_create_private_message", e).into()); return Err(LemmyError::from(e).with_message("couldnt_create_private_message"));
} }
}; };
@ -80,7 +81,8 @@ impl PerformCrud for CreatePrivateMessage {
}, },
) )
.await? .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"))?;
CreateOrUpdatePrivateMessage::send( CreateOrUpdatePrivateMessage::send(
updated_private_message.into(), updated_private_message.into(),

View file

@ -13,13 +13,14 @@ use lemmy_db_schema::{
source::private_message::PrivateMessage, source::private_message::PrivateMessage,
traits::{Crud, DeleteableOrRemoveable}, traits::{Crud, DeleteableOrRemoveable},
}; };
use lemmy_utils::{ApiError, ConnectionId, LemmyError}; use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperationCrud}; use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperationCrud};
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl PerformCrud for DeletePrivateMessage { impl PerformCrud for DeletePrivateMessage {
type Response = PrivateMessageResponse; type Response = PrivateMessageResponse;
#[tracing::instrument(skip(self, context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -36,7 +37,7 @@ impl PerformCrud for DeletePrivateMessage {
}) })
.await??; .await??;
if local_user_view.person.id != orig_private_message.creator_id { 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"));
} }
// Doing the update // Doing the update
@ -46,7 +47,8 @@ impl PerformCrud for DeletePrivateMessage {
PrivateMessage::update_deleted(conn, private_message_id, deleted) PrivateMessage::update_deleted(conn, private_message_id, deleted)
}) })
.await? .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"))?;
// Send the apub update // Send the apub update
if data.deleted { if data.deleted {

View file

@ -14,6 +14,7 @@ use lemmy_websocket::LemmyContext;
impl PerformCrud for GetPrivateMessages { impl PerformCrud for GetPrivateMessages {
type Response = PrivateMessagesResponse; type Response = PrivateMessagesResponse;
#[tracing::instrument(skip(self, context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -21,7 +22,7 @@ impl PerformCrud for GetPrivateMessages {
) -> Result<PrivateMessagesResponse, LemmyError> { ) -> Result<PrivateMessagesResponse, LemmyError> {
let data: &GetPrivateMessages = self; let data: &GetPrivateMessages = self;
let local_user_view = let local_user_view =
get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?; get_local_user_view_from_jwt(data.auth.as_ref(), context.pool(), context.secret()).await?;
let person_id = local_user_view.person.id; let person_id = local_user_view.person.id;
let page = data.page; let page = data.page;

View file

@ -10,13 +10,14 @@ use lemmy_apub::protocol::activities::{
CreateOrUpdateType, CreateOrUpdateType,
}; };
use lemmy_db_schema::{source::private_message::PrivateMessage, traits::Crud}; 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}; use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperationCrud};
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl PerformCrud for EditPrivateMessage { impl PerformCrud for EditPrivateMessage {
type Response = PrivateMessageResponse; type Response = PrivateMessageResponse;
#[tracing::instrument(skip(self, context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -33,7 +34,7 @@ impl PerformCrud for EditPrivateMessage {
}) })
.await??; .await??;
if local_user_view.person.id != orig_private_message.creator_id { 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"));
} }
// Doing the update // Doing the update
@ -43,7 +44,8 @@ impl PerformCrud for EditPrivateMessage {
PrivateMessage::update_content(conn, private_message_id, &content_slurs_removed) PrivateMessage::update_content(conn, private_message_id, &content_slurs_removed)
}) })
.await? .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"))?;
// Send the apub update // Send the apub update
CreateOrUpdatePrivateMessage::send( CreateOrUpdatePrivateMessage::send(

View file

@ -16,7 +16,6 @@ use lemmy_db_schema::{
use lemmy_db_views::site_view::SiteView; use lemmy_db_views::site_view::SiteView;
use lemmy_utils::{ use lemmy_utils::{
utils::{check_slurs, check_slurs_opt}, utils::{check_slurs, check_slurs_opt},
ApiError,
ConnectionId, ConnectionId,
LemmyError, LemmyError,
}; };
@ -26,6 +25,7 @@ use lemmy_websocket::LemmyContext;
impl PerformCrud for CreateSite { impl PerformCrud for CreateSite {
type Response = SiteResponse; type Response = SiteResponse;
#[tracing::instrument(skip(context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -35,7 +35,7 @@ impl PerformCrud for CreateSite {
let read_site = Site::read_simple; let read_site = Site::read_simple;
if blocking(context.pool(), read_site).await?.is_ok() { 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"));
}; };
let local_user_view = let local_user_view =
@ -72,7 +72,7 @@ impl PerformCrud for CreateSite {
let create_site = move |conn: &'_ _| Site::create(conn, &site_form); let create_site = move |conn: &'_ _| Site::create(conn, &site_form);
if blocking(context.pool(), create_site).await?.is_err() { 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"));
} }
let site_view = blocking(context.pool(), SiteView::read).await??; let site_view = blocking(context.pool(), SiteView::read).await??;

View file

@ -15,7 +15,7 @@ use lemmy_db_views_actor::{
person_block_view::PersonBlockView, person_block_view::PersonBlockView,
person_view::PersonViewSafe, person_view::PersonViewSafe,
}; };
use lemmy_utils::{version, ApiError, ConnectionId, LemmyError}; use lemmy_utils::{version, ConnectionId, LemmyError};
use lemmy_websocket::{messages::GetUsersOnline, LemmyContext}; use lemmy_websocket::{messages::GetUsersOnline, LemmyContext};
use tracing::info; use tracing::info;
@ -23,6 +23,7 @@ use tracing::info;
impl PerformCrud for GetSite { impl PerformCrud for GetSite {
type Response = GetSiteResponse; type Response = GetSiteResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -37,9 +38,9 @@ impl PerformCrud for GetSite {
if let Some(setup) = context.settings().setup.as_ref() { if let Some(setup) = context.settings().setup.as_ref() {
let register = Register { let register = Register {
username: setup.admin_username.to_owned(), username: setup.admin_username.to_owned(),
email: setup.admin_email.to_owned(), email: setup.admin_email.clone().map(|s| s.into()),
password: setup.admin_password.to_owned(), password: setup.admin_password.clone().into(),
password_verify: setup.admin_password.to_owned(), password_verify: setup.admin_password.clone().into(),
show_nsfw: true, show_nsfw: true,
captcha_uuid: None, captcha_uuid: None,
captcha_answer: None, captcha_answer: None,
@ -91,36 +92,43 @@ impl PerformCrud for GetSite {
.unwrap_or(1); .unwrap_or(1);
// Build the local user // Build the local user
let my_user = if let Some(local_user_view) = let my_user = if let Some(local_user_view) = get_local_user_settings_view_from_jwt_opt(
get_local_user_settings_view_from_jwt_opt(&data.auth, context.pool(), context.secret()) data.auth.as_ref(),
.await? context.pool(),
context.secret(),
)
.await?
{ {
let person_id = local_user_view.person.id; let person_id = local_user_view.person.id;
let follows = blocking(context.pool(), move |conn| { let follows = blocking(context.pool(), move |conn| {
CommunityFollowerView::for_person(conn, person_id) CommunityFollowerView::for_person(conn, person_id)
}) })
.await? .await?
.map_err(|e| ApiError::err("system_err_login", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("system_err_login"))?;
let person_id = local_user_view.person.id; let person_id = local_user_view.person.id;
let community_blocks = blocking(context.pool(), move |conn| { let community_blocks = blocking(context.pool(), move |conn| {
CommunityBlockView::for_person(conn, person_id) CommunityBlockView::for_person(conn, person_id)
}) })
.await? .await?
.map_err(|e| ApiError::err("system_err_login", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("system_err_login"))?;
let person_id = local_user_view.person.id; let person_id = local_user_view.person.id;
let person_blocks = blocking(context.pool(), move |conn| { let person_blocks = blocking(context.pool(), move |conn| {
PersonBlockView::for_person(conn, person_id) PersonBlockView::for_person(conn, person_id)
}) })
.await? .await?
.map_err(|e| ApiError::err("system_err_login", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("system_err_login"))?;
let moderates = blocking(context.pool(), move |conn| { let moderates = blocking(context.pool(), move |conn| {
CommunityModeratorView::for_person(conn, person_id) CommunityModeratorView::for_person(conn, person_id)
}) })
.await? .await?
.map_err(|e| ApiError::err("system_err_login", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("system_err_login"))?;
Some(MyUserInfo { Some(MyUserInfo {
local_user_view, local_user_view,

View file

@ -15,12 +15,14 @@ use lemmy_db_schema::{
traits::Crud, traits::Crud,
}; };
use lemmy_db_views::site_view::SiteView; 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}; use lemmy_websocket::{messages::SendAllMessage, LemmyContext, UserOperationCrud};
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl PerformCrud for EditSite { impl PerformCrud for EditSite {
type Response = SiteResponse; type Response = SiteResponse;
#[tracing::instrument(skip(context, websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -64,7 +66,8 @@ impl PerformCrud for EditSite {
let update_site = move |conn: &'_ _| Site::update(conn, 1, &site_form); let update_site = move |conn: &'_ _| Site::update(conn, 1, &site_form);
blocking(context.pool(), update_site) blocking(context.pool(), update_site)
.await? .await?
.map_err(|e| ApiError::err("couldnt_update_site", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_update_site"))?;
let site_view = blocking(context.pool(), SiteView::read).await??; let site_view = blocking(context.pool(), SiteView::read).await??;

View file

@ -32,7 +32,6 @@ use lemmy_utils::{
apub::generate_actor_keypair, apub::generate_actor_keypair,
claims::Claims, claims::Claims,
utils::{check_slurs, is_valid_actor_name}, utils::{check_slurs, is_valid_actor_name},
ApiError,
ConnectionId, ConnectionId,
LemmyError, LemmyError,
}; };
@ -42,6 +41,7 @@ use lemmy_websocket::{messages::CheckCaptcha, LemmyContext};
impl PerformCrud for Register { impl PerformCrud for Register {
type Response = LoginResponse; type Response = LoginResponse;
#[tracing::instrument(skip(self, context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -52,7 +52,7 @@ impl PerformCrud for Register {
// Make sure site has open registration // Make sure site has open registration
if let Ok(site) = blocking(context.pool(), Site::read_simple).await? { if let Ok(site) = blocking(context.pool(), Site::read_simple).await? {
if !site.open_registration { if !site.open_registration {
return Err(ApiError::err_plain("registration_closed").into()); return Err(LemmyError::from_message("registration_closed"));
} }
} }
@ -61,7 +61,7 @@ impl PerformCrud for Register {
// Make sure passwords match // Make sure passwords match
if data.password != data.password_verify { if data.password != data.password_verify {
return Err(ApiError::err_plain("passwords_dont_match").into()); return Err(LemmyError::from_message("passwords_dont_match"));
} }
// Check if there are admins. False if admins exist // Check if there are admins. False if admins exist
@ -86,7 +86,7 @@ impl PerformCrud for Register {
}) })
.await?; .await?;
if !check { if !check {
return Err(ApiError::err_plain("captcha_incorrect").into()); return Err(LemmyError::from_message("captcha_incorrect"));
} }
} }
@ -94,7 +94,7 @@ impl PerformCrud for Register {
let actor_keypair = generate_actor_keypair()?; let actor_keypair = generate_actor_keypair()?;
if !is_valid_actor_name(&data.username, context.settings().actor_name_max_length) { 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"));
} }
let actor_id = generate_local_apub_endpoint( let actor_id = generate_local_apub_endpoint(
EndpointType::Person, EndpointType::Person,
@ -121,14 +121,15 @@ impl PerformCrud for Register {
Person::create(conn, &person_form) Person::create(conn, &person_form)
}) })
.await? .await?
.map_err(|e| ApiError::err("user_already_exists", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("user_already_exists"))?;
// Create the local user // Create the local user
// TODO some of these could probably use the DB defaults // TODO some of these could probably use the DB defaults
let local_user_form = LocalUserForm { let local_user_form = LocalUserForm {
person_id: inserted_person.id, person_id: inserted_person.id,
email: Some(data.email.to_owned()), email: Some(data.email.as_deref().map(|s| s.to_owned())),
password_encrypted: data.password.to_owned(), password_encrypted: data.password.to_string(),
show_nsfw: Some(data.show_nsfw), show_nsfw: Some(data.show_nsfw),
show_bot_accounts: Some(true), show_bot_accounts: Some(true),
theme: Some("browser".into()), theme: Some("browser".into()),
@ -163,7 +164,7 @@ impl PerformCrud for Register {
}) })
.await??; .await??;
return Err(ApiError::err(err_type, e).into()); return Err(LemmyError::from(e).with_message(err_type));
} }
}; };
@ -213,7 +214,8 @@ impl PerformCrud for Register {
let follow = move |conn: &'_ _| CommunityFollower::follow(conn, &community_follower_form); let follow = move |conn: &'_ _| CommunityFollower::follow(conn, &community_follower_form);
blocking(context.pool(), follow) blocking(context.pool(), follow)
.await? .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"))?;
// If its an admin, add them as a mod and follower to main // If its an admin, add them as a mod and follower to main
if no_admins { if no_admins {
@ -225,7 +227,8 @@ impl PerformCrud for Register {
let join = move |conn: &'_ _| CommunityModerator::join(conn, &community_moderator_form); let join = move |conn: &'_ _| CommunityModerator::join(conn, &community_moderator_form);
blocking(context.pool(), join) blocking(context.pool(), join)
.await? .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"))?;
} }
// Return the jwt // Return the jwt
@ -234,7 +237,8 @@ impl PerformCrud for Register {
inserted_local_user.id.0, inserted_local_user.id.0,
&context.secret().jwt_secret, &context.secret().jwt_secret,
&context.settings().hostname, &context.settings().hostname,
)?, )?
.into(),
}) })
} }
} }

View file

@ -3,13 +3,14 @@ use actix_web::web::Data;
use bcrypt::verify; use bcrypt::verify;
use lemmy_api_common::{blocking, get_local_user_view_from_jwt, person::*}; 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_db_schema::source::{comment::Comment, person::Person, post::Post};
use lemmy_utils::{ApiError, ConnectionId, LemmyError}; use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext; use lemmy_websocket::LemmyContext;
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl PerformCrud for DeleteAccount { impl PerformCrud for DeleteAccount {
type Response = LoginResponse; type Response = LoginResponse;
#[tracing::instrument(skip(self, context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -17,7 +18,7 @@ impl PerformCrud for DeleteAccount {
) -> Result<LoginResponse, LemmyError> { ) -> Result<LoginResponse, LemmyError> {
let data: &DeleteAccount = self; let data: &DeleteAccount = self;
let local_user_view = let local_user_view =
get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?; get_local_user_view_from_jwt(data.auth.as_ref(), context.pool(), context.secret()).await?;
// Verify the password // Verify the password
let valid: bool = verify( let valid: bool = verify(
@ -26,7 +27,7 @@ impl PerformCrud for DeleteAccount {
) )
.unwrap_or(false); .unwrap_or(false);
if !valid { if !valid {
return Err(ApiError::err_plain("password_incorrect").into()); return Err(LemmyError::from_message("password_incorrect"));
} }
// Comments // Comments
@ -34,13 +35,15 @@ impl PerformCrud for DeleteAccount {
let permadelete = move |conn: &'_ _| Comment::permadelete_for_creator(conn, person_id); let permadelete = move |conn: &'_ _| Comment::permadelete_for_creator(conn, person_id);
blocking(context.pool(), permadelete) blocking(context.pool(), permadelete)
.await? .await?
.map_err(|e| ApiError::err("couldnt_update_comment", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_update_comment"))?;
// Posts // Posts
let permadelete = move |conn: &'_ _| Post::permadelete_for_creator(conn, person_id); let permadelete = move |conn: &'_ _| Post::permadelete_for_creator(conn, person_id);
blocking(context.pool(), permadelete) blocking(context.pool(), permadelete)
.await? .await?
.map_err(|e| ApiError::err("couldnt_update_post", e))?; .map_err(LemmyError::from)
.map_err(|e| e.with_message("couldnt_update_post"))?;
blocking(context.pool(), move |conn| { blocking(context.pool(), move |conn| {
Person::delete_account(conn, person_id) Person::delete_account(conn, person_id)
@ -48,7 +51,7 @@ impl PerformCrud for DeleteAccount {
.await??; .await??;
Ok(LoginResponse { Ok(LoginResponse {
jwt: data.auth.to_owned(), jwt: data.auth.clone(),
}) })
} }
} }

View file

@ -13,13 +13,14 @@ use lemmy_db_views_actor::{
community_moderator_view::CommunityModeratorView, community_moderator_view::CommunityModeratorView,
person_view::PersonViewSafe, person_view::PersonViewSafe,
}; };
use lemmy_utils::{ApiError, ConnectionId, LemmyError}; use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext; use lemmy_websocket::LemmyContext;
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl PerformCrud for GetPersonDetails { impl PerformCrud for GetPersonDetails {
type Response = GetPersonDetailsResponse; type Response = GetPersonDetailsResponse;
#[tracing::instrument(skip(self, context, _websocket_id))]
async fn perform( async fn perform(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -27,7 +28,8 @@ impl PerformCrud for GetPersonDetails {
) -> Result<GetPersonDetailsResponse, LemmyError> { ) -> Result<GetPersonDetailsResponse, LemmyError> {
let data: &GetPersonDetails = self; let data: &GetPersonDetails = self;
let local_user_view = let local_user_view =
get_local_user_view_from_jwt_opt(&data.auth, context.pool(), context.secret()).await?; get_local_user_view_from_jwt_opt(data.auth.as_ref(), context.pool(), context.secret())
.await?;
let show_nsfw = local_user_view.as_ref().map(|t| t.local_user.show_nsfw); let show_nsfw = local_user_view.as_ref().map(|t| t.local_user.show_nsfw);
let show_bot_accounts = local_user_view let show_bot_accounts = local_user_view
@ -53,7 +55,8 @@ impl PerformCrud for GetPersonDetails {
.dereference(context, &mut 0) .dereference(context, &mut 0)
.await; .await;
person 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"))?
.id .id
} }
}; };

View file

@ -28,6 +28,7 @@ use lemmy_utils::LemmyError;
use lemmy_websocket::{send::send_comment_ws_message, LemmyContext, UserOperationCrud}; use lemmy_websocket::{send::send_comment_ws_message, LemmyContext, UserOperationCrud};
impl CreateOrUpdateComment { impl CreateOrUpdateComment {
#[tracing::instrument(skip(comment, actor, kind, context))]
pub async fn send( pub async fn send(
comment: ApubComment, comment: ApubComment,
actor: &ApubPerson, actor: &ApubPerson,
@ -83,6 +84,7 @@ impl CreateOrUpdateComment {
impl ActivityHandler for CreateOrUpdateComment { impl ActivityHandler for CreateOrUpdateComment {
type DataType = LemmyContext; type DataType = LemmyContext;
#[tracing::instrument(skip_all)]
async fn verify( async fn verify(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -102,6 +104,7 @@ impl ActivityHandler for CreateOrUpdateComment {
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn receive( async fn receive(
self, self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -131,6 +134,7 @@ impl ActivityHandler for CreateOrUpdateComment {
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl GetCommunity for CreateOrUpdateComment { impl GetCommunity for CreateOrUpdateComment {
#[tracing::instrument(skip_all)]
async fn get_community( async fn get_community(
&self, &self,
context: &LemmyContext, context: &LemmyContext,

View file

@ -11,6 +11,7 @@ use lemmy_websocket::{send::send_local_notifs, LemmyContext};
pub mod create_or_update; pub mod create_or_update;
#[tracing::instrument(skip_all)]
async fn get_notif_recipients( async fn get_notif_recipients(
actor: &ObjectId<ApubPerson>, actor: &ObjectId<ApubPerson>,
comment: &Comment, comment: &Comment,

View file

@ -32,6 +32,7 @@ use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext; use lemmy_websocket::LemmyContext;
impl AddMod { impl AddMod {
#[tracing::instrument(skip_all)]
pub async fn send( pub async fn send(
community: &ApubCommunity, community: &ApubCommunity,
added_mod: &ApubPerson, added_mod: &ApubPerson,
@ -63,6 +64,7 @@ impl AddMod {
impl ActivityHandler for AddMod { impl ActivityHandler for AddMod {
type DataType = LemmyContext; type DataType = LemmyContext;
#[tracing::instrument(skip_all)]
async fn verify( async fn verify(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -77,6 +79,7 @@ impl ActivityHandler for AddMod {
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn receive( async fn receive(
self, self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -109,6 +112,7 @@ impl ActivityHandler for AddMod {
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl GetCommunity for AddMod { impl GetCommunity for AddMod {
#[tracing::instrument(skip_all)]
async fn get_community( async fn get_community(
&self, &self,
context: &LemmyContext, context: &LemmyContext,

View file

@ -44,6 +44,7 @@ impl AnnounceActivity {
}) })
} }
#[tracing::instrument(skip_all)]
pub async fn send( pub async fn send(
object: AnnouncableActivities, object: AnnouncableActivities,
community: &ApubCommunity, community: &ApubCommunity,
@ -85,6 +86,8 @@ impl AnnounceActivity {
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl ActivityHandler for AnnounceActivity { impl ActivityHandler for AnnounceActivity {
type DataType = LemmyContext; type DataType = LemmyContext;
#[tracing::instrument(skip_all)]
async fn verify( async fn verify(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -96,6 +99,7 @@ impl ActivityHandler for AnnounceActivity {
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn receive( async fn receive(
self, self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,

View file

@ -52,6 +52,7 @@ impl BlockUserFromCommunity {
}) })
} }
#[tracing::instrument(skip_all)]
pub async fn send( pub async fn send(
community: &ApubCommunity, community: &ApubCommunity,
target: &ApubPerson, target: &ApubPerson,
@ -70,6 +71,8 @@ impl BlockUserFromCommunity {
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl ActivityHandler for BlockUserFromCommunity { impl ActivityHandler for BlockUserFromCommunity {
type DataType = LemmyContext; type DataType = LemmyContext;
#[tracing::instrument(skip_all)]
async fn verify( async fn verify(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -83,6 +86,7 @@ impl ActivityHandler for BlockUserFromCommunity {
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn receive( async fn receive(
self, self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -119,6 +123,7 @@ impl ActivityHandler for BlockUserFromCommunity {
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl GetCommunity for BlockUserFromCommunity { impl GetCommunity for BlockUserFromCommunity {
#[tracing::instrument(skip_all)]
async fn get_community( async fn get_community(
&self, &self,
context: &LemmyContext, context: &LemmyContext,

View file

@ -17,6 +17,7 @@ pub mod report;
pub mod undo_block_user; pub mod undo_block_user;
pub mod update; pub mod update;
#[tracing::instrument(skip_all)]
pub(crate) async fn send_activity_in_community<T: ActorType>( pub(crate) async fn send_activity_in_community<T: ActorType>(
activity: AnnouncableActivities, activity: AnnouncableActivities,
activity_id: &Url, activity_id: &Url,
@ -35,6 +36,7 @@ pub(crate) async fn send_activity_in_community<T: ActorType>(
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn get_community_from_moderators_url( async fn get_community_from_moderators_url(
moderators: &Url, moderators: &Url,
context: &LemmyContext, context: &LemmyContext,

View file

@ -32,6 +32,7 @@ use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext; use lemmy_websocket::LemmyContext;
impl RemoveMod { impl RemoveMod {
#[tracing::instrument(skip_all)]
pub async fn send( pub async fn send(
community: &ApubCommunity, community: &ApubCommunity,
removed_mod: &ApubPerson, removed_mod: &ApubPerson,
@ -62,6 +63,8 @@ impl RemoveMod {
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl ActivityHandler for RemoveMod { impl ActivityHandler for RemoveMod {
type DataType = LemmyContext; type DataType = LemmyContext;
#[tracing::instrument(skip_all)]
async fn verify( async fn verify(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -76,6 +79,7 @@ impl ActivityHandler for RemoveMod {
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn receive( async fn receive(
self, self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -99,6 +103,7 @@ impl ActivityHandler for RemoveMod {
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl GetCommunity for RemoveMod { impl GetCommunity for RemoveMod {
#[tracing::instrument(skip_all)]
async fn get_community( async fn get_community(
&self, &self,
context: &LemmyContext, context: &LemmyContext,

View file

@ -28,6 +28,7 @@ use lemmy_utils::LemmyError;
use lemmy_websocket::{messages::SendModRoomMessage, LemmyContext, UserOperation}; use lemmy_websocket::{messages::SendModRoomMessage, LemmyContext, UserOperation};
impl Report { impl Report {
#[tracing::instrument(skip_all)]
pub async fn send( pub async fn send(
object_id: ObjectId<PostOrComment>, object_id: ObjectId<PostOrComment>,
actor: &ApubPerson, actor: &ApubPerson,
@ -65,6 +66,8 @@ impl Report {
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl ActivityHandler for Report { impl ActivityHandler for Report {
type DataType = LemmyContext; type DataType = LemmyContext;
#[tracing::instrument(skip_all)]
async fn verify( async fn verify(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -76,6 +79,7 @@ impl ActivityHandler for Report {
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn receive( async fn receive(
self, self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,

View file

@ -29,6 +29,7 @@ use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext; use lemmy_websocket::LemmyContext;
impl UndoBlockUserFromCommunity { impl UndoBlockUserFromCommunity {
#[tracing::instrument(skip_all)]
pub async fn send( pub async fn send(
community: &ApubCommunity, community: &ApubCommunity,
target: &ApubPerson, target: &ApubPerson,
@ -60,6 +61,8 @@ impl UndoBlockUserFromCommunity {
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl ActivityHandler for UndoBlockUserFromCommunity { impl ActivityHandler for UndoBlockUserFromCommunity {
type DataType = LemmyContext; type DataType = LemmyContext;
#[tracing::instrument(skip_all)]
async fn verify( async fn verify(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -74,6 +77,7 @@ impl ActivityHandler for UndoBlockUserFromCommunity {
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn receive( async fn receive(
self, self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -102,6 +106,7 @@ impl ActivityHandler for UndoBlockUserFromCommunity {
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl GetCommunity for UndoBlockUserFromCommunity { impl GetCommunity for UndoBlockUserFromCommunity {
#[tracing::instrument(skip_all)]
async fn get_community( async fn get_community(
&self, &self,
context: &LemmyContext, context: &LemmyContext,

View file

@ -26,6 +26,7 @@ use lemmy_utils::LemmyError;
use lemmy_websocket::{send::send_community_ws_message, LemmyContext, UserOperationCrud}; use lemmy_websocket::{send::send_community_ws_message, LemmyContext, UserOperationCrud};
impl UpdateCommunity { impl UpdateCommunity {
#[tracing::instrument(skip_all)]
pub async fn send( pub async fn send(
community: ApubCommunity, community: ApubCommunity,
actor: &ApubPerson, actor: &ApubPerson,
@ -53,6 +54,8 @@ impl UpdateCommunity {
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl ActivityHandler for UpdateCommunity { impl ActivityHandler for UpdateCommunity {
type DataType = LemmyContext; type DataType = LemmyContext;
#[tracing::instrument(skip_all)]
async fn verify( async fn verify(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -73,6 +76,7 @@ impl ActivityHandler for UpdateCommunity {
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn receive( async fn receive(
self, self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -110,6 +114,7 @@ impl ActivityHandler for UpdateCommunity {
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl GetCommunity for UpdateCommunity { impl GetCommunity for UpdateCommunity {
#[tracing::instrument(skip_all)]
async fn get_community( async fn get_community(
&self, &self,
context: &LemmyContext, context: &LemmyContext,

View file

@ -11,7 +11,6 @@ use crate::{
protocol::activities::deletion::delete::Delete, protocol::activities::deletion::delete::Delete,
}; };
use activitystreams_kinds::{activity::DeleteType, public}; use activitystreams_kinds::{activity::DeleteType, public};
use anyhow::anyhow;
use lemmy_api_common::blocking; use lemmy_api_common::blocking;
use lemmy_apub_lib::{ use lemmy_apub_lib::{
data::Data, data::Data,
@ -45,6 +44,8 @@ use url::Url;
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl ActivityHandler for Delete { impl ActivityHandler for Delete {
type DataType = LemmyContext; type DataType = LemmyContext;
#[tracing::instrument(skip_all)]
async fn verify( async fn verify(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -65,6 +66,7 @@ impl ActivityHandler for Delete {
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn receive( async fn receive(
self, self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -112,6 +114,8 @@ impl Delete {
unparsed: Default::default(), unparsed: Default::default(),
}) })
} }
#[tracing::instrument(skip_all)]
pub(in crate::activities::deletion) async fn send( pub(in crate::activities::deletion) async fn send(
actor: &ApubPerson, actor: &ApubPerson,
community: &ApubCommunity, community: &ApubCommunity,
@ -127,6 +131,7 @@ impl Delete {
} }
} }
#[tracing::instrument(skip_all)]
pub(in crate::activities) async fn receive_remove_action( pub(in crate::activities) async fn receive_remove_action(
actor: &ObjectId<ApubPerson>, actor: &ObjectId<ApubPerson>,
object: &Url, object: &Url,
@ -139,7 +144,9 @@ pub(in crate::activities) async fn receive_remove_action(
match DeletableObjects::read_from_db(object, context).await? { match DeletableObjects::read_from_db(object, context).await? {
DeletableObjects::Community(community) => { DeletableObjects::Community(community) => {
if community.local { if community.local {
return Err(anyhow!("Only local admin can remove community").into()); return Err(LemmyError::from_message(
"Only local admin can remove community",
));
} }
let form = ModRemoveCommunityForm { let form = ModRemoveCommunityForm {
mod_person_id: actor.id, mod_person_id: actor.id,
@ -201,6 +208,7 @@ pub(in crate::activities) async fn receive_remove_action(
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl GetCommunity for Delete { impl GetCommunity for Delete {
#[tracing::instrument(skip_all)]
async fn get_community( async fn get_community(
&self, &self,
context: &LemmyContext, context: &LemmyContext,

View file

@ -20,6 +20,7 @@ use url::Url;
pub mod delete; pub mod delete;
pub mod undo_delete; pub mod undo_delete;
#[tracing::instrument(skip_all)]
pub async fn send_apub_delete( pub async fn send_apub_delete(
actor: &ApubPerson, actor: &ApubPerson,
community: &ApubCommunity, community: &ApubCommunity,
@ -36,6 +37,7 @@ pub async fn send_apub_delete(
// TODO: remove reason is actually optional in lemmy. we set an empty string in that case, but its // TODO: remove reason is actually optional in lemmy. we set an empty string in that case, but its
// ugly // ugly
#[tracing::instrument(skip_all)]
pub async fn send_apub_remove( pub async fn send_apub_remove(
actor: &ApubPerson, actor: &ApubPerson,
community: &ApubCommunity, community: &ApubCommunity,
@ -58,6 +60,7 @@ pub enum DeletableObjects {
} }
impl DeletableObjects { impl DeletableObjects {
#[tracing::instrument(skip_all)]
pub(crate) async fn read_from_db( pub(crate) async fn read_from_db(
ap_id: &Url, ap_id: &Url,
context: &LemmyContext, context: &LemmyContext,
@ -83,6 +86,7 @@ impl DeletableObjects {
} }
} }
#[tracing::instrument(skip_all)]
pub(in crate::activities) async fn verify_delete_activity( pub(in crate::activities) async fn verify_delete_activity(
object: &Url, object: &Url,
actor: &ObjectId<ApubPerson>, actor: &ObjectId<ApubPerson>,
@ -128,6 +132,7 @@ pub(in crate::activities) async fn verify_delete_activity(
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn verify_delete_activity_post_or_comment( async fn verify_delete_activity_post_or_comment(
actor: &ObjectId<ApubPerson>, actor: &ObjectId<ApubPerson>,
object_id: &Url, object_id: &Url,
@ -149,6 +154,7 @@ async fn verify_delete_activity_post_or_comment(
/// Write deletion or restoring of an object to the database, and send websocket message. /// Write deletion or restoring of an object to the database, and send websocket message.
/// TODO: we should do something similar for receive_remove_action(), but its much more complicated /// TODO: we should do something similar for receive_remove_action(), but its much more complicated
/// because of the mod log /// because of the mod log
#[tracing::instrument(skip_all)]
async fn receive_delete_action( async fn receive_delete_action(
object: &Url, object: &Url,
actor: &ObjectId<ApubPerson>, actor: &ObjectId<ApubPerson>,

View file

@ -11,7 +11,6 @@ use crate::{
protocol::activities::deletion::{delete::Delete, undo_delete::UndoDelete}, protocol::activities::deletion::{delete::Delete, undo_delete::UndoDelete},
}; };
use activitystreams_kinds::{activity::UndoType, public}; use activitystreams_kinds::{activity::UndoType, public};
use anyhow::anyhow;
use lemmy_api_common::blocking; use lemmy_api_common::blocking;
use lemmy_apub_lib::{ use lemmy_apub_lib::{
data::Data, data::Data,
@ -30,6 +29,8 @@ use url::Url;
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl ActivityHandler for UndoDelete { impl ActivityHandler for UndoDelete {
type DataType = LemmyContext; type DataType = LemmyContext;
#[tracing::instrument(skip_all)]
async fn verify( async fn verify(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -51,6 +52,7 @@ impl ActivityHandler for UndoDelete {
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn receive( async fn receive(
self, self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -72,6 +74,7 @@ impl ActivityHandler for UndoDelete {
} }
impl UndoDelete { impl UndoDelete {
#[tracing::instrument(skip_all)]
pub(in crate::activities::deletion) async fn send( pub(in crate::activities::deletion) async fn send(
actor: &ApubPerson, actor: &ApubPerson,
community: &ApubCommunity, community: &ApubCommunity,
@ -99,6 +102,7 @@ impl UndoDelete {
send_activity_in_community(activity, &id, actor, community, vec![], context).await send_activity_in_community(activity, &id, actor, community, vec![], context).await
} }
#[tracing::instrument(skip_all)]
pub(in crate::activities) async fn receive_undo_remove_action( pub(in crate::activities) async fn receive_undo_remove_action(
object: &Url, object: &Url,
context: &LemmyContext, context: &LemmyContext,
@ -107,7 +111,9 @@ impl UndoDelete {
match DeletableObjects::read_from_db(object, context).await? { match DeletableObjects::read_from_db(object, context).await? {
DeletableObjects::Community(community) => { DeletableObjects::Community(community) => {
if community.local { if community.local {
return Err(anyhow!("Only local admin can restore community").into()); return Err(LemmyError::from_message(
"Only local admin can restore community",
));
} }
let deleted_community = blocking(context.pool(), move |conn| { let deleted_community = blocking(context.pool(), move |conn| {
Community::update_removed(conn, community.id, false) Community::update_removed(conn, community.id, false)
@ -136,6 +142,7 @@ impl UndoDelete {
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl GetCommunity for UndoDelete { impl GetCommunity for UndoDelete {
#[tracing::instrument(skip_all)]
async fn get_community( async fn get_community(
&self, &self,
context: &LemmyContext, context: &LemmyContext,

View file

@ -15,6 +15,7 @@ use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext; use lemmy_websocket::LemmyContext;
impl AcceptFollowCommunity { impl AcceptFollowCommunity {
#[tracing::instrument(skip_all)]
pub async fn send( pub async fn send(
follow: FollowCommunity, follow: FollowCommunity,
context: &LemmyContext, context: &LemmyContext,
@ -45,6 +46,8 @@ impl AcceptFollowCommunity {
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl ActivityHandler for AcceptFollowCommunity { impl ActivityHandler for AcceptFollowCommunity {
type DataType = LemmyContext; type DataType = LemmyContext;
#[tracing::instrument(skip_all)]
async fn verify( async fn verify(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -56,6 +59,7 @@ impl ActivityHandler for AcceptFollowCommunity {
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn receive( async fn receive(
self, self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,

View file

@ -40,6 +40,8 @@ impl FollowCommunity {
unparsed: Default::default(), unparsed: Default::default(),
}) })
} }
#[tracing::instrument(skip_all)]
pub async fn send( pub async fn send(
actor: &ApubPerson, actor: &ApubPerson,
community: &ApubCommunity, community: &ApubCommunity,
@ -64,6 +66,8 @@ impl FollowCommunity {
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl ActivityHandler for FollowCommunity { impl ActivityHandler for FollowCommunity {
type DataType = LemmyContext; type DataType = LemmyContext;
#[tracing::instrument(skip_all)]
async fn verify( async fn verify(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -76,6 +80,7 @@ impl ActivityHandler for FollowCommunity {
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn receive( async fn receive(
self, self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,

View file

@ -19,6 +19,7 @@ use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext; use lemmy_websocket::LemmyContext;
impl UndoFollowCommunity { impl UndoFollowCommunity {
#[tracing::instrument(skip_all)]
pub async fn send( pub async fn send(
actor: &ApubPerson, actor: &ApubPerson,
community: &ApubCommunity, community: &ApubCommunity,
@ -43,6 +44,8 @@ impl UndoFollowCommunity {
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl ActivityHandler for UndoFollowCommunity { impl ActivityHandler for UndoFollowCommunity {
type DataType = LemmyContext; type DataType = LemmyContext;
#[tracing::instrument(skip_all)]
async fn verify( async fn verify(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -55,6 +58,7 @@ impl ActivityHandler for UndoFollowCommunity {
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn receive( async fn receive(
self, self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,

View file

@ -6,7 +6,6 @@ use crate::{
objects::{community::ApubCommunity, person::ApubPerson}, objects::{community::ApubCommunity, person::ApubPerson},
}; };
use activitystreams_kinds::public; use activitystreams_kinds::public;
use anyhow::anyhow;
use lemmy_api_common::blocking; use lemmy_api_common::blocking;
use lemmy_apub_lib::{ use lemmy_apub_lib::{
activity_queue::send_activity, activity_queue::send_activity,
@ -36,6 +35,7 @@ pub mod voting;
/// Checks that the specified Url actually identifies a Person (by fetching it), and that the person /// Checks that the specified Url actually identifies a Person (by fetching it), and that the person
/// doesn't have a site ban. /// doesn't have a site ban.
#[tracing::instrument(skip_all)]
async fn verify_person( async fn verify_person(
person_id: &ObjectId<ApubPerson>, person_id: &ObjectId<ApubPerson>,
context: &LemmyContext, context: &LemmyContext,
@ -43,13 +43,15 @@ async fn verify_person(
) -> Result<(), LemmyError> { ) -> Result<(), LemmyError> {
let person = person_id.dereference(context, request_counter).await?; let person = person_id.dereference(context, request_counter).await?;
if person.banned { if person.banned {
return Err(anyhow!("Person {} is banned", person_id).into()); let error = LemmyError::from(anyhow::anyhow!("Person {} is banned", person_id));
return Err(error.with_message("banned"));
} }
Ok(()) Ok(())
} }
/// Fetches the person and community to verify their type, then checks if person is banned from site /// Fetches the person and community to verify their type, then checks if person is banned from site
/// or community. /// or community.
#[tracing::instrument(skip_all)]
pub(crate) async fn verify_person_in_community( pub(crate) async fn verify_person_in_community(
person_id: &ObjectId<ApubPerson>, person_id: &ObjectId<ApubPerson>,
community: &ApubCommunity, community: &ApubCommunity,
@ -58,14 +60,14 @@ pub(crate) async fn verify_person_in_community(
) -> Result<(), LemmyError> { ) -> Result<(), LemmyError> {
let person = person_id.dereference(context, request_counter).await?; let person = person_id.dereference(context, request_counter).await?;
if person.banned { if person.banned {
return Err(anyhow!("Person is banned from site").into()); return Err(LemmyError::from_message("Person is banned from site"));
} }
let person_id = person.id; let person_id = person.id;
let community_id = community.id; let community_id = community.id;
let is_banned = let is_banned =
move |conn: &'_ _| CommunityPersonBanView::get(conn, person_id, community_id).is_ok(); move |conn: &'_ _| CommunityPersonBanView::get(conn, person_id, community_id).is_ok();
if blocking(context.pool(), is_banned).await? { if blocking(context.pool(), is_banned).await? {
return Err(anyhow!("Person is banned from community").into()); return Err(LemmyError::from_message("Person is banned from community"));
} }
Ok(()) Ok(())
@ -80,6 +82,7 @@ fn verify_activity(id: &Url, actor: &Url, settings: &Settings) -> Result<(), Lem
/// Verify that the actor is a community mod. This check is only run if the community is local, /// Verify that the actor is a community mod. This check is only run if the community is local,
/// because in case of remote communities, admins can also perform mod actions. As admin status /// because in case of remote communities, admins can also perform mod actions. As admin status
/// is not federated, we cant verify their actions remotely. /// is not federated, we cant verify their actions remotely.
#[tracing::instrument(skip_all)]
pub(crate) async fn verify_mod_action( pub(crate) async fn verify_mod_action(
actor_id: &ObjectId<ApubPerson>, actor_id: &ObjectId<ApubPerson>,
community: &ApubCommunity, community: &ApubCommunity,
@ -98,7 +101,7 @@ pub(crate) async fn verify_mod_action(
}) })
.await?; .await?;
if !is_mod_or_admin { if !is_mod_or_admin {
return Err(anyhow!("Not a mod").into()); return Err(LemmyError::from_message("Not a mod"));
} }
} }
Ok(()) Ok(())
@ -111,21 +114,23 @@ fn verify_add_remove_moderator_target(
community: &ApubCommunity, community: &ApubCommunity,
) -> Result<(), LemmyError> { ) -> Result<(), LemmyError> {
if target != &generate_moderators_url(&community.actor_id)?.into() { if target != &generate_moderators_url(&community.actor_id)?.into() {
return Err(anyhow!("Unkown target url").into()); return Err(LemmyError::from_message("Unkown target url"));
} }
Ok(()) Ok(())
} }
pub(crate) fn verify_is_public(to: &[Url], cc: &[Url]) -> Result<(), LemmyError> { pub(crate) fn verify_is_public(to: &[Url], cc: &[Url]) -> Result<(), LemmyError> {
if ![to, cc].iter().any(|set| set.contains(&public())) { if ![to, cc].iter().any(|set| set.contains(&public())) {
return Err(anyhow!("Object is not public").into()); return Err(LemmyError::from_message("Object is not public"));
} }
Ok(()) Ok(())
} }
pub(crate) fn check_community_deleted_or_removed(community: &Community) -> Result<(), LemmyError> { pub(crate) fn check_community_deleted_or_removed(community: &Community) -> Result<(), LemmyError> {
if community.deleted || community.removed { if community.deleted || community.removed {
Err(anyhow!("New post or comment cannot be created in deleted or removed community").into()) Err(LemmyError::from_message(
"New post or comment cannot be created in deleted or removed community",
))
} else { } else {
Ok(()) Ok(())
} }
@ -146,6 +151,7 @@ where
Url::parse(&id) Url::parse(&id)
} }
#[tracing::instrument(skip_all)]
async fn send_lemmy_activity<T: Serialize>( async fn send_lemmy_activity<T: Serialize>(
context: &LemmyContext, context: &LemmyContext,
activity: &T, activity: &T,

View file

@ -13,7 +13,6 @@ use crate::{
protocol::activities::{create_or_update::post::CreateOrUpdatePost, CreateOrUpdateType}, protocol::activities::{create_or_update::post::CreateOrUpdatePost, CreateOrUpdateType},
}; };
use activitystreams_kinds::public; use activitystreams_kinds::public;
use anyhow::anyhow;
use lemmy_api_common::blocking; use lemmy_api_common::blocking;
use lemmy_apub_lib::{ use lemmy_apub_lib::{
data::Data, data::Data,
@ -47,6 +46,8 @@ impl CreateOrUpdatePost {
unparsed: Default::default(), unparsed: Default::default(),
}) })
} }
#[tracing::instrument(skip_all)]
pub async fn send( pub async fn send(
post: ApubPost, post: ApubPost,
actor: &ApubPerson, actor: &ApubPerson,
@ -70,6 +71,8 @@ impl CreateOrUpdatePost {
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl ActivityHandler for CreateOrUpdatePost { impl ActivityHandler for CreateOrUpdatePost {
type DataType = LemmyContext; type DataType = LemmyContext;
#[tracing::instrument(skip_all)]
async fn verify( async fn verify(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -92,7 +95,9 @@ impl ActivityHandler for CreateOrUpdatePost {
let is_stickied_or_locked = let is_stickied_or_locked =
self.object.stickied == Some(true) || self.object.comments_enabled == Some(false); self.object.stickied == Some(true) || self.object.comments_enabled == Some(false);
if community.local && is_stickied_or_locked { if community.local && is_stickied_or_locked {
return Err(anyhow!("New post cannot be stickied or locked").into()); return Err(LemmyError::from_message(
"New post cannot be stickied or locked",
));
} }
} }
CreateOrUpdateType::Update => { CreateOrUpdateType::Update => {
@ -109,6 +114,7 @@ impl ActivityHandler for CreateOrUpdatePost {
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn receive( async fn receive(
self, self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -127,6 +133,7 @@ impl ActivityHandler for CreateOrUpdatePost {
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl GetCommunity for CreateOrUpdatePost { impl GetCommunity for CreateOrUpdatePost {
#[tracing::instrument(skip_all)]
async fn get_community( async fn get_community(
&self, &self,
context: &LemmyContext, context: &LemmyContext,

View file

@ -18,6 +18,7 @@ use lemmy_utils::LemmyError;
use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperationCrud}; use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperationCrud};
impl CreateOrUpdatePrivateMessage { impl CreateOrUpdatePrivateMessage {
#[tracing::instrument(skip_all)]
pub async fn send( pub async fn send(
private_message: ApubPrivateMessage, private_message: ApubPrivateMessage,
actor: &ApubPerson, actor: &ApubPerson,
@ -46,9 +47,12 @@ impl CreateOrUpdatePrivateMessage {
send_lemmy_activity(context, &create_or_update, &id, actor, inbox, true).await send_lemmy_activity(context, &create_or_update, &id, actor, inbox, true).await
} }
} }
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl ActivityHandler for CreateOrUpdatePrivateMessage { impl ActivityHandler for CreateOrUpdatePrivateMessage {
type DataType = LemmyContext; type DataType = LemmyContext;
#[tracing::instrument(skip_all)]
async fn verify( async fn verify(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -61,6 +65,7 @@ impl ActivityHandler for CreateOrUpdatePrivateMessage {
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn receive( async fn receive(
self, self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,

View file

@ -36,6 +36,8 @@ impl DeletePrivateMessage {
unparsed: Default::default(), unparsed: Default::default(),
}) })
} }
#[tracing::instrument(skip_all)]
pub async fn send( pub async fn send(
actor: &ApubPerson, actor: &ApubPerson,
pm: &ApubPrivateMessage, pm: &ApubPrivateMessage,
@ -57,6 +59,8 @@ impl DeletePrivateMessage {
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl ActivityHandler for DeletePrivateMessage { impl ActivityHandler for DeletePrivateMessage {
type DataType = LemmyContext; type DataType = LemmyContext;
#[tracing::instrument(skip_all)]
async fn verify( async fn verify(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -68,6 +72,7 @@ impl ActivityHandler for DeletePrivateMessage {
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn receive( async fn receive(
self, self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,

View file

@ -22,6 +22,7 @@ use lemmy_utils::LemmyError;
use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperationCrud}; use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperationCrud};
impl UndoDeletePrivateMessage { impl UndoDeletePrivateMessage {
#[tracing::instrument(skip_all)]
pub async fn send( pub async fn send(
actor: &ApubPerson, actor: &ApubPerson,
pm: &ApubPrivateMessage, pm: &ApubPrivateMessage,
@ -54,6 +55,8 @@ impl UndoDeletePrivateMessage {
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl ActivityHandler for UndoDeletePrivateMessage { impl ActivityHandler for UndoDeletePrivateMessage {
type DataType = LemmyContext; type DataType = LemmyContext;
#[tracing::instrument(skip_all)]
async fn verify( async fn verify(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -67,6 +70,7 @@ impl ActivityHandler for UndoDeletePrivateMessage {
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn receive( async fn receive(
self, self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,

View file

@ -21,6 +21,7 @@ use crate::{
pub mod undo_vote; pub mod undo_vote;
pub mod vote; pub mod vote;
#[tracing::instrument(skip_all)]
async fn vote_comment( async fn vote_comment(
vote_type: &VoteType, vote_type: &VoteType,
actor: ApubPerson, actor: ApubPerson,
@ -45,6 +46,7 @@ async fn vote_comment(
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn vote_post( async fn vote_post(
vote_type: &VoteType, vote_type: &VoteType,
actor: ApubPerson, actor: ApubPerson,
@ -68,6 +70,7 @@ async fn vote_post(
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn undo_vote_comment( async fn undo_vote_comment(
actor: ApubPerson, actor: ApubPerson,
comment: &ApubComment, comment: &ApubComment,
@ -84,6 +87,7 @@ async fn undo_vote_comment(
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn undo_vote_post( async fn undo_vote_post(
actor: ApubPerson, actor: ApubPerson,
post: &ApubPost, post: &ApubPost,

View file

@ -28,6 +28,7 @@ use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext; use lemmy_websocket::LemmyContext;
impl UndoVote { impl UndoVote {
#[tracing::instrument(skip_all)]
pub async fn send( pub async fn send(
object: &PostOrComment, object: &PostOrComment,
actor: &ApubPerson, actor: &ApubPerson,
@ -63,6 +64,8 @@ impl UndoVote {
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl ActivityHandler for UndoVote { impl ActivityHandler for UndoVote {
type DataType = LemmyContext; type DataType = LemmyContext;
#[tracing::instrument(skip_all)]
async fn verify( async fn verify(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -77,6 +80,7 @@ impl ActivityHandler for UndoVote {
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn receive( async fn receive(
self, self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -97,6 +101,7 @@ impl ActivityHandler for UndoVote {
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl GetCommunity for UndoVote { impl GetCommunity for UndoVote {
#[tracing::instrument(skip_all)]
async fn get_community( async fn get_community(
&self, &self,
context: &LemmyContext, context: &LemmyContext,

View file

@ -46,6 +46,7 @@ impl Vote {
}) })
} }
#[tracing::instrument(skip_all)]
pub async fn send( pub async fn send(
object: &PostOrComment, object: &PostOrComment,
actor: &ApubPerson, actor: &ApubPerson,
@ -69,6 +70,8 @@ impl Vote {
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl ActivityHandler for Vote { impl ActivityHandler for Vote {
type DataType = LemmyContext; type DataType = LemmyContext;
#[tracing::instrument(skip_all)]
async fn verify( async fn verify(
&self, &self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -81,6 +84,7 @@ impl ActivityHandler for Vote {
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn receive( async fn receive(
self, self,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
@ -97,6 +101,7 @@ impl ActivityHandler for Vote {
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl GetCommunity for Vote { impl GetCommunity for Vote {
#[tracing::instrument(skip_all)]
async fn get_community( async fn get_community(
&self, &self,
context: &LemmyContext, context: &LemmyContext,

View file

@ -88,6 +88,7 @@ pub enum AnnouncableActivities {
#[async_trait::async_trait(?Send)] #[async_trait::async_trait(?Send)]
impl GetCommunity for AnnouncableActivities { impl GetCommunity for AnnouncableActivities {
#[tracing::instrument(skip(self, context))]
async fn get_community( async fn get_community(
&self, &self,
context: &LemmyContext, context: &LemmyContext,

View file

@ -29,6 +29,7 @@ impl ApubObject for ApubCommunityModerators {
None None
} }
#[tracing::instrument(skip_all)]
async fn read_from_apub_id( async fn read_from_apub_id(
_object_id: Url, _object_id: Url,
data: &Self::DataType, data: &Self::DataType,
@ -46,10 +47,12 @@ impl ApubObject for ApubCommunityModerators {
} }
} }
#[tracing::instrument(skip_all)]
async fn delete(self, _data: &Self::DataType) -> Result<(), LemmyError> { async fn delete(self, _data: &Self::DataType) -> Result<(), LemmyError> {
unimplemented!() unimplemented!()
} }
#[tracing::instrument(skip_all)]
async fn into_apub(self, data: &Self::DataType) -> Result<Self::ApubType, LemmyError> { async fn into_apub(self, data: &Self::DataType) -> Result<Self::ApubType, LemmyError> {
let ordered_items = self let ordered_items = self
.0 .0
@ -67,6 +70,7 @@ impl ApubObject for ApubCommunityModerators {
unimplemented!() unimplemented!()
} }
#[tracing::instrument(skip_all)]
async fn verify( async fn verify(
group_moderators: &GroupModerators, group_moderators: &GroupModerators,
expected_domain: &Url, expected_domain: &Url,
@ -77,6 +81,7 @@ impl ApubObject for ApubCommunityModerators {
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn from_apub( async fn from_apub(
apub: Self::ApubType, apub: Self::ApubType,
data: &Self::DataType, data: &Self::DataType,

View file

@ -33,6 +33,7 @@ impl ApubObject for ApubCommunityOutbox {
None None
} }
#[tracing::instrument(skip_all)]
async fn read_from_apub_id( async fn read_from_apub_id(
_object_id: Url, _object_id: Url,
data: &Self::DataType, data: &Self::DataType,
@ -58,6 +59,7 @@ impl ApubObject for ApubCommunityOutbox {
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn into_apub(self, data: &Self::DataType) -> Result<Self::ApubType, LemmyError> { async fn into_apub(self, data: &Self::DataType) -> Result<Self::ApubType, LemmyError> {
let mut ordered_items = vec![]; let mut ordered_items = vec![];
for post in self.0 { for post in self.0 {
@ -80,6 +82,7 @@ impl ApubObject for ApubCommunityOutbox {
unimplemented!() unimplemented!()
} }
#[tracing::instrument(skip_all)]
async fn verify( async fn verify(
group_outbox: &GroupOutbox, group_outbox: &GroupOutbox,
expected_domain: &Url, expected_domain: &Url,
@ -90,6 +93,7 @@ impl ApubObject for ApubCommunityOutbox {
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn from_apub( async fn from_apub(
apub: Self::ApubType, apub: Self::ApubType,
data: &Self::DataType, data: &Self::DataType,

View file

@ -33,6 +33,7 @@ impl ApubObject for PostOrComment {
} }
// TODO: this can probably be implemented using a single sql query // TODO: this can probably be implemented using a single sql query
#[tracing::instrument(skip_all)]
async fn read_from_apub_id( async fn read_from_apub_id(
object_id: Url, object_id: Url,
data: &Self::DataType, data: &Self::DataType,
@ -46,6 +47,7 @@ impl ApubObject for PostOrComment {
}) })
} }
#[tracing::instrument(skip_all)]
async fn delete(self, data: &Self::DataType) -> Result<(), LemmyError> { async fn delete(self, data: &Self::DataType) -> Result<(), LemmyError> {
match self { match self {
PostOrComment::Post(p) => p.delete(data).await, PostOrComment::Post(p) => p.delete(data).await,
@ -61,6 +63,7 @@ impl ApubObject for PostOrComment {
unimplemented!() unimplemented!()
} }
#[tracing::instrument(skip_all)]
async fn verify( async fn verify(
apub: &Self::ApubType, apub: &Self::ApubType,
expected_domain: &Url, expected_domain: &Url,
@ -73,6 +76,7 @@ impl ApubObject for PostOrComment {
} }
} }
#[tracing::instrument(skip_all)]
async fn from_apub( async fn from_apub(
apub: PageOrNote, apub: PageOrNote,
context: &LemmyContext, context: &LemmyContext,

View file

@ -4,7 +4,6 @@ use crate::{
protocol::objects::{group::Group, note::Note, page::Page, person::Person}, protocol::objects::{group::Group, note::Note, page::Page, person::Person},
EndpointType, EndpointType,
}; };
use anyhow::anyhow;
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use lemmy_apub_lib::{object_id::ObjectId, traits::ApubObject}; use lemmy_apub_lib::{object_id::ObjectId, traits::ApubObject};
use lemmy_utils::LemmyError; use lemmy_utils::LemmyError;
@ -19,6 +18,7 @@ use url::Url;
/// http://lemmy_beta:8551/u/lemmy_alpha, or @lemmy_beta@lemmy_beta:8551 /// http://lemmy_beta:8551/u/lemmy_alpha, or @lemmy_beta@lemmy_beta:8551
/// http://lemmy_gamma:8561/post/3 /// http://lemmy_gamma:8561/post/3
/// http://lemmy_delta:8571/comment/2 /// http://lemmy_delta:8571/comment/2
#[tracing::instrument(skip_all)]
pub async fn search_by_apub_id( pub async fn search_by_apub_id(
query: &str, query: &str,
context: &LemmyContext, context: &LemmyContext,
@ -61,7 +61,7 @@ pub async fn search_by_apub_id(
.await?, .await?,
)) ))
} }
_ => Err(anyhow!("invalid query").into()), _ => Err(LemmyError::from_message("invalid query")),
} }
} }
} }
@ -105,6 +105,7 @@ impl ApubObject for SearchableObjects {
// a single query. // a single query.
// we could skip this and always return an error, but then it would always fetch objects // we could skip this and always return an error, but then it would always fetch objects
// over http, and not be able to mark objects as deleted that were deleted by remote server. // over http, and not be able to mark objects as deleted that were deleted by remote server.
#[tracing::instrument(skip_all)]
async fn read_from_apub_id( async fn read_from_apub_id(
object_id: Url, object_id: Url,
context: &LemmyContext, context: &LemmyContext,
@ -128,6 +129,7 @@ impl ApubObject for SearchableObjects {
Ok(None) Ok(None)
} }
#[tracing::instrument(skip_all)]
async fn delete(self, data: &Self::DataType) -> Result<(), LemmyError> { async fn delete(self, data: &Self::DataType) -> Result<(), LemmyError> {
match self { match self {
SearchableObjects::Person(p) => p.delete(data).await, SearchableObjects::Person(p) => p.delete(data).await,
@ -145,6 +147,7 @@ impl ApubObject for SearchableObjects {
unimplemented!() unimplemented!()
} }
#[tracing::instrument(skip_all)]
async fn verify( async fn verify(
apub: &Self::ApubType, apub: &Self::ApubType,
expected_domain: &Url, expected_domain: &Url,
@ -167,6 +170,7 @@ impl ApubObject for SearchableObjects {
} }
} }
#[tracing::instrument(skip_all)]
async fn from_apub( async fn from_apub(
apub: Self::ApubType, apub: Self::ApubType,
context: &LemmyContext, context: &LemmyContext,

View file

@ -35,6 +35,7 @@ impl ApubObject for UserOrCommunity {
}) })
} }
#[tracing::instrument(skip_all)]
async fn read_from_apub_id( async fn read_from_apub_id(
object_id: Url, object_id: Url,
data: &Self::DataType, data: &Self::DataType,
@ -48,6 +49,7 @@ impl ApubObject for UserOrCommunity {
}) })
} }
#[tracing::instrument(skip_all)]
async fn delete(self, data: &Self::DataType) -> Result<(), LemmyError> { async fn delete(self, data: &Self::DataType) -> Result<(), LemmyError> {
match self { match self {
UserOrCommunity::User(p) => p.delete(data).await, UserOrCommunity::User(p) => p.delete(data).await,
@ -63,6 +65,7 @@ impl ApubObject for UserOrCommunity {
unimplemented!() unimplemented!()
} }
#[tracing::instrument(skip_all)]
async fn verify( async fn verify(
apub: &Self::ApubType, apub: &Self::ApubType,
expected_domain: &Url, expected_domain: &Url,
@ -79,6 +82,7 @@ impl ApubObject for UserOrCommunity {
} }
} }
#[tracing::instrument(skip_all)]
async fn from_apub( async fn from_apub(
apub: Self::ApubType, apub: Self::ApubType,
data: &Self::DataType, data: &Self::DataType,

View file

@ -1,5 +1,4 @@
use crate::{generate_local_apub_endpoint, EndpointType}; use crate::{generate_local_apub_endpoint, EndpointType};
use anyhow::anyhow;
use itertools::Itertools; use itertools::Itertools;
use lemmy_apub_lib::{ use lemmy_apub_lib::{
object_id::ObjectId, object_id::ObjectId,
@ -34,6 +33,7 @@ pub struct WebfingerResponse {
/// ///
/// TODO: later provide a method in ApubObject to generate the endpoint, so that we dont have to /// TODO: later provide a method in ApubObject to generate the endpoint, so that we dont have to
/// pass in EndpointType /// pass in EndpointType
#[tracing::instrument(skip_all)]
pub async fn webfinger_resolve<Kind>( pub async fn webfinger_resolve<Kind>(
identifier: &str, identifier: &str,
endpoint_type: EndpointType, endpoint_type: EndpointType,
@ -61,6 +61,7 @@ where
/// Turns a person id like `@name@example.com` into an apub ID, like `https://example.com/user/name`, /// Turns a person id like `@name@example.com` into an apub ID, like `https://example.com/user/name`,
/// using webfinger. /// using webfinger.
#[tracing::instrument(skip_all)]
pub(crate) async fn webfinger_resolve_actor<Kind>( pub(crate) async fn webfinger_resolve_actor<Kind>(
identifier: &str, identifier: &str,
context: &LemmyContext, context: &LemmyContext,
@ -114,5 +115,9 @@ where
return object.map(|o| o.actor_id().into()); return object.map(|o| o.actor_id().into());
} }
} }
Err(anyhow!("Failed to resolve actor for {}", identifier).into()) let error = LemmyError::from(anyhow::anyhow!(
"Failed to resolve actor for {}",
identifier
));
Err(error.with_message("failed_to_resolve"))
} }

View file

@ -2,7 +2,7 @@ use crate::{
http::{create_apub_response, create_apub_tombstone_response}, http::{create_apub_response, create_apub_tombstone_response},
objects::comment::ApubComment, objects::comment::ApubComment,
}; };
use actix_web::{body::Body, web, web::Path, HttpResponse}; use actix_web::{body::AnyBody, web, web::Path, HttpResponse};
use diesel::result::Error::NotFound; use diesel::result::Error::NotFound;
use lemmy_api_common::blocking; use lemmy_api_common::blocking;
use lemmy_apub_lib::traits::ApubObject; use lemmy_apub_lib::traits::ApubObject;
@ -17,10 +17,11 @@ pub(crate) struct CommentQuery {
} }
/// Return the ActivityPub json representation of a local comment over HTTP. /// Return the ActivityPub json representation of a local comment over HTTP.
#[tracing::instrument(skip_all)]
pub(crate) async fn get_apub_comment( pub(crate) async fn get_apub_comment(
info: Path<CommentQuery>, info: Path<CommentQuery>,
context: web::Data<LemmyContext>, context: web::Data<LemmyContext>,
) -> Result<HttpResponse<Body>, LemmyError> { ) -> Result<HttpResponse<AnyBody>, LemmyError> {
let id = CommentId(info.comment_id.parse::<i32>()?); let id = CommentId(info.comment_id.parse::<i32>()?);
let comment: ApubComment = blocking(context.pool(), move |conn| Comment::read(conn, id)) let comment: ApubComment = blocking(context.pool(), move |conn| Comment::read(conn, id))
.await?? .await??

View file

@ -21,7 +21,7 @@ use crate::{
collections::group_followers::GroupFollowers, collections::group_followers::GroupFollowers,
}, },
}; };
use actix_web::{body::Body, web, web::Payload, HttpRequest, HttpResponse}; use actix_web::{body::AnyBody, web, web::Payload, HttpRequest, HttpResponse};
use lemmy_api_common::blocking; use lemmy_api_common::blocking;
use lemmy_apub_lib::{object_id::ObjectId, traits::ApubObject}; use lemmy_apub_lib::{object_id::ObjectId, traits::ApubObject};
use lemmy_db_schema::source::community::Community; use lemmy_db_schema::source::community::Community;
@ -36,10 +36,11 @@ pub(crate) struct CommunityQuery {
} }
/// Return the ActivityPub json representation of a local community over HTTP. /// Return the ActivityPub json representation of a local community over HTTP.
#[tracing::instrument(skip_all)]
pub(crate) async fn get_apub_community_http( pub(crate) async fn get_apub_community_http(
info: web::Path<CommunityQuery>, info: web::Path<CommunityQuery>,
context: web::Data<LemmyContext>, context: web::Data<LemmyContext>,
) -> Result<HttpResponse<Body>, LemmyError> { ) -> Result<HttpResponse<AnyBody>, LemmyError> {
let community: ApubCommunity = blocking(context.pool(), move |conn| { let community: ApubCommunity = blocking(context.pool(), move |conn| {
Community::read_from_name(conn, &info.community_name) Community::read_from_name(conn, &info.community_name)
}) })
@ -56,6 +57,7 @@ pub(crate) async fn get_apub_community_http(
} }
/// Handler for all incoming receive to community inboxes. /// Handler for all incoming receive to community inboxes.
#[tracing::instrument(skip_all)]
pub async fn community_inbox( pub async fn community_inbox(
request: HttpRequest, request: HttpRequest,
payload: Payload, payload: Payload,
@ -96,7 +98,7 @@ pub(in crate::http) async fn receive_group_inbox(
pub(crate) async fn get_apub_community_followers( pub(crate) async fn get_apub_community_followers(
info: web::Path<CommunityQuery>, info: web::Path<CommunityQuery>,
context: web::Data<LemmyContext>, context: web::Data<LemmyContext>,
) -> Result<HttpResponse<Body>, LemmyError> { ) -> Result<HttpResponse<AnyBody>, LemmyError> {
let community = blocking(context.pool(), move |conn| { let community = blocking(context.pool(), move |conn| {
Community::read_from_name(conn, &info.community_name) Community::read_from_name(conn, &info.community_name)
}) })
@ -110,7 +112,7 @@ pub(crate) async fn get_apub_community_followers(
pub(crate) async fn get_apub_community_outbox( pub(crate) async fn get_apub_community_outbox(
info: web::Path<CommunityQuery>, info: web::Path<CommunityQuery>,
context: web::Data<LemmyContext>, context: web::Data<LemmyContext>,
) -> Result<HttpResponse<Body>, LemmyError> { ) -> Result<HttpResponse<AnyBody>, LemmyError> {
let community = blocking(context.pool(), move |conn| { let community = blocking(context.pool(), move |conn| {
Community::read_from_name(conn, &info.community_name) Community::read_from_name(conn, &info.community_name)
}) })
@ -121,10 +123,11 @@ pub(crate) async fn get_apub_community_outbox(
Ok(create_apub_response(&outbox.into_apub(&outbox_data).await?)) Ok(create_apub_response(&outbox.into_apub(&outbox_data).await?))
} }
#[tracing::instrument(skip_all)]
pub(crate) async fn get_apub_community_moderators( pub(crate) async fn get_apub_community_moderators(
info: web::Path<CommunityQuery>, info: web::Path<CommunityQuery>,
context: web::Data<LemmyContext>, context: web::Data<LemmyContext>,
) -> Result<HttpResponse<Body>, LemmyError> { ) -> Result<HttpResponse<AnyBody>, LemmyError> {
let community: ApubCommunity = blocking(context.pool(), move |conn| { let community: ApubCommunity = blocking(context.pool(), move |conn| {
Community::read_from_name(conn, &info.community_name) Community::read_from_name(conn, &info.community_name)
}) })

View file

@ -7,13 +7,13 @@ use crate::{
insert_activity, insert_activity,
}; };
use actix_web::{ use actix_web::{
body::Body, body::AnyBody,
web, web,
web::{Bytes, BytesMut, Payload}, web::{Bytes, BytesMut, Payload},
HttpRequest, HttpRequest,
HttpResponse, HttpResponse,
}; };
use anyhow::{anyhow, Context}; use anyhow::Context;
use futures::StreamExt; use futures::StreamExt;
use http::StatusCode; use http::StatusCode;
use lemmy_api_common::blocking; use lemmy_api_common::blocking;
@ -38,6 +38,7 @@ mod person;
mod post; mod post;
pub mod routes; pub mod routes;
#[tracing::instrument(skip_all)]
pub async fn shared_inbox( pub async fn shared_inbox(
request: HttpRequest, request: HttpRequest,
payload: Payload, payload: Payload,
@ -75,6 +76,7 @@ pub(crate) struct ActivityCommonFields {
} }
// TODO: move most of this code to library // TODO: move most of this code to library
#[tracing::instrument(skip_all)]
async fn receive_activity<'a, T>( async fn receive_activity<'a, T>(
request: HttpRequest, request: HttpRequest,
activity: T, activity: T,
@ -117,7 +119,7 @@ where
/// Convert the data to json and turn it into an HTTP Response with the correct ActivityPub /// Convert the data to json and turn it into an HTTP Response with the correct ActivityPub
/// headers. /// headers.
fn create_apub_response<T>(data: &T) -> HttpResponse<Body> fn create_apub_response<T>(data: &T) -> HttpResponse<AnyBody>
where where
T: Serialize, T: Serialize,
{ {
@ -126,13 +128,13 @@ where
.json(WithContext::new(data)) .json(WithContext::new(data))
} }
fn create_json_apub_response(data: serde_json::Value) -> HttpResponse<Body> { fn create_json_apub_response(data: serde_json::Value) -> HttpResponse<AnyBody> {
HttpResponse::Ok() HttpResponse::Ok()
.content_type(APUB_JSON_CONTENT_TYPE) .content_type(APUB_JSON_CONTENT_TYPE)
.json(data) .json(data)
} }
fn create_apub_tombstone_response<T>(data: &T) -> HttpResponse<Body> fn create_apub_tombstone_response<T>(data: &T) -> HttpResponse<AnyBody>
where where
T: Serialize, T: Serialize,
{ {
@ -149,10 +151,11 @@ pub struct ActivityQuery {
} }
/// Return the ActivityPub json representation of a local activity over HTTP. /// Return the ActivityPub json representation of a local activity over HTTP.
#[tracing::instrument(skip_all)]
pub(crate) async fn get_activity( pub(crate) async fn get_activity(
info: web::Path<ActivityQuery>, info: web::Path<ActivityQuery>,
context: web::Data<LemmyContext>, context: web::Data<LemmyContext>,
) -> Result<HttpResponse<Body>, LemmyError> { ) -> Result<HttpResponse<AnyBody>, LemmyError> {
let settings = context.settings(); let settings = context.settings();
let activity_id = Url::parse(&format!( let activity_id = Url::parse(&format!(
"{}/activities/{}/{}", "{}/activities/{}/{}",
@ -178,13 +181,11 @@ fn assert_activity_not_local(id: &Url, hostname: &str) -> Result<(), LemmyError>
let activity_domain = id.domain().context(location_info!())?; let activity_domain = id.domain().context(location_info!())?;
if activity_domain == hostname { if activity_domain == hostname {
return Err( let error = LemmyError::from(anyhow::anyhow!(
anyhow!( "Error: received activity which was sent by local instance: {:?}",
"Error: received activity which was sent by local instance: {:?}", id
id ));
) return Err(error.with_message("received_local_activity"));
.into(),
);
} }
Ok(()) Ok(())
} }

View file

@ -11,7 +11,7 @@ use crate::{
objects::person::ApubPerson, objects::person::ApubPerson,
protocol::collections::person_outbox::PersonOutbox, protocol::collections::person_outbox::PersonOutbox,
}; };
use actix_web::{body::Body, web, web::Payload, HttpRequest, HttpResponse}; use actix_web::{body::AnyBody, web, web::Payload, HttpRequest, HttpResponse};
use lemmy_api_common::blocking; use lemmy_api_common::blocking;
use lemmy_apub_lib::traits::ApubObject; use lemmy_apub_lib::traits::ApubObject;
use lemmy_db_schema::source::person::Person; use lemmy_db_schema::source::person::Person;
@ -26,10 +26,11 @@ pub struct PersonQuery {
} }
/// Return the ActivityPub json representation of a local person over HTTP. /// Return the ActivityPub json representation of a local person over HTTP.
#[tracing::instrument(skip_all)]
pub(crate) async fn get_apub_person_http( pub(crate) async fn get_apub_person_http(
info: web::Path<PersonQuery>, info: web::Path<PersonQuery>,
context: web::Data<LemmyContext>, context: web::Data<LemmyContext>,
) -> Result<HttpResponse<Body>, LemmyError> { ) -> Result<HttpResponse<AnyBody>, LemmyError> {
let user_name = info.into_inner().user_name; let user_name = info.into_inner().user_name;
// TODO: this needs to be able to read deleted persons, so that it can send tombstones // TODO: this needs to be able to read deleted persons, so that it can send tombstones
let person: ApubPerson = blocking(context.pool(), move |conn| { let person: ApubPerson = blocking(context.pool(), move |conn| {
@ -47,6 +48,7 @@ pub(crate) async fn get_apub_person_http(
} }
} }
#[tracing::instrument(skip_all)]
pub async fn person_inbox( pub async fn person_inbox(
request: HttpRequest, request: HttpRequest,
payload: Payload, payload: Payload,
@ -69,10 +71,11 @@ pub(in crate::http) async fn receive_person_inbox(
receive_activity(request, activity, activity_data, context).await receive_activity(request, activity, activity_data, context).await
} }
#[tracing::instrument(skip_all)]
pub(crate) async fn get_apub_person_outbox( pub(crate) async fn get_apub_person_outbox(
info: web::Path<PersonQuery>, info: web::Path<PersonQuery>,
context: web::Data<LemmyContext>, context: web::Data<LemmyContext>,
) -> Result<HttpResponse<Body>, LemmyError> { ) -> Result<HttpResponse<AnyBody>, LemmyError> {
let person = blocking(context.pool(), move |conn| { let person = blocking(context.pool(), move |conn| {
Person::find_by_name(conn, &info.user_name) Person::find_by_name(conn, &info.user_name)
}) })

View file

@ -2,7 +2,7 @@ use crate::{
http::{create_apub_response, create_apub_tombstone_response}, http::{create_apub_response, create_apub_tombstone_response},
objects::post::ApubPost, objects::post::ApubPost,
}; };
use actix_web::{body::Body, web, HttpResponse}; use actix_web::{body::AnyBody, web, HttpResponse};
use diesel::result::Error::NotFound; use diesel::result::Error::NotFound;
use lemmy_api_common::blocking; use lemmy_api_common::blocking;
use lemmy_apub_lib::traits::ApubObject; use lemmy_apub_lib::traits::ApubObject;
@ -17,10 +17,11 @@ pub(crate) struct PostQuery {
} }
/// Return the ActivityPub json representation of a local post over HTTP. /// Return the ActivityPub json representation of a local post over HTTP.
#[tracing::instrument(skip_all)]
pub(crate) async fn get_apub_post( pub(crate) async fn get_apub_post(
info: web::Path<PostQuery>, info: web::Path<PostQuery>,
context: web::Data<LemmyContext>, context: web::Data<LemmyContext>,
) -> Result<HttpResponse<Body>, LemmyError> { ) -> Result<HttpResponse<AnyBody>, LemmyError> {
let id = PostId(info.post_id.parse::<i32>()?); let id = PostId(info.post_id.parse::<i32>()?);
let post: ApubPost = blocking(context.pool(), move |conn| Post::read(conn, id)) let post: ApubPost = blocking(context.pool(), move |conn| Post::read(conn, id))
.await?? .await??

View file

@ -1,5 +1,5 @@
use crate::fetcher::post_or_comment::PostOrComment; use crate::fetcher::post_or_comment::PostOrComment;
use anyhow::{anyhow, Context}; use anyhow::Context;
use lemmy_api_common::blocking; use lemmy_api_common::blocking;
use lemmy_db_schema::{newtypes::DbUrl, source::activity::Activity, DbPool}; use lemmy_db_schema::{newtypes::DbUrl, source::activity::Activity, DbPool};
use lemmy_utils::{location_info, settings::structs::Settings, LemmyError}; use lemmy_utils::{location_info, settings::structs::Settings, LemmyError};
@ -28,6 +28,7 @@ pub mod protocol;
/// ///
/// `use_strict_allowlist` should be true only when parsing a remote community, or when parsing a /// `use_strict_allowlist` should be true only when parsing a remote community, or when parsing a
/// post/comment in a local community. /// post/comment in a local community.
#[tracing::instrument(skip(settings))]
pub(crate) fn check_is_apub_id_valid( pub(crate) fn check_is_apub_id_valid(
apub_id: &Url, apub_id: &Url,
use_strict_allowlist: bool, use_strict_allowlist: bool,
@ -40,24 +41,28 @@ pub(crate) fn check_is_apub_id_valid(
return if domain == local_instance { return if domain == local_instance {
Ok(()) Ok(())
} else { } else {
Err( let error = LemmyError::from(anyhow::anyhow!(
anyhow!( "Trying to connect with {}, but federation is disabled",
"Trying to connect with {}, but federation is disabled", domain
domain ));
) Err(error.with_message("federation_disabled"))
.into(),
)
}; };
} }
let host = apub_id.host_str().context(location_info!())?; let host = apub_id.host_str().context(location_info!())?;
let host_as_ip = host.parse::<IpAddr>(); let host_as_ip = host.parse::<IpAddr>();
if host == "localhost" || host_as_ip.is_ok() { if host == "localhost" || host_as_ip.is_ok() {
return Err(anyhow!("invalid hostname {}: {}", host, apub_id).into()); let error = LemmyError::from(anyhow::anyhow!("invalid hostname {}: {}", host, apub_id));
return Err(error.with_message("invalid_hostname"));
} }
if apub_id.scheme() != settings.get_protocol_string() { if apub_id.scheme() != settings.get_protocol_string() {
return Err(anyhow!("invalid apub id scheme {}: {}", apub_id.scheme(), apub_id).into()); let error = LemmyError::from(anyhow::anyhow!(
"invalid apub id scheme {}: {}",
apub_id.scheme(),
apub_id
));
return Err(error.with_message("invalid_scheme"));
} }
// TODO: might be good to put the part above in one method, and below in another // TODO: might be good to put the part above in one method, and below in another
@ -65,7 +70,8 @@ pub(crate) fn check_is_apub_id_valid(
// -> no that doesnt make sense, we still need the code below for blocklist and strict allowlist // -> no that doesnt make sense, we still need the code below for blocklist and strict allowlist
if let Some(blocked) = settings.to_owned().federation.blocked_instances { if let Some(blocked) = settings.to_owned().federation.blocked_instances {
if blocked.contains(&domain) { if blocked.contains(&domain) {
return Err(anyhow!("{} is in federation blocklist", domain).into()); let error = LemmyError::from(anyhow::anyhow!("{} is in federation blocklist", domain));
return Err(error.with_message("federation_blocked"));
} }
} }
@ -78,7 +84,8 @@ pub(crate) fn check_is_apub_id_valid(
allowed.push(local_instance); allowed.push(local_instance);
if !allowed.contains(&domain) { if !allowed.contains(&domain) {
return Err(anyhow!("{} not in federation allowlist", domain).into()); let error = LemmyError::from(anyhow::anyhow!("{} not in federation allowlist", domain));
return Err(error.with_message("federation_not_allowed"));
} }
} }
} }
@ -163,6 +170,7 @@ fn generate_moderators_url(community_id: &DbUrl) -> Result<DbUrl, LemmyError> {
/// Store a sent or received activity in the database, for logging purposes. These records are not /// Store a sent or received activity in the database, for logging purposes. These records are not
/// persistent. /// persistent.
#[tracing::instrument(skip(pool))]
async fn insert_activity( async fn insert_activity(
ap_id: &Url, ap_id: &Url,
activity: serde_json::Value, activity: serde_json::Value,

View file

@ -34,6 +34,7 @@ pub struct MentionsAndAddresses {
/// This takes a comment, and builds a list of to_addresses, inboxes, /// This takes a comment, and builds a list of to_addresses, inboxes,
/// and mention tags, so they know where to be sent to. /// and mention tags, so they know where to be sent to.
/// Addresses are the persons / addresses that go in the cc field. /// Addresses are the persons / addresses that go in the cc field.
#[tracing::instrument(skip(comment, community_id, context))]
pub async fn collect_non_local_mentions( pub async fn collect_non_local_mentions(
comment: &ApubComment, comment: &ApubComment,
community_id: ObjectId<ApubCommunity>, community_id: ObjectId<ApubCommunity>,
@ -88,6 +89,7 @@ pub async fn collect_non_local_mentions(
/// Returns the apub ID of the person this comment is responding to. Meaning, in case this is a /// Returns the apub ID of the person this comment is responding to. Meaning, in case this is a
/// top-level comment, the creator of the post, otherwise the creator of the parent comment. /// top-level comment, the creator of the post, otherwise the creator of the parent comment.
#[tracing::instrument(skip(pool, comment))]
async fn get_comment_parent_creator( async fn get_comment_parent_creator(
pool: &DbPool, pool: &DbPool,
comment: &Comment, comment: &Comment,

View file

@ -12,7 +12,6 @@ use crate::{
PostOrComment, PostOrComment,
}; };
use activitystreams_kinds::{object::NoteType, public}; use activitystreams_kinds::{object::NoteType, public};
use anyhow::anyhow;
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use html2md::parse_html; use html2md::parse_html;
use lemmy_api_common::blocking; use lemmy_api_common::blocking;
@ -65,6 +64,7 @@ impl ApubObject for ApubComment {
None None
} }
#[tracing::instrument(skip_all)]
async fn read_from_apub_id( async fn read_from_apub_id(
object_id: Url, object_id: Url,
context: &LemmyContext, context: &LemmyContext,
@ -78,6 +78,7 @@ impl ApubObject for ApubComment {
) )
} }
#[tracing::instrument(skip_all)]
async fn delete(self, context: &LemmyContext) -> Result<(), LemmyError> { async fn delete(self, context: &LemmyContext) -> Result<(), LemmyError> {
if !self.deleted { if !self.deleted {
blocking(context.pool(), move |conn| { blocking(context.pool(), move |conn| {
@ -88,6 +89,7 @@ impl ApubObject for ApubComment {
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn into_apub(self, context: &LemmyContext) -> Result<Note, LemmyError> { async fn into_apub(self, context: &LemmyContext) -> Result<Note, LemmyError> {
let creator_id = self.creator_id; let creator_id = self.creator_id;
let creator = blocking(context.pool(), move |conn| Person::read(conn, creator_id)).await??; let creator = blocking(context.pool(), move |conn| Person::read(conn, creator_id)).await??;
@ -136,6 +138,7 @@ impl ApubObject for ApubComment {
Ok(Tombstone::new(self.ap_id.clone().into())) Ok(Tombstone::new(self.ap_id.clone().into()))
} }
#[tracing::instrument(skip_all)]
async fn verify( async fn verify(
note: &Note, note: &Note,
expected_domain: &Url, expected_domain: &Url,
@ -160,7 +163,7 @@ impl ApubObject for ApubComment {
) )
.await?; .await?;
if post.locked { if post.locked {
return Err(anyhow!("Post is locked").into()); return Err(LemmyError::from_message("Post is locked"));
} }
Ok(()) Ok(())
} }
@ -168,6 +171,7 @@ impl ApubObject for ApubComment {
/// Converts a `Note` to `Comment`. /// Converts a `Note` to `Comment`.
/// ///
/// If the parent community, post and comment(s) are not known locally, these are also fetched. /// If the parent community, post and comment(s) are not known locally, these are also fetched.
#[tracing::instrument(skip_all)]
async fn from_apub( async fn from_apub(
note: Note, note: Note,
context: &LemmyContext, context: &LemmyContext,

View file

@ -55,6 +55,7 @@ impl ApubObject for ApubCommunity {
Some(self.last_refreshed_at) Some(self.last_refreshed_at)
} }
#[tracing::instrument(skip_all)]
async fn read_from_apub_id( async fn read_from_apub_id(
object_id: Url, object_id: Url,
context: &LemmyContext, context: &LemmyContext,
@ -68,6 +69,7 @@ impl ApubObject for ApubCommunity {
) )
} }
#[tracing::instrument(skip_all)]
async fn delete(self, context: &LemmyContext) -> Result<(), LemmyError> { async fn delete(self, context: &LemmyContext) -> Result<(), LemmyError> {
blocking(context.pool(), move |conn| { blocking(context.pool(), move |conn| {
Community::update_deleted(conn, self.id, true) Community::update_deleted(conn, self.id, true)
@ -76,6 +78,7 @@ impl ApubObject for ApubCommunity {
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn into_apub(self, _context: &LemmyContext) -> Result<Group, LemmyError> { async fn into_apub(self, _context: &LemmyContext) -> Result<Group, LemmyError> {
let source = self.description.clone().map(|bio| Source { let source = self.description.clone().map(|bio| Source {
content: bio, content: bio,
@ -115,6 +118,7 @@ impl ApubObject for ApubCommunity {
Ok(Tombstone::new(self.actor_id())) Ok(Tombstone::new(self.actor_id()))
} }
#[tracing::instrument(skip_all)]
async fn verify( async fn verify(
group: &Group, group: &Group,
expected_domain: &Url, expected_domain: &Url,
@ -125,6 +129,7 @@ impl ApubObject for ApubCommunity {
} }
/// Converts a `Group` to `Community`, inserts it into the database and updates moderators. /// Converts a `Group` to `Community`, inserts it into the database and updates moderators.
#[tracing::instrument(skip_all)]
async fn from_apub( async fn from_apub(
group: Group, group: Group,
context: &LemmyContext, context: &LemmyContext,
@ -181,6 +186,7 @@ impl ActorType for ApubCommunity {
impl ApubCommunity { impl ApubCommunity {
/// For a given community, returns the inboxes of all followers. /// For a given community, returns the inboxes of all followers.
#[tracing::instrument(skip_all)]
pub(crate) async fn get_follower_inboxes( pub(crate) async fn get_follower_inboxes(
&self, &self,
context: &LemmyContext, context: &LemmyContext,

View file

@ -57,6 +57,7 @@ impl ApubObject for ApubPerson {
Some(self.last_refreshed_at) Some(self.last_refreshed_at)
} }
#[tracing::instrument(skip_all)]
async fn read_from_apub_id( async fn read_from_apub_id(
object_id: Url, object_id: Url,
context: &LemmyContext, context: &LemmyContext,
@ -70,6 +71,7 @@ impl ApubObject for ApubPerson {
) )
} }
#[tracing::instrument(skip_all)]
async fn delete(self, context: &LemmyContext) -> Result<(), LemmyError> { async fn delete(self, context: &LemmyContext) -> Result<(), LemmyError> {
blocking(context.pool(), move |conn| { blocking(context.pool(), move |conn| {
DbPerson::update_deleted(conn, self.id, true) DbPerson::update_deleted(conn, self.id, true)
@ -78,6 +80,7 @@ impl ApubObject for ApubPerson {
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn into_apub(self, _pool: &LemmyContext) -> Result<Person, LemmyError> { async fn into_apub(self, _pool: &LemmyContext) -> Result<Person, LemmyError> {
let kind = if self.bot_account { let kind = if self.bot_account {
UserTypes::Service UserTypes::Service
@ -118,6 +121,7 @@ impl ApubObject for ApubPerson {
unimplemented!() unimplemented!()
} }
#[tracing::instrument(skip_all)]
async fn verify( async fn verify(
person: &Person, person: &Person,
expected_domain: &Url, expected_domain: &Url,
@ -135,6 +139,7 @@ impl ApubObject for ApubPerson {
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn from_apub( async fn from_apub(
person: Person, person: Person,
context: &LemmyContext, context: &LemmyContext,

View file

@ -60,6 +60,7 @@ impl ApubObject for ApubPost {
None None
} }
#[tracing::instrument(skip_all)]
async fn read_from_apub_id( async fn read_from_apub_id(
object_id: Url, object_id: Url,
context: &LemmyContext, context: &LemmyContext,
@ -73,6 +74,7 @@ impl ApubObject for ApubPost {
) )
} }
#[tracing::instrument(skip_all)]
async fn delete(self, context: &LemmyContext) -> Result<(), LemmyError> { async fn delete(self, context: &LemmyContext) -> Result<(), LemmyError> {
if !self.deleted { if !self.deleted {
blocking(context.pool(), move |conn| { blocking(context.pool(), move |conn| {
@ -84,6 +86,7 @@ impl ApubObject for ApubPost {
} }
// Turn a Lemmy post into an ActivityPub page that can be sent out over the network. // Turn a Lemmy post into an ActivityPub page that can be sent out over the network.
#[tracing::instrument(skip_all)]
async fn into_apub(self, context: &LemmyContext) -> Result<Page, LemmyError> { async fn into_apub(self, context: &LemmyContext) -> Result<Page, LemmyError> {
let creator_id = self.creator_id; let creator_id = self.creator_id;
let creator = blocking(context.pool(), move |conn| Person::read(conn, creator_id)).await??; let creator = blocking(context.pool(), move |conn| Person::read(conn, creator_id)).await??;
@ -125,6 +128,7 @@ impl ApubObject for ApubPost {
Ok(Tombstone::new(self.ap_id.clone().into())) Ok(Tombstone::new(self.ap_id.clone().into()))
} }
#[tracing::instrument(skip_all)]
async fn verify( async fn verify(
page: &Page, page: &Page,
expected_domain: &Url, expected_domain: &Url,
@ -146,6 +150,7 @@ impl ApubObject for ApubPost {
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn from_apub( async fn from_apub(
page: Page, page: Page,
context: &LemmyContext, context: &LemmyContext,

View file

@ -2,7 +2,6 @@ use crate::protocol::{
objects::chat_message::{ChatMessage, ChatMessageType}, objects::chat_message::{ChatMessage, ChatMessageType},
Source, Source,
}; };
use anyhow::anyhow;
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use html2md::parse_html; use html2md::parse_html;
use lemmy_api_common::blocking; use lemmy_api_common::blocking;
@ -53,6 +52,7 @@ impl ApubObject for ApubPrivateMessage {
None None
} }
#[tracing::instrument(skip_all)]
async fn read_from_apub_id( async fn read_from_apub_id(
object_id: Url, object_id: Url,
context: &LemmyContext, context: &LemmyContext,
@ -71,6 +71,7 @@ impl ApubObject for ApubPrivateMessage {
unimplemented!() unimplemented!()
} }
#[tracing::instrument(skip_all)]
async fn into_apub(self, context: &LemmyContext) -> Result<ChatMessage, LemmyError> { async fn into_apub(self, context: &LemmyContext) -> Result<ChatMessage, LemmyError> {
let creator_id = self.creator_id; let creator_id = self.creator_id;
let creator = blocking(context.pool(), move |conn| Person::read(conn, creator_id)).await??; let creator = blocking(context.pool(), move |conn| Person::read(conn, creator_id)).await??;
@ -101,6 +102,7 @@ impl ApubObject for ApubPrivateMessage {
unimplemented!() unimplemented!()
} }
#[tracing::instrument(skip_all)]
async fn verify( async fn verify(
note: &ChatMessage, note: &ChatMessage,
expected_domain: &Url, expected_domain: &Url,
@ -114,11 +116,12 @@ impl ApubObject for ApubPrivateMessage {
.dereference(context, request_counter) .dereference(context, request_counter)
.await?; .await?;
if person.banned { if person.banned {
return Err(anyhow!("Person is banned from site").into()); return Err(LemmyError::from_message("Person is banned from site"));
} }
Ok(()) Ok(())
} }
#[tracing::instrument(skip_all)]
async fn from_apub( async fn from_apub(
note: ChatMessage, note: ChatMessage,
context: &LemmyContext, context: &LemmyContext,

View file

@ -3,7 +3,6 @@ use crate::{
objects::person::ApubPerson, objects::person::ApubPerson,
protocol::Unparsed, protocol::Unparsed,
}; };
use anyhow::anyhow;
use lemmy_apub_lib::object_id::ObjectId; use lemmy_apub_lib::object_id::ObjectId;
use lemmy_utils::LemmyError; use lemmy_utils::LemmyError;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -40,7 +39,7 @@ impl TryFrom<i16> for VoteType {
match value { match value {
1 => Ok(VoteType::Like), 1 => Ok(VoteType::Like),
-1 => Ok(VoteType::Dislike), -1 => Ok(VoteType::Dislike),
_ => Err(anyhow!("invalid vote value").into()), _ => Err(LemmyError::from_message("invalid vote value")),
} }
} }
} }

View file

@ -3,7 +3,6 @@ use crate::{
protocol::{ImageObject, Source, Unparsed}, protocol::{ImageObject, Source, Unparsed},
}; };
use activitystreams_kinds::object::PageType; use activitystreams_kinds::object::PageType;
use anyhow::anyhow;
use chrono::{DateTime, FixedOffset}; use chrono::{DateTime, FixedOffset};
use lemmy_apub_lib::{ use lemmy_apub_lib::{
data::Data, data::Data,
@ -75,7 +74,7 @@ impl Page {
break Ok(c); break Ok(c);
} }
} else { } else {
return Err(anyhow!("No community found in cc").into()); return Err(LemmyError::from_message("No community found in cc"));
} }
} }
} }

View file

@ -21,7 +21,7 @@ pub type DbPool = diesel::r2d2::Pool<diesel::r2d2::ConnectionManager<diesel::PgC
use crate::newtypes::DbUrl; use crate::newtypes::DbUrl;
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use diesel::{Connection, PgConnection}; use diesel::{Connection, PgConnection};
use lemmy_utils::ApiError; use lemmy_utils::LemmyError;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use regex::Regex; use regex::Regex;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -100,13 +100,13 @@ pub fn diesel_option_overwrite(opt: &Option<String>) -> Option<Option<String>> {
pub fn diesel_option_overwrite_to_url( pub fn diesel_option_overwrite_to_url(
opt: &Option<String>, opt: &Option<String>,
) -> Result<Option<Option<DbUrl>>, ApiError> { ) -> Result<Option<Option<DbUrl>>, LemmyError> {
match opt.as_ref().map(|s| s.as_str()) { match opt.as_ref().map(|s| s.as_str()) {
// An empty string is an erase // An empty string is an erase
Some("") => Ok(Some(None)), Some("") => Ok(Some(None)),
Some(str_url) => match Url::parse(str_url) { Some(str_url) => match Url::parse(str_url) {
Ok(url) => Ok(Some(Some(url.into()))), 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")),
}, },
None => Ok(None), None => Ok(None),
} }

View file

@ -32,3 +32,4 @@ awc = { version = "3.0.0-beta.8", default-features = false }
url = { version = "2.2.2", features = ["serde"] } url = { version = "2.2.2", features = ["serde"] }
strum = "0.21.0" strum = "0.21.0"
once_cell = "1.8.0" once_cell = "1.8.0"
tracing = "0.1.29"

View file

@ -58,6 +58,7 @@ static RSS_NAMESPACE: Lazy<HashMap<String, String>> = Lazy::new(|| {
h h
}); });
#[tracing::instrument(skip_all)]
async fn get_all_feed( async fn get_all_feed(
info: web::Query<Params>, info: web::Query<Params>,
context: web::Data<LemmyContext>, context: web::Data<LemmyContext>,
@ -66,6 +67,7 @@ async fn get_all_feed(
Ok(get_feed_data(&context, ListingType::All, sort_type).await?) Ok(get_feed_data(&context, ListingType::All, sort_type).await?)
} }
#[tracing::instrument(skip_all)]
async fn get_local_feed( async fn get_local_feed(
info: web::Query<Params>, info: web::Query<Params>,
context: web::Data<LemmyContext>, context: web::Data<LemmyContext>,
@ -74,6 +76,7 @@ async fn get_local_feed(
Ok(get_feed_data(&context, ListingType::Local, sort_type).await?) Ok(get_feed_data(&context, ListingType::Local, sort_type).await?)
} }
#[tracing::instrument(skip_all)]
async fn get_feed_data( async fn get_feed_data(
context: &LemmyContext, context: &LemmyContext,
listing_type: ListingType, listing_type: ListingType,
@ -114,6 +117,7 @@ async fn get_feed_data(
) )
} }
#[tracing::instrument(skip_all)]
async fn get_feed( async fn get_feed(
req: HttpRequest, req: HttpRequest,
info: web::Query<Params>, info: web::Query<Params>,
@ -167,6 +171,7 @@ fn get_sort_type(info: web::Query<Params>) -> Result<SortType, ParseError> {
SortType::from_str(&sort_query) SortType::from_str(&sort_query)
} }
#[tracing::instrument(skip_all)]
fn get_feed_user( fn get_feed_user(
conn: &PgConnection, conn: &PgConnection,
sort_type: &SortType, sort_type: &SortType,
@ -194,6 +199,7 @@ fn get_feed_user(
Ok(channel_builder) Ok(channel_builder)
} }
#[tracing::instrument(skip_all)]
fn get_feed_community( fn get_feed_community(
conn: &PgConnection, conn: &PgConnection,
sort_type: &SortType, sort_type: &SortType,
@ -225,6 +231,7 @@ fn get_feed_community(
Ok(channel_builder) Ok(channel_builder)
} }
#[tracing::instrument(skip_all)]
fn get_feed_front( fn get_feed_front(
conn: &PgConnection, conn: &PgConnection,
jwt_secret: &str, jwt_secret: &str,
@ -260,6 +267,7 @@ fn get_feed_front(
Ok(channel_builder) Ok(channel_builder)
} }
#[tracing::instrument(skip_all)]
fn get_feed_inbox( fn get_feed_inbox(
conn: &PgConnection, conn: &PgConnection,
jwt_secret: &str, jwt_secret: &str,
@ -303,6 +311,7 @@ fn get_feed_inbox(
Ok(channel_builder) Ok(channel_builder)
} }
#[tracing::instrument(skip_all)]
fn create_reply_and_mention_items( fn create_reply_and_mention_items(
replies: Vec<CommentView>, replies: Vec<CommentView>,
mentions: Vec<PersonMentionView>, mentions: Vec<PersonMentionView>,
@ -346,6 +355,7 @@ fn create_reply_and_mention_items(
Ok(reply_items) Ok(reply_items)
} }
#[tracing::instrument(skip_all)]
fn build_item( fn build_item(
creator_name: &str, creator_name: &str,
published: &NaiveDateTime, published: &NaiveDateTime,
@ -376,6 +386,7 @@ fn build_item(
Ok(i.build().map_err(|e| anyhow!(e))?) Ok(i.build().map_err(|e| anyhow!(e))?)
} }
#[tracing::instrument(skip_all)]
fn create_post_items( fn create_post_items(
posts: Vec<PostView>, posts: Vec<PostView>,
protocol_and_hostname: &str, protocol_and_hostname: &str,

View file

@ -15,10 +15,13 @@ mod test;
pub mod utils; pub mod utils;
pub mod version; pub mod version;
mod sensitive;
pub use sensitive::Sensitive;
use actix_web::HttpResponse;
use http::StatusCode; use http::StatusCode;
use std::{fmt, fmt::Display}; use std::{fmt, fmt::Display};
use thiserror::Error;
use tracing::warn;
use tracing_error::SpanTrace; use tracing_error::SpanTrace;
pub type ConnectionId = usize; pub type ConnectionId = usize;
@ -44,47 +47,71 @@ macro_rules! location_info {
}; };
} }
#[derive(Debug, Error)] #[derive(serde::Serialize)]
#[error("{{\"error\":\"{message}\"}}")] struct ApiError {
pub struct ApiError { error: &'static str,
message: String,
} }
impl ApiError {
pub fn err_plain(msg: &str) -> Self {
ApiError {
message: msg.to_string(),
}
}
pub fn err<E: Display>(msg: &str, original_error: E) -> Self {
warn!("{}", original_error);
ApiError {
message: msg.to_string(),
}
}
}
#[derive(Debug)]
pub struct LemmyError { pub struct LemmyError {
pub message: Option<&'static str>,
pub inner: anyhow::Error, pub inner: anyhow::Error,
pub context: SpanTrace, pub context: SpanTrace,
} }
impl LemmyError {
pub fn from_message(message: &'static str) -> Self {
let inner = anyhow::anyhow!("{}", message);
LemmyError {
message: Some(message),
inner,
context: SpanTrace::capture(),
}
}
pub fn with_message(self, message: &'static str) -> Self {
LemmyError {
message: Some(message),
..self
}
}
pub fn to_json(&self) -> Result<String, Self> {
let api_error = match self.message {
Some(error) => ApiError { error },
None => ApiError { error: "Unknown" },
};
Ok(serde_json::to_string(&api_error)?)
}
}
impl<T> From<T> for LemmyError impl<T> From<T> for LemmyError
where where
T: Into<anyhow::Error>, T: Into<anyhow::Error>,
{ {
fn from(t: T) -> Self { fn from(t: T) -> Self {
LemmyError { LemmyError {
message: None,
inner: t.into(), inner: t.into(),
context: SpanTrace::capture(), context: SpanTrace::capture(),
} }
} }
} }
impl std::fmt::Debug for LemmyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("LemmyError")
.field("message", &self.message)
.field("inner", &self.inner)
.field("context", &"SpanTrace")
.finish()
}
}
impl Display for LemmyError { impl Display for LemmyError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
self.inner.fmt(f)?; if let Some(message) = self.message {
write!(f, "{}: ", message)?;
}
writeln!(f, "{}", self.inner)?;
self.context.fmt(f) self.context.fmt(f)
} }
} }
@ -93,7 +120,17 @@ impl actix_web::error::ResponseError for LemmyError {
fn status_code(&self) -> StatusCode { fn status_code(&self) -> StatusCode {
match self.inner.downcast_ref::<diesel::result::Error>() { match self.inner.downcast_ref::<diesel::result::Error>() {
Some(diesel::result::Error::NotFound) => StatusCode::NOT_FOUND, 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 })
} else {
HttpResponse::build(self.status_code())
.content_type("text/plain")
.body(self.inner.to_string())
} }
} }
} }

View file

@ -1,4 +1,4 @@
use crate::{ApiError, IpAddr, LemmyError}; use crate::{IpAddr, LemmyError};
use std::{collections::HashMap, time::SystemTime}; use std::{collections::HashMap, time::SystemTime};
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
use tracing::debug; use tracing::debug;
@ -79,18 +79,14 @@ impl RateLimiter {
time_passed, time_passed,
rate_limit.allowance rate_limit.allowance
); );
Err( let error = LemmyError::from(anyhow::anyhow!(
ApiError { "Too many requests. type: {}, IP: {}, {} per {} seconds",
message: format!( type_.as_ref(),
"Too many requests. type: {}, IP: {}, {} per {} seconds", ip,
type_.as_ref(), rate,
ip, per
rate, ));
per Err(error.with_message("too_many_requests"))
),
}
.into(),
)
} else { } else {
if !check_only { if !check_only {
rate_limit.allowance -= 1.0; rate_limit.allowance -= 1.0;

View file

@ -0,0 +1,98 @@
use std::{
borrow::Borrow,
ops::{Deref, DerefMut},
};
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Deserialize, serde::Serialize)]
#[serde(transparent)]
pub struct Sensitive<T>(T);
impl<T> Sensitive<T> {
pub fn new(item: T) -> Self {
Sensitive(item)
}
pub fn into_inner(this: Self) -> T {
this.0
}
}
impl<T> std::fmt::Debug for Sensitive<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Sensitive").finish()
}
}
impl<T> AsRef<T> for Sensitive<T> {
fn as_ref(&self) -> &T {
&self.0
}
}
impl AsRef<str> for Sensitive<String> {
fn as_ref(&self) -> &str {
&self.0
}
}
impl AsRef<[u8]> for Sensitive<String> {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
impl AsRef<[u8]> for Sensitive<Vec<u8>> {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
impl<T> AsMut<T> for Sensitive<T> {
fn as_mut(&mut self) -> &mut T {
&mut self.0
}
}
impl AsMut<str> for Sensitive<String> {
fn as_mut(&mut self) -> &mut str {
&mut self.0
}
}
impl Deref for Sensitive<String> {
type Target = str;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Sensitive<String> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<T> From<T> for Sensitive<T> {
fn from(t: T) -> Self {
Sensitive(t)
}
}
impl From<&str> for Sensitive<String> {
fn from(s: &str) -> Self {
Sensitive(s.into())
}
}
impl<T> Borrow<T> for Sensitive<T> {
fn borrow(&self) -> &T {
&self.0
}
}
impl Borrow<str> for Sensitive<String> {
fn borrow(&self) -> &str {
&self.0
}
}

View file

@ -1,4 +1,4 @@
use crate::{ApiError, IpAddr}; use crate::{IpAddr, LemmyError};
use actix_web::dev::ConnectionInfo; use actix_web::dev::ConnectionInfo;
use chrono::{DateTime, FixedOffset, NaiveDateTime}; use chrono::{DateTime, FixedOffset, NaiveDateTime};
use itertools::Itertools; use itertools::Itertools;
@ -60,15 +60,19 @@ pub(crate) fn slur_check<'a>(
} }
} }
pub fn check_slurs(text: &str, slur_regex: &Option<Regex>) -> Result<(), ApiError> { pub fn check_slurs(text: &str, slur_regex: &Option<Regex>) -> Result<(), LemmyError> {
if let Err(slurs) = slur_check(text, slur_regex) { if let Err(slurs) = slur_check(text, slur_regex) {
Err(ApiError::err_plain(&slurs_vec_to_str(slurs))) let error = LemmyError::from(anyhow::anyhow!("{}", slurs_vec_to_str(slurs)));
Err(error.with_message("slurs"))
} else { } else {
Ok(()) Ok(())
} }
} }
pub fn check_slurs_opt(text: &Option<String>, slur_regex: &Option<Regex>) -> Result<(), ApiError> { pub fn check_slurs_opt(
text: &Option<String>,
slur_regex: &Option<Regex>,
) -> Result<(), LemmyError> {
match text { match text {
Some(t) => check_slurs(t, slur_regex), Some(t) => check_slurs(t, slur_regex),
None => Ok(()), None => Ok(()),

View file

@ -22,7 +22,6 @@ use lemmy_utils::{
location_info, location_info,
rate_limit::RateLimit, rate_limit::RateLimit,
settings::structs::Settings, settings::structs::Settings,
ApiError,
ConnectionId, ConnectionId,
IpAddr, IpAddr,
LemmyError, LemmyError,
@ -477,7 +476,7 @@ impl ChatServer {
let data = &json["data"].to_string(); let data = &json["data"].to_string();
let op = &json["op"] let op = &json["op"]
.as_str() .as_str()
.ok_or_else(|| ApiError::err_plain("missing op"))?; .ok_or_else(|| LemmyError::from_message("missing op"))?;
if let Ok(user_operation_crud) = UserOperationCrud::from_str(op) { if let Ok(user_operation_crud) = UserOperationCrud::from_str(op) {
let fut = (message_handler_crud)(context, msg.id, user_operation_crud.clone(), data); let fut = (message_handler_crud)(context, msg.id, user_operation_crud.clone(), data);

View file

@ -76,7 +76,10 @@ impl Handler<StandardMessage> for ChatServer {
} }
Err(e) => { Err(e) => {
error!("Error during message handling {}", e); error!("Error during message handling {}", e);
Ok(e.to_string()) Ok(
e.to_json()
.unwrap_or_else(|_| String::from(r#"{"error":"failed to serialize json"}"#)),
)
} }
} }
}) })

View file

@ -115,7 +115,6 @@ impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for WsSession {
} }
ws::Message::Text(text) => { ws::Message::Text(text) => {
let m = text.trim().to_owned(); let m = text.trim().to_owned();
info!("Message received: {:?} from id: {}", &m, self.id);
self self
.cs_addr .cs_addr

View file

@ -1,4 +1,4 @@
use actix_web::{error::ErrorBadRequest, *}; use actix_web::*;
use lemmy_api::Perform; use lemmy_api::Perform;
use lemmy_api_common::{comment::*, community::*, person::*, post::*, site::*, websocket::*}; use lemmy_api_common::{comment::*, community::*, person::*, post::*, site::*, websocket::*};
use lemmy_api_crud::PerformCrud; use lemmy_api_crud::PerformCrud;
@ -232,8 +232,7 @@ where
let res = data let res = data
.perform(&context, None) .perform(&context, None)
.await .await
.map(|json| HttpResponse::Ok().json(json)) .map(|json| HttpResponse::Ok().json(json))?;
.map_err(ErrorBadRequest)?;
Ok(res) Ok(res)
} }
@ -268,8 +267,7 @@ where
let res = data let res = data
.perform(&context, None) .perform(&context, None)
.await .await
.map(|json| HttpResponse::Ok().json(json)) .map(|json| HttpResponse::Ok().json(json))?;
.map_err(ErrorBadRequest)?;
Ok(res) Ok(res)
} }

View file

@ -1,21 +1,20 @@
#![recursion_limit = "512"] #![recursion_limit = "512"]
pub mod api_routes; pub mod api_routes;
pub mod code_migrations; pub mod code_migrations;
pub mod root_span_builder;
pub mod scheduled_tasks; pub mod scheduled_tasks;
use lemmy_utils::LemmyError; use lemmy_utils::LemmyError;
use tracing::subscriber::set_global_default; use tracing::subscriber::set_global_default;
use tracing_error::ErrorLayer; use tracing_error::ErrorLayer;
use tracing_log::LogTracer; use tracing_log::LogTracer;
use tracing_subscriber::{fmt::format::FmtSpan, layer::SubscriberExt, EnvFilter, Registry}; use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Registry};
pub fn init_tracing() -> Result<(), LemmyError> { pub fn init_tracing() -> Result<(), LemmyError> {
LogTracer::init()?; LogTracer::init()?;
let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")); let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
let format_layer = tracing_subscriber::fmt::layer() let format_layer = tracing_subscriber::fmt::layer();
.with_span_events(FmtSpan::NEW | FmtSpan::CLOSE)
.pretty();
let subscriber = Registry::default() let subscriber = Registry::default()
.with(env_filter) .with(env_filter)

View file

@ -18,6 +18,7 @@ use lemmy_server::{
api_routes, api_routes,
code_migrations::run_advanced_migrations, code_migrations::run_advanced_migrations,
init_tracing, init_tracing,
root_span_builder::QuieterRootSpanBuilder,
scheduled_tasks, scheduled_tasks,
}; };
use lemmy_utils::{ use lemmy_utils::{
@ -123,7 +124,8 @@ async fn main() -> Result<(), LemmyError> {
); );
let rate_limiter = rate_limiter.clone(); let rate_limiter = rate_limiter.clone();
App::new() App::new()
.wrap(TracingLogger::default()) .wrap(actix_web::middleware::Logger::default())
.wrap(TracingLogger::<QuieterRootSpanBuilder>::new())
.app_data(Data::new(context)) .app_data(Data::new(context))
// The routes // The routes
.configure(|cfg| api_routes::config(cfg, &rate_limiter)) .configure(|cfg| api_routes::config(cfg, &rate_limiter))

Some files were not shown because too many files have changed in this diff Show more