diff --git a/crates/apub/src/activities/block/block_user.rs b/crates/apub/src/activities/block/block_user.rs index e291cc4a41..64d5e7816a 100644 --- a/crates/apub/src/activities/block/block_user.rs +++ b/crates/apub/src/activities/block/block_user.rs @@ -39,10 +39,7 @@ use lemmy_db_schema::{ }, traits::{Bannable, Crud, Followable}, }; -use lemmy_utils::{ - error::{LemmyError, LemmyResult}, - LemmyErrorType, -}; +use lemmy_utils::error::{FederationError, LemmyError, LemmyResult}; use url::Url; impl BlockUser { @@ -135,7 +132,7 @@ impl ActivityHandler for BlockUser { .object .inner() .domain() - .ok_or(LemmyErrorType::UrlWithoutDomain)?; + .ok_or(FederationError::UrlWithoutDomain)?; if context.settings().hostname == domain { return Err( anyhow!("Site bans from remote instance can't affect user's home instance").into(), diff --git a/crates/apub/src/activities/community/announce.rs b/crates/apub/src/activities/community/announce.rs index 0a506a7915..e374d28747 100644 --- a/crates/apub/src/activities/community/announce.rs +++ b/crates/apub/src/activities/community/announce.rs @@ -26,7 +26,7 @@ use lemmy_db_schema::{ source::{activity::ActivitySendTargets, community::CommunityFollower}, CommunityVisibility, }; -use lemmy_utils::error::{LemmyError, LemmyErrorType, LemmyResult}; +use lemmy_utils::error::{FederationError, LemmyError, LemmyErrorType, LemmyResult}; use serde_json::Value; use url::Url; @@ -54,7 +54,7 @@ impl ActivityHandler for RawAnnouncableActivities { // This is only for sending, not receiving so we reject it. if let AnnouncableActivities::Page(_) = activity { - Err(LemmyErrorType::CannotReceivePage)? + Err(FederationError::CannotReceivePage)? } // Need to treat community as optional here because `Delete/PrivateMessage` gets routed through @@ -165,7 +165,7 @@ impl ActivityHandler for AnnounceActivity { // This is only for sending, not receiving so we reject it. if let AnnouncableActivities::Page(_) = object { - Err(LemmyErrorType::CannotReceivePage)? + Err(FederationError::CannotReceivePage)? } let community = object.community(context).await?; diff --git a/crates/apub/src/activities/deletion/delete.rs b/crates/apub/src/activities/deletion/delete.rs index ec2a0de951..1ddf642b96 100644 --- a/crates/apub/src/activities/deletion/delete.rs +++ b/crates/apub/src/activities/deletion/delete.rs @@ -27,7 +27,7 @@ use lemmy_db_schema::{ }, traits::{Crud, Reportable}, }; -use lemmy_utils::error::{LemmyError, LemmyErrorType, LemmyResult}; +use lemmy_utils::error::{FederationError, LemmyError, LemmyErrorType, LemmyResult}; use url::Url; #[async_trait::async_trait] @@ -118,7 +118,7 @@ pub(in crate::activities) async fn receive_remove_action( match DeletableObjects::read_from_db(object, context).await? { DeletableObjects::Community(community) => { if community.local { - Err(LemmyErrorType::OnlyLocalAdminCanRemoveCommunity)? + Err(FederationError::OnlyLocalAdminCanRemoveCommunity)? } let form = ModRemoveCommunityForm { mod_person_id: actor.id, diff --git a/crates/apub/src/activities/deletion/undo_delete.rs b/crates/apub/src/activities/deletion/undo_delete.rs index 102c726783..6328bb4278 100644 --- a/crates/apub/src/activities/deletion/undo_delete.rs +++ b/crates/apub/src/activities/deletion/undo_delete.rs @@ -25,7 +25,7 @@ use lemmy_db_schema::{ }, traits::Crud, }; -use lemmy_utils::error::{LemmyError, LemmyErrorType, LemmyResult}; +use lemmy_utils::error::{FederationError, LemmyError, LemmyErrorType, LemmyResult}; use url::Url; #[async_trait::async_trait] @@ -100,7 +100,7 @@ impl UndoDelete { match DeletableObjects::read_from_db(object, context).await? { DeletableObjects::Community(community) => { if community.local { - Err(LemmyErrorType::OnlyLocalAdminCanRestoreCommunity)? + Err(FederationError::OnlyLocalAdminCanRestoreCommunity)? } let form = ModRemoveCommunityForm { mod_person_id: actor.id, diff --git a/crates/apub/src/activities/mod.rs b/crates/apub/src/activities/mod.rs index 2c371f71c8..21723c3909 100644 --- a/crates/apub/src/activities/mod.rs +++ b/crates/apub/src/activities/mod.rs @@ -42,7 +42,7 @@ use lemmy_db_schema::{ traits::Crud, }; use lemmy_db_views_actor::structs::{CommunityPersonBanView, CommunityView}; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType, LemmyResult}; +use lemmy_utils::error::{FederationError, LemmyError, LemmyErrorExt, LemmyErrorType, LemmyResult}; use serde::Serialize; use tracing::info; use url::{ParseError, Url}; @@ -81,7 +81,7 @@ pub(crate) async fn verify_person_in_community( ) -> LemmyResult<()> { let person = person_id.dereference(context).await?; if person.banned { - Err(LemmyErrorType::PersonIsBannedFromSite( + Err(FederationError::PersonIsBannedFromSite( person.actor_id.to_string(), ))? } @@ -114,7 +114,7 @@ pub(crate) async fn verify_mod_action( pub(crate) fn verify_is_public(to: &[Url], cc: &[Url]) -> LemmyResult<()> { if ![to, cc].iter().any(|set| set.contains(&public())) { - Err(LemmyErrorType::ObjectIsNotPublic)? + Err(FederationError::ObjectIsNotPublic)? } else { Ok(()) } @@ -126,7 +126,7 @@ where { let b: ObjectId = b.into(); if a != &b { - Err(LemmyErrorType::InvalidCommunity)? + Err(FederationError::InvalidCommunity)? } else { Ok(()) } @@ -134,7 +134,7 @@ where pub(crate) fn check_community_deleted_or_removed(community: &Community) -> LemmyResult<()> { if community.deleted || community.removed { - Err(LemmyErrorType::CannotCreatePostOrCommentInDeletedOrRemovedCommunity)? + Err(FederationError::CannotCreatePostOrCommentInDeletedOrRemovedCommunity)? } else { Ok(()) } diff --git a/crates/apub/src/fetcher/post_or_comment.rs b/crates/apub/src/fetcher/post_or_comment.rs index 8502ffb1a8..be48e8ebd5 100644 --- a/crates/apub/src/fetcher/post_or_comment.rs +++ b/crates/apub/src/fetcher/post_or_comment.rs @@ -26,7 +26,7 @@ pub enum PostOrComment { #[serde(untagged)] pub enum PageOrNote { Page(Box), - Note(Note), + Note(Box), } #[async_trait::async_trait] @@ -61,7 +61,7 @@ impl Object for PostOrComment { async fn into_json(self, data: &Data) -> LemmyResult { Ok(match self { PostOrComment::Post(p) => PageOrNote::Page(Box::new(p.into_json(data).await?)), - PostOrComment::Comment(c) => PageOrNote::Note(c.into_json(data).await?), + PostOrComment::Comment(c) => PageOrNote::Note(Box::new(c.into_json(data).await?)), }) } @@ -81,7 +81,7 @@ impl Object for PostOrComment { async fn from_json(apub: PageOrNote, context: &Data) -> LemmyResult { Ok(match apub { PageOrNote::Page(p) => PostOrComment::Post(ApubPost::from_json(*p, context).await?), - PageOrNote::Note(n) => PostOrComment::Comment(ApubComment::from_json(n, context).await?), + PageOrNote::Note(n) => PostOrComment::Comment(ApubComment::from_json(*n, context).await?), }) } } diff --git a/crates/apub/src/http/mod.rs b/crates/apub/src/http/mod.rs index dad39881f8..bc148eb9c7 100644 --- a/crates/apub/src/http/mod.rs +++ b/crates/apub/src/http/mod.rs @@ -17,7 +17,7 @@ use lemmy_db_schema::{ source::{activity::SentActivity, community::Community}, CommunityVisibility, }; -use lemmy_utils::error::{LemmyErrorType, LemmyResult}; +use lemmy_utils::error::{FederationError, LemmyErrorType, LemmyResult}; use serde::{Deserialize, Serialize}; use std::{ops::Deref, time::Duration}; use tokio::time::timeout; @@ -45,7 +45,7 @@ pub async fn shared_inbox( // consider the activity broken and move on. timeout(INCOMING_ACTIVITY_TIMEOUT, receive_fut) .await - .map_err(|_| LemmyErrorType::InboxTimeout)? + .map_err(|_| FederationError::InboxTimeout)? } /// Convert the data to json and turn it into an HTTP Response with the correct ActivityPub @@ -106,7 +106,9 @@ pub(crate) async fn get_activity( info.id ))? .into(); - let activity = SentActivity::read_from_apub_id(&mut context.pool(), &activity_id).await?; + let activity = SentActivity::read_from_apub_id(&mut context.pool(), &activity_id) + .await + .map_err(|_| FederationError::CouldntFindActivity)?; let sensitive = activity.sensitive; if sensitive { diff --git a/crates/apub/src/lib.rs b/crates/apub/src/lib.rs index c8506da52b..a04aec6552 100644 --- a/crates/apub/src/lib.rs +++ b/crates/apub/src/lib.rs @@ -10,7 +10,7 @@ use lemmy_db_schema::{ utils::{ActualDbPool, DbPool}, }; use lemmy_utils::{ - error::{LemmyError, LemmyErrorType, LemmyResult}, + error::{FederationError, LemmyError, LemmyErrorType, LemmyResult}, CACHE_DURATION_FEDERATION, }; use moka::future::Cache; @@ -51,17 +51,18 @@ impl UrlVerifier for VerifyUrlData { let local_site_data = local_site_data_cached(&mut (&self.0).into()) .await .expect("read local site data"); + use FederationError::*; check_apub_id_valid(url, &local_site_data).map_err(|err| match err { LemmyError { - error_type: LemmyErrorType::FederationDisabled, + error_type: LemmyErrorType::FederationError(Some(FederationDisabled)), .. } => ActivityPubError::Other("Federation disabled".into()), LemmyError { - error_type: LemmyErrorType::DomainBlocked(domain), + error_type: LemmyErrorType::FederationError(Some(DomainBlocked(domain))), .. } => ActivityPubError::Other(format!("Domain {domain:?} is blocked")), LemmyError { - error_type: LemmyErrorType::DomainNotInAllowList(domain), + error_type: LemmyErrorType::FederationError(Some(DomainNotInAllowList(domain))), .. } => ActivityPubError::Other(format!("Domain {domain:?} is not in allowlist")), _ => ActivityPubError::Other("Failed validating apub id".into()), @@ -81,7 +82,7 @@ impl UrlVerifier for VerifyUrlData { fn check_apub_id_valid(apub_id: &Url, local_site_data: &LocalSiteData) -> LemmyResult<()> { let domain = apub_id .domain() - .ok_or(LemmyErrorType::UrlWithoutDomain)? + .ok_or(FederationError::UrlWithoutDomain)? .to_string(); if !local_site_data @@ -90,7 +91,7 @@ fn check_apub_id_valid(apub_id: &Url, local_site_data: &LocalSiteData) -> LemmyR .map(|l| l.federation_enabled) .unwrap_or(true) { - Err(LemmyErrorType::FederationDisabled)? + Err(FederationError::FederationDisabled)? } if local_site_data @@ -98,7 +99,7 @@ fn check_apub_id_valid(apub_id: &Url, local_site_data: &LocalSiteData) -> LemmyR .iter() .any(|i| domain.to_lowercase().eq(&i.domain.to_lowercase())) { - Err(LemmyErrorType::DomainBlocked(domain.clone()))? + Err(FederationError::DomainBlocked(domain.clone()))? } // Only check this if there are instances in the allowlist @@ -108,7 +109,7 @@ fn check_apub_id_valid(apub_id: &Url, local_site_data: &LocalSiteData) -> LemmyR .iter() .any(|i| domain.to_lowercase().eq(&i.domain.to_lowercase())) { - Err(LemmyErrorType::DomainNotInAllowList(domain))? + Err(FederationError::DomainNotInAllowList(domain))? } Ok(()) @@ -164,7 +165,7 @@ pub(crate) async fn check_apub_id_valid_with_strictness( ) -> LemmyResult<()> { let domain = apub_id .domain() - .ok_or(LemmyErrorType::UrlWithoutDomain)? + .ok_or(FederationError::UrlWithoutDomain)? .to_string(); let local_instance = context .settings() @@ -194,10 +195,10 @@ pub(crate) async fn check_apub_id_valid_with_strictness( let domain = apub_id .domain() - .ok_or(LemmyErrorType::UrlWithoutDomain)? + .ok_or(FederationError::UrlWithoutDomain)? .to_string(); if !allowed_and_local.contains(&domain) { - Err(LemmyErrorType::FederationDisabledByStrictAllowList)? + Err(FederationError::FederationDisabledByStrictAllowList)? } } Ok(()) diff --git a/crates/apub/src/mentions.rs b/crates/apub/src/mentions.rs index 6aa1d97fb7..cb46be52a0 100644 --- a/crates/apub/src/mentions.rs +++ b/crates/apub/src/mentions.rs @@ -11,7 +11,10 @@ use lemmy_db_schema::{ traits::Crud, utils::DbPool, }; -use lemmy_utils::{error::LemmyResult, utils::mention::scrape_text_for_mentions, LemmyErrorType}; +use lemmy_utils::{ + error::{FederationError, LemmyResult}, + utils::mention::scrape_text_for_mentions, +}; use serde::{Deserialize, Serialize}; use serde_json::Value; use url::Url; @@ -57,7 +60,7 @@ pub async fn collect_non_local_mentions( &parent_creator .id() .domain() - .ok_or(LemmyErrorType::UrlWithoutDomain)? + .ok_or(FederationError::UrlWithoutDomain)? )), kind: MentionType::Mention, }; diff --git a/crates/apub/src/objects/comment.rs b/crates/apub/src/objects/comment.rs index b6b411ec64..403ecbf949 100644 --- a/crates/apub/src/objects/comment.rs +++ b/crates/apub/src/objects/comment.rs @@ -33,7 +33,7 @@ use lemmy_db_schema::{ utils::naive_now, }; use lemmy_utils::{ - error::{LemmyError, LemmyErrorType, LemmyResult}, + error::{FederationError, LemmyError, LemmyResult}, utils::markdown::markdown_to_html, }; use std::ops::Deref; @@ -162,7 +162,7 @@ impl Object for ApubComment { .await .is_ok(); if post.locked && !is_mod_or_admin { - Err(LemmyErrorType::PostIsLocked)? + Err(FederationError::PostIsLocked)? } else { Ok(()) } diff --git a/crates/apub/src/objects/instance.rs b/crates/apub/src/objects/instance.rs index 6ee0a41dcb..a123c85ba8 100644 --- a/crates/apub/src/objects/instance.rs +++ b/crates/apub/src/objects/instance.rs @@ -42,12 +42,11 @@ use lemmy_db_schema::{ utils::naive_now, }; use lemmy_utils::{ - error::{LemmyError, LemmyResult}, + error::{FederationError, LemmyError, LemmyResult}, utils::{ markdown::markdown_to_html, slurs::{check_slurs, check_slurs_opt}, }, - LemmyErrorType, }; use std::ops::Deref; use tracing::debug; @@ -89,7 +88,7 @@ impl Object for ApubSite { } async fn delete(self, _data: &Data) -> LemmyResult<()> { - Err(LemmyErrorType::CantDeleteSite.into()) + Err(FederationError::CantDeleteSite.into()) } #[tracing::instrument(skip_all)] @@ -144,7 +143,7 @@ impl Object for ApubSite { .id .inner() .domain() - .ok_or(LemmyErrorType::UrlWithoutDomain)?; + .ok_or(FederationError::UrlWithoutDomain)?; let instance = DbInstance::read_or_create(&mut context.pool(), domain.to_string()).await?; let local_site = LocalSite::read(&mut context.pool()).await.ok(); @@ -220,7 +219,7 @@ pub(in crate::objects) async fn fetch_instance_actor_for_object + C debug!("Failed to dereference site for {}: {}", &instance_id, e); let domain = instance_id .domain() - .ok_or(LemmyErrorType::UrlWithoutDomain)?; + .ok_or(FederationError::UrlWithoutDomain)?; Ok( DbInstance::read_or_create(&mut context.pool(), domain.to_string()) .await? diff --git a/crates/apub/src/objects/private_message.rs b/crates/apub/src/objects/private_message.rs index 3ed5b35722..5a191cc662 100644 --- a/crates/apub/src/objects/private_message.rs +++ b/crates/apub/src/objects/private_message.rs @@ -29,7 +29,7 @@ use lemmy_db_schema::{ utils::naive_now, }; use lemmy_utils::{ - error::{LemmyError, LemmyErrorType, LemmyResult}, + error::{FederationError, LemmyError, LemmyErrorType, LemmyResult}, utils::markdown::markdown_to_html, }; use std::ops::Deref; @@ -113,7 +113,7 @@ impl Object for ApubPrivateMessage { check_apub_id_valid_with_strictness(note.id.inner(), false, context).await?; let person = note.attributed_to.dereference(context).await?; if person.banned { - Err(LemmyErrorType::PersonIsBannedFromSite( + Err(FederationError::PersonIsBannedFromSite( person.actor_id.to_string(), ))? } else { diff --git a/crates/apub/src/protocol/activities/voting/vote.rs b/crates/apub/src/protocol/activities/voting/vote.rs index 9fae264a51..883fc85fb0 100644 --- a/crates/apub/src/protocol/activities/voting/vote.rs +++ b/crates/apub/src/protocol/activities/voting/vote.rs @@ -6,7 +6,7 @@ use crate::{ }; use activitypub_federation::{config::Data, fetch::object_id::ObjectId}; use lemmy_api_common::context::LemmyContext; -use lemmy_utils::error::{LemmyError, LemmyErrorType, LemmyResult}; +use lemmy_utils::error::{FederationError, LemmyError, LemmyResult}; use serde::{Deserialize, Serialize}; use strum::Display; use url::Url; @@ -35,7 +35,7 @@ impl TryFrom for VoteType { match value { 1 => Ok(VoteType::Like), -1 => Ok(VoteType::Dislike), - _ => Err(LemmyErrorType::InvalidVoteValue.into()), + _ => Err(FederationError::InvalidVoteValue.into()), } } } diff --git a/crates/apub/src/protocol/objects/page.rs b/crates/apub/src/protocol/objects/page.rs index 9a9866cfba..97f767573a 100644 --- a/crates/apub/src/protocol/objects/page.rs +++ b/crates/apub/src/protocol/objects/page.rs @@ -20,7 +20,7 @@ use activitypub_federation::{ use chrono::{DateTime, Utc}; use itertools::Itertools; use lemmy_api_common::context::LemmyContext; -use lemmy_utils::error::{LemmyError, LemmyErrorType, LemmyResult}; +use lemmy_utils::error::{FederationError, LemmyError, LemmyErrorType, LemmyResult}; use serde::{de::Error, Deserialize, Deserializer, Serialize}; use serde_with::skip_serializing_none; use url::Url; @@ -162,7 +162,7 @@ impl Page { .iter() .find(|a| a.kind == PersonOrGroupType::Person) .map(|a| ObjectId::::from(a.id.clone().into_inner())) - .ok_or_else(|| LemmyErrorType::PageDoesNotSpecifyCreator.into()), + .ok_or_else(|| FederationError::PageDoesNotSpecifyCreator.into()), } } } diff --git a/crates/utils/src/error.rs b/crates/utils/src/error.rs index b0add40e7c..1f29bf5892 100644 --- a/crates/utils/src/error.rs +++ b/crates/utils/src/error.rs @@ -23,19 +23,15 @@ pub enum LemmyErrorType { CouldntUpdateComment, CouldntUpdatePrivateMessage, CannotLeaveAdmin, - NoLinesInHtml, - SiteMetadataPageIsNotDoctypeHtml, + // TODO: also remove the translations of unused errors PictrsResponseError(String), PictrsPurgeResponseError(String), - PictrsCachingDisabled, ImageUrlMissingPathSegments, ImageUrlMissingLastPathSegment, PictrsApiKeyNotProvided, NoContentTypeHeader, NotAnImageType, NotAModOrAdmin, - NoAdmins, - NotTopAdmin, NotTopMod, NotLoggedIn, NotHigherMod, @@ -46,7 +42,6 @@ pub enum LemmyErrorType { PersonIsBlocked, CommunityIsBlocked, InstanceIsBlocked, - VoteNotAllowed, InstanceIsPrivate, /// Password must be between 10 and 60 characters InvalidPassword, @@ -61,7 +56,6 @@ pub enum LemmyErrorType { OnlyAdminsCanCreateCommunities, CommunityAlreadyExists, LanguageNotAllowed, - OnlyModsCanPostInCommunity, CouldntUpdatePost, NoPostEditAllowed, EditPrivateMessageNotAllowed, @@ -73,23 +67,10 @@ pub enum LemmyErrorType { RegistrationUsernameRequired, EmailAlreadyExists, UsernameAlreadyExists, - FederationForbiddenByStrictAllowList, PersonIsBannedFromCommunity, - ObjectIsNotPublic, - InvalidCommunity, - CannotCreatePostOrCommentInDeletedOrRemovedCommunity, - CannotReceivePage, - NewPostCannotBeLocked, - OnlyLocalAdminCanRemoveCommunity, - OnlyLocalAdminCanRestoreCommunity, NoIdGiven, IncorrectLogin, - InvalidQuery, ObjectNotLocal, - PostIsLocked, - PersonIsBannedFromSite(String), - InvalidVoteValue, - PageDoesNotSpecifyCreator, NoEmailSetup, LocalSiteNotSetup, EmailSmtpServerNeedsAPort, @@ -126,7 +107,6 @@ pub enum LemmyErrorType { CouldntUpdateCommunity, CouldntUpdateReplies, CouldntUpdatePersonMentions, - PostTitleTooLong, CouldntCreatePost, CouldntCreatePrivateMessage, CouldntUpdatePrivate, @@ -141,10 +121,6 @@ pub enum LemmyErrorType { EmailSendFailed, Slurs, RegistrationDenied(Option), - FederationDisabled, - DomainBlocked(String), - DomainNotInAllowList(String), - FederationDisabledByStrictAllowList, SiteNameRequired, SiteNameLengthOverflow, PermissiveRegex, @@ -158,23 +134,51 @@ pub enum LemmyErrorType { /// Thrown when an API call is submitted with more than 1000 array elements, see /// [[MAX_API_PARAM_ELEMENTS]] TooManyItems, - CommunityHasNoFollowers, BanExpirationInPast, InvalidUnixTime, InvalidBotAction, CantBlockLocalInstance, - UrlWithoutDomain, - InboxTimeout, + Unknown(String), + UrlLengthOverflow, OauthAuthorizationInvalid, OauthLoginFailed, OauthRegistrationClosed, CouldntDeleteOauthProvider, - Unknown(String), - CantDeleteSite, - UrlLengthOverflow, + NotFound, + CommunityHasNoFollowers, PostScheduleTimeMustBeInFuture, TooManyScheduledPosts, - NotFound, + FederationError(Option), +} + +/// Federation related errors, these dont need to be translated. +#[derive(Display, Debug, Serialize, Deserialize, Clone, PartialEq, Eq, EnumIter, Hash)] +#[cfg_attr(feature = "full", derive(ts_rs::TS))] +#[cfg_attr(feature = "full", ts(export))] +#[non_exhaustive] +pub enum FederationError { + // TODO: merge into a single NotFound error + CouldntFindActivity, + InvalidCommunity, + CannotCreatePostOrCommentInDeletedOrRemovedCommunity, + CannotReceivePage, + OnlyLocalAdminCanRemoveCommunity, + OnlyLocalAdminCanRestoreCommunity, + PostIsLocked, + PersonIsBannedFromSite(String), + InvalidVoteValue, + PageDoesNotSpecifyCreator, + CouldntGetComments, + CouldntGetPosts, + FederationDisabled, + DomainBlocked(String), + DomainNotInAllowList(String), + FederationDisabledByStrictAllowList, + ContradictingFilters, + UrlWithoutDomain, + InboxTimeout, + CantDeleteSite, + ObjectIsNotPublic, } cfg_if! { @@ -255,6 +259,17 @@ cfg_if! { } } + impl From for LemmyError { + fn from(error_type: FederationError) -> Self { + let inner = anyhow::anyhow!("{}", error_type); + LemmyError { + error_type: LemmyErrorType::FederationError(Some(error_type)), + inner, + context: Backtrace::capture(), + } + } + } + pub trait LemmyErrorExt> { fn with_lemmy_type(self, error_type: LemmyErrorType) -> LemmyResult; } @@ -306,12 +321,12 @@ cfg_if! { #[test] fn deserializes_with_message() -> LemmyResult<()> { - let reg_banned = LemmyErrorType::PersonIsBannedFromSite(String::from("reason")); + let reg_banned = LemmyErrorType::PictrsResponseError(String::from("reason")); let err = LemmyError::from(reg_banned).error_response(); let json = String::from_utf8(err.into_body().try_into_bytes().unwrap_or_default().to_vec())?; assert_eq!( &json, - "{\"error\":\"person_is_banned_from_site\",\"message\":\"reason\"}" + "{\"error\":\"pictrs_response_error\",\"message\":\"reason\"}" ); Ok(()) diff --git a/crates/utils/tests/test_errors_used.rs b/crates/utils/tests/test_errors_used.rs new file mode 100644 index 0000000000..81b92e469e --- /dev/null +++ b/crates/utils/tests/test_errors_used.rs @@ -0,0 +1,44 @@ +use lemmy_utils::LemmyErrorType; +use std::{env::current_dir, process::Command}; +use strum::IntoEnumIterator; + +#[test] +#[allow(clippy::unwrap_used)] +fn test_errors_used() { + let mut unused_error_found = false; + let mut current_dir = current_dir().unwrap(); + current_dir.pop(); + current_dir.pop(); + for error in LemmyErrorType::iter() { + let mut grep_all = Command::new("grep"); + let grep_all = grep_all + .current_dir(current_dir.clone()) + .arg("-R") + .arg("--exclude=error.rs") + .arg(error.to_string()) + .arg("crates/") + .arg("src/"); + let output = grep_all.output().unwrap(); + let grep_all_out = std::str::from_utf8(&output.stdout).unwrap(); + + let mut grep_apub = Command::new("grep"); + let grep_apub = grep_apub + .current_dir(current_dir.clone()) + .arg("-R") + .arg("--exclude-dir=api") + .arg(error.to_string()) + .arg("crates/apub/"); + let output = grep_apub.output().unwrap(); + let grep_apub_out = std::str::from_utf8(&output.stdout).unwrap(); + + if grep_all_out.is_empty() { + println!("LemmyErrorType::{} is unused", error); + unused_error_found = true; + } + if grep_all_out == grep_apub_out { + println!("LemmyErrorType::{} is only used for federation", error); + unused_error_found = true; + } + } + assert!(!unused_error_found); +}