Error enum fixed (#3487)
* Create error type enum * Replace magic string slices with LemmyErrorTypes * Remove unused enum * Add rename snake case to error enum * Rename functions * clippy * Fix merge errors * Serialize in PascalCase instead of snake_case * Revert src/lib * Add serialization tests * Update translations * Fix compilation error in test * Fix another compilation error * Add code for generating typescript types * Various fixes to avoid breaking api * impl From<LemmyErrorType> for LemmyError * with_lemmy_type * trigger ci --------- Co-authored-by: SleeplessOne1917 <abias1122@gmail.com>
This commit is contained in:
parent
b50634e2cf
commit
93225e5ddf
82 changed files with 664 additions and 483 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -2911,6 +2911,7 @@ dependencies = [
|
||||||
"totp-rs",
|
"totp-rs",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-error",
|
"tracing-error",
|
||||||
|
"ts-rs",
|
||||||
"typed-builder",
|
"typed-builder",
|
||||||
"url",
|
"url",
|
||||||
"uuid",
|
"uuid",
|
||||||
|
|
|
@ -10,7 +10,7 @@ use lemmy_db_schema::{
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::CommentView;
|
use lemmy_db_views::structs::CommentView;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl Perform for DistinguishComment {
|
impl Perform for DistinguishComment {
|
||||||
|
@ -46,7 +46,7 @@ impl Perform for DistinguishComment {
|
||||||
.build();
|
.build();
|
||||||
Comment::update(context.pool(), comment_id, &form)
|
Comment::update(context.pool(), comment_id, &form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_comment"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?;
|
||||||
|
|
||||||
let comment_id = data.comment_id;
|
let comment_id = data.comment_id;
|
||||||
let person_id = local_user_view.person.id;
|
let person_id = local_user_view.person.id;
|
||||||
|
|
|
@ -16,7 +16,7 @@ use lemmy_db_schema::{
|
||||||
traits::Likeable,
|
traits::Likeable,
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::{CommentView, LocalUserView};
|
use lemmy_db_views::structs::{CommentView, LocalUserView};
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl Perform for CreateCommentLike {
|
impl Perform for CreateCommentLike {
|
||||||
|
@ -69,7 +69,7 @@ impl Perform for CreateCommentLike {
|
||||||
if do_add {
|
if do_add {
|
||||||
CommentLike::like(context.pool(), &like_form)
|
CommentLike::like(context.pool(), &like_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_like_comment"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntLikeComment)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
build_comment_response(
|
build_comment_response(
|
||||||
|
|
|
@ -10,7 +10,7 @@ use lemmy_db_schema::{
|
||||||
traits::Saveable,
|
traits::Saveable,
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::CommentView;
|
use lemmy_db_views::structs::CommentView;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl Perform for SaveComment {
|
impl Perform for SaveComment {
|
||||||
|
@ -29,11 +29,11 @@ impl Perform for SaveComment {
|
||||||
if data.save {
|
if data.save {
|
||||||
CommentSaved::save(context.pool(), &comment_saved_form)
|
CommentSaved::save(context.pool(), &comment_saved_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_save_comment"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntSaveComment)?;
|
||||||
} else {
|
} else {
|
||||||
CommentSaved::unsave(context.pool(), &comment_saved_form)
|
CommentSaved::unsave(context.pool(), &comment_saved_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_save_comment"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntSaveComment)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let comment_id = data.comment_id;
|
let comment_id = data.comment_id;
|
||||||
|
|
|
@ -13,7 +13,7 @@ use lemmy_db_schema::{
|
||||||
traits::Reportable,
|
traits::Reportable,
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::{CommentReportView, CommentView};
|
use lemmy_db_views::structs::{CommentReportView, CommentView};
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
|
||||||
/// Creates a comment report and notifies the moderators of the community
|
/// Creates a comment report and notifies the moderators of the community
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
|
@ -47,7 +47,7 @@ impl Perform for CreateCommentReport {
|
||||||
|
|
||||||
let report = CommentReport::report(context.pool(), &report_form)
|
let report = CommentReport::report(context.pool(), &report_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_create_report"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntCreateReport)?;
|
||||||
|
|
||||||
let comment_report_view = CommentReportView::read(context.pool(), report.id, person_id).await?;
|
let comment_report_view = CommentReportView::read(context.pool(), report.id, person_id).await?;
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ use lemmy_api_common::{
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{source::comment_report::CommentReport, traits::Reportable};
|
use lemmy_db_schema::{source::comment_report::CommentReport, traits::Reportable};
|
||||||
use lemmy_db_views::structs::CommentReportView;
|
use lemmy_db_views::structs::CommentReportView;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
|
||||||
/// Resolves or unresolves a comment report and notifies the moderators of the community
|
/// Resolves or unresolves a comment report and notifies the moderators of the community
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
|
@ -32,11 +32,11 @@ impl Perform for ResolveCommentReport {
|
||||||
if data.resolved {
|
if data.resolved {
|
||||||
CommentReport::resolve(context.pool(), report_id, person_id)
|
CommentReport::resolve(context.pool(), report_id, person_id)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_resolve_report"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntResolveReport)?;
|
||||||
} else {
|
} else {
|
||||||
CommentReport::unresolve(context.pool(), report_id, person_id)
|
CommentReport::unresolve(context.pool(), report_id, person_id)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_resolve_report"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntResolveReport)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let report_id = data.report_id;
|
let report_id = data.report_id;
|
||||||
|
|
|
@ -13,7 +13,7 @@ use lemmy_db_schema::{
|
||||||
traits::{Crud, Joinable},
|
traits::{Crud, Joinable},
|
||||||
};
|
};
|
||||||
use lemmy_db_views_actor::structs::CommunityModeratorView;
|
use lemmy_db_views_actor::structs::CommunityModeratorView;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl Perform for AddModToCommunity {
|
impl Perform for AddModToCommunity {
|
||||||
|
@ -33,7 +33,7 @@ impl Perform for AddModToCommunity {
|
||||||
is_mod_or_admin(context.pool(), local_user_view.person.id, community_id).await?;
|
is_mod_or_admin(context.pool(), local_user_view.person.id, community_id).await?;
|
||||||
let community = Community::read(context.pool(), community_id).await?;
|
let community = Community::read(context.pool(), community_id).await?;
|
||||||
if local_user_view.person.admin && !community.local {
|
if local_user_view.person.admin && !community.local {
|
||||||
return Err(LemmyError::from_message("not_a_moderator"));
|
return Err(LemmyErrorType::NotAModerator)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update in local database
|
// Update in local database
|
||||||
|
@ -44,11 +44,11 @@ impl Perform for AddModToCommunity {
|
||||||
if data.added {
|
if data.added {
|
||||||
CommunityModerator::join(context.pool(), &community_moderator_form)
|
CommunityModerator::join(context.pool(), &community_moderator_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "community_moderator_already_exists"))?;
|
.with_lemmy_type(LemmyErrorType::CommunityModeratorAlreadyExists)?;
|
||||||
} else {
|
} else {
|
||||||
CommunityModerator::leave(context.pool(), &community_moderator_form)
|
CommunityModerator::leave(context.pool(), &community_moderator_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "community_moderator_already_exists"))?;
|
.with_lemmy_type(LemmyErrorType::CommunityModeratorAlreadyExists)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mod tables
|
// Mod tables
|
||||||
|
|
|
@ -19,7 +19,7 @@ use lemmy_db_schema::{
|
||||||
};
|
};
|
||||||
use lemmy_db_views_actor::structs::PersonView;
|
use lemmy_db_views_actor::structs::PersonView;
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
error::LemmyError,
|
error::{LemmyError, LemmyErrorExt, LemmyErrorType},
|
||||||
utils::{time::naive_from_unix, validation::is_valid_body_field},
|
utils::{time::naive_from_unix, validation::is_valid_body_field},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ impl Perform for BanFromCommunity {
|
||||||
if data.ban {
|
if data.ban {
|
||||||
CommunityPersonBan::ban(context.pool(), &community_user_ban_form)
|
CommunityPersonBan::ban(context.pool(), &community_user_ban_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "community_user_already_banned"))?;
|
.with_lemmy_type(LemmyErrorType::CommunityUserAlreadyBanned)?;
|
||||||
|
|
||||||
// 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 {
|
||||||
|
@ -68,7 +68,7 @@ impl Perform for BanFromCommunity {
|
||||||
} else {
|
} else {
|
||||||
CommunityPersonBan::unban(context.pool(), &community_user_ban_form)
|
CommunityPersonBan::unban(context.pool(), &community_user_ban_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "community_user_already_banned"))?;
|
.with_lemmy_type(LemmyErrorType::CommunityUserAlreadyBanned)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove/Restore their data if that's desired
|
// Remove/Restore their data if that's desired
|
||||||
|
|
|
@ -13,7 +13,7 @@ use lemmy_db_schema::{
|
||||||
traits::{Blockable, Followable},
|
traits::{Blockable, Followable},
|
||||||
};
|
};
|
||||||
use lemmy_db_views_actor::structs::CommunityView;
|
use lemmy_db_views_actor::structs::CommunityView;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl Perform for BlockCommunity {
|
impl Perform for BlockCommunity {
|
||||||
|
@ -37,7 +37,7 @@ impl Perform for BlockCommunity {
|
||||||
if data.block {
|
if data.block {
|
||||||
CommunityBlock::block(context.pool(), &community_block_form)
|
CommunityBlock::block(context.pool(), &community_block_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "community_block_already_exists"))?;
|
.with_lemmy_type(LemmyErrorType::CommunityBlockAlreadyExists)?;
|
||||||
|
|
||||||
// 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 {
|
||||||
|
@ -52,7 +52,7 @@ impl Perform for BlockCommunity {
|
||||||
} else {
|
} else {
|
||||||
CommunityBlock::unblock(context.pool(), &community_block_form)
|
CommunityBlock::unblock(context.pool(), &community_block_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "community_block_already_exists"))?;
|
.with_lemmy_type(LemmyErrorType::CommunityBlockAlreadyExists)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let community_view =
|
let community_view =
|
||||||
|
|
|
@ -13,7 +13,7 @@ use lemmy_db_schema::{
|
||||||
traits::{Crud, Followable},
|
traits::{Crud, Followable},
|
||||||
};
|
};
|
||||||
use lemmy_db_views_actor::structs::CommunityView;
|
use lemmy_db_views_actor::structs::CommunityView;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl Perform for FollowCommunity {
|
impl Perform for FollowCommunity {
|
||||||
|
@ -39,19 +39,19 @@ impl Perform for FollowCommunity {
|
||||||
|
|
||||||
CommunityFollower::follow(context.pool(), &community_follower_form)
|
CommunityFollower::follow(context.pool(), &community_follower_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "community_follower_already_exists"))?;
|
.with_lemmy_type(LemmyErrorType::CommunityFollowerAlreadyExists)?;
|
||||||
} else {
|
} else {
|
||||||
// Mark as pending, the actual federation activity is sent via `SendActivity` handler
|
// Mark as pending, the actual federation activity is sent via `SendActivity` handler
|
||||||
community_follower_form.pending = true;
|
community_follower_form.pending = true;
|
||||||
CommunityFollower::follow(context.pool(), &community_follower_form)
|
CommunityFollower::follow(context.pool(), &community_follower_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "community_follower_already_exists"))?;
|
.with_lemmy_type(LemmyErrorType::CommunityFollowerAlreadyExists)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !data.follow {
|
if !data.follow {
|
||||||
CommunityFollower::unfollow(context.pool(), &community_follower_form)
|
CommunityFollower::unfollow(context.pool(), &community_follower_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "community_follower_already_exists"))?;
|
.with_lemmy_type(LemmyErrorType::CommunityFollowerAlreadyExists)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let community_id = data.community_id;
|
let community_id = data.community_id;
|
||||||
|
|
|
@ -13,7 +13,7 @@ use lemmy_db_schema::{
|
||||||
},
|
},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
};
|
};
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl Perform for HideCommunity {
|
impl Perform for HideCommunity {
|
||||||
|
@ -41,7 +41,7 @@ impl Perform for HideCommunity {
|
||||||
let community_id = data.community_id;
|
let community_id = data.community_id;
|
||||||
Community::update(context.pool(), community_id, &community_form)
|
Community::update(context.pool(), community_id, &community_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_community_hidden_status"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntUpdateCommunityHiddenStatus)?;
|
||||||
|
|
||||||
ModHideCommunity::create(context.pool(), &mod_hide_community_form).await?;
|
ModHideCommunity::create(context.pool(), &mod_hide_community_form).await?;
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,10 @@ use lemmy_db_schema::{
|
||||||
traits::{Crud, Joinable},
|
traits::{Crud, Joinable},
|
||||||
};
|
};
|
||||||
use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView};
|
use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView};
|
||||||
use lemmy_utils::{error::LemmyError, location_info};
|
use lemmy_utils::{
|
||||||
|
error::{LemmyError, LemmyErrorExt, LemmyErrorType},
|
||||||
|
location_info,
|
||||||
|
};
|
||||||
|
|
||||||
// TODO: we dont do anything for federation here, it should be updated the next time the community
|
// TODO: we dont do anything for federation here, it should be updated the next time the community
|
||||||
// gets fetched. i hope we can get rid of the community creator role soon.
|
// gets fetched. i hope we can get rid of the community creator role soon.
|
||||||
|
@ -39,7 +42,7 @@ impl Perform for TransferCommunity {
|
||||||
if !(is_top_mod(&local_user_view, &community_mods).is_ok()
|
if !(is_top_mod(&local_user_view, &community_mods).is_ok()
|
||||||
|| is_admin(&local_user_view).is_ok())
|
|| is_admin(&local_user_view).is_ok())
|
||||||
{
|
{
|
||||||
return Err(LemmyError::from_message("not_an_admin"));
|
return Err(LemmyErrorType::NotAnAdmin)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// You have to re-do the community_moderator table, reordering it.
|
// You have to re-do the community_moderator table, reordering it.
|
||||||
|
@ -66,7 +69,7 @@ impl Perform for TransferCommunity {
|
||||||
|
|
||||||
CommunityModerator::join(context.pool(), &community_moderator_form)
|
CommunityModerator::join(context.pool(), &community_moderator_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "community_moderator_already_exists"))?;
|
.with_lemmy_type(LemmyErrorType::CommunityModeratorAlreadyExists)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mod tables
|
// Mod tables
|
||||||
|
@ -82,12 +85,12 @@ impl Perform for TransferCommunity {
|
||||||
let person_id = local_user_view.person.id;
|
let person_id = local_user_view.person.id;
|
||||||
let community_view = CommunityView::read(context.pool(), community_id, Some(person_id), None)
|
let community_view = CommunityView::read(context.pool(), community_id, Some(person_id), None)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_find_community"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntFindCommunity)?;
|
||||||
|
|
||||||
let community_id = data.community_id;
|
let community_id = data.community_id;
|
||||||
let moderators = CommunityModeratorView::for_community(context.pool(), community_id)
|
let moderators = CommunityModeratorView::for_community(context.pool(), community_id)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_find_community"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntFindCommunity)?;
|
||||||
|
|
||||||
// Return the jwt
|
// Return the jwt
|
||||||
Ok(GetCommunityResponse {
|
Ok(GetCommunityResponse {
|
||||||
|
|
|
@ -3,7 +3,10 @@ use base64::{engine::general_purpose::STANDARD_NO_PAD as base64, Engine};
|
||||||
use captcha::Captcha;
|
use captcha::Captcha;
|
||||||
use lemmy_api_common::{context::LemmyContext, utils::local_site_to_slur_regex};
|
use lemmy_api_common::{context::LemmyContext, utils::local_site_to_slur_regex};
|
||||||
use lemmy_db_schema::source::local_site::LocalSite;
|
use lemmy_db_schema::source::local_site::LocalSite;
|
||||||
use lemmy_utils::{error::LemmyError, utils::slurs::check_slurs};
|
use lemmy_utils::{
|
||||||
|
error::{LemmyError, LemmyErrorExt, LemmyErrorType},
|
||||||
|
utils::slurs::check_slurs,
|
||||||
|
};
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
mod comment;
|
mod comment;
|
||||||
|
@ -37,7 +40,7 @@ pub(crate) fn captcha_as_wav_base64(captcha: &Captcha) -> Result<String, LemmyEr
|
||||||
if let Some(samples16) = samples.as_sixteen() {
|
if let Some(samples16) = samples.as_sixteen() {
|
||||||
concat_samples.extend(samples16);
|
concat_samples.extend(samples16);
|
||||||
} else {
|
} else {
|
||||||
return Err(LemmyError::from_message("couldnt_create_audio_captcha"));
|
return Err(LemmyErrorType::CouldntCreateAudioCaptcha)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,19 +48,14 @@ pub(crate) fn captcha_as_wav_base64(captcha: &Captcha) -> Result<String, LemmyEr
|
||||||
let mut output_buffer = Cursor::new(vec![]);
|
let mut output_buffer = Cursor::new(vec![]);
|
||||||
let header = match any_header {
|
let header = match any_header {
|
||||||
Some(header) => header,
|
Some(header) => header,
|
||||||
None => return Err(LemmyError::from_message("couldnt_create_audio_captcha")),
|
None => return Err(LemmyErrorType::CouldntCreateAudioCaptcha)?,
|
||||||
};
|
};
|
||||||
let wav_write_result = wav::write(
|
wav::write(
|
||||||
header,
|
header,
|
||||||
&wav::BitDepth::Sixteen(concat_samples),
|
&wav::BitDepth::Sixteen(concat_samples),
|
||||||
&mut output_buffer,
|
&mut output_buffer,
|
||||||
);
|
)
|
||||||
if let Err(e) = wav_write_result {
|
.with_lemmy_type(LemmyErrorType::CouldntCreateAudioCaptcha)?;
|
||||||
return Err(LemmyError::from_error_message(
|
|
||||||
e,
|
|
||||||
"couldnt_create_audio_captcha",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(base64.encode(output_buffer.into_inner()))
|
Ok(base64.encode(output_buffer.into_inner()))
|
||||||
}
|
}
|
||||||
|
@ -68,10 +66,10 @@ pub(crate) fn check_report_reason(reason: &str, local_site: &LocalSite) -> Resul
|
||||||
|
|
||||||
check_slurs(reason, slur_regex)?;
|
check_slurs(reason, slur_regex)?;
|
||||||
if reason.is_empty() {
|
if reason.is_empty() {
|
||||||
return Err(LemmyError::from_message("report_reason_required"));
|
return Err(LemmyErrorType::ReportReasonRequired)?;
|
||||||
}
|
}
|
||||||
if reason.chars().count() > 1000 {
|
if reason.chars().count() > 1000 {
|
||||||
return Err(LemmyError::from_message("report_too_long"));
|
return Err(LemmyErrorType::ReportTooLong)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ use lemmy_db_schema::{
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
};
|
};
|
||||||
use lemmy_db_views_actor::structs::PersonView;
|
use lemmy_db_views_actor::structs::PersonView;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl Perform for AddAdmin {
|
impl Perform for AddAdmin {
|
||||||
|
@ -35,7 +35,7 @@ impl Perform for AddAdmin {
|
||||||
&PersonUpdateForm::builder().admin(Some(added)).build(),
|
&PersonUpdateForm::builder().admin(Some(added)).build(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_user"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntUpdateUser)?;
|
||||||
|
|
||||||
// Mod tables
|
// Mod tables
|
||||||
let form = ModAddForm {
|
let form = ModAddForm {
|
||||||
|
|
|
@ -14,7 +14,7 @@ use lemmy_db_schema::{
|
||||||
};
|
};
|
||||||
use lemmy_db_views_actor::structs::PersonView;
|
use lemmy_db_views_actor::structs::PersonView;
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
error::LemmyError,
|
error::{LemmyError, LemmyErrorExt, LemmyErrorType},
|
||||||
utils::{time::naive_from_unix, validation::is_valid_body_field},
|
utils::{time::naive_from_unix, validation::is_valid_body_field},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ impl Perform for BanPerson {
|
||||||
.build(),
|
.build(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_user"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntUpdateUser)?;
|
||||||
|
|
||||||
// Remove their data if that's desired
|
// Remove their data if that's desired
|
||||||
let remove_data = data.remove_data.unwrap_or(false);
|
let remove_data = data.remove_data.unwrap_or(false);
|
||||||
|
|
|
@ -10,7 +10,7 @@ use lemmy_db_schema::{
|
||||||
traits::Blockable,
|
traits::Blockable,
|
||||||
};
|
};
|
||||||
use lemmy_db_views_actor::structs::PersonView;
|
use lemmy_db_views_actor::structs::PersonView;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl Perform for BlockPerson {
|
impl Perform for BlockPerson {
|
||||||
|
@ -26,7 +26,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(LemmyError::from_message("cant_block_yourself"));
|
return Err(LemmyErrorType::CantBlockYourself)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let person_block_form = PersonBlockForm {
|
let person_block_form = PersonBlockForm {
|
||||||
|
@ -37,17 +37,17 @@ impl Perform for BlockPerson {
|
||||||
let target_person_view = PersonView::read(context.pool(), target_id).await?;
|
let target_person_view = PersonView::read(context.pool(), target_id).await?;
|
||||||
|
|
||||||
if target_person_view.person.admin {
|
if target_person_view.person.admin {
|
||||||
return Err(LemmyError::from_message("cant_block_admin"));
|
return Err(LemmyErrorType::CantBlockAdmin)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if data.block {
|
if data.block {
|
||||||
PersonBlock::block(context.pool(), &person_block_form)
|
PersonBlock::block(context.pool(), &person_block_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "person_block_already_exists"))?;
|
.with_lemmy_type(LemmyErrorType::PersonBlockAlreadyExists)?;
|
||||||
} else {
|
} else {
|
||||||
PersonBlock::unblock(context.pool(), &person_block_form)
|
PersonBlock::unblock(context.pool(), &person_block_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "person_block_already_exists"))?;
|
.with_lemmy_type(LemmyErrorType::PersonBlockAlreadyExists)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(BlockPersonResponse {
|
Ok(BlockPersonResponse {
|
||||||
|
|
|
@ -7,7 +7,10 @@ use lemmy_api_common::{
|
||||||
utils::{local_user_view_from_jwt, password_length_check},
|
utils::{local_user_view_from_jwt, password_length_check},
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::source::local_user::LocalUser;
|
use lemmy_db_schema::source::local_user::LocalUser;
|
||||||
use lemmy_utils::{claims::Claims, error::LemmyError};
|
use lemmy_utils::{
|
||||||
|
claims::Claims,
|
||||||
|
error::{LemmyError, LemmyErrorType},
|
||||||
|
};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl Perform for ChangePassword {
|
impl Perform for ChangePassword {
|
||||||
|
@ -22,7 +25,7 @@ impl Perform for ChangePassword {
|
||||||
|
|
||||||
// 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(LemmyError::from_message("passwords_dont_match"));
|
return Err(LemmyErrorType::PasswordsDoNotMatch)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the old password
|
// Check the old password
|
||||||
|
@ -32,7 +35,7 @@ impl Perform for ChangePassword {
|
||||||
)
|
)
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
if !valid {
|
if !valid {
|
||||||
return Err(LemmyError::from_message("password_incorrect"));
|
return Err(LemmyErrorType::IncorrectLogin)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let local_user_id = local_user_view.local_user.id;
|
let local_user_id = local_user_view.local_user.id;
|
||||||
|
|
|
@ -10,7 +10,10 @@ use lemmy_db_schema::{
|
||||||
RegistrationMode,
|
RegistrationMode,
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::SiteView;
|
use lemmy_db_views::structs::SiteView;
|
||||||
use lemmy_utils::{claims::Claims, error::LemmyError};
|
use lemmy_utils::{
|
||||||
|
claims::Claims,
|
||||||
|
error::{LemmyError, LemmyErrorExt, LemmyErrorType},
|
||||||
|
};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl Perform for PasswordChangeAfterReset {
|
impl Perform for PasswordChangeAfterReset {
|
||||||
|
@ -30,14 +33,14 @@ impl Perform for PasswordChangeAfterReset {
|
||||||
|
|
||||||
// Make sure passwords match
|
// Make sure passwords match
|
||||||
if data.password != data.password_verify {
|
if data.password != data.password_verify {
|
||||||
return Err(LemmyError::from_message("passwords_dont_match"));
|
return Err(LemmyErrorType::PasswordsDoNotMatch)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the user with the new password
|
// Update the user with the new password
|
||||||
let password = data.password.clone();
|
let password = data.password.clone();
|
||||||
let updated_local_user = LocalUser::update_password(context.pool(), local_user_id, &password)
|
let updated_local_user = LocalUser::update_password(context.pool(), local_user_id, &password)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_user"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntUpdateUser)?;
|
||||||
|
|
||||||
// Return the jwt if login is allowed
|
// Return the jwt if login is allowed
|
||||||
let site_view = SiteView::read_local(context.pool()).await?;
|
let site_view = SiteView::read_local(context.pool()).await?;
|
||||||
|
|
|
@ -7,7 +7,11 @@ use lemmy_api_common::{
|
||||||
utils::{check_registration_application, check_user_valid},
|
utils::{check_registration_application, check_user_valid},
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::{LocalUserView, SiteView};
|
use lemmy_db_views::structs::{LocalUserView, SiteView};
|
||||||
use lemmy_utils::{claims::Claims, error::LemmyError, utils::validation::check_totp_2fa_valid};
|
use lemmy_utils::{
|
||||||
|
claims::Claims,
|
||||||
|
error::{LemmyError, LemmyErrorExt, LemmyErrorType},
|
||||||
|
utils::validation::check_totp_2fa_valid,
|
||||||
|
};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl Perform for Login {
|
impl Perform for Login {
|
||||||
|
@ -23,7 +27,7 @@ impl Perform for Login {
|
||||||
let username_or_email = data.username_or_email.clone();
|
let username_or_email = data.username_or_email.clone();
|
||||||
let local_user_view = LocalUserView::find_by_email_or_name(context.pool(), &username_or_email)
|
let local_user_view = LocalUserView::find_by_email_or_name(context.pool(), &username_or_email)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "incorrect_login"))?;
|
.with_lemmy_type(LemmyErrorType::IncorrectLogin)?;
|
||||||
|
|
||||||
// Verify the password
|
// Verify the password
|
||||||
let valid: bool = verify(
|
let valid: bool = verify(
|
||||||
|
@ -32,7 +36,7 @@ impl Perform for Login {
|
||||||
)
|
)
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
if !valid {
|
if !valid {
|
||||||
return Err(LemmyError::from_message("incorrect_login"));
|
return Err(LemmyErrorType::IncorrectLogin)?;
|
||||||
}
|
}
|
||||||
check_user_valid(
|
check_user_valid(
|
||||||
local_user_view.person.banned,
|
local_user_view.person.banned,
|
||||||
|
@ -46,7 +50,7 @@ impl Perform for Login {
|
||||||
&& site_view.local_site.require_email_verification
|
&& site_view.local_site.require_email_verification
|
||||||
&& !local_user_view.local_user.email_verified
|
&& !local_user_view.local_user.email_verified
|
||||||
{
|
{
|
||||||
return Err(LemmyError::from_message("email_not_verified"));
|
return Err(LemmyErrorType::EmailNotVerified)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
check_registration_application(&local_user_view, &site_view.local_site, context.pool()).await?;
|
check_registration_application(&local_user_view, &site_view.local_site, context.pool()).await?;
|
||||||
|
|
|
@ -10,7 +10,7 @@ use lemmy_db_schema::source::{
|
||||||
person_mention::PersonMention,
|
person_mention::PersonMention,
|
||||||
private_message::PrivateMessage,
|
private_message::PrivateMessage,
|
||||||
};
|
};
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl Perform for MarkAllAsRead {
|
impl Perform for MarkAllAsRead {
|
||||||
|
@ -25,17 +25,17 @@ impl Perform for MarkAllAsRead {
|
||||||
// Mark all comment_replies as read
|
// Mark all comment_replies as read
|
||||||
CommentReply::mark_all_as_read(context.pool(), person_id)
|
CommentReply::mark_all_as_read(context.pool(), person_id)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_comment"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?;
|
||||||
|
|
||||||
// Mark all user mentions as read
|
// Mark all user mentions as read
|
||||||
PersonMention::mark_all_as_read(context.pool(), person_id)
|
PersonMention::mark_all_as_read(context.pool(), person_id)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_comment"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?;
|
||||||
|
|
||||||
// Mark all private_messages as read
|
// Mark all private_messages as read
|
||||||
PrivateMessage::mark_all_as_read(context.pool(), person_id)
|
PrivateMessage::mark_all_as_read(context.pool(), person_id)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_private_message"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntUpdatePrivateMessage)?;
|
||||||
|
|
||||||
Ok(GetRepliesResponse { replies: vec![] })
|
Ok(GetRepliesResponse { replies: vec![] })
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ use lemmy_db_schema::{
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
};
|
};
|
||||||
use lemmy_db_views_actor::structs::PersonMentionView;
|
use lemmy_db_views_actor::structs::PersonMentionView;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl Perform for MarkPersonMentionAsRead {
|
impl Perform for MarkPersonMentionAsRead {
|
||||||
|
@ -28,7 +28,7 @@ impl Perform for MarkPersonMentionAsRead {
|
||||||
let read_person_mention = PersonMention::read(context.pool(), person_mention_id).await?;
|
let read_person_mention = PersonMention::read(context.pool(), person_mention_id).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(LemmyError::from_message("couldnt_update_comment"));
|
return Err(LemmyErrorType::CouldntUpdateComment)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let person_mention_id = read_person_mention.id;
|
let person_mention_id = read_person_mention.id;
|
||||||
|
@ -39,7 +39,7 @@ impl Perform for MarkPersonMentionAsRead {
|
||||||
&PersonMentionUpdateForm { read },
|
&PersonMentionUpdateForm { read },
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_comment"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?;
|
||||||
|
|
||||||
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;
|
||||||
|
|
|
@ -10,7 +10,7 @@ use lemmy_db_schema::{
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
};
|
};
|
||||||
use lemmy_db_views_actor::structs::CommentReplyView;
|
use lemmy_db_views_actor::structs::CommentReplyView;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl Perform for MarkCommentReplyAsRead {
|
impl Perform for MarkCommentReplyAsRead {
|
||||||
|
@ -28,7 +28,7 @@ impl Perform for MarkCommentReplyAsRead {
|
||||||
let read_comment_reply = CommentReply::read(context.pool(), comment_reply_id).await?;
|
let read_comment_reply = CommentReply::read(context.pool(), comment_reply_id).await?;
|
||||||
|
|
||||||
if local_user_view.person.id != read_comment_reply.recipient_id {
|
if local_user_view.person.id != read_comment_reply.recipient_id {
|
||||||
return Err(LemmyError::from_message("couldnt_update_comment"));
|
return Err(LemmyErrorType::CouldntUpdateComment)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let comment_reply_id = read_comment_reply.id;
|
let comment_reply_id = read_comment_reply.id;
|
||||||
|
@ -40,7 +40,7 @@ impl Perform for MarkCommentReplyAsRead {
|
||||||
&CommentReplyUpdateForm { read },
|
&CommentReplyUpdateForm { read },
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_comment"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?;
|
||||||
|
|
||||||
let comment_reply_id = read_comment_reply.id;
|
let comment_reply_id = read_comment_reply.id;
|
||||||
let person_id = local_user_view.person.id;
|
let person_id = local_user_view.person.id;
|
||||||
|
|
|
@ -7,7 +7,7 @@ use lemmy_api_common::{
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::source::password_reset_request::PasswordResetRequest;
|
use lemmy_db_schema::source::password_reset_request::PasswordResetRequest;
|
||||||
use lemmy_db_views::structs::LocalUserView;
|
use lemmy_db_views::structs::LocalUserView;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl Perform for PasswordReset {
|
impl Perform for PasswordReset {
|
||||||
|
@ -24,7 +24,7 @@ impl Perform for PasswordReset {
|
||||||
let email = data.email.to_lowercase();
|
let email = data.email.to_lowercase();
|
||||||
let local_user_view = LocalUserView::find_by_email(context.pool(), &email)
|
let local_user_view = LocalUserView::find_by_email(context.pool(), &email)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_find_that_username_or_email"))?;
|
.with_lemmy_type(LemmyErrorType::IncorrectLogin)?;
|
||||||
|
|
||||||
// Check for too many attempts (to limit potential abuse)
|
// Check for too many attempts (to limit potential abuse)
|
||||||
let recent_resets_count = PasswordResetRequest::get_recent_password_resets_count(
|
let recent_resets_count = PasswordResetRequest::get_recent_password_resets_count(
|
||||||
|
@ -33,7 +33,7 @@ impl Perform for PasswordReset {
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
if recent_resets_count >= 3 {
|
if recent_resets_count >= 3 {
|
||||||
return Err(LemmyError::from_message("password_reset_limit_reached"));
|
return Err(LemmyErrorType::PasswordResetLimitReached)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Email the pure token to the user.
|
// Email the pure token to the user.
|
||||||
|
|
|
@ -17,7 +17,7 @@ use lemmy_db_schema::{
|
||||||
use lemmy_db_views::structs::SiteView;
|
use lemmy_db_views::structs::SiteView;
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
claims::Claims,
|
claims::Claims,
|
||||||
error::LemmyError,
|
error::{LemmyError, LemmyErrorExt, LemmyErrorType},
|
||||||
utils::validation::{
|
utils::validation::{
|
||||||
build_totp_2fa,
|
build_totp_2fa,
|
||||||
generate_totp_2fa_secret,
|
generate_totp_2fa_secret,
|
||||||
|
@ -57,7 +57,7 @@ impl Perform for SaveUserSettings {
|
||||||
// When the site requires email, make sure email is not Some(None). IE, an overwrite to a None value
|
// When the site requires email, make sure email is not Some(None). IE, an overwrite to a None value
|
||||||
if let Some(email) = &email {
|
if let Some(email) = &email {
|
||||||
if email.is_none() && site_view.local_site.require_email_verification {
|
if email.is_none() && site_view.local_site.require_email_verification {
|
||||||
return Err(LemmyError::from_message("email_required"));
|
return Err(LemmyErrorType::EmailRequired)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ impl Perform for SaveUserSettings {
|
||||||
|
|
||||||
Person::update(context.pool(), person_id, &person_form)
|
Person::update(context.pool(), person_id, &person_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "user_already_exists"))?;
|
.with_lemmy_type(LemmyErrorType::UserAlreadyExists)?;
|
||||||
|
|
||||||
if let Some(discussion_languages) = data.discussion_languages.clone() {
|
if let Some(discussion_languages) = data.discussion_languages.clone() {
|
||||||
LocalUserLanguage::update(context.pool(), discussion_languages, local_user_id).await?;
|
LocalUserLanguage::update(context.pool(), discussion_languages, local_user_id).await?;
|
||||||
|
@ -137,12 +137,12 @@ impl Perform for SaveUserSettings {
|
||||||
let err_type = if e.to_string()
|
let err_type = if e.to_string()
|
||||||
== "duplicate key value violates unique constraint \"local_user_email_key\""
|
== "duplicate key value violates unique constraint \"local_user_email_key\""
|
||||||
{
|
{
|
||||||
"email_already_exists"
|
LemmyErrorType::EmailAlreadyExists
|
||||||
} else {
|
} else {
|
||||||
"user_already_exists"
|
LemmyErrorType::UserAlreadyExists
|
||||||
};
|
};
|
||||||
|
|
||||||
return Err(LemmyError::from_error_message(e, err_type));
|
return Err(e).with_lemmy_type(err_type);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ use lemmy_db_schema::{
|
||||||
},
|
},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
};
|
};
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl Perform for VerifyEmail {
|
impl Perform for VerifyEmail {
|
||||||
|
@ -21,7 +21,7 @@ impl Perform for VerifyEmail {
|
||||||
let token = self.token.clone();
|
let token = self.token.clone();
|
||||||
let verification = EmailVerification::read_for_token(context.pool(), &token)
|
let verification = EmailVerification::read_for_token(context.pool(), &token)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "token_not_found"))?;
|
.with_lemmy_type(LemmyErrorType::TokenNotFound)?;
|
||||||
|
|
||||||
let form = LocalUserUpdateForm::builder()
|
let form = LocalUserUpdateForm::builder()
|
||||||
// necessary in case this is a new signup
|
// necessary in case this is a new signup
|
||||||
|
|
|
@ -19,7 +19,7 @@ use lemmy_db_schema::{
|
||||||
},
|
},
|
||||||
traits::{Crud, Likeable},
|
traits::{Crud, Likeable},
|
||||||
};
|
};
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl Perform for CreatePostLike {
|
impl Perform for CreatePostLike {
|
||||||
|
@ -57,7 +57,7 @@ impl Perform for CreatePostLike {
|
||||||
if do_add {
|
if do_add {
|
||||||
PostLike::like(context.pool(), &like_form)
|
PostLike::like(context.pool(), &like_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_like_post"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntLikePost)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark the post as read
|
// Mark the post as read
|
||||||
|
|
|
@ -10,7 +10,7 @@ use lemmy_db_schema::{
|
||||||
traits::Saveable,
|
traits::Saveable,
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::PostView;
|
use lemmy_db_views::structs::PostView;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl Perform for SavePost {
|
impl Perform for SavePost {
|
||||||
|
@ -29,11 +29,11 @@ impl Perform for SavePost {
|
||||||
if data.save {
|
if data.save {
|
||||||
PostSaved::save(context.pool(), &post_saved_form)
|
PostSaved::save(context.pool(), &post_saved_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_save_post"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntSavePost)?;
|
||||||
} else {
|
} else {
|
||||||
PostSaved::unsave(context.pool(), &post_saved_form)
|
PostSaved::unsave(context.pool(), &post_saved_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_save_post"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntSavePost)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let post_id = data.post_id;
|
let post_id = data.post_id;
|
||||||
|
|
|
@ -13,7 +13,7 @@ use lemmy_db_schema::{
|
||||||
traits::Reportable,
|
traits::Reportable,
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::{PostReportView, PostView};
|
use lemmy_db_views::structs::{PostReportView, PostView};
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
|
||||||
/// Creates a post report and notifies the moderators of the community
|
/// Creates a post report and notifies the moderators of the community
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
|
@ -46,7 +46,7 @@ impl Perform for CreatePostReport {
|
||||||
|
|
||||||
let report = PostReport::report(context.pool(), &report_form)
|
let report = PostReport::report(context.pool(), &report_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_create_report"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntCreateReport)?;
|
||||||
|
|
||||||
let post_report_view = PostReportView::read(context.pool(), report.id, person_id).await?;
|
let post_report_view = PostReportView::read(context.pool(), report.id, person_id).await?;
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ use lemmy_api_common::{
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{source::post_report::PostReport, traits::Reportable};
|
use lemmy_db_schema::{source::post_report::PostReport, traits::Reportable};
|
||||||
use lemmy_db_views::structs::PostReportView;
|
use lemmy_db_views::structs::PostReportView;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
|
||||||
/// Resolves or unresolves a post report and notifies the moderators of the community
|
/// Resolves or unresolves a post report and notifies the moderators of the community
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
|
@ -29,11 +29,11 @@ impl Perform for ResolvePostReport {
|
||||||
if data.resolved {
|
if data.resolved {
|
||||||
PostReport::resolve(context.pool(), report_id, person_id)
|
PostReport::resolve(context.pool(), report_id, person_id)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_resolve_report"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntResolveReport)?;
|
||||||
} else {
|
} else {
|
||||||
PostReport::unresolve(context.pool(), report_id, person_id)
|
PostReport::unresolve(context.pool(), report_id, person_id)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_resolve_report"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntResolveReport)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let post_report_view = PostReportView::read(context.pool(), report_id, person_id).await?;
|
let post_report_view = PostReportView::read(context.pool(), report_id, person_id).await?;
|
||||||
|
|
|
@ -10,7 +10,7 @@ use lemmy_db_schema::{
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::PrivateMessageView;
|
use lemmy_db_views::structs::PrivateMessageView;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl Perform for MarkPrivateMessageAsRead {
|
impl Perform for MarkPrivateMessageAsRead {
|
||||||
|
@ -28,7 +28,7 @@ impl Perform for MarkPrivateMessageAsRead {
|
||||||
let private_message_id = data.private_message_id;
|
let private_message_id = data.private_message_id;
|
||||||
let orig_private_message = PrivateMessage::read(context.pool(), private_message_id).await?;
|
let orig_private_message = PrivateMessage::read(context.pool(), private_message_id).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(LemmyError::from_message("couldnt_update_private_message"));
|
return Err(LemmyErrorType::CouldntUpdatePrivateMessage)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Doing the update
|
// Doing the update
|
||||||
|
@ -40,7 +40,7 @@ impl Perform for MarkPrivateMessageAsRead {
|
||||||
&PrivateMessageUpdateForm::builder().read(Some(read)).build(),
|
&PrivateMessageUpdateForm::builder().read(Some(read)).build(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_private_message"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntUpdatePrivateMessage)?;
|
||||||
|
|
||||||
let view = PrivateMessageView::read(context.pool(), private_message_id).await?;
|
let view = PrivateMessageView::read(context.pool(), private_message_id).await?;
|
||||||
Ok(PrivateMessageResponse {
|
Ok(PrivateMessageResponse {
|
||||||
|
|
|
@ -14,7 +14,7 @@ use lemmy_db_schema::{
|
||||||
traits::{Crud, Reportable},
|
traits::{Crud, Reportable},
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::PrivateMessageReportView;
|
use lemmy_db_views::structs::PrivateMessageReportView;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl Perform for CreatePrivateMessageReport {
|
impl Perform for CreatePrivateMessageReport {
|
||||||
|
@ -41,7 +41,7 @@ impl Perform for CreatePrivateMessageReport {
|
||||||
|
|
||||||
let report = PrivateMessageReport::report(context.pool(), &report_form)
|
let report = PrivateMessageReport::report(context.pool(), &report_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_create_report"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntCreateReport)?;
|
||||||
|
|
||||||
let private_message_report_view =
|
let private_message_report_view =
|
||||||
PrivateMessageReportView::read(context.pool(), report.id).await?;
|
PrivateMessageReportView::read(context.pool(), report.id).await?;
|
||||||
|
|
|
@ -7,7 +7,7 @@ use lemmy_api_common::{
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{source::private_message_report::PrivateMessageReport, traits::Reportable};
|
use lemmy_db_schema::{source::private_message_report::PrivateMessageReport, traits::Reportable};
|
||||||
use lemmy_db_views::structs::PrivateMessageReportView;
|
use lemmy_db_views::structs::PrivateMessageReportView;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl Perform for ResolvePrivateMessageReport {
|
impl Perform for ResolvePrivateMessageReport {
|
||||||
|
@ -24,11 +24,11 @@ impl Perform for ResolvePrivateMessageReport {
|
||||||
if self.resolved {
|
if self.resolved {
|
||||||
PrivateMessageReport::resolve(context.pool(), report_id, person_id)
|
PrivateMessageReport::resolve(context.pool(), report_id, person_id)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_resolve_report"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntResolveReport)?;
|
||||||
} else {
|
} else {
|
||||||
PrivateMessageReport::unresolve(context.pool(), report_id, person_id)
|
PrivateMessageReport::unresolve(context.pool(), report_id, person_id)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_resolve_report"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntResolveReport)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let private_message_report_view =
|
let private_message_report_view =
|
||||||
|
|
|
@ -17,7 +17,10 @@ use lemmy_db_schema::{
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::{CustomEmojiView, SiteView};
|
use lemmy_db_views::structs::{CustomEmojiView, SiteView};
|
||||||
use lemmy_db_views_actor::structs::PersonView;
|
use lemmy_db_views_actor::structs::PersonView;
|
||||||
use lemmy_utils::{error::LemmyError, version};
|
use lemmy_utils::{
|
||||||
|
error::{LemmyError, LemmyErrorType},
|
||||||
|
version,
|
||||||
|
};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl Perform for LeaveAdmin {
|
impl Perform for LeaveAdmin {
|
||||||
|
@ -33,7 +36,7 @@ impl Perform for LeaveAdmin {
|
||||||
// Make sure there isn't just one admin (so if one leaves, there will still be one left)
|
// Make sure there isn't just one admin (so if one leaves, there will still be one left)
|
||||||
let admins = PersonView::admins(context.pool()).await?;
|
let admins = PersonView::admins(context.pool()).await?;
|
||||||
if admins.len() == 1 {
|
if admins.len() == 1 {
|
||||||
return Err(LemmyError::from_message("cannot_leave_admin"));
|
return Err(LemmyErrorType::CannotLeaveAdmin)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let person_id = local_user_view.person.id;
|
let person_id = local_user_view.person.id;
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::post::SiteMetadata;
|
||||||
use encoding::{all::encodings, DecoderTrap};
|
use encoding::{all::encodings, DecoderTrap};
|
||||||
use lemmy_db_schema::newtypes::DbUrl;
|
use lemmy_db_schema::newtypes::DbUrl;
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
error::LemmyError,
|
error::{LemmyError, LemmyErrorType},
|
||||||
settings::structs::Settings,
|
settings::structs::Settings,
|
||||||
version::VERSION,
|
version::VERSION,
|
||||||
REQWEST_TIMEOUT,
|
REQWEST_TIMEOUT,
|
||||||
|
@ -40,13 +40,11 @@ fn html_to_site_metadata(html_bytes: &[u8], url: &Url) -> Result<SiteMetadata, L
|
||||||
.trim_start()
|
.trim_start()
|
||||||
.lines()
|
.lines()
|
||||||
.next()
|
.next()
|
||||||
.ok_or_else(|| LemmyError::from_message("No lines in html"))?
|
.ok_or(LemmyErrorType::NoLinesInHtml)?
|
||||||
.to_lowercase();
|
.to_lowercase();
|
||||||
|
|
||||||
if !first_line.starts_with("<!doctype html>") {
|
if !first_line.starts_with("<!doctype html>") {
|
||||||
return Err(LemmyError::from_message(
|
return Err(LemmyErrorType::SiteMetadataPageIsNotDoctypeHtml)?;
|
||||||
"Site metadata page fetch is not DOCTYPE html",
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut page = HTML::from_string(html.to_string(), None)?;
|
let mut page = HTML::from_string(html.to_string(), None)?;
|
||||||
|
@ -142,7 +140,7 @@ pub(crate) async fn fetch_pictrs(
|
||||||
if response.msg == "ok" {
|
if response.msg == "ok" {
|
||||||
Ok(response)
|
Ok(response)
|
||||||
} else {
|
} else {
|
||||||
Err(LemmyError::from_message(&response.msg))
|
Err(LemmyErrorType::PictrsResponseError(response.msg))?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,15 +159,15 @@ pub async fn purge_image_from_pictrs(
|
||||||
|
|
||||||
let alias = image_url
|
let alias = image_url
|
||||||
.path_segments()
|
.path_segments()
|
||||||
.ok_or_else(|| LemmyError::from_message("Image URL missing path segments"))?
|
.ok_or(LemmyErrorType::ImageUrlMissingPathSegments)?
|
||||||
.next_back()
|
.next_back()
|
||||||
.ok_or_else(|| LemmyError::from_message("Image URL missing last path segment"))?;
|
.ok_or(LemmyErrorType::ImageUrlMissingLastPathSegment)?;
|
||||||
|
|
||||||
let purge_url = format!("{}/internal/purge?alias={}", pictrs_config.url, alias);
|
let purge_url = format!("{}/internal/purge?alias={}", pictrs_config.url, alias);
|
||||||
|
|
||||||
let pictrs_api_key = pictrs_config
|
let pictrs_api_key = pictrs_config
|
||||||
.api_key
|
.api_key
|
||||||
.ok_or_else(|| LemmyError::from_message("pictrs_api_key_not_provided"))?;
|
.ok_or(LemmyErrorType::PictrsApiKeyNotProvided)?;
|
||||||
let response = client
|
let response = client
|
||||||
.post(&purge_url)
|
.post(&purge_url)
|
||||||
.timeout(REQWEST_TIMEOUT)
|
.timeout(REQWEST_TIMEOUT)
|
||||||
|
@ -182,7 +180,7 @@ pub async fn purge_image_from_pictrs(
|
||||||
if response.msg == "ok" {
|
if response.msg == "ok" {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(LemmyError::from_message(&response.msg))
|
Err(LemmyErrorType::PictrsPurgeResponseError(response.msg))?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,13 +250,13 @@ async fn is_image_content_type(client: &ClientWithMiddleware, url: &Url) -> Resu
|
||||||
if response
|
if response
|
||||||
.headers()
|
.headers()
|
||||||
.get("Content-Type")
|
.get("Content-Type")
|
||||||
.ok_or_else(|| LemmyError::from_message("No Content-Type header"))?
|
.ok_or(LemmyErrorType::NoContentTypeHeader)?
|
||||||
.to_str()?
|
.to_str()?
|
||||||
.starts_with("image/")
|
.starts_with("image/")
|
||||||
{
|
{
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(LemmyError::from_message("Not an image type."))
|
Err(LemmyErrorType::NotAnImageType)?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ use lemmy_db_views_actor::structs::{
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
claims::Claims,
|
claims::Claims,
|
||||||
email::{send_email, translations::Lang},
|
email::{send_email, translations::Lang},
|
||||||
error::LemmyError,
|
error::{LemmyError, LemmyErrorExt, LemmyErrorExt2, LemmyErrorType},
|
||||||
location_info,
|
location_info,
|
||||||
rate_limit::RateLimitConfig,
|
rate_limit::RateLimitConfig,
|
||||||
settings::structs::Settings,
|
settings::structs::Settings,
|
||||||
|
@ -56,7 +56,7 @@ pub async fn is_mod_or_admin(
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
let is_mod_or_admin = CommunityView::is_mod_or_admin(pool, person_id, community_id).await?;
|
let is_mod_or_admin = CommunityView::is_mod_or_admin(pool, person_id, community_id).await?;
|
||||||
if !is_mod_or_admin {
|
if !is_mod_or_admin {
|
||||||
return Err(LemmyError::from_message("not_a_mod_or_admin"));
|
return Err(LemmyErrorType::NotAModOrAdmin)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -74,13 +74,13 @@ pub async fn is_mod_or_admin_opt(
|
||||||
is_admin(local_user_view)
|
is_admin(local_user_view)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(LemmyError::from_message("not_a_mod_or_admin"))
|
Err(LemmyErrorType::NotAModOrAdmin)?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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(LemmyError::from_message("not_an_admin"));
|
return Err(LemmyErrorType::NotAnAdmin)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,7 @@ pub fn is_top_mod(
|
||||||
.map(|cm| cm.moderator.id)
|
.map(|cm| cm.moderator.id)
|
||||||
.unwrap_or(PersonId(0))
|
.unwrap_or(PersonId(0))
|
||||||
{
|
{
|
||||||
return Err(LemmyError::from_message("not_top_mod"));
|
return Err(LemmyErrorType::NotTopMod)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -104,7 +104,7 @@ pub fn is_top_mod(
|
||||||
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> {
|
||||||
Post::read(pool, post_id)
|
Post::read(pool, post_id)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_find_post"))
|
.with_lemmy_type(LemmyErrorType::CouldntFindPost)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
|
@ -117,7 +117,7 @@ pub async fn mark_post_as_read(
|
||||||
|
|
||||||
PostRead::mark_as_read(pool, &post_read_form)
|
PostRead::mark_as_read(pool, &post_read_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_mark_post_as_read"))
|
.with_lemmy_type(LemmyErrorType::CouldntMarkPostAsRead)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
|
@ -130,7 +130,7 @@ pub async fn mark_post_as_unread(
|
||||||
|
|
||||||
PostRead::mark_as_unread(pool, &post_read_form)
|
PostRead::mark_as_unread(pool, &post_read_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_mark_post_as_read"))
|
.with_lemmy_type(LemmyErrorType::CouldntMarkPostAsRead)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
|
@ -139,7 +139,7 @@ pub async fn local_user_view_from_jwt(
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
) -> Result<LocalUserView, LemmyError> {
|
) -> Result<LocalUserView, LemmyError> {
|
||||||
let claims = Claims::decode(jwt, &context.secret().jwt_secret)
|
let claims = Claims::decode(jwt, &context.secret().jwt_secret)
|
||||||
.map_err(|e| e.with_message("not_logged_in"))?
|
.with_lemmy_type(LemmyErrorType::NotLoggedIn)?
|
||||||
.claims;
|
.claims;
|
||||||
let local_user_id = LocalUserId(claims.sub);
|
let local_user_id = LocalUserId(claims.sub);
|
||||||
let local_user_view = LocalUserView::read(context.pool(), local_user_id).await?;
|
let local_user_view = LocalUserView::read(context.pool(), local_user_id).await?;
|
||||||
|
@ -169,7 +169,7 @@ 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(LemmyError::from_message("not_logged_in"))
|
Err(LemmyErrorType::NotLoggedIn)?
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -182,12 +182,12 @@ pub fn check_user_valid(
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
// Check for a site ban
|
// Check for a site ban
|
||||||
if is_banned(banned, ban_expires) {
|
if is_banned(banned, ban_expires) {
|
||||||
return Err(LemmyError::from_message("site_ban"));
|
return Err(LemmyErrorType::SiteBan)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for account deletion
|
// check for account deletion
|
||||||
if deleted {
|
if deleted {
|
||||||
return Err(LemmyError::from_message("deleted"));
|
return Err(LemmyErrorType::Deleted)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -203,7 +203,7 @@ pub async fn check_community_ban(
|
||||||
.await
|
.await
|
||||||
.is_ok();
|
.is_ok();
|
||||||
if is_banned {
|
if is_banned {
|
||||||
Err(LemmyError::from_message("community_ban"))
|
Err(LemmyErrorType::BannedFromCommunity)?
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -216,9 +216,9 @@ pub async fn check_community_deleted_or_removed(
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
let community = Community::read(pool, community_id)
|
let community = Community::read(pool, community_id)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_find_community"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntFindCommunity)?;
|
||||||
if community.deleted || community.removed {
|
if community.deleted || community.removed {
|
||||||
Err(LemmyError::from_message("deleted"))
|
Err(LemmyErrorType::Deleted)?
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -226,7 +226,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(LemmyError::from_message("deleted"))
|
Err(LemmyErrorType::Deleted)?
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -242,7 +242,7 @@ pub async fn check_person_block(
|
||||||
.await
|
.await
|
||||||
.is_ok();
|
.is_ok();
|
||||||
if is_blocked {
|
if is_blocked {
|
||||||
Err(LemmyError::from_message("person_block"))
|
Err(LemmyErrorType::PersonIsBlocked)?
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -251,7 +251,7 @@ pub async fn check_person_block(
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub fn check_downvotes_enabled(score: i16, local_site: &LocalSite) -> Result<(), LemmyError> {
|
pub fn check_downvotes_enabled(score: i16, local_site: &LocalSite) -> Result<(), LemmyError> {
|
||||||
if score == -1 && !local_site.enable_downvotes {
|
if score == -1 && !local_site.enable_downvotes {
|
||||||
return Err(LemmyError::from_message("downvotes_disabled"));
|
return Err(LemmyErrorType::DownvotesAreDisabled)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -262,7 +262,7 @@ pub fn check_private_instance(
|
||||||
local_site: &LocalSite,
|
local_site: &LocalSite,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
if local_user_view.is_none() && local_site.private_instance {
|
if local_user_view.is_none() && local_site.private_instance {
|
||||||
return Err(LemmyError::from_message("instance_is_private"));
|
return Err(LemmyErrorType::InstanceIsPrivate)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -293,7 +293,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.chars().count()) {
|
if !(10..=60).contains(&pass.chars().count()) {
|
||||||
Err(LemmyError::from_message("invalid_password"))
|
Err(LemmyErrorType::InvalidPassword)?
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -302,7 +302,7 @@ pub fn password_length_check(pass: &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() && honeypot != &Some(String::new()) {
|
if honeypot.is_some() && honeypot != &Some(String::new()) {
|
||||||
Err(LemmyError::from_message("honeypot_fail"))
|
Err(LemmyErrorType::HoneypotFailed)?
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -509,10 +509,12 @@ pub async fn check_registration_application(
|
||||||
let registration = RegistrationApplication::find_by_local_user_id(pool, local_user_id).await?;
|
let registration = RegistrationApplication::find_by_local_user_id(pool, local_user_id).await?;
|
||||||
if let Some(deny_reason) = registration.deny_reason {
|
if let Some(deny_reason) = registration.deny_reason {
|
||||||
let lang = get_interface_language(local_user_view);
|
let lang = get_interface_language(local_user_view);
|
||||||
let registration_denied_message = format!("{}: {}", lang.registration_denied(), &deny_reason);
|
let registration_denied_message = format!("{}: {}", lang.registration_denied(), deny_reason);
|
||||||
return Err(LemmyError::from_message(®istration_denied_message));
|
return Err(LemmyErrorType::RegistrationDenied(
|
||||||
|
registration_denied_message,
|
||||||
|
))?;
|
||||||
} else {
|
} else {
|
||||||
return Err(LemmyError::from_message("registration_application_pending"));
|
return Err(LemmyErrorType::RegistrationApplicationIsPending)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -522,9 +524,7 @@ pub fn check_private_instance_and_federation_enabled(
|
||||||
local_site: &LocalSite,
|
local_site: &LocalSite,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
if local_site.private_instance && local_site.federation_enabled {
|
if local_site.private_instance && local_site.federation_enabled {
|
||||||
return Err(LemmyError::from_message(
|
return Err(LemmyErrorType::CantEnablePrivateInstanceAndFederationTogether)?;
|
||||||
"Cannot have both private instance and federation enabled.",
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -712,12 +712,12 @@ pub async fn delete_user_account(
|
||||||
// Comments
|
// Comments
|
||||||
Comment::permadelete_for_creator(pool, person_id)
|
Comment::permadelete_for_creator(pool, person_id)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_comment"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?;
|
||||||
|
|
||||||
// Posts
|
// Posts
|
||||||
Post::permadelete_for_creator(pool, person_id)
|
Post::permadelete_for_creator(pool, person_id)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_post"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntUpdatePost)?;
|
||||||
|
|
||||||
// Purge image posts
|
// Purge image posts
|
||||||
purge_image_posts_for_person(person_id, pool, settings, client).await?;
|
purge_image_posts_for_person(person_id, pool, settings, client).await?;
|
||||||
|
|
|
@ -26,13 +26,14 @@ use lemmy_db_schema::{
|
||||||
traits::{Crud, Likeable},
|
traits::{Crud, Likeable},
|
||||||
};
|
};
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
error::LemmyError,
|
error::{LemmyError, LemmyErrorExt, LemmyErrorType},
|
||||||
utils::{
|
utils::{
|
||||||
mention::scrape_text_for_mentions,
|
mention::scrape_text_for_mentions,
|
||||||
slurs::remove_slurs,
|
slurs::remove_slurs,
|
||||||
validation::is_valid_body_field,
|
validation::is_valid_body_field,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const MAX_COMMENT_DEPTH_LIMIT: usize = 100;
|
const MAX_COMMENT_DEPTH_LIMIT: usize = 100;
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
|
@ -62,7 +63,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(LemmyError::from_message("locked"));
|
return Err(LemmyErrorType::Locked)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch the parent, if it exists
|
// Fetch the parent, if it exists
|
||||||
|
@ -76,7 +77,7 @@ impl PerformCrud for CreateComment {
|
||||||
// Strange issue where sometimes the post ID of the parent comment is incorrect
|
// Strange issue where sometimes the post ID of the parent comment is incorrect
|
||||||
if let Some(parent) = parent_opt.as_ref() {
|
if let Some(parent) = parent_opt.as_ref() {
|
||||||
if parent.post_id != post_id {
|
if parent.post_id != post_id {
|
||||||
return Err(LemmyError::from_message("couldnt_create_comment"));
|
return Err(LemmyErrorType::CouldntCreateComment)?;
|
||||||
}
|
}
|
||||||
check_comment_depth(parent)?;
|
check_comment_depth(parent)?;
|
||||||
}
|
}
|
||||||
|
@ -106,7 +107,7 @@ impl PerformCrud for CreateComment {
|
||||||
let parent_path = parent_opt.clone().map(|t| t.path);
|
let parent_path = parent_opt.clone().map(|t| t.path);
|
||||||
let inserted_comment = Comment::create(context.pool(), &comment_form, parent_path.as_ref())
|
let inserted_comment = Comment::create(context.pool(), &comment_form, parent_path.as_ref())
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_create_comment"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntCreateComment)?;
|
||||||
|
|
||||||
// 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;
|
||||||
|
@ -123,7 +124,7 @@ impl PerformCrud for CreateComment {
|
||||||
&CommentUpdateForm::builder().ap_id(Some(apub_id)).build(),
|
&CommentUpdateForm::builder().ap_id(Some(apub_id)).build(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_create_comment"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntCreateComment)?;
|
||||||
|
|
||||||
// Scan the comment for user mentions, add those rows
|
// Scan the comment for user mentions, add those rows
|
||||||
let mentions = scrape_text_for_mentions(&content_slurs_removed);
|
let mentions = scrape_text_for_mentions(&content_slurs_removed);
|
||||||
|
@ -147,7 +148,7 @@ impl PerformCrud for CreateComment {
|
||||||
|
|
||||||
CommentLike::like(context.pool(), &like_form)
|
CommentLike::like(context.pool(), &like_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_like_comment"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntLikeComment)?;
|
||||||
|
|
||||||
// If its a reply, mark the parent as read
|
// If its a reply, mark the parent as read
|
||||||
if let Some(parent) = parent_opt {
|
if let Some(parent) = parent_opt {
|
||||||
|
@ -160,7 +161,7 @@ impl PerformCrud for CreateComment {
|
||||||
&CommentReplyUpdateForm { read: Some(true) },
|
&CommentReplyUpdateForm { read: Some(true) },
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_replies"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntUpdateReplies)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the parent has PersonMentions mark them as read too
|
// If the parent has PersonMentions mark them as read too
|
||||||
|
@ -174,7 +175,7 @@ impl PerformCrud for CreateComment {
|
||||||
&PersonMentionUpdateForm { read: Some(true) },
|
&PersonMentionUpdateForm { read: Some(true) },
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_person_mentions"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntUpdatePersonMentions)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,7 +194,7 @@ pub fn check_comment_depth(comment: &Comment) -> Result<(), LemmyError> {
|
||||||
let path = &comment.path.0;
|
let path = &comment.path.0;
|
||||||
let length = path.split('.').count();
|
let length = path.split('.').count();
|
||||||
if length > MAX_COMMENT_DEPTH_LIMIT {
|
if length > MAX_COMMENT_DEPTH_LIMIT {
|
||||||
Err(LemmyError::from_message("max_comment_depth_reached"))
|
Err(LemmyErrorType::MaxCommentDepthReached)?
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ use lemmy_db_schema::{
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::CommentView;
|
use lemmy_db_views::structs::CommentView;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl PerformCrud for DeleteComment {
|
impl PerformCrud for DeleteComment {
|
||||||
|
@ -30,7 +30,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(LemmyError::from_message("couldnt_update_comment"));
|
return Err(LemmyErrorType::CouldntUpdateComment)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
check_community_ban(
|
check_community_ban(
|
||||||
|
@ -42,7 +42,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(LemmyError::from_message("no_comment_edit_allowed"));
|
return Err(LemmyErrorType::NoCommentEditAllowed)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do the delete
|
// Do the delete
|
||||||
|
@ -53,7 +53,7 @@ impl PerformCrud for DeleteComment {
|
||||||
&CommentUpdateForm::builder().deleted(Some(deleted)).build(),
|
&CommentUpdateForm::builder().deleted(Some(deleted)).build(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_comment"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?;
|
||||||
|
|
||||||
let post_id = updated_comment.post_id;
|
let post_id = updated_comment.post_id;
|
||||||
let post = Post::read(context.pool(), post_id).await?;
|
let post = Post::read(context.pool(), post_id).await?;
|
||||||
|
|
|
@ -15,7 +15,7 @@ use lemmy_db_schema::{
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::CommentView;
|
use lemmy_db_views::structs::CommentView;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl PerformCrud for RemoveComment {
|
impl PerformCrud for RemoveComment {
|
||||||
|
@ -52,7 +52,7 @@ impl PerformCrud for RemoveComment {
|
||||||
&CommentUpdateForm::builder().removed(Some(removed)).build(),
|
&CommentUpdateForm::builder().removed(Some(removed)).build(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_comment"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?;
|
||||||
|
|
||||||
// Mod tables
|
// Mod tables
|
||||||
let form = ModRemoveCommentForm {
|
let form = ModRemoveCommentForm {
|
||||||
|
|
|
@ -17,7 +17,7 @@ use lemmy_db_schema::{
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::CommentView;
|
use lemmy_db_views::structs::CommentView;
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
error::LemmyError,
|
error::{LemmyError, LemmyErrorExt, LemmyErrorType},
|
||||||
utils::{
|
utils::{
|
||||||
mention::scrape_text_for_mentions,
|
mention::scrape_text_for_mentions,
|
||||||
slurs::remove_slurs,
|
slurs::remove_slurs,
|
||||||
|
@ -47,7 +47,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(LemmyError::from_message("no_comment_edit_allowed"));
|
return Err(LemmyErrorType::NoCommentEditAllowed)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let language_id = self.language_id;
|
let language_id = self.language_id;
|
||||||
|
@ -74,7 +74,7 @@ impl PerformCrud for EditComment {
|
||||||
.build();
|
.build();
|
||||||
let updated_comment = Comment::update(context.pool(), comment_id, &form)
|
let updated_comment = Comment::update(context.pool(), comment_id, &form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_comment"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?;
|
||||||
|
|
||||||
// Do the mentions / recipients
|
// Do the mentions / recipients
|
||||||
let updated_comment_content = updated_comment.content.clone();
|
let updated_comment_content = updated_comment.content.clone();
|
||||||
|
|
|
@ -33,7 +33,7 @@ use lemmy_db_schema::{
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::SiteView;
|
use lemmy_db_views::structs::SiteView;
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
error::LemmyError,
|
error::{LemmyError, LemmyErrorExt, LemmyErrorType},
|
||||||
utils::{
|
utils::{
|
||||||
slurs::{check_slurs, check_slurs_opt},
|
slurs::{check_slurs, check_slurs_opt},
|
||||||
validation::{is_valid_actor_name, is_valid_body_field},
|
validation::{is_valid_actor_name, is_valid_body_field},
|
||||||
|
@ -52,9 +52,7 @@ impl PerformCrud for CreateCommunity {
|
||||||
let local_site = site_view.local_site;
|
let local_site = site_view.local_site;
|
||||||
|
|
||||||
if local_site.community_creation_admin_only && is_admin(&local_user_view).is_err() {
|
if local_site.community_creation_admin_only && is_admin(&local_user_view).is_err() {
|
||||||
return Err(LemmyError::from_message(
|
return Err(LemmyErrorType::OnlyAdminsCanCreateCommunities)?;
|
||||||
"only_admins_can_create_communities",
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check to make sure the icon and banners are urls
|
// Check to make sure the icon and banners are urls
|
||||||
|
@ -77,7 +75,7 @@ impl PerformCrud for CreateCommunity {
|
||||||
)?;
|
)?;
|
||||||
let community_dupe = Community::read_from_apub_id(context.pool(), &community_actor_id).await?;
|
let community_dupe = Community::read_from_apub_id(context.pool(), &community_actor_id).await?;
|
||||||
if community_dupe.is_some() {
|
if community_dupe.is_some() {
|
||||||
return Err(LemmyError::from_message("community_already_exists"));
|
return Err(LemmyErrorType::CommunityAlreadyExists)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// When you create a community, make sure the user becomes a moderator and a follower
|
// When you create a community, make sure the user becomes a moderator and a follower
|
||||||
|
@ -102,7 +100,7 @@ impl PerformCrud for CreateCommunity {
|
||||||
|
|
||||||
let inserted_community = Community::create(context.pool(), &community_form)
|
let inserted_community = Community::create(context.pool(), &community_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "community_already_exists"))?;
|
.with_lemmy_type(LemmyErrorType::CommunityAlreadyExists)?;
|
||||||
|
|
||||||
// The community creator becomes a moderator
|
// The community creator becomes a moderator
|
||||||
let community_moderator_form = CommunityModeratorForm {
|
let community_moderator_form = CommunityModeratorForm {
|
||||||
|
@ -112,7 +110,7 @@ impl PerformCrud for CreateCommunity {
|
||||||
|
|
||||||
CommunityModerator::join(context.pool(), &community_moderator_form)
|
CommunityModerator::join(context.pool(), &community_moderator_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "community_moderator_already_exists"))?;
|
.with_lemmy_type(LemmyErrorType::CommunityModeratorAlreadyExists)?;
|
||||||
|
|
||||||
// Follow your own community
|
// Follow your own community
|
||||||
let community_follower_form = CommunityFollowerForm {
|
let community_follower_form = CommunityFollowerForm {
|
||||||
|
@ -123,7 +121,7 @@ impl PerformCrud for CreateCommunity {
|
||||||
|
|
||||||
CommunityFollower::follow(context.pool(), &community_follower_form)
|
CommunityFollower::follow(context.pool(), &community_follower_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "community_follower_already_exists"))?;
|
.with_lemmy_type(LemmyErrorType::CommunityFollowerAlreadyExists)?;
|
||||||
|
|
||||||
// Update the discussion_languages if that's provided
|
// Update the discussion_languages if that's provided
|
||||||
let community_id = inserted_community.id;
|
let community_id = inserted_community.id;
|
||||||
|
@ -133,7 +131,7 @@ impl PerformCrud for CreateCommunity {
|
||||||
// https://stackoverflow.com/a/64227550
|
// https://stackoverflow.com/a/64227550
|
||||||
let is_subset = languages.iter().all(|item| site_languages.contains(item));
|
let is_subset = languages.iter().all(|item| site_languages.contains(item));
|
||||||
if !is_subset {
|
if !is_subset {
|
||||||
return Err(LemmyError::from_message("language_not_allowed"));
|
return Err(LemmyErrorType::LanguageNotAllowed)?;
|
||||||
}
|
}
|
||||||
CommunityLanguage::update(context.pool(), languages, community_id).await?;
|
CommunityLanguage::update(context.pool(), languages, community_id).await?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ use lemmy_db_schema::{
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
};
|
};
|
||||||
use lemmy_db_views_actor::structs::CommunityModeratorView;
|
use lemmy_db_views_actor::structs::CommunityModeratorView;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl PerformCrud for DeleteCommunity {
|
impl PerformCrud for DeleteCommunity {
|
||||||
|
@ -41,7 +41,7 @@ impl PerformCrud for DeleteCommunity {
|
||||||
.build(),
|
.build(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_community"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntUpdateCommunity)?;
|
||||||
|
|
||||||
build_community_response(context, local_user_view, community_id).await
|
build_community_response(context, local_user_view, community_id).await
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,10 @@ use lemmy_db_schema::{
|
||||||
},
|
},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
};
|
};
|
||||||
use lemmy_utils::{error::LemmyError, utils::time::naive_from_unix};
|
use lemmy_utils::{
|
||||||
|
error::{LemmyError, LemmyErrorExt, LemmyErrorType},
|
||||||
|
utils::time::naive_from_unix,
|
||||||
|
};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl PerformCrud for RemoveCommunity {
|
impl PerformCrud for RemoveCommunity {
|
||||||
|
@ -38,7 +41,7 @@ impl PerformCrud for RemoveCommunity {
|
||||||
.build(),
|
.build(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_community"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntUpdateCommunity)?;
|
||||||
|
|
||||||
// Mod tables
|
// Mod tables
|
||||||
let expires = data.expires.map(naive_from_unix);
|
let expires = data.expires.map(naive_from_unix);
|
||||||
|
|
|
@ -18,7 +18,7 @@ use lemmy_db_schema::{
|
||||||
};
|
};
|
||||||
use lemmy_db_views_actor::structs::CommunityModeratorView;
|
use lemmy_db_views_actor::structs::CommunityModeratorView;
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
error::LemmyError,
|
error::{LemmyError, LemmyErrorExt, LemmyErrorType},
|
||||||
utils::{slurs::check_slurs_opt, validation::is_valid_body_field},
|
utils::{slurs::check_slurs_opt, validation::is_valid_body_field},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ impl PerformCrud for EditCommunity {
|
||||||
.await
|
.await
|
||||||
.map(|v| v.into_iter().map(|m| m.moderator.id).collect())?;
|
.map(|v| v.into_iter().map(|m| m.moderator.id).collect())?;
|
||||||
if !mods.contains(&local_user_view.person.id) {
|
if !mods.contains(&local_user_view.person.id) {
|
||||||
return Err(LemmyError::from_message("not_a_moderator"));
|
return Err(LemmyErrorType::NotAModerator)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let community_id = data.community_id;
|
let community_id = data.community_id;
|
||||||
|
@ -57,7 +57,7 @@ impl PerformCrud for EditCommunity {
|
||||||
// https://stackoverflow.com/a/64227550
|
// https://stackoverflow.com/a/64227550
|
||||||
let is_subset = languages.iter().all(|item| site_languages.contains(item));
|
let is_subset = languages.iter().all(|item| site_languages.contains(item));
|
||||||
if !is_subset {
|
if !is_subset {
|
||||||
return Err(LemmyError::from_message("language_not_allowed"));
|
return Err(LemmyErrorType::LanguageNotAllowed)?;
|
||||||
}
|
}
|
||||||
CommunityLanguage::update(context.pool(), languages, community_id).await?;
|
CommunityLanguage::update(context.pool(), languages, community_id).await?;
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ impl PerformCrud for EditCommunity {
|
||||||
let community_id = data.community_id;
|
let community_id = data.community_id;
|
||||||
Community::update(context.pool(), community_id, &community_form)
|
Community::update(context.pool(), community_id, &community_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_community"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntUpdateCommunity)?;
|
||||||
|
|
||||||
build_community_response(context, local_user_view, community_id).await
|
build_community_response(context, local_user_view, community_id).await
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ use lemmy_db_schema::{
|
||||||
};
|
};
|
||||||
use lemmy_db_views_actor::structs::CommunityView;
|
use lemmy_db_views_actor::structs::CommunityView;
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
error::LemmyError,
|
error::{LemmyError, LemmyErrorExt, LemmyErrorType},
|
||||||
spawn_try_task,
|
spawn_try_task,
|
||||||
utils::{
|
utils::{
|
||||||
slurs::{check_slurs, check_slurs_opt},
|
slurs::{check_slurs, check_slurs_opt},
|
||||||
|
@ -76,7 +76,7 @@ impl PerformCrud for CreatePost {
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
if !is_mod {
|
if !is_mod {
|
||||||
return Err(LemmyError::from_message("only_mods_can_post_in_community"));
|
return Err(LemmyErrorType::OnlyModsCanPostInCommunity)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +112,7 @@ impl PerformCrud for CreatePost {
|
||||||
|
|
||||||
let inserted_post = Post::create(context.pool(), &post_form)
|
let inserted_post = Post::create(context.pool(), &post_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_create_post"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntCreatePost)?;
|
||||||
|
|
||||||
let inserted_post_id = inserted_post.id;
|
let inserted_post_id = inserted_post.id;
|
||||||
let protocol_and_hostname = context.settings().get_protocol_and_hostname();
|
let protocol_and_hostname = context.settings().get_protocol_and_hostname();
|
||||||
|
@ -127,7 +127,7 @@ impl PerformCrud for CreatePost {
|
||||||
&PostUpdateForm::builder().ap_id(Some(apub_id)).build(),
|
&PostUpdateForm::builder().ap_id(Some(apub_id)).build(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_create_post"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntCreatePost)?;
|
||||||
|
|
||||||
// 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;
|
||||||
|
@ -140,7 +140,7 @@ impl PerformCrud for CreatePost {
|
||||||
|
|
||||||
PostLike::like(context.pool(), &like_form)
|
PostLike::like(context.pool(), &like_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_like_post"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntLikePost)?;
|
||||||
|
|
||||||
// Mark the post as read
|
// Mark the post as read
|
||||||
mark_post_as_read(person_id, post_id, context.pool()).await?;
|
mark_post_as_read(person_id, post_id, context.pool()).await?;
|
||||||
|
@ -157,10 +157,7 @@ impl PerformCrud for CreatePost {
|
||||||
{
|
{
|
||||||
Err(WebmentionError::NoEndpointDiscovered(_)) => Ok(()),
|
Err(WebmentionError::NoEndpointDiscovered(_)) => Ok(()),
|
||||||
Ok(_) => Ok(()),
|
Ok(_) => Ok(()),
|
||||||
Err(e) => Err(LemmyError::from_error_message(
|
Err(e) => Err(e).with_lemmy_type(LemmyErrorType::CouldntSendWebmention),
|
||||||
e,
|
|
||||||
"Couldn't send webmention",
|
|
||||||
)),
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if *SYNCHRONOUS_FEDERATION {
|
if *SYNCHRONOUS_FEDERATION {
|
||||||
|
|
|
@ -10,7 +10,7 @@ use lemmy_db_schema::{
|
||||||
source::post::{Post, PostUpdateForm},
|
source::post::{Post, PostUpdateForm},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
};
|
};
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorType};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl PerformCrud for DeletePost {
|
impl PerformCrud for DeletePost {
|
||||||
|
@ -26,7 +26,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(LemmyError::from_message("couldnt_update_post"));
|
return Err(LemmyErrorType::CouldntUpdatePost)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
check_community_ban(
|
check_community_ban(
|
||||||
|
@ -39,7 +39,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(LemmyError::from_message("no_post_edit_allowed"));
|
return Err(LemmyErrorType::NoPostEditAllowed)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the post
|
// Update the post
|
||||||
|
|
|
@ -17,7 +17,7 @@ use lemmy_db_schema::{
|
||||||
};
|
};
|
||||||
use lemmy_db_views::{post_view::PostQuery, structs::PostView};
|
use lemmy_db_views::{post_view::PostQuery, structs::PostView};
|
||||||
use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView};
|
use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView};
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl PerformCrud for GetPost {
|
impl PerformCrud for GetPost {
|
||||||
|
@ -39,10 +39,10 @@ impl PerformCrud for GetPost {
|
||||||
} else if let Some(comment_id) = data.comment_id {
|
} else if let Some(comment_id) = data.comment_id {
|
||||||
Comment::read(context.pool(), comment_id)
|
Comment::read(context.pool(), comment_id)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_find_post"))?
|
.with_lemmy_type(LemmyErrorType::CouldntFindPost)?
|
||||||
.post_id
|
.post_id
|
||||||
} else {
|
} else {
|
||||||
Err(LemmyError::from_message("couldnt_find_post"))?
|
Err(LemmyErrorType::CouldntFindPost)?
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check to see if the person is a mod or admin, to show deleted / removed
|
// Check to see if the person is a mod or admin, to show deleted / removed
|
||||||
|
@ -54,7 +54,7 @@ impl PerformCrud for GetPost {
|
||||||
|
|
||||||
let post_view = PostView::read(context.pool(), post_id, person_id, Some(is_mod_or_admin))
|
let post_view = PostView::read(context.pool(), post_id, person_id, Some(is_mod_or_admin))
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_find_post"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntFindPost)?;
|
||||||
|
|
||||||
// Mark the post as read
|
// Mark the post as read
|
||||||
let post_id = post_view.post.id;
|
let post_id = post_view.post.id;
|
||||||
|
@ -70,7 +70,7 @@ impl PerformCrud for GetPost {
|
||||||
Some(is_mod_or_admin),
|
Some(is_mod_or_admin),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_find_community"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntFindCommunity)?;
|
||||||
|
|
||||||
// Insert into PersonPostAggregates
|
// Insert into PersonPostAggregates
|
||||||
// to update the read_comments count
|
// to update the read_comments count
|
||||||
|
@ -84,7 +84,7 @@ impl PerformCrud for GetPost {
|
||||||
};
|
};
|
||||||
PersonPostAggregates::upsert(context.pool(), &person_post_agg_form)
|
PersonPostAggregates::upsert(context.pool(), &person_post_agg_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_find_post"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntFindPost)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let moderators = CommunityModeratorView::for_community(context.pool(), community_id).await?;
|
let moderators = CommunityModeratorView::for_community(context.pool(), community_id).await?;
|
||||||
|
|
|
@ -17,7 +17,7 @@ use lemmy_db_schema::{
|
||||||
utils::{diesel_option_overwrite, naive_now},
|
utils::{diesel_option_overwrite, naive_now},
|
||||||
};
|
};
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
error::LemmyError,
|
error::{LemmyError, LemmyErrorExt, LemmyErrorType},
|
||||||
utils::{
|
utils::{
|
||||||
slurs::check_slurs_opt,
|
slurs::check_slurs_opt,
|
||||||
validation::{check_url_scheme, clean_url_params, is_valid_body_field, is_valid_post_title},
|
validation::{check_url_scheme, clean_url_params, is_valid_body_field, is_valid_post_title},
|
||||||
|
@ -64,7 +64,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(LemmyError::from_message("no_post_edit_allowed"));
|
return Err(LemmyErrorType::NoPostEditAllowed)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch post links and Pictrs cached image
|
// Fetch post links and Pictrs cached image
|
||||||
|
@ -99,7 +99,7 @@ impl PerformCrud for EditPost {
|
||||||
let post_id = data.post_id;
|
let post_id = data.post_id;
|
||||||
Post::update(context.pool(), post_id, &post_form)
|
Post::update(context.pool(), post_id, &post_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_create_post"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntUpdatePost)?;
|
||||||
|
|
||||||
build_post_response(
|
build_post_response(
|
||||||
context,
|
context,
|
||||||
|
|
|
@ -22,7 +22,7 @@ use lemmy_db_schema::{
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::{LocalUserView, PrivateMessageView};
|
use lemmy_db_views::structs::{LocalUserView, PrivateMessageView};
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
error::LemmyError,
|
error::{LemmyError, LemmyErrorExt, LemmyErrorType},
|
||||||
utils::{slurs::remove_slurs, validation::is_valid_body_field},
|
utils::{slurs::remove_slurs, validation::is_valid_body_field},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -53,16 +53,9 @@ impl PerformCrud for CreatePrivateMessage {
|
||||||
.recipient_id(data.recipient_id)
|
.recipient_id(data.recipient_id)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let inserted_private_message =
|
let inserted_private_message = PrivateMessage::create(context.pool(), &private_message_form)
|
||||||
match PrivateMessage::create(context.pool(), &private_message_form).await {
|
.await
|
||||||
Ok(private_message) => private_message,
|
.with_lemmy_type(LemmyErrorType::CouldntCreatePrivateMessage)?;
|
||||||
Err(e) => {
|
|
||||||
return Err(LemmyError::from_error_message(
|
|
||||||
e,
|
|
||||||
"couldnt_create_private_message",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let inserted_private_message_id = inserted_private_message.id;
|
let inserted_private_message_id = inserted_private_message.id;
|
||||||
let protocol_and_hostname = context.settings().get_protocol_and_hostname();
|
let protocol_and_hostname = context.settings().get_protocol_and_hostname();
|
||||||
|
@ -79,7 +72,7 @@ impl PerformCrud for CreatePrivateMessage {
|
||||||
.build(),
|
.build(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_create_private_message"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntCreatePrivateMessage)?;
|
||||||
|
|
||||||
let view = PrivateMessageView::read(context.pool(), inserted_private_message.id).await?;
|
let view = PrivateMessageView::read(context.pool(), inserted_private_message.id).await?;
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ use lemmy_db_schema::{
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::PrivateMessageView;
|
use lemmy_db_views::structs::PrivateMessageView;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl PerformCrud for DeletePrivateMessage {
|
impl PerformCrud for DeletePrivateMessage {
|
||||||
|
@ -28,7 +28,7 @@ impl PerformCrud for DeletePrivateMessage {
|
||||||
let private_message_id = data.private_message_id;
|
let private_message_id = data.private_message_id;
|
||||||
let orig_private_message = PrivateMessage::read(context.pool(), private_message_id).await?;
|
let orig_private_message = PrivateMessage::read(context.pool(), private_message_id).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(LemmyError::from_message("no_private_message_edit_allowed"));
|
return Err(LemmyErrorType::EditPrivateMessageNotAllowed)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Doing the update
|
// Doing the update
|
||||||
|
@ -42,7 +42,7 @@ impl PerformCrud for DeletePrivateMessage {
|
||||||
.build(),
|
.build(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_private_message"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntUpdatePrivateMessage)?;
|
||||||
|
|
||||||
let view = PrivateMessageView::read(context.pool(), private_message_id).await?;
|
let view = PrivateMessageView::read(context.pool(), private_message_id).await?;
|
||||||
Ok(PrivateMessageResponse {
|
Ok(PrivateMessageResponse {
|
||||||
|
|
|
@ -15,7 +15,7 @@ use lemmy_db_schema::{
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::PrivateMessageView;
|
use lemmy_db_views::structs::PrivateMessageView;
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
error::LemmyError,
|
error::{LemmyError, LemmyErrorExt, LemmyErrorType},
|
||||||
utils::{slurs::remove_slurs, validation::is_valid_body_field},
|
utils::{slurs::remove_slurs, validation::is_valid_body_field},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ impl PerformCrud for EditPrivateMessage {
|
||||||
let private_message_id = data.private_message_id;
|
let private_message_id = data.private_message_id;
|
||||||
let orig_private_message = PrivateMessage::read(context.pool(), private_message_id).await?;
|
let orig_private_message = PrivateMessage::read(context.pool(), private_message_id).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(LemmyError::from_message("no_private_message_edit_allowed"));
|
return Err(LemmyErrorType::EditPrivateMessageNotAllowed)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Doing the update
|
// Doing the update
|
||||||
|
@ -53,7 +53,7 @@ impl PerformCrud for EditPrivateMessage {
|
||||||
.build(),
|
.build(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_update_private_message"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntUpdatePrivateMessage)?;
|
||||||
|
|
||||||
let view = PrivateMessageView::read(context.pool(), private_message_id).await?;
|
let view = PrivateMessageView::read(context.pool(), private_message_id).await?;
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ use lemmy_db_schema::{
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::SiteView;
|
use lemmy_db_views::structs::SiteView;
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
error::{LemmyError, LemmyResult},
|
error::{LemmyError, LemmyErrorType, LemmyResult},
|
||||||
utils::{
|
utils::{
|
||||||
slurs::{check_slurs, check_slurs_opt},
|
slurs::{check_slurs, check_slurs_opt},
|
||||||
validation::{
|
validation::{
|
||||||
|
@ -140,7 +140,7 @@ impl PerformCrud for CreateSite {
|
||||||
fn validate_create_payload(local_site: &LocalSite, create_site: &CreateSite) -> LemmyResult<()> {
|
fn validate_create_payload(local_site: &LocalSite, create_site: &CreateSite) -> LemmyResult<()> {
|
||||||
// Make sure the site hasn't already been set up...
|
// Make sure the site hasn't already been set up...
|
||||||
if local_site.site_setup {
|
if local_site.site_setup {
|
||||||
return Err(LemmyError::from_message("site_already_exists"));
|
return Err(LemmyErrorType::SiteAlreadyExists)?;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check that the slur regex compiles, and returns the regex if valid...
|
// Check that the slur regex compiles, and returns the regex if valid...
|
||||||
|
@ -186,13 +186,14 @@ mod tests {
|
||||||
use crate::site::create::validate_create_payload;
|
use crate::site::create::validate_create_payload;
|
||||||
use lemmy_api_common::site::CreateSite;
|
use lemmy_api_common::site::CreateSite;
|
||||||
use lemmy_db_schema::{source::local_site::LocalSite, ListingType, RegistrationMode};
|
use lemmy_db_schema::{source::local_site::LocalSite, ListingType, RegistrationMode};
|
||||||
|
use lemmy_utils::error::LemmyErrorType;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_validate_invalid_create_payload() {
|
fn test_validate_invalid_create_payload() {
|
||||||
let invalid_payloads = [
|
let invalid_payloads = [
|
||||||
(
|
(
|
||||||
"CreateSite attempted on set up LocalSite",
|
"CreateSite attempted on set up LocalSite",
|
||||||
"site_already_exists",
|
LemmyErrorType::SiteAlreadyExists,
|
||||||
&generate_local_site(
|
&generate_local_site(
|
||||||
true,
|
true,
|
||||||
None::<String>,
|
None::<String>,
|
||||||
|
@ -215,7 +216,7 @@ mod tests {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"CreateSite name matches LocalSite slur filter",
|
"CreateSite name matches LocalSite slur filter",
|
||||||
"slurs",
|
LemmyErrorType::Slurs,
|
||||||
&generate_local_site(
|
&generate_local_site(
|
||||||
false,
|
false,
|
||||||
Some(String::from("(foo|bar)")),
|
Some(String::from("(foo|bar)")),
|
||||||
|
@ -238,7 +239,7 @@ mod tests {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"CreateSite name matches new slur filter",
|
"CreateSite name matches new slur filter",
|
||||||
"slurs",
|
LemmyErrorType::Slurs,
|
||||||
&generate_local_site(
|
&generate_local_site(
|
||||||
false,
|
false,
|
||||||
Some(String::from("(foo|bar)")),
|
Some(String::from("(foo|bar)")),
|
||||||
|
@ -261,7 +262,7 @@ mod tests {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"CreateSite listing type is Subscribed, which is invalid",
|
"CreateSite listing type is Subscribed, which is invalid",
|
||||||
"invalid_default_post_listing_type",
|
LemmyErrorType::InvalidDefaultPostListingType,
|
||||||
&generate_local_site(
|
&generate_local_site(
|
||||||
false,
|
false,
|
||||||
None::<String>,
|
None::<String>,
|
||||||
|
@ -284,7 +285,7 @@ mod tests {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"CreateSite is both private and federated",
|
"CreateSite is both private and federated",
|
||||||
"cant_enable_private_instance_and_federation_together",
|
LemmyErrorType::CantEnablePrivateInstanceAndFederationTogether,
|
||||||
&generate_local_site(
|
&generate_local_site(
|
||||||
false,
|
false,
|
||||||
None::<String>,
|
None::<String>,
|
||||||
|
@ -307,7 +308,7 @@ mod tests {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"LocalSite is private, but CreateSite also makes it federated",
|
"LocalSite is private, but CreateSite also makes it federated",
|
||||||
"cant_enable_private_instance_and_federation_together",
|
LemmyErrorType::CantEnablePrivateInstanceAndFederationTogether,
|
||||||
&generate_local_site(
|
&generate_local_site(
|
||||||
false,
|
false,
|
||||||
None::<String>,
|
None::<String>,
|
||||||
|
@ -330,7 +331,7 @@ mod tests {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"CreateSite requires application, but neither it nor LocalSite has an application question",
|
"CreateSite requires application, but neither it nor LocalSite has an application question",
|
||||||
"application_question_required",
|
LemmyErrorType::ApplicationQuestionRequired,
|
||||||
&generate_local_site(
|
&generate_local_site(
|
||||||
false,
|
false,
|
||||||
None::<String>,
|
None::<String>,
|
||||||
|
@ -356,7 +357,7 @@ mod tests {
|
||||||
invalid_payloads.iter().enumerate().for_each(
|
invalid_payloads.iter().enumerate().for_each(
|
||||||
|(
|
|(
|
||||||
idx,
|
idx,
|
||||||
&(reason, expected_err, local_site, create_site),
|
&(reason, ref expected_err, local_site, create_site),
|
||||||
)| {
|
)| {
|
||||||
match validate_create_payload(
|
match validate_create_payload(
|
||||||
local_site,
|
local_site,
|
||||||
|
@ -370,9 +371,9 @@ mod tests {
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
assert!(
|
assert!(
|
||||||
error.message.eq(&Some(String::from(expected_err))),
|
error.error_type.eq(&Some(expected_err.clone())),
|
||||||
"Got Err {:?}, but should have failed with message: {} for reason: {}. invalid_payloads.nth({})",
|
"Got Err {:?}, but should have failed with message: {} for reason: {}. invalid_payloads.nth({})",
|
||||||
error.message,
|
error.error_type,
|
||||||
expected_err,
|
expected_err,
|
||||||
reason,
|
reason,
|
||||||
idx
|
idx
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use lemmy_db_schema::{ListingType, RegistrationMode};
|
use lemmy_db_schema::{ListingType, RegistrationMode};
|
||||||
use lemmy_utils::error::{LemmyError, LemmyResult};
|
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
|
||||||
|
|
||||||
mod create;
|
mod create;
|
||||||
mod read;
|
mod read;
|
||||||
|
@ -12,9 +12,7 @@ pub fn site_default_post_listing_type_check(
|
||||||
if let Some(listing_type) = default_post_listing_type {
|
if let Some(listing_type) = default_post_listing_type {
|
||||||
// Only allow all or local as default listing types...
|
// Only allow all or local as default listing types...
|
||||||
if listing_type != &ListingType::All && listing_type != &ListingType::Local {
|
if listing_type != &ListingType::All && listing_type != &ListingType::Local {
|
||||||
Err(LemmyError::from_message(
|
Err(LemmyErrorType::InvalidDefaultPostListingType)?
|
||||||
"invalid_default_post_listing_type",
|
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -36,7 +34,7 @@ pub fn application_question_check(
|
||||||
if registration_mode == RegistrationMode::RequireApplication
|
if registration_mode == RegistrationMode::RequireApplication
|
||||||
&& (has_no_question || is_nullifying_question)
|
&& (has_no_question || is_nullifying_question)
|
||||||
{
|
{
|
||||||
Err(LemmyError::from_message("application_question_required"))
|
Err(LemmyErrorType::ApplicationQuestionRequired)?
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,11 @@ use lemmy_db_views_actor::structs::{
|
||||||
PersonBlockView,
|
PersonBlockView,
|
||||||
PersonView,
|
PersonView,
|
||||||
};
|
};
|
||||||
use lemmy_utils::{claims::Claims, error::LemmyError, version};
|
use lemmy_utils::{
|
||||||
|
claims::Claims,
|
||||||
|
error::{LemmyError, LemmyErrorExt, LemmyErrorType},
|
||||||
|
version,
|
||||||
|
};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl PerformCrud for GetSite {
|
impl PerformCrud for GetSite {
|
||||||
|
@ -45,25 +49,25 @@ impl PerformCrud for GetSite {
|
||||||
|
|
||||||
let follows = CommunityFollowerView::for_person(context.pool(), person_id)
|
let follows = CommunityFollowerView::for_person(context.pool(), person_id)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "system_err_login"))?;
|
.with_lemmy_type(LemmyErrorType::SystemErrLogin)?;
|
||||||
|
|
||||||
let person_id = local_user_view.person.id;
|
let person_id = local_user_view.person.id;
|
||||||
let community_blocks = CommunityBlockView::for_person(context.pool(), person_id)
|
let community_blocks = CommunityBlockView::for_person(context.pool(), person_id)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "system_err_login"))?;
|
.with_lemmy_type(LemmyErrorType::SystemErrLogin)?;
|
||||||
|
|
||||||
let person_id = local_user_view.person.id;
|
let person_id = local_user_view.person.id;
|
||||||
let person_blocks = PersonBlockView::for_person(context.pool(), person_id)
|
let person_blocks = PersonBlockView::for_person(context.pool(), person_id)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "system_err_login"))?;
|
.with_lemmy_type(LemmyErrorType::SystemErrLogin)?;
|
||||||
|
|
||||||
let moderates = CommunityModeratorView::for_person(context.pool(), person_id)
|
let moderates = CommunityModeratorView::for_person(context.pool(), person_id)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "system_err_login"))?;
|
.with_lemmy_type(LemmyErrorType::SystemErrLogin)?;
|
||||||
|
|
||||||
let discussion_languages = LocalUserLanguage::read(context.pool(), local_user_id)
|
let discussion_languages = LocalUserLanguage::read(context.pool(), local_user_id)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "system_err_login"))?;
|
.with_lemmy_type(LemmyErrorType::SystemErrLogin)?;
|
||||||
|
|
||||||
Some(MyUserInfo {
|
Some(MyUserInfo {
|
||||||
local_user_view,
|
local_user_view,
|
||||||
|
|
|
@ -25,7 +25,7 @@ use lemmy_db_schema::{
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::SiteView;
|
use lemmy_db_views::structs::SiteView;
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
error::{LemmyError, LemmyResult},
|
error::{LemmyError, LemmyErrorExt, LemmyErrorType, LemmyResult},
|
||||||
utils::{
|
utils::{
|
||||||
slurs::check_slurs_opt,
|
slurs::check_slurs_opt,
|
||||||
validation::{
|
validation::{
|
||||||
|
@ -139,7 +139,7 @@ impl PerformCrud for EditSite {
|
||||||
if !old_require_application && new_require_application {
|
if !old_require_application && new_require_application {
|
||||||
LocalUser::set_all_users_registration_applications_accepted(context.pool())
|
LocalUser::set_all_users_registration_applications_accepted(context.pool())
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_set_all_registrations_accepted"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntSetAllRegistrationsAccepted)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_require_email_verification = update_local_site
|
let new_require_email_verification = update_local_site
|
||||||
|
@ -149,7 +149,7 @@ impl PerformCrud for EditSite {
|
||||||
if !local_site.require_email_verification && new_require_email_verification {
|
if !local_site.require_email_verification && new_require_email_verification {
|
||||||
LocalUser::set_all_users_email_verified(context.pool())
|
LocalUser::set_all_users_email_verified(context.pool())
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_set_all_email_verified"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntSetAllEmailVerified)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_taglines = data.taglines.clone();
|
let new_taglines = data.taglines.clone();
|
||||||
|
@ -220,13 +220,14 @@ mod tests {
|
||||||
use crate::site::update::validate_update_payload;
|
use crate::site::update::validate_update_payload;
|
||||||
use lemmy_api_common::site::EditSite;
|
use lemmy_api_common::site::EditSite;
|
||||||
use lemmy_db_schema::{source::local_site::LocalSite, ListingType, RegistrationMode};
|
use lemmy_db_schema::{source::local_site::LocalSite, ListingType, RegistrationMode};
|
||||||
|
use lemmy_utils::error::LemmyErrorType;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_validate_invalid_update_payload() {
|
fn test_validate_invalid_update_payload() {
|
||||||
let invalid_payloads = [
|
let invalid_payloads = [
|
||||||
(
|
(
|
||||||
"EditSite name matches LocalSite slur filter",
|
"EditSite name matches LocalSite slur filter",
|
||||||
"slurs",
|
LemmyErrorType::Slurs,
|
||||||
&generate_local_site(
|
&generate_local_site(
|
||||||
Some(String::from("(foo|bar)")),
|
Some(String::from("(foo|bar)")),
|
||||||
true,
|
true,
|
||||||
|
@ -248,7 +249,7 @@ mod tests {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"EditSite name matches new slur filter",
|
"EditSite name matches new slur filter",
|
||||||
"slurs",
|
LemmyErrorType::Slurs,
|
||||||
&generate_local_site(
|
&generate_local_site(
|
||||||
Some(String::from("(foo|bar)")),
|
Some(String::from("(foo|bar)")),
|
||||||
true,
|
true,
|
||||||
|
@ -270,7 +271,7 @@ mod tests {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"EditSite listing type is Subscribed, which is invalid",
|
"EditSite listing type is Subscribed, which is invalid",
|
||||||
"invalid_default_post_listing_type",
|
LemmyErrorType::InvalidDefaultPostListingType,
|
||||||
&generate_local_site(
|
&generate_local_site(
|
||||||
None::<String>,
|
None::<String>,
|
||||||
true,
|
true,
|
||||||
|
@ -292,7 +293,7 @@ mod tests {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"EditSite is both private and federated",
|
"EditSite is both private and federated",
|
||||||
"cant_enable_private_instance_and_federation_together",
|
LemmyErrorType::CantEnablePrivateInstanceAndFederationTogether,
|
||||||
&generate_local_site(
|
&generate_local_site(
|
||||||
None::<String>,
|
None::<String>,
|
||||||
true,
|
true,
|
||||||
|
@ -314,7 +315,7 @@ mod tests {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"LocalSite is private, but EditSite also makes it federated",
|
"LocalSite is private, but EditSite also makes it federated",
|
||||||
"cant_enable_private_instance_and_federation_together",
|
LemmyErrorType::CantEnablePrivateInstanceAndFederationTogether,
|
||||||
&generate_local_site(
|
&generate_local_site(
|
||||||
None::<String>,
|
None::<String>,
|
||||||
true,
|
true,
|
||||||
|
@ -336,7 +337,7 @@ mod tests {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"EditSite requires application, but neither it nor LocalSite has an application question",
|
"EditSite requires application, but neither it nor LocalSite has an application question",
|
||||||
"application_question_required",
|
LemmyErrorType::ApplicationQuestionRequired,
|
||||||
&generate_local_site(
|
&generate_local_site(
|
||||||
None::<String>,
|
None::<String>,
|
||||||
true,
|
true,
|
||||||
|
@ -361,7 +362,7 @@ mod tests {
|
||||||
invalid_payloads.iter().enumerate().for_each(
|
invalid_payloads.iter().enumerate().for_each(
|
||||||
|(
|
|(
|
||||||
idx,
|
idx,
|
||||||
&(reason, expected_err, local_site, edit_site),
|
&(reason, ref expected_err, local_site, edit_site),
|
||||||
)| {
|
)| {
|
||||||
match validate_update_payload(local_site, edit_site) {
|
match validate_update_payload(local_site, edit_site) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
|
@ -372,9 +373,9 @@ mod tests {
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
assert!(
|
assert!(
|
||||||
error.message.eq(&Some(String::from(expected_err))),
|
error.error_type.eq(&Some(expected_err.clone())),
|
||||||
"Got Err {:?}, but should have failed with message: {} for reason: {}. invalid_payloads.nth({})",
|
"Got Err {:?}, but should have failed with message: {} for reason: {}. invalid_payloads.nth({})",
|
||||||
error.message,
|
error.error_type,
|
||||||
expected_err,
|
expected_err,
|
||||||
reason,
|
reason,
|
||||||
idx
|
idx
|
||||||
|
|
|
@ -30,7 +30,7 @@ use lemmy_db_schema::{
|
||||||
use lemmy_db_views::structs::{LocalUserView, SiteView};
|
use lemmy_db_views::structs::{LocalUserView, SiteView};
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
claims::Claims,
|
claims::Claims,
|
||||||
error::LemmyError,
|
error::{LemmyError, LemmyErrorExt, LemmyErrorType},
|
||||||
utils::{
|
utils::{
|
||||||
slurs::{check_slurs, check_slurs_opt},
|
slurs::{check_slurs, check_slurs_opt},
|
||||||
validation::is_valid_actor_name,
|
validation::is_valid_actor_name,
|
||||||
|
@ -51,25 +51,23 @@ impl PerformCrud for Register {
|
||||||
local_site.registration_mode == RegistrationMode::RequireApplication;
|
local_site.registration_mode == RegistrationMode::RequireApplication;
|
||||||
|
|
||||||
if local_site.registration_mode == RegistrationMode::Closed {
|
if local_site.registration_mode == RegistrationMode::Closed {
|
||||||
return Err(LemmyError::from_message("registration_closed"));
|
return Err(LemmyErrorType::RegistrationClosed)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
password_length_check(&data.password)?;
|
password_length_check(&data.password)?;
|
||||||
honeypot_check(&data.honeypot)?;
|
honeypot_check(&data.honeypot)?;
|
||||||
|
|
||||||
if local_site.require_email_verification && data.email.is_none() {
|
if local_site.require_email_verification && data.email.is_none() {
|
||||||
return Err(LemmyError::from_message("email_required"));
|
return Err(LemmyErrorType::EmailRequired)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if local_site.site_setup && require_registration_application && data.answer.is_none() {
|
if local_site.site_setup && require_registration_application && data.answer.is_none() {
|
||||||
return Err(LemmyError::from_message(
|
return Err(LemmyErrorType::RegistrationApplicationAnswerRequired)?;
|
||||||
"registration_application_answer_required",
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure passwords match
|
// Make sure passwords match
|
||||||
if data.password != data.password_verify {
|
if data.password != data.password_verify {
|
||||||
return Err(LemmyError::from_message("passwords_dont_match"));
|
return Err(LemmyErrorType::PasswordsDoNotMatch)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if local_site.site_setup && local_site.captcha_enabled {
|
if local_site.site_setup && local_site.captcha_enabled {
|
||||||
|
@ -84,10 +82,10 @@ impl PerformCrud for Register {
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
if !check {
|
if !check {
|
||||||
return Err(LemmyError::from_message("captcha_incorrect"));
|
return Err(LemmyErrorType::CaptchaIncorrect)?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(LemmyError::from_message("captcha_incorrect"));
|
return Err(LemmyErrorType::CaptchaIncorrect)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,7 +103,7 @@ impl PerformCrud for Register {
|
||||||
|
|
||||||
if let Some(email) = &data.email {
|
if let Some(email) = &data.email {
|
||||||
if LocalUser::is_email_taken(context.pool(), email).await? {
|
if LocalUser::is_email_taken(context.pool(), email).await? {
|
||||||
return Err(LemmyError::from_message("email_already_exists"));
|
return Err(LemmyErrorType::EmailAlreadyExists)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,7 +125,7 @@ impl PerformCrud for Register {
|
||||||
// insert the person
|
// insert the person
|
||||||
let inserted_person = Person::create(context.pool(), &person_form)
|
let inserted_person = Person::create(context.pool(), &person_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "user_already_exists"))?;
|
.with_lemmy_type(LemmyErrorType::UserAlreadyExists)?;
|
||||||
|
|
||||||
// Automatically set their application as accepted, if they created this with open registration.
|
// Automatically set their application as accepted, if they created this with open registration.
|
||||||
// Also fixes a bug which allows users to log in when registrations are changed to closed.
|
// Also fixes a bug which allows users to log in when registrations are changed to closed.
|
||||||
|
|
|
@ -6,7 +6,7 @@ use lemmy_api_common::{
|
||||||
person::{DeleteAccount, DeleteAccountResponse},
|
person::{DeleteAccount, DeleteAccountResponse},
|
||||||
utils::local_user_view_from_jwt,
|
utils::local_user_view_from_jwt,
|
||||||
};
|
};
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorType};
|
||||||
|
|
||||||
#[async_trait::async_trait(?Send)]
|
#[async_trait::async_trait(?Send)]
|
||||||
impl PerformCrud for DeleteAccount {
|
impl PerformCrud for DeleteAccount {
|
||||||
|
@ -24,7 +24,7 @@ impl PerformCrud for DeleteAccount {
|
||||||
)
|
)
|
||||||
.unwrap_or(false);
|
.unwrap_or(false);
|
||||||
if !valid {
|
if !valid {
|
||||||
return Err(LemmyError::from_message("password_incorrect"));
|
return Err(LemmyErrorType::IncorrectLogin)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(DeleteAccountResponse {})
|
Ok(DeleteAccountResponse {})
|
||||||
|
|
|
@ -21,7 +21,7 @@ use activitypub_federation::{
|
||||||
traits::{ActivityHandler, Actor},
|
traits::{ActivityHandler, Actor},
|
||||||
};
|
};
|
||||||
use lemmy_api_common::context::LemmyContext;
|
use lemmy_api_common::context::LemmyContext;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorType};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ impl ActivityHandler for RawAnnouncableActivities {
|
||||||
let activity: AnnouncableActivities = self.clone().try_into()?;
|
let activity: AnnouncableActivities = self.clone().try_into()?;
|
||||||
// This is only for sending, not receiving so we reject it.
|
// This is only for sending, not receiving so we reject it.
|
||||||
if let AnnouncableActivities::Page(_) = activity {
|
if let AnnouncableActivities::Page(_) = activity {
|
||||||
return Err(LemmyError::from_message("Cant receive page"));
|
return Err(LemmyErrorType::CannotReceivePage)?;
|
||||||
}
|
}
|
||||||
let community = activity.community(data).await?;
|
let community = activity.community(data).await?;
|
||||||
let actor_id = activity.actor().clone().into();
|
let actor_id = activity.actor().clone().into();
|
||||||
|
@ -144,7 +144,7 @@ impl ActivityHandler for AnnounceActivity {
|
||||||
let object: AnnouncableActivities = self.object.object(context).await?.try_into()?;
|
let object: AnnouncableActivities = self.object.object(context).await?.try_into()?;
|
||||||
// This is only for sending, not receiving so we reject it.
|
// This is only for sending, not receiving so we reject it.
|
||||||
if let AnnouncableActivities::Page(_) = object {
|
if let AnnouncableActivities::Page(_) = object {
|
||||||
return Err(LemmyError::from_message("Cant receive page"));
|
return Err(LemmyErrorType::CannotReceivePage)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify here in order to avoid fetching the object twice over http
|
// verify here in order to avoid fetching the object twice over http
|
||||||
|
|
|
@ -36,7 +36,7 @@ use lemmy_db_schema::{
|
||||||
},
|
},
|
||||||
traits::{Crud, Likeable},
|
traits::{Crud, Likeable},
|
||||||
};
|
};
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorType};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
@ -159,7 +159,7 @@ impl ActivityHandler for CreateOrUpdatePage {
|
||||||
// because then we will definitely receive all create and update activities separately.
|
// because then we will definitely receive all create and update activities separately.
|
||||||
let is_locked = self.object.comments_enabled == Some(false);
|
let is_locked = self.object.comments_enabled == Some(false);
|
||||||
if community.local && is_locked {
|
if community.local && is_locked {
|
||||||
return Err(LemmyError::from_message("New post cannot be locked"));
|
return Err(LemmyErrorType::NewPostCannotBeLocked)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CreateOrUpdateType::Update => {
|
CreateOrUpdateType::Update => {
|
||||||
|
|
|
@ -25,7 +25,7 @@ use lemmy_db_schema::{
|
||||||
},
|
},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
};
|
};
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorType};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
@ -108,9 +108,7 @@ 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(LemmyError::from_message(
|
return Err(LemmyErrorType::OnlyLocalAdminCanRemoveCommunity)?;
|
||||||
"Only local admin can remove community",
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
let form = ModRemoveCommunityForm {
|
let form = ModRemoveCommunityForm {
|
||||||
mod_person_id: actor.id,
|
mod_person_id: actor.id,
|
||||||
|
|
|
@ -25,7 +25,7 @@ use lemmy_db_schema::{
|
||||||
},
|
},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
};
|
};
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorType};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
@ -100,9 +100,7 @@ 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(LemmyError::from_message(
|
return Err(LemmyErrorType::OnlyLocalAdminCanRestoreCommunity)?;
|
||||||
"Only local admin can restore community",
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
let form = ModRemoveCommunityForm {
|
let form = ModRemoveCommunityForm {
|
||||||
mod_person_id: actor.id,
|
mod_person_id: actor.id,
|
||||||
|
|
|
@ -15,7 +15,7 @@ use anyhow::anyhow;
|
||||||
use lemmy_api_common::context::LemmyContext;
|
use lemmy_api_common::context::LemmyContext;
|
||||||
use lemmy_db_schema::{newtypes::CommunityId, source::community::Community};
|
use lemmy_db_schema::{newtypes::CommunityId, source::community::Community};
|
||||||
use lemmy_db_views_actor::structs::{CommunityPersonBanView, CommunityView};
|
use lemmy_db_views_actor::structs::{CommunityPersonBanView, CommunityView};
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
@ -39,8 +39,8 @@ async fn verify_person(
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
let person = person_id.dereference(context).await?;
|
let person = person_id.dereference(context).await?;
|
||||||
if person.banned {
|
if person.banned {
|
||||||
let err = anyhow!("Person {} is banned", person_id);
|
return Err(anyhow!("Person {} is banned", person_id))
|
||||||
return Err(LemmyError::from_error_message(err, "banned"));
|
.with_lemmy_type(LemmyErrorType::CouldntUpdateComment);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ pub(crate) async fn verify_person_in_community(
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
let person = person_id.dereference(context).await?;
|
let person = person_id.dereference(context).await?;
|
||||||
if person.banned {
|
if person.banned {
|
||||||
return Err(LemmyError::from_message("Person is banned from site"));
|
return Err(LemmyErrorType::PersonIsBannedFromSite)?;
|
||||||
}
|
}
|
||||||
let person_id = person.id;
|
let person_id = person.id;
|
||||||
let community_id = community.id;
|
let community_id = community.id;
|
||||||
|
@ -63,7 +63,7 @@ pub(crate) async fn verify_person_in_community(
|
||||||
.await
|
.await
|
||||||
.is_ok();
|
.is_ok();
|
||||||
if is_banned {
|
if is_banned {
|
||||||
return Err(LemmyError::from_message("Person is banned from community"));
|
return Err(LemmyErrorType::PersonIsBannedFromCommunity)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -96,12 +96,12 @@ pub(crate) async fn verify_mod_action(
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(LemmyError::from_message("Not a mod"))
|
Err(LemmyErrorType::NotAModerator)?
|
||||||
}
|
}
|
||||||
|
|
||||||
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(LemmyError::from_message("Object is not public"));
|
return Err(LemmyErrorType::ObjectIsNotPublic)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -115,16 +115,14 @@ where
|
||||||
{
|
{
|
||||||
let b: ObjectId<ApubCommunity> = b.into();
|
let b: ObjectId<ApubCommunity> = b.into();
|
||||||
if a != &b {
|
if a != &b {
|
||||||
return Err(LemmyError::from_message("Invalid community"));
|
return Err(LemmyErrorType::InvalidCommunity)?;
|
||||||
}
|
}
|
||||||
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(LemmyError::from_message(
|
Err(LemmyErrorType::CannotCreatePostOrCommentInDeletedOrRemovedCommunity)?
|
||||||
"New post or comment cannot be created in deleted or removed community",
|
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ use lemmy_db_schema::{
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
};
|
};
|
||||||
use lemmy_db_views::comment_view::CommentQuery;
|
use lemmy_db_views::comment_view::CommentQuery;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
|
||||||
#[tracing::instrument(skip(context))]
|
#[tracing::instrument(skip(context))]
|
||||||
pub async fn list_comments(
|
pub async fn list_comments(
|
||||||
|
@ -66,7 +66,7 @@ pub async fn list_comments(
|
||||||
.build()
|
.build()
|
||||||
.list()
|
.list()
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_get_comments"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntGetComments)?;
|
||||||
|
|
||||||
Ok(Json(GetCommentsResponse { comments }))
|
Ok(Json(GetCommentsResponse { comments }))
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ use lemmy_api_common::{
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::source::{community::Community, local_site::LocalSite};
|
use lemmy_db_schema::source::{community::Community, local_site::LocalSite};
|
||||||
use lemmy_db_views::post_view::PostQuery;
|
use lemmy_db_views::post_view::PostQuery;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
|
|
||||||
#[tracing::instrument(skip(context))]
|
#[tracing::instrument(skip(context))]
|
||||||
pub async fn list_posts(
|
pub async fn list_posts(
|
||||||
|
@ -55,7 +55,7 @@ pub async fn list_posts(
|
||||||
.build()
|
.build()
|
||||||
.list()
|
.list()
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_get_posts"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntGetPosts)?;
|
||||||
|
|
||||||
Ok(Json(GetPostsResponse { posts }))
|
Ok(Json(GetPostsResponse { posts }))
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ use lemmy_db_schema::source::{
|
||||||
site::Site,
|
site::Site,
|
||||||
};
|
};
|
||||||
use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView};
|
use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView};
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorExt2, LemmyErrorType};
|
||||||
|
|
||||||
#[tracing::instrument(skip(context))]
|
#[tracing::instrument(skip(context))]
|
||||||
pub async fn read_community(
|
pub async fn read_community(
|
||||||
|
@ -24,7 +24,7 @@ pub async fn read_community(
|
||||||
let local_site = LocalSite::read(context.pool()).await?;
|
let local_site = LocalSite::read(context.pool()).await?;
|
||||||
|
|
||||||
if data.name.is_none() && data.id.is_none() {
|
if data.name.is_none() && data.id.is_none() {
|
||||||
return Err(LemmyError::from_message("no_id_given"));
|
return Err(LemmyErrorType::NoIdGiven)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
check_private_instance(&local_user_view, &local_site)?;
|
check_private_instance(&local_user_view, &local_site)?;
|
||||||
|
@ -37,7 +37,7 @@ pub async fn read_community(
|
||||||
let name = data.name.clone().unwrap_or_else(|| "main".to_string());
|
let name = data.name.clone().unwrap_or_else(|| "main".to_string());
|
||||||
resolve_actor_identifier::<ApubCommunity, Community>(&name, &context, &local_user_view, true)
|
resolve_actor_identifier::<ApubCommunity, Community>(&name, &context, &local_user_view, true)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| e.with_message("couldnt_find_community"))?
|
.with_lemmy_type(LemmyErrorType::CouldntFindCommunity)?
|
||||||
.id
|
.id
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -54,11 +54,11 @@ pub async fn read_community(
|
||||||
Some(is_mod_or_admin),
|
Some(is_mod_or_admin),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_find_community"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntFindCommunity)?;
|
||||||
|
|
||||||
let moderators = CommunityModeratorView::for_community(context.pool(), community_id)
|
let moderators = CommunityModeratorView::for_community(context.pool(), community_id)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "couldnt_find_community"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntFindCommunity)?;
|
||||||
|
|
||||||
let site_id = Site::instance_actor_id_from_url(community_view.community.actor_id.clone().into());
|
let site_id = Site::instance_actor_id_from_url(community_view.community.actor_id.clone().into());
|
||||||
let mut site = Site::read_from_apub_id(context.pool(), &site_id.into()).await?;
|
let mut site = Site::read_from_apub_id(context.pool(), &site_id.into()).await?;
|
||||||
|
|
|
@ -12,7 +12,7 @@ use lemmy_db_schema::{
|
||||||
};
|
};
|
||||||
use lemmy_db_views::{comment_view::CommentQuery, post_view::PostQuery};
|
use lemmy_db_views::{comment_view::CommentQuery, post_view::PostQuery};
|
||||||
use lemmy_db_views_actor::structs::{CommunityModeratorView, PersonView};
|
use lemmy_db_views_actor::structs::{CommunityModeratorView, PersonView};
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt2, LemmyErrorType};
|
||||||
|
|
||||||
#[tracing::instrument(skip(context))]
|
#[tracing::instrument(skip(context))]
|
||||||
pub async fn read_person(
|
pub async fn read_person(
|
||||||
|
@ -21,7 +21,7 @@ pub async fn read_person(
|
||||||
) -> Result<Json<GetPersonDetailsResponse>, LemmyError> {
|
) -> Result<Json<GetPersonDetailsResponse>, LemmyError> {
|
||||||
// Check to make sure a person name or an id is given
|
// Check to make sure a person name or an id is given
|
||||||
if data.username.is_none() && data.person_id.is_none() {
|
if data.username.is_none() && data.person_id.is_none() {
|
||||||
return Err(LemmyError::from_message("no_id_given"));
|
return Err(LemmyErrorType::NoIdGiven)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let local_user_view = local_user_view_from_jwt_opt(data.auth.as_ref(), &context).await;
|
let local_user_view = local_user_view_from_jwt_opt(data.auth.as_ref(), &context).await;
|
||||||
|
@ -36,12 +36,10 @@ pub async fn read_person(
|
||||||
if let Some(username) = &data.username {
|
if let Some(username) = &data.username {
|
||||||
resolve_actor_identifier::<ApubPerson, Person>(username, &context, &local_user_view, true)
|
resolve_actor_identifier::<ApubPerson, Person>(username, &context, &local_user_view, true)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| e.with_message("couldnt_find_that_username_or_email"))?
|
.with_lemmy_type(LemmyErrorType::CouldntFindPerson)?
|
||||||
.id
|
.id
|
||||||
} else {
|
} else {
|
||||||
return Err(LemmyError::from_message(
|
return Err(LemmyErrorType::CouldntFindPerson)?;
|
||||||
"couldnt_find_that_username_or_email",
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,7 +10,7 @@ use lemmy_api_common::{
|
||||||
use lemmy_db_schema::{newtypes::PersonId, source::local_site::LocalSite, utils::DbPool};
|
use lemmy_db_schema::{newtypes::PersonId, source::local_site::LocalSite, utils::DbPool};
|
||||||
use lemmy_db_views::structs::{CommentView, PostView};
|
use lemmy_db_views::structs::{CommentView, PostView};
|
||||||
use lemmy_db_views_actor::structs::{CommunityView, PersonView};
|
use lemmy_db_views_actor::structs::{CommunityView, PersonView};
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt2, LemmyErrorType};
|
||||||
|
|
||||||
#[tracing::instrument(skip(context))]
|
#[tracing::instrument(skip(context))]
|
||||||
pub async fn resolve_object(
|
pub async fn resolve_object(
|
||||||
|
@ -24,10 +24,10 @@ pub async fn resolve_object(
|
||||||
|
|
||||||
let res = search_query_to_object_id(&data.q, &context)
|
let res = search_query_to_object_id(&data.q, &context)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| e.with_message("couldnt_find_object"))?;
|
.with_lemmy_type(LemmyErrorType::CouldntFindObject)?;
|
||||||
convert_response(res, person_id, context.pool())
|
convert_response(res, person_id, context.pool())
|
||||||
.await
|
.await
|
||||||
.map_err(|e| e.with_message("couldnt_find_object"))
|
.with_lemmy_type(LemmyErrorType::CouldntFindObject)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn convert_response(
|
async fn convert_response(
|
||||||
|
|
|
@ -9,7 +9,7 @@ use activitypub_federation::{
|
||||||
};
|
};
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
use lemmy_api_common::context::LemmyContext;
|
use lemmy_api_common::context::LemmyContext;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorType};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ pub(crate) async fn search_query_to_object_id(
|
||||||
Some('!') => SearchableObjects::Community(
|
Some('!') => SearchableObjects::Community(
|
||||||
webfinger_resolve_actor::<LemmyContext, ApubCommunity>(identifier, context).await?,
|
webfinger_resolve_actor::<LemmyContext, ApubCommunity>(identifier, context).await?,
|
||||||
),
|
),
|
||||||
_ => return Err(LemmyError::from_message("invalid query")),
|
_ => return Err(LemmyErrorType::InvalidQuery)?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -18,7 +18,7 @@ use activitypub_federation::{
|
||||||
use actix_web::{web, web::Bytes, HttpRequest, HttpResponse};
|
use actix_web::{web, web::Bytes, HttpRequest, HttpResponse};
|
||||||
use lemmy_api_common::context::LemmyContext;
|
use lemmy_api_common::context::LemmyContext;
|
||||||
use lemmy_db_schema::{source::community::Community, traits::ApubActor};
|
use lemmy_db_schema::{source::community::Community, traits::ApubActor};
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorType};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
@ -80,7 +80,7 @@ pub(crate) async fn get_apub_community_outbox(
|
||||||
.await?
|
.await?
|
||||||
.into();
|
.into();
|
||||||
if community.deleted || community.removed {
|
if community.deleted || community.removed {
|
||||||
return Err(LemmyError::from_message("deleted"));
|
return Err(LemmyErrorType::Deleted)?;
|
||||||
}
|
}
|
||||||
let outbox = ApubCommunityOutbox::read_local(&community, &context).await?;
|
let outbox = ApubCommunityOutbox::read_local(&community, &context).await?;
|
||||||
create_apub_response(&outbox)
|
create_apub_response(&outbox)
|
||||||
|
@ -96,7 +96,7 @@ pub(crate) async fn get_apub_community_moderators(
|
||||||
.await?
|
.await?
|
||||||
.into();
|
.into();
|
||||||
if community.deleted || community.removed {
|
if community.deleted || community.removed {
|
||||||
return Err(LemmyError::from_message("deleted"));
|
return Err(LemmyErrorType::Deleted)?;
|
||||||
}
|
}
|
||||||
let moderators = ApubCommunityModerators::read_local(&community, &context).await?;
|
let moderators = ApubCommunityModerators::read_local(&community, &context).await?;
|
||||||
create_apub_response(&moderators)
|
create_apub_response(&moderators)
|
||||||
|
@ -112,7 +112,7 @@ pub(crate) async fn get_apub_community_featured(
|
||||||
.await?
|
.await?
|
||||||
.into();
|
.into();
|
||||||
if community.deleted || community.removed {
|
if community.deleted || community.removed {
|
||||||
return Err(LemmyError::from_message("deleted"));
|
return Err(LemmyErrorType::Deleted)?;
|
||||||
}
|
}
|
||||||
let featured = ApubCommunityFeatured::read_local(&community, &context).await?;
|
let featured = ApubCommunityFeatured::read_local(&community, &context).await?;
|
||||||
create_apub_response(&featured)
|
create_apub_response(&featured)
|
||||||
|
|
|
@ -14,7 +14,7 @@ use actix_web::{web, web::Bytes, HttpRequest, HttpResponse};
|
||||||
use http::StatusCode;
|
use http::StatusCode;
|
||||||
use lemmy_api_common::context::LemmyContext;
|
use lemmy_api_common::context::LemmyContext;
|
||||||
use lemmy_db_schema::source::activity::Activity;
|
use lemmy_db_schema::source::activity::Activity;
|
||||||
use lemmy_utils::error::{LemmyError, LemmyResult};
|
use lemmy_utils::error::{LemmyError, LemmyErrorType, LemmyResult};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
@ -65,7 +65,7 @@ fn create_apub_tombstone_response<T: Into<Url>>(id: T) -> LemmyResult<HttpRespon
|
||||||
}
|
}
|
||||||
|
|
||||||
fn err_object_not_local() -> LemmyError {
|
fn err_object_not_local() -> LemmyError {
|
||||||
LemmyError::from_message("Object not local, fetch it from original instance")
|
LemmyErrorType::ObjectNotLocal.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
|
|
@ -12,7 +12,7 @@ use lemmy_db_schema::{
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
utils::DbPool,
|
utils::DbPool,
|
||||||
};
|
};
|
||||||
use lemmy_utils::error::{LemmyError, LemmyResult};
|
use lemmy_utils::error::{LemmyError, LemmyErrorType, LemmyResult};
|
||||||
use moka::future::Cache;
|
use moka::future::Cache;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
@ -145,7 +145,12 @@ pub(crate) async fn check_apub_id_valid_with_strictness(
|
||||||
}
|
}
|
||||||
|
|
||||||
let local_site_data = local_site_data_cached(context.pool()).await?;
|
let local_site_data = local_site_data_cached(context.pool()).await?;
|
||||||
check_apub_id_valid(apub_id, &local_site_data).map_err(LemmyError::from_message)?;
|
check_apub_id_valid(apub_id, &local_site_data).map_err(|err| match err {
|
||||||
|
"Federation disabled" => LemmyErrorType::FederationDisabled,
|
||||||
|
"Domain is blocked" => LemmyErrorType::DomainBlocked,
|
||||||
|
"Domain is not in allowlist" => LemmyErrorType::DomainNotInAllowList,
|
||||||
|
_ => panic!("Could not handle apub error!"),
|
||||||
|
})?;
|
||||||
|
|
||||||
// Only check allowlist if this is a community, and there are instances in the allowlist
|
// Only check allowlist if this is a community, and there are instances in the allowlist
|
||||||
if is_strict && !local_site_data.allowed_instances.is_empty() {
|
if is_strict && !local_site_data.allowed_instances.is_empty() {
|
||||||
|
@ -164,9 +169,7 @@ pub(crate) async fn check_apub_id_valid_with_strictness(
|
||||||
|
|
||||||
let domain = apub_id.domain().expect("apud id has domain").to_string();
|
let domain = apub_id.domain().expect("apud id has domain").to_string();
|
||||||
if !allowed_and_local.contains(&domain) {
|
if !allowed_and_local.contains(&domain) {
|
||||||
return Err(LemmyError::from_message(
|
return Err(LemmyErrorType::FederationDisabledByStrictAllowList)?;
|
||||||
"Federation forbidden by strict allowlist",
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -28,7 +28,7 @@ use lemmy_db_schema::{
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
};
|
};
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
error::LemmyError,
|
error::{LemmyError, LemmyErrorType},
|
||||||
utils::{markdown::markdown_to_html, slurs::remove_slurs, time::convert_datetime},
|
utils::{markdown::markdown_to_html, slurs::remove_slurs, time::convert_datetime},
|
||||||
};
|
};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
@ -137,7 +137,7 @@ impl Object for ApubComment {
|
||||||
verify_person_in_community(¬e.attributed_to, &community, context).await?;
|
verify_person_in_community(¬e.attributed_to, &community, context).await?;
|
||||||
let (post, _) = note.get_parents(context).await?;
|
let (post, _) = note.get_parents(context).await?;
|
||||||
if post.locked {
|
if post.locked {
|
||||||
return Err(LemmyError::from_message("Post is locked"));
|
return Err(LemmyErrorType::PostIsLocked)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ use lemmy_db_schema::{
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
};
|
};
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
error::LemmyError,
|
error::{LemmyError, LemmyErrorType},
|
||||||
utils::{markdown::markdown_to_html, time::convert_datetime},
|
utils::{markdown::markdown_to_html, time::convert_datetime},
|
||||||
};
|
};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
@ -104,7 +104,7 @@ impl Object for ApubPrivateMessage {
|
||||||
check_apub_id_valid_with_strictness(note.id.inner(), false, context).await?;
|
check_apub_id_valid_with_strictness(note.id.inner(), false, context).await?;
|
||||||
let person = note.attributed_to.dereference(context).await?;
|
let person = note.attributed_to.dereference(context).await?;
|
||||||
if person.banned {
|
if person.banned {
|
||||||
return Err(LemmyError::from_message("Person is banned from site"));
|
return Err(LemmyErrorType::PersonIsBannedFromSite)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use activitypub_federation::{config::Data, fetch::object_id::ObjectId};
|
use activitypub_federation::{config::Data, fetch::object_id::ObjectId};
|
||||||
use lemmy_api_common::context::LemmyContext;
|
use lemmy_api_common::context::LemmyContext;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorType};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use strum_macros::Display;
|
use strum_macros::Display;
|
||||||
|
@ -36,7 +36,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(LemmyError::from_message("invalid vote value")),
|
_ => Err(LemmyErrorType::InvalidVoteValue.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ use chrono::{DateTime, FixedOffset};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use lemmy_api_common::context::LemmyContext;
|
use lemmy_api_common::context::LemmyContext;
|
||||||
use lemmy_db_schema::newtypes::DbUrl;
|
use lemmy_db_schema::newtypes::DbUrl;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorType};
|
||||||
use serde::{de::Error, Deserialize, Deserializer, Serialize};
|
use serde::{de::Error, Deserialize, Deserializer, Serialize};
|
||||||
use serde_with::skip_serializing_none;
|
use serde_with::skip_serializing_none;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
@ -161,7 +161,7 @@ impl Page {
|
||||||
.iter()
|
.iter()
|
||||||
.find(|a| a.kind == PersonOrGroupType::Person)
|
.find(|a| a.kind == PersonOrGroupType::Person)
|
||||||
.map(|a| ObjectId::<ApubPerson>::from(a.id.clone().into_inner()))
|
.map(|a| ObjectId::<ApubPerson>::from(a.id.clone().into_inner()))
|
||||||
.ok_or_else(|| LemmyError::from_message("page does not specify creator person")),
|
.ok_or_else(|| LemmyErrorType::PageDoesNotSpecifyCreator.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -208,7 +208,7 @@ impl InCommunity for Page {
|
||||||
break c;
|
break c;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(LemmyError::from_message("No community found in cc"));
|
return Err(LemmyErrorType::NoCommunityFoundInCc)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -216,7 +216,7 @@ impl InCommunity for Page {
|
||||||
p.iter()
|
p.iter()
|
||||||
.find(|a| a.kind == PersonOrGroupType::Group)
|
.find(|a| a.kind == PersonOrGroupType::Group)
|
||||||
.map(|a| ObjectId::<ApubCommunity>::from(a.id.clone().into_inner()))
|
.map(|a| ObjectId::<ApubCommunity>::from(a.id.clone().into_inner()))
|
||||||
.ok_or_else(|| LemmyError::from_message("page does not specify group"))?
|
.ok_or(LemmyErrorType::PageDoesNotSpecifyGroup)?
|
||||||
.dereference(context)
|
.dereference(context)
|
||||||
.await?
|
.await?
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ use diesel_async::{
|
||||||
AsyncPgConnection,
|
AsyncPgConnection,
|
||||||
RunQueryDsl,
|
RunQueryDsl,
|
||||||
};
|
};
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::{LemmyError, LemmyErrorType};
|
||||||
use tokio::sync::OnceCell;
|
use tokio::sync::OnceCell;
|
||||||
|
|
||||||
pub const UNDETERMINED_ID: LanguageId = LanguageId(0);
|
pub const UNDETERMINED_ID: LanguageId = LanguageId(0);
|
||||||
|
@ -217,7 +217,7 @@ impl CommunityLanguage {
|
||||||
if is_allowed {
|
if is_allowed {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(LemmyError::from_message("language_not_allowed"))
|
Err(LemmyErrorType::LanguageNotAllowed)?
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -26,7 +26,10 @@ use diesel_async::{
|
||||||
};
|
};
|
||||||
use diesel_migrations::EmbeddedMigrations;
|
use diesel_migrations::EmbeddedMigrations;
|
||||||
use futures_util::{future::BoxFuture, FutureExt};
|
use futures_util::{future::BoxFuture, FutureExt};
|
||||||
use lemmy_utils::{error::LemmyError, settings::structs::Settings};
|
use lemmy_utils::{
|
||||||
|
error::{LemmyError, LemmyErrorExt, LemmyErrorType},
|
||||||
|
settings::structs::Settings,
|
||||||
|
};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use rustls::{
|
use rustls::{
|
||||||
|
@ -118,13 +121,12 @@ 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>>, LemmyError> {
|
) -> Result<Option<Option<DbUrl>>, LemmyError> {
|
||||||
match opt.as_ref().map(std::string::String::as_str) {
|
match opt.as_ref().map(String::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) => Url::parse(str_url)
|
||||||
Ok(url) => Ok(Some(Some(url.into()))),
|
.map(|u| Some(Some(u.into())))
|
||||||
Err(e) => Err(LemmyError::from_error_message(e, "invalid_url")),
|
.with_lemmy_type(LemmyErrorType::InvalidUrl),
|
||||||
},
|
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,13 +134,12 @@ pub fn diesel_option_overwrite_to_url(
|
||||||
pub fn diesel_option_overwrite_to_url_create(
|
pub fn diesel_option_overwrite_to_url_create(
|
||||||
opt: &Option<String>,
|
opt: &Option<String>,
|
||||||
) -> Result<Option<DbUrl>, LemmyError> {
|
) -> Result<Option<DbUrl>, LemmyError> {
|
||||||
match opt.as_ref().map(std::string::String::as_str) {
|
match opt.as_ref().map(String::as_str) {
|
||||||
// An empty string is nothing
|
// An empty string is nothing
|
||||||
Some("") => Ok(None),
|
Some("") => Ok(None),
|
||||||
Some(str_url) => match Url::parse(str_url) {
|
Some(str_url) => Url::parse(str_url)
|
||||||
Ok(url) => Ok(Some(url.into())),
|
.map(|u| Some(u.into()))
|
||||||
Err(e) => Err(LemmyError::from_error_message(e, "invalid_url")),
|
.with_lemmy_type(LemmyErrorType::InvalidUrl),
|
||||||
},
|
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,9 @@ name = "lemmy_utils"
|
||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
doctest = false
|
doctest = false
|
||||||
|
|
||||||
|
[features]
|
||||||
|
full = ["ts-rs"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
regex = { workspace = true }
|
regex = { workspace = true }
|
||||||
chrono = { workspace = true }
|
chrono = { workspace = true }
|
||||||
|
@ -45,6 +48,7 @@ jsonwebtoken = "8.3.0"
|
||||||
lettre = { version = "0.10.4", features = ["tokio1", "tokio1-native-tls"] }
|
lettre = { version = "0.10.4", features = ["tokio1", "tokio1-native-tls"] }
|
||||||
markdown-it = "0.5.1"
|
markdown-it = "0.5.1"
|
||||||
totp-rs = { version = "5.0.2", features = ["gen_secret", "otpauth"] }
|
totp-rs = { version = "5.0.2", features = ["gen_secret", "otpauth"] }
|
||||||
|
ts-rs = { workspace = true, optional = true }
|
||||||
enum-map = "2.6"
|
enum-map = "2.6"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
use crate::{error::LemmyError, settings::structs::Settings};
|
use crate::{
|
||||||
|
error::{LemmyError, LemmyErrorExt, LemmyErrorType},
|
||||||
|
settings::structs::Settings,
|
||||||
|
};
|
||||||
use html2text;
|
use html2text;
|
||||||
use lettre::{
|
use lettre::{
|
||||||
message::{Mailbox, MultiPart},
|
message::{Mailbox, MultiPart},
|
||||||
|
@ -23,22 +26,17 @@ pub async fn send_email(
|
||||||
html: &str,
|
html: &str,
|
||||||
settings: &Settings,
|
settings: &Settings,
|
||||||
) -> Result<(), LemmyError> {
|
) -> Result<(), LemmyError> {
|
||||||
let email_config = settings
|
let email_config = settings.email.clone().ok_or(LemmyErrorType::NoEmailSetup)?;
|
||||||
.email
|
|
||||||
.clone()
|
|
||||||
.ok_or_else(|| LemmyError::from_message("no_email_setup"))?;
|
|
||||||
let domain = settings.hostname.clone();
|
let domain = settings.hostname.clone();
|
||||||
|
|
||||||
let (smtp_server, smtp_port) = {
|
let (smtp_server, smtp_port) = {
|
||||||
let email_and_port = email_config.smtp_server.split(':').collect::<Vec<&str>>();
|
let email_and_port = email_config.smtp_server.split(':').collect::<Vec<&str>>();
|
||||||
let email = *email_and_port
|
let email = *email_and_port
|
||||||
.first()
|
.first()
|
||||||
.ok_or_else(|| LemmyError::from_message("missing an email"))?;
|
.ok_or(LemmyErrorType::MissingAnEmail)?;
|
||||||
let port = email_and_port
|
let port = email_and_port
|
||||||
.get(1)
|
.get(1)
|
||||||
.ok_or_else(|| {
|
.ok_or(LemmyErrorType::EmailSmtpServerNeedsAPort)?
|
||||||
LemmyError::from_message("email.smtp_server needs a port, IE smtp.xxx.com:465")
|
|
||||||
})?
|
|
||||||
.parse::<u16>()?;
|
.parse::<u16>()?;
|
||||||
|
|
||||||
(email, port)
|
(email, port)
|
||||||
|
@ -89,10 +87,10 @@ pub async fn send_email(
|
||||||
|
|
||||||
let mailer = builder.hello_name(ClientId::Domain(domain)).build();
|
let mailer = builder.hello_name(ClientId::Domain(domain)).build();
|
||||||
|
|
||||||
let result = mailer.send(email).await;
|
mailer
|
||||||
|
.send(email)
|
||||||
|
.await
|
||||||
|
.with_lemmy_type(LemmyErrorType::EmailSendFailed)?;
|
||||||
|
|
||||||
match result {
|
Ok(())
|
||||||
Ok(_) => Ok(()),
|
|
||||||
Err(e) => Err(LemmyError::from_error_message(e, "email_send_failed")),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,74 +1,27 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
fmt,
|
fmt,
|
||||||
fmt::{Debug, Display},
|
fmt::{Debug, Display},
|
||||||
};
|
};
|
||||||
use tracing_error::SpanTrace;
|
use tracing_error::SpanTrace;
|
||||||
|
#[cfg(feature = "full")]
|
||||||
#[derive(serde::Serialize)]
|
use ts_rs::TS;
|
||||||
struct ApiError {
|
|
||||||
error: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type LemmyResult<T> = Result<T, LemmyError>;
|
pub type LemmyResult<T> = Result<T, LemmyError>;
|
||||||
|
|
||||||
pub struct LemmyError {
|
pub struct LemmyError {
|
||||||
pub message: Option<String>,
|
pub error_type: Option<LemmyErrorType>,
|
||||||
pub inner: anyhow::Error,
|
pub inner: anyhow::Error,
|
||||||
pub context: SpanTrace,
|
pub context: SpanTrace,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LemmyError {
|
|
||||||
/// Create LemmyError from a message, including stack trace
|
|
||||||
pub fn from_message(message: &str) -> Self {
|
|
||||||
let inner = anyhow::anyhow!("{}", message);
|
|
||||||
LemmyError {
|
|
||||||
message: Some(message.into()),
|
|
||||||
inner,
|
|
||||||
context: SpanTrace::capture(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a LemmyError from error and message, including stack trace
|
|
||||||
pub fn from_error_message<E>(error: E, message: &str) -> Self
|
|
||||||
where
|
|
||||||
E: Into<anyhow::Error>,
|
|
||||||
{
|
|
||||||
LemmyError {
|
|
||||||
message: Some(message.into()),
|
|
||||||
inner: error.into(),
|
|
||||||
context: SpanTrace::capture(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add message to existing LemmyError (or overwrite existing error)
|
|
||||||
pub fn with_message(self, message: &str) -> Self {
|
|
||||||
LemmyError {
|
|
||||||
message: Some(message.into()),
|
|
||||||
..self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_json(&self) -> Result<String, Self> {
|
|
||||||
let api_error = match &self.message {
|
|
||||||
Some(error) => ApiError {
|
|
||||||
error: error.into(),
|
|
||||||
},
|
|
||||||
None => ApiError {
|
|
||||||
error: "Unknown".into(),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
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,
|
error_type: None,
|
||||||
inner: t.into(),
|
inner: t.into(),
|
||||||
context: SpanTrace::capture(),
|
context: SpanTrace::capture(),
|
||||||
}
|
}
|
||||||
|
@ -78,7 +31,7 @@ where
|
||||||
impl Debug for LemmyError {
|
impl Debug for LemmyError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.debug_struct("LemmyError")
|
f.debug_struct("LemmyError")
|
||||||
.field("message", &self.message)
|
.field("message", &self.error_type)
|
||||||
.field("inner", &self.inner)
|
.field("inner", &self.inner)
|
||||||
.field("context", &self.context)
|
.field("context", &self.context)
|
||||||
.finish()
|
.finish()
|
||||||
|
@ -87,7 +40,7 @@ impl Debug for LemmyError {
|
||||||
|
|
||||||
impl Display for LemmyError {
|
impl Display for LemmyError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
if let Some(message) = &self.message {
|
if let Some(message) = &self.error_type {
|
||||||
write!(f, "{message}: ")?;
|
write!(f, "{message}: ")?;
|
||||||
}
|
}
|
||||||
// print anyhow including trace
|
// print anyhow including trace
|
||||||
|
@ -108,10 +61,8 @@ impl actix_web::error::ResponseError for LemmyError {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error_response(&self) -> actix_web::HttpResponse {
|
fn error_response(&self) -> actix_web::HttpResponse {
|
||||||
if let Some(message) = &self.message {
|
if let Some(message) = &self.error_type {
|
||||||
actix_web::HttpResponse::build(self.status_code()).json(ApiError {
|
actix_web::HttpResponse::build(self.status_code()).json(message)
|
||||||
error: message.into(),
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
actix_web::HttpResponse::build(self.status_code())
|
actix_web::HttpResponse::build(self.status_code())
|
||||||
.content_type("text/plain")
|
.content_type("text/plain")
|
||||||
|
@ -119,3 +70,230 @@ impl actix_web::error::ResponseError for LemmyError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Display, Debug, Serialize, Deserialize, Clone, PartialEq, EnumIter)]
|
||||||
|
#[cfg_attr(feature = "full", derive(TS))]
|
||||||
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
|
#[serde(tag = "error", content = "message", rename_all = "snake_case")]
|
||||||
|
// TODO: order these based on the crate they belong to (utils, federation, db, api)
|
||||||
|
pub enum LemmyErrorType {
|
||||||
|
ReportReasonRequired,
|
||||||
|
ReportTooLong,
|
||||||
|
NotAModerator,
|
||||||
|
NotAnAdmin,
|
||||||
|
CantBlockYourself,
|
||||||
|
CantBlockAdmin,
|
||||||
|
CouldntUpdateUser,
|
||||||
|
PasswordsDoNotMatch,
|
||||||
|
EmailNotVerified,
|
||||||
|
EmailRequired,
|
||||||
|
CouldntUpdateComment,
|
||||||
|
CouldntUpdatePrivateMessage,
|
||||||
|
CannotLeaveAdmin,
|
||||||
|
NoLinesInHtml,
|
||||||
|
SiteMetadataPageIsNotDoctypeHtml,
|
||||||
|
PictrsResponseError(String),
|
||||||
|
PictrsPurgeResponseError(String),
|
||||||
|
ImageUrlMissingPathSegments,
|
||||||
|
ImageUrlMissingLastPathSegment,
|
||||||
|
PictrsApiKeyNotProvided,
|
||||||
|
NoContentTypeHeader,
|
||||||
|
NotAnImageType,
|
||||||
|
NotAModOrAdmin,
|
||||||
|
NoAdmins,
|
||||||
|
NotTopAdmin,
|
||||||
|
NotTopMod,
|
||||||
|
NotLoggedIn,
|
||||||
|
SiteBan,
|
||||||
|
Deleted,
|
||||||
|
BannedFromCommunity,
|
||||||
|
CouldntFindCommunity,
|
||||||
|
CouldntFindPerson,
|
||||||
|
PersonIsBlocked,
|
||||||
|
DownvotesAreDisabled,
|
||||||
|
InstanceIsPrivate,
|
||||||
|
InvalidPassword,
|
||||||
|
SiteDescriptionLengthOverflow,
|
||||||
|
HoneypotFailed,
|
||||||
|
RegistrationApplicationIsPending,
|
||||||
|
CantEnablePrivateInstanceAndFederationTogether,
|
||||||
|
Locked,
|
||||||
|
CouldntCreateComment,
|
||||||
|
MaxCommentDepthReached,
|
||||||
|
NoCommentEditAllowed,
|
||||||
|
OnlyAdminsCanCreateCommunities,
|
||||||
|
CommunityAlreadyExists,
|
||||||
|
LanguageNotAllowed,
|
||||||
|
OnlyModsCanPostInCommunity,
|
||||||
|
CouldntUpdatePost,
|
||||||
|
NoPostEditAllowed,
|
||||||
|
CouldntFindPost,
|
||||||
|
EditPrivateMessageNotAllowed,
|
||||||
|
SiteAlreadyExists,
|
||||||
|
ApplicationQuestionRequired,
|
||||||
|
InvalidDefaultPostListingType,
|
||||||
|
RegistrationClosed,
|
||||||
|
RegistrationApplicationAnswerRequired,
|
||||||
|
EmailAlreadyExists,
|
||||||
|
FederationForbiddenByStrictAllowList,
|
||||||
|
PersonIsBannedFromCommunity,
|
||||||
|
ObjectIsNotPublic,
|
||||||
|
InvalidCommunity,
|
||||||
|
CannotCreatePostOrCommentInDeletedOrRemovedCommunity,
|
||||||
|
CannotReceivePage,
|
||||||
|
NewPostCannotBeLocked,
|
||||||
|
OnlyLocalAdminCanRemoveCommunity,
|
||||||
|
OnlyLocalAdminCanRestoreCommunity,
|
||||||
|
NoIdGiven,
|
||||||
|
IncorrectLogin,
|
||||||
|
InvalidQuery,
|
||||||
|
ObjectNotLocal,
|
||||||
|
PostIsLocked,
|
||||||
|
PersonIsBannedFromSite,
|
||||||
|
InvalidVoteValue,
|
||||||
|
PageDoesNotSpecifyCreator,
|
||||||
|
PageDoesNotSpecifyGroup,
|
||||||
|
NoCommunityFoundInCc,
|
||||||
|
NoEmailSetup,
|
||||||
|
EmailSmtpServerNeedsAPort,
|
||||||
|
MissingAnEmail,
|
||||||
|
RateLimitError,
|
||||||
|
InvalidName,
|
||||||
|
InvalidDisplayName,
|
||||||
|
InvalidMatrixId,
|
||||||
|
InvalidPostTitle,
|
||||||
|
InvalidBodyField,
|
||||||
|
BioLengthOverflow,
|
||||||
|
MissingTotpToken,
|
||||||
|
IncorrectTotpToken,
|
||||||
|
CouldntParseTotpSecret,
|
||||||
|
CouldntLikeComment,
|
||||||
|
CouldntSaveComment,
|
||||||
|
CouldntCreateReport,
|
||||||
|
CouldntResolveReport,
|
||||||
|
CommunityModeratorAlreadyExists,
|
||||||
|
CommunityUserAlreadyBanned,
|
||||||
|
CommunityBlockAlreadyExists,
|
||||||
|
CommunityFollowerAlreadyExists,
|
||||||
|
CouldntUpdateCommunityHiddenStatus,
|
||||||
|
PersonBlockAlreadyExists,
|
||||||
|
UserAlreadyExists,
|
||||||
|
TokenNotFound,
|
||||||
|
CouldntLikePost,
|
||||||
|
CouldntSavePost,
|
||||||
|
CouldntMarkPostAsRead,
|
||||||
|
CouldntUpdateCommunity,
|
||||||
|
CouldntUpdateReplies,
|
||||||
|
CouldntUpdatePersonMentions,
|
||||||
|
PostTitleTooLong,
|
||||||
|
CouldntCreatePost,
|
||||||
|
CouldntCreatePrivateMessage,
|
||||||
|
CouldntUpdatePrivate,
|
||||||
|
SystemErrLogin,
|
||||||
|
CouldntSetAllRegistrationsAccepted,
|
||||||
|
CouldntSetAllEmailVerified,
|
||||||
|
Banned,
|
||||||
|
CouldntGetComments,
|
||||||
|
CouldntGetPosts,
|
||||||
|
InvalidUrl,
|
||||||
|
EmailSendFailed,
|
||||||
|
Slurs,
|
||||||
|
CouldntGenerateTotp,
|
||||||
|
CouldntFindObject,
|
||||||
|
RegistrationDenied(String),
|
||||||
|
FederationDisabled,
|
||||||
|
DomainBlocked,
|
||||||
|
DomainNotInAllowList,
|
||||||
|
FederationDisabledByStrictAllowList,
|
||||||
|
SiteNameRequired,
|
||||||
|
SiteNameLengthOverflow,
|
||||||
|
PermissiveRegex,
|
||||||
|
InvalidRegex,
|
||||||
|
CaptchaIncorrect,
|
||||||
|
PasswordResetLimitReached,
|
||||||
|
CouldntCreateAudioCaptcha,
|
||||||
|
InvalidUrlScheme,
|
||||||
|
CouldntSendWebmention,
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<LemmyErrorType> for LemmyError {
|
||||||
|
fn from(error_type: LemmyErrorType) -> Self {
|
||||||
|
let inner = anyhow::anyhow!("{}", error_type);
|
||||||
|
LemmyError {
|
||||||
|
error_type: Some(error_type),
|
||||||
|
inner,
|
||||||
|
context: SpanTrace::capture(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait LemmyErrorExt<T, E: Into<anyhow::Error>> {
|
||||||
|
fn with_lemmy_type(self, error_type: LemmyErrorType) -> Result<T, LemmyError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, E: Into<anyhow::Error>> LemmyErrorExt<T, E> for Result<T, E> {
|
||||||
|
fn with_lemmy_type(self, error_type: LemmyErrorType) -> Result<T, LemmyError> {
|
||||||
|
self.map_err(|error| LemmyError {
|
||||||
|
error_type: Some(error_type),
|
||||||
|
inner: error.into(),
|
||||||
|
context: SpanTrace::capture(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub trait LemmyErrorExt2<T> {
|
||||||
|
fn with_lemmy_type(self, error_type: LemmyErrorType) -> Result<T, LemmyError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> LemmyErrorExt2<T> for Result<T, LemmyError> {
|
||||||
|
fn with_lemmy_type(self, error_type: LemmyErrorType) -> Result<T, LemmyError> {
|
||||||
|
self.map_err(|mut e| {
|
||||||
|
e.error_type = Some(error_type);
|
||||||
|
e
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use actix_web::{body::MessageBody, ResponseError};
|
||||||
|
use std::fs::read_to_string;
|
||||||
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserializes_no_message() {
|
||||||
|
let err = LemmyError::from(LemmyErrorType::Banned).error_response();
|
||||||
|
let json = String::from_utf8(err.into_body().try_into_bytes().unwrap().to_vec()).unwrap();
|
||||||
|
assert_eq!(&json, "{\"error\":\"banned\"}")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserializes_with_message() {
|
||||||
|
let reg_denied = LemmyErrorType::RegistrationDenied(String::from("reason"));
|
||||||
|
let err = LemmyError::from(reg_denied).error_response();
|
||||||
|
let json = String::from_utf8(err.into_body().try_into_bytes().unwrap().to_vec()).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
&json,
|
||||||
|
"{\"error\":\"registration_denied\",\"message\":\"reason\"}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if errors match translations. Disabled because many are not translated at all.
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn test_translations_match() {
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Err {
|
||||||
|
error: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
let translations = read_to_string("translations/translations/en.json").unwrap();
|
||||||
|
LemmyErrorType::iter().for_each(|e| {
|
||||||
|
let msg = serde_json::to_string(&e).unwrap();
|
||||||
|
let msg: Err = serde_json::from_str(&msg).unwrap();
|
||||||
|
let msg = msg.error;
|
||||||
|
assert!(translations.contains(&format!("\"{msg}\"")), "{msg}");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::error::LemmyError;
|
use crate::error::{LemmyError, LemmyErrorType};
|
||||||
use actix_web::dev::{ConnectionInfo, Service, ServiceRequest, ServiceResponse, Transform};
|
use actix_web::dev::{ConnectionInfo, Service, ServiceRequest, ServiceResponse, Transform};
|
||||||
use enum_map::enum_map;
|
use enum_map::enum_map;
|
||||||
use futures::future::{ok, Ready};
|
use futures::future::{ok, Ready};
|
||||||
|
@ -246,7 +246,7 @@ where
|
||||||
} else {
|
} else {
|
||||||
let (http_req, _) = req.into_parts();
|
let (http_req, _) = req.into_parts();
|
||||||
Ok(ServiceResponse::from_err(
|
Ok(ServiceResponse::from_err(
|
||||||
LemmyError::from_message("rate_limit_error"),
|
LemmyError::from(LemmyErrorType::RateLimitError),
|
||||||
http_req,
|
http_req,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::error::LemmyError;
|
use crate::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
|
||||||
use regex::{Regex, RegexBuilder};
|
use regex::{Regex, RegexBuilder};
|
||||||
|
|
||||||
pub fn remove_slurs(test: &str, slur_regex: &Option<Regex>) -> String {
|
pub fn remove_slurs(test: &str, slur_regex: &Option<Regex>) -> String {
|
||||||
|
@ -41,10 +41,7 @@ pub fn build_slur_regex(regex_str: Option<&str>) -> Option<Regex> {
|
||||||
|
|
||||||
pub fn check_slurs(text: &str, slur_regex: &Option<Regex>) -> Result<(), LemmyError> {
|
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(LemmyError::from_error_message(
|
Err(anyhow::anyhow!("{}", slurs_vec_to_str(&slurs))).with_lemmy_type(LemmyErrorType::Slurs)
|
||||||
anyhow::anyhow!("{}", slurs_vec_to_str(&slurs)),
|
|
||||||
"slurs",
|
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::error::{LemmyError, LemmyResult};
|
use crate::error::{LemmyError, LemmyErrorExt, LemmyErrorType, LemmyResult};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use regex::{Regex, RegexBuilder};
|
use regex::{Regex, RegexBuilder};
|
||||||
|
@ -90,7 +90,7 @@ pub fn is_valid_actor_name(name: &str, actor_name_max_length: usize) -> LemmyRes
|
||||||
&& VALID_ACTOR_NAME_REGEX.is_match(name)
|
&& VALID_ACTOR_NAME_REGEX.is_match(name)
|
||||||
&& !has_newline(name);
|
&& !has_newline(name);
|
||||||
if !check {
|
if !check {
|
||||||
Err(LemmyError::from_message("invalid_name"))
|
Err(LemmyErrorType::InvalidName.into())
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -104,7 +104,7 @@ pub fn is_valid_display_name(name: &str, actor_name_max_length: usize) -> LemmyR
|
||||||
&& name.chars().count() <= actor_name_max_length
|
&& name.chars().count() <= actor_name_max_length
|
||||||
&& !has_newline(name);
|
&& !has_newline(name);
|
||||||
if !check {
|
if !check {
|
||||||
Err(LemmyError::from_message("invalid_username"))
|
Err(LemmyErrorType::InvalidDisplayName.into())
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -113,7 +113,7 @@ pub fn is_valid_display_name(name: &str, actor_name_max_length: usize) -> LemmyR
|
||||||
pub fn is_valid_matrix_id(matrix_id: &str) -> LemmyResult<()> {
|
pub fn is_valid_matrix_id(matrix_id: &str) -> LemmyResult<()> {
|
||||||
let check = VALID_MATRIX_ID_REGEX.is_match(matrix_id) && !has_newline(matrix_id);
|
let check = VALID_MATRIX_ID_REGEX.is_match(matrix_id) && !has_newline(matrix_id);
|
||||||
if !check {
|
if !check {
|
||||||
Err(LemmyError::from_message("invalid_matrix_id"))
|
Err(LemmyErrorType::InvalidMatrixId.into())
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -122,7 +122,7 @@ pub fn is_valid_matrix_id(matrix_id: &str) -> LemmyResult<()> {
|
||||||
pub fn is_valid_post_title(title: &str) -> LemmyResult<()> {
|
pub fn is_valid_post_title(title: &str) -> LemmyResult<()> {
|
||||||
let check = VALID_POST_TITLE_REGEX.is_match(title) && !has_newline(title);
|
let check = VALID_POST_TITLE_REGEX.is_match(title) && !has_newline(title);
|
||||||
if !check {
|
if !check {
|
||||||
Err(LemmyError::from_message("invalid_post_title"))
|
Err(LemmyErrorType::InvalidPostTitle.into())
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -138,7 +138,7 @@ pub fn is_valid_body_field(body: &Option<String>, post: bool) -> LemmyResult<()>
|
||||||
};
|
};
|
||||||
|
|
||||||
if !check {
|
if !check {
|
||||||
Err(LemmyError::from_message("invalid_body_field"))
|
Err(LemmyErrorType::InvalidBodyField.into())
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -148,7 +148,7 @@ pub fn is_valid_body_field(body: &Option<String>, post: bool) -> LemmyResult<()>
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_valid_bio_field(bio: &str) -> LemmyResult<()> {
|
pub fn is_valid_bio_field(bio: &str) -> LemmyResult<()> {
|
||||||
max_length_check(bio, BIO_MAX_LENGTH, String::from("bio_length_overflow"))
|
max_length_check(bio, BIO_MAX_LENGTH, LemmyErrorType::BioLengthOverflow)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks the site name length, the limit as defined in the DB.
|
/// Checks the site name length, the limit as defined in the DB.
|
||||||
|
@ -157,8 +157,8 @@ pub fn site_name_length_check(name: &str) -> LemmyResult<()> {
|
||||||
name,
|
name,
|
||||||
SITE_NAME_MIN_LENGTH,
|
SITE_NAME_MIN_LENGTH,
|
||||||
SITE_NAME_MAX_LENGTH,
|
SITE_NAME_MAX_LENGTH,
|
||||||
String::from("site_name_required"),
|
LemmyErrorType::SiteNameRequired,
|
||||||
String::from("site_name_length_overflow"),
|
LemmyErrorType::SiteNameLengthOverflow,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,13 +167,13 @@ pub fn site_description_length_check(description: &str) -> LemmyResult<()> {
|
||||||
max_length_check(
|
max_length_check(
|
||||||
description,
|
description,
|
||||||
SITE_DESCRIPTION_MAX_LENGTH,
|
SITE_DESCRIPTION_MAX_LENGTH,
|
||||||
String::from("site_description_length_overflow"),
|
LemmyErrorType::SiteDescriptionLengthOverflow,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn max_length_check(item: &str, max_length: usize, msg: String) -> LemmyResult<()> {
|
fn max_length_check(item: &str, max_length: usize, error_type: LemmyErrorType) -> LemmyResult<()> {
|
||||||
if item.len() > max_length {
|
if item.len() > max_length {
|
||||||
Err(LemmyError::from_message(&msg))
|
Err(error_type.into())
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -183,13 +183,13 @@ fn min_max_length_check(
|
||||||
item: &str,
|
item: &str,
|
||||||
min_length: usize,
|
min_length: usize,
|
||||||
max_length: usize,
|
max_length: usize,
|
||||||
min_msg: String,
|
min_msg: LemmyErrorType,
|
||||||
max_msg: String,
|
max_msg: LemmyErrorType,
|
||||||
) -> LemmyResult<()> {
|
) -> LemmyResult<()> {
|
||||||
if item.len() > max_length {
|
if item.len() > max_length {
|
||||||
Err(LemmyError::from_message(&max_msg))
|
Err(max_msg.into())
|
||||||
} else if item.len() < min_length {
|
} else if item.len() < min_length {
|
||||||
Err(LemmyError::from_message(&min_msg))
|
Err(min_msg.into())
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -209,14 +209,14 @@ pub fn build_and_check_regex(regex_str_opt: &Option<&str>) -> LemmyResult<Option
|
||||||
RegexBuilder::new(regex_str)
|
RegexBuilder::new(regex_str)
|
||||||
.case_insensitive(true)
|
.case_insensitive(true)
|
||||||
.build()
|
.build()
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "invalid_regex"))
|
.with_lemmy_type(LemmyErrorType::InvalidRegex)
|
||||||
.and_then(|regex| {
|
.and_then(|regex| {
|
||||||
// NOTE: It is difficult to know, in the universe of user-crafted regex, which ones
|
// NOTE: It is difficult to know, in the universe of user-crafted regex, which ones
|
||||||
// may match against any string text. To keep it simple, we'll match the regex
|
// may match against any string text. To keep it simple, we'll match the regex
|
||||||
// against an innocuous string - a single number - which should help catch a regex
|
// against an innocuous string - a single number - which should help catch a regex
|
||||||
// that accidentally matches against all strings.
|
// that accidentally matches against all strings.
|
||||||
if regex.is_match("1") {
|
if regex.is_match("1") {
|
||||||
return Err(LemmyError::from_message("permissive_regex"));
|
return Err(LemmyErrorType::PermissiveRegex.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Some(regex))
|
Ok(Some(regex))
|
||||||
|
@ -249,13 +249,13 @@ pub fn check_totp_2fa_valid(
|
||||||
// Throw an error if their token is missing
|
// Throw an error if their token is missing
|
||||||
let token = totp_token
|
let token = totp_token
|
||||||
.as_deref()
|
.as_deref()
|
||||||
.ok_or_else(|| LemmyError::from_message("missing_totp_token"))?;
|
.ok_or(LemmyErrorType::MissingTotpToken)?;
|
||||||
|
|
||||||
let totp = build_totp_2fa(site_name, username, totp_secret)?;
|
let totp = build_totp_2fa(site_name, username, totp_secret)?;
|
||||||
|
|
||||||
let check_passed = totp.check_current(token)?;
|
let check_passed = totp.check_current(token)?;
|
||||||
if !check_passed {
|
if !check_passed {
|
||||||
return Err(LemmyError::from_message("incorrect_totp token"));
|
return Err(LemmyErrorType::IncorrectTotpToken.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,7 +270,7 @@ pub fn build_totp_2fa(site_name: &str, username: &str, secret: &str) -> Result<T
|
||||||
let sec = Secret::Raw(secret.as_bytes().to_vec());
|
let sec = Secret::Raw(secret.as_bytes().to_vec());
|
||||||
let sec_bytes = sec
|
let sec_bytes = sec
|
||||||
.to_bytes()
|
.to_bytes()
|
||||||
.map_err(|_| LemmyError::from_message("Couldnt parse totp secret"))?;
|
.map_err(|_| LemmyErrorType::CouldntParseTotpSecret)?;
|
||||||
|
|
||||||
TOTP::new(
|
TOTP::new(
|
||||||
totp_rs::Algorithm::SHA256,
|
totp_rs::Algorithm::SHA256,
|
||||||
|
@ -281,7 +281,7 @@ pub fn build_totp_2fa(site_name: &str, username: &str, secret: &str) -> Result<T
|
||||||
Some(site_name.to_string()),
|
Some(site_name.to_string()),
|
||||||
username.to_string(),
|
username.to_string(),
|
||||||
)
|
)
|
||||||
.map_err(|e| LemmyError::from_error_message(e, "Couldnt generate TOTP"))
|
.with_lemmy_type(LemmyErrorType::CouldntGenerateTotp)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_site_visibility_valid(
|
pub fn check_site_visibility_valid(
|
||||||
|
@ -294,9 +294,7 @@ pub fn check_site_visibility_valid(
|
||||||
let federation_enabled = new_federation_enabled.unwrap_or(current_federation_enabled);
|
let federation_enabled = new_federation_enabled.unwrap_or(current_federation_enabled);
|
||||||
|
|
||||||
if private_instance && federation_enabled {
|
if private_instance && federation_enabled {
|
||||||
return Err(LemmyError::from_message(
|
return Err(LemmyErrorType::CantEnablePrivateInstanceAndFederationTogether.into());
|
||||||
"cant_enable_private_instance_and_federation_together",
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -305,7 +303,7 @@ pub fn check_site_visibility_valid(
|
||||||
pub fn check_url_scheme(url: &Option<Url>) -> LemmyResult<()> {
|
pub fn check_url_scheme(url: &Option<Url>) -> LemmyResult<()> {
|
||||||
if let Some(url) = url {
|
if let Some(url) = url {
|
||||||
if url.scheme() != "http" && url.scheme() != "https" {
|
if url.scheme() != "http" && url.scheme() != "https" {
|
||||||
return Err(LemmyError::from_message("invalid_url_scheme"));
|
return Err(LemmyErrorType::InvalidUrlScheme.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -314,7 +312,9 @@ pub fn check_url_scheme(url: &Option<Url>) -> LemmyResult<()> {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::build_totp_2fa;
|
use super::build_totp_2fa;
|
||||||
use crate::utils::validation::{
|
use crate::{
|
||||||
|
error::LemmyErrorType,
|
||||||
|
utils::validation::{
|
||||||
build_and_check_regex,
|
build_and_check_regex,
|
||||||
check_site_visibility_valid,
|
check_site_visibility_valid,
|
||||||
check_url_scheme,
|
check_url_scheme,
|
||||||
|
@ -330,6 +330,7 @@ mod tests {
|
||||||
BIO_MAX_LENGTH,
|
BIO_MAX_LENGTH,
|
||||||
SITE_DESCRIPTION_MAX_LENGTH,
|
SITE_DESCRIPTION_MAX_LENGTH,
|
||||||
SITE_NAME_MAX_LENGTH,
|
SITE_NAME_MAX_LENGTH,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
@ -409,9 +410,9 @@ mod tests {
|
||||||
&(0..SITE_NAME_MAX_LENGTH + 1)
|
&(0..SITE_NAME_MAX_LENGTH + 1)
|
||||||
.map(|_| 'A')
|
.map(|_| 'A')
|
||||||
.collect::<String>(),
|
.collect::<String>(),
|
||||||
"site_name_length_overflow",
|
LemmyErrorType::SiteNameLengthOverflow,
|
||||||
),
|
),
|
||||||
(&String::new(), "site_name_required"),
|
(&String::new(), LemmyErrorType::SiteNameRequired),
|
||||||
];
|
];
|
||||||
|
|
||||||
valid_names.iter().for_each(|valid_name| {
|
valid_names.iter().for_each(|valid_name| {
|
||||||
|
@ -425,15 +426,15 @@ mod tests {
|
||||||
|
|
||||||
invalid_names
|
invalid_names
|
||||||
.iter()
|
.iter()
|
||||||
.for_each(|&(invalid_name, expected_err)| {
|
.for_each(|(invalid_name, expected_err)| {
|
||||||
let result = site_name_length_check(invalid_name);
|
let result = site_name_length_check(invalid_name);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
assert!(
|
assert!(
|
||||||
result
|
result
|
||||||
.unwrap_err()
|
.unwrap_err()
|
||||||
.message
|
.error_type
|
||||||
.eq(&Some(String::from(expected_err))),
|
.eq(&Some(expected_err.clone())),
|
||||||
"Testing {}, expected error {}",
|
"Testing {}, expected error {}",
|
||||||
invalid_name,
|
invalid_name,
|
||||||
expected_err
|
expected_err
|
||||||
|
@ -452,8 +453,8 @@ mod tests {
|
||||||
invalid_result.is_err()
|
invalid_result.is_err()
|
||||||
&& invalid_result
|
&& invalid_result
|
||||||
.unwrap_err()
|
.unwrap_err()
|
||||||
.message
|
.error_type
|
||||||
.eq(&Some(String::from("bio_length_overflow")))
|
.eq(&Some(LemmyErrorType::BioLengthOverflow))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -476,8 +477,8 @@ mod tests {
|
||||||
invalid_result.is_err()
|
invalid_result.is_err()
|
||||||
&& invalid_result
|
&& invalid_result
|
||||||
.unwrap_err()
|
.unwrap_err()
|
||||||
.message
|
.error_type
|
||||||
.eq(&Some(String::from("site_description_length_overflow")))
|
.eq(&Some(LemmyErrorType::SiteDescriptionLengthOverflow))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -495,22 +496,22 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_too_permissive_slur_regex() {
|
fn test_too_permissive_slur_regex() {
|
||||||
let match_everything_regexes = [
|
let match_everything_regexes = [
|
||||||
(&Some("["), "invalid_regex"),
|
(&Some("["), LemmyErrorType::InvalidRegex),
|
||||||
(&Some("(foo|bar|)"), "permissive_regex"),
|
(&Some("(foo|bar|)"), LemmyErrorType::PermissiveRegex),
|
||||||
(&Some(".*"), "permissive_regex"),
|
(&Some(".*"), LemmyErrorType::PermissiveRegex),
|
||||||
];
|
];
|
||||||
|
|
||||||
match_everything_regexes
|
match_everything_regexes
|
||||||
.iter()
|
.iter()
|
||||||
.for_each(|&(regex_str, expected_err)| {
|
.for_each(|(regex_str, expected_err)| {
|
||||||
let result = build_and_check_regex(regex_str);
|
let result = build_and_check_regex(regex_str);
|
||||||
|
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
assert!(
|
assert!(
|
||||||
result
|
result
|
||||||
.unwrap_err()
|
.unwrap_err()
|
||||||
.message
|
.error_type
|
||||||
.eq(&Some(String::from(expected_err))),
|
.eq(&Some(expected_err.clone())),
|
||||||
"Testing regex {:?}, expected error {}",
|
"Testing regex {:?}, expected error {}",
|
||||||
regex_str,
|
regex_str,
|
||||||
expected_err
|
expected_err
|
||||||
|
|
Loading…
Reference in a new issue