@ -50,7 +50,6 @@ use lemmy_utils::{
email ::send_email ,
location_info ,
utils ::{ generate_random_string , is_valid_display_name , is_valid_matrix_id , naive_from_unix } ,
ApiError ,
ConnectionId ,
LemmyError ,
} ;
@ -65,6 +64,7 @@ use lemmy_websocket::{
impl Perform for Login {
type Response = LoginResponse ;
#[ tracing::instrument(skip(context, _websocket_id)) ]
async fn perform (
& self ,
context : & Data < LemmyContext > ,
@ -78,7 +78,8 @@ impl Perform for Login {
LocalUserView ::find_by_email_or_name ( conn , & username_or_email )
} )
. await ?
. map_err ( | e | ApiError ::err ( "couldnt_find_that_username_or_email" , e ) ) ? ;
. map_err ( LemmyError ::from )
. map_err ( | e | e . with_message ( "couldnt_find_that_username_or_email" ) ) ? ;
// Verify the password
let valid : bool = verify (
@ -87,21 +88,24 @@ impl Perform for Login {
)
. unwrap_or ( false ) ;
if ! valid {
return Err ( ApiError::err_plain ( "password_incorrect" ) . into ( ) ) ;
return Err ( LemmyError::from_message ( "password_incorrect" ) ) ;
}
let site = blocking ( context . pool ( ) , Site ::read_simple ) . await ? ? ;
if site . require_email_verification & & ! local_user_view . local_user . email_verified {
return Err ( ApiError::err_plain ( "email_not_verified" ) . into ( ) ) ;
return Err ( LemmyError::from_message ( "email_not_verified" ) ) ;
}
// Return the jwt
Ok ( LoginResponse {
jwt : Some ( Claims ::jwt (
local_user_view . local_user . id . 0 ,
& context . secret ( ) . jwt_secret ,
& context . settings ( ) . hostname ,
) ? ) ,
jwt : Some (
Claims ::jwt (
local_user_view . local_user . id . 0 ,
& context . secret ( ) . jwt_secret ,
& context . settings ( ) . hostname ,
) ?
. into ( ) ,
) ,
verify_email_sent : false ,
registration_created : false ,
} )
@ -112,6 +116,7 @@ impl Perform for Login {
impl Perform for GetCaptcha {
type Response = GetCaptchaResponse ;
#[ tracing::instrument(skip(context, _websocket_id)) ]
async fn perform (
& self ,
context : & Data < LemmyContext > ,
@ -157,6 +162,7 @@ impl Perform for GetCaptcha {
impl Perform for SaveUserSettings {
type Response = LoginResponse ;
#[ tracing::instrument(skip(context, _websocket_id)) ]
async fn perform (
& self ,
context : & Data < LemmyContext > ,
@ -172,8 +178,9 @@ impl Perform for SaveUserSettings {
let display_name = diesel_option_overwrite ( & data . display_name ) ;
let matrix_user_id = diesel_option_overwrite ( & data . matrix_user_id ) ;
let bot_account = data . bot_account ;
let email_deref = data . email . as_deref ( ) . map ( | e | e . to_owned ( ) ) ;
let email = if let Some ( email ) = & data. email {
let email = if let Some ( email ) = & email_deref {
let site = blocking ( context . pool ( ) , Site ::read_simple ) . await ? ? ;
if site . require_email_verification {
send_verification_email (
@ -185,7 +192,7 @@ impl Perform for SaveUserSettings {
. await ? ;
None
} else {
diesel_option_overwrite ( & data. email)
diesel_option_overwrite ( & email_deref )
}
} else {
None
@ -193,7 +200,7 @@ impl Perform for SaveUserSettings {
if let Some ( Some ( bio ) ) = & bio {
if bio . chars ( ) . count ( ) > 300 {
return Err ( ApiError::err_plain ( "bio_length_overflow" ) . into ( ) ) ;
return Err ( LemmyError::from_message ( "bio_length_overflow" ) ) ;
}
}
@ -202,13 +209,13 @@ impl Perform for SaveUserSettings {
display_name . trim ( ) ,
context . settings ( ) . actor_name_max_length ,
) {
return Err ( ApiError::err_plain ( "invalid_username" ) . into ( ) ) ;
return Err ( LemmyError::from_message ( "invalid_username" ) ) ;
}
}
if let Some ( Some ( matrix_user_id ) ) = & matrix_user_id {
if ! is_valid_matrix_id ( matrix_user_id ) {
return Err ( ApiError::err_plain ( "invalid_matrix_id" ) . into ( ) ) ;
return Err ( LemmyError::from_message ( "invalid_matrix_id" ) ) ;
}
}
@ -245,7 +252,8 @@ impl Perform for SaveUserSettings {
Person ::update ( conn , person_id , & person_form )
} )
. await ?
. map_err ( | e | ApiError ::err ( "user_already_exists" , e ) ) ? ;
. map_err ( LemmyError ::from )
. map_err ( | e | e . with_message ( "user_already_exists" ) ) ? ;
let local_user_form = LocalUserForm {
person_id : Some ( person_id ) ,
@ -281,17 +289,20 @@ impl Perform for SaveUserSettings {
"user_already_exists"
} ;
return Err ( ApiError::err ( err_type , e ) . into ( ) ) ;
return Err ( LemmyError::from ( e ) . with_message ( err_type ) ) ;
}
} ;
// Return the jwt
Ok ( LoginResponse {
jwt : Some ( Claims ::jwt (
updated_local_user . id . 0 ,
& context . secret ( ) . jwt_secret ,
& context . settings ( ) . hostname ,
) ? ) ,
jwt : Some (
Claims ::jwt (
updated_local_user . id . 0 ,
& context . secret ( ) . jwt_secret ,
& context . settings ( ) . hostname ,
) ?
. into ( ) ,
) ,
verify_email_sent : false ,
registration_created : false ,
} )
@ -302,6 +313,7 @@ impl Perform for SaveUserSettings {
impl Perform for ChangePassword {
type Response = LoginResponse ;
#[ tracing::instrument(skip(self, context, _websocket_id)) ]
async fn perform (
& self ,
context : & Data < LemmyContext > ,
@ -309,13 +321,13 @@ impl Perform for ChangePassword {
) -> Result < LoginResponse , LemmyError > {
let data : & ChangePassword = self ;
let local_user_view =
get_local_user_view_from_jwt ( & data . auth , context . pool ( ) , context . secret ( ) ) . await ? ;
get_local_user_view_from_jwt ( data . auth . as_ref ( ) , context . pool ( ) , context . secret ( ) ) . await ? ;
password_length_check ( & data . new_password ) ? ;
// Make sure passwords match
if data . new_password ! = data . new_password_verify {
return Err ( ApiError::err_plain ( "passwords_dont_match" ) . into ( ) ) ;
return Err ( LemmyError::from_message ( "passwords_dont_match" ) ) ;
}
// Check the old password
@ -325,7 +337,7 @@ impl Perform for ChangePassword {
)
. unwrap_or ( false ) ;
if ! valid {
return Err ( ApiError::err_plain ( "password_incorrect" ) . into ( ) ) ;
return Err ( LemmyError::from_message ( "password_incorrect" ) ) ;
}
let local_user_id = local_user_view . local_user . id ;
@ -337,11 +349,14 @@ impl Perform for ChangePassword {
// Return the jwt
Ok ( LoginResponse {
jwt : Some ( Claims ::jwt (
updated_local_user . id . 0 ,
& context . secret ( ) . jwt_secret ,
& context . settings ( ) . hostname ,
) ? ) ,
jwt : Some (
Claims ::jwt (
updated_local_user . id . 0 ,
& context . secret ( ) . jwt_secret ,
& context . settings ( ) . hostname ,
) ?
. into ( ) ,
) ,
verify_email_sent : false ,
registration_created : false ,
} )
@ -352,6 +367,7 @@ impl Perform for ChangePassword {
impl Perform for AddAdmin {
type Response = AddAdminResponse ;
#[ tracing::instrument(skip(context, websocket_id)) ]
async fn perform (
& self ,
context : & Data < LemmyContext > ,
@ -370,7 +386,8 @@ impl Perform for AddAdmin {
Person ::add_admin ( conn , added_person_id , added )
} )
. await ?
. map_err ( | e | ApiError ::err ( "couldnt_update_user" , e ) ) ? ;
. map_err ( LemmyError ::from )
. map_err ( | e | e . with_message ( "couldnt_update_user" ) ) ? ;
// Mod tables
let form = ModAddForm {
@ -410,6 +427,7 @@ impl Perform for AddAdmin {
impl Perform for BanPerson {
type Response = BanPersonResponse ;
#[ tracing::instrument(skip(context, websocket_id)) ]
async fn perform (
& self ,
context : & Data < LemmyContext > ,
@ -427,7 +445,8 @@ impl Perform for BanPerson {
let ban_person = move | conn : & ' _ _ | Person ::ban_person ( conn , banned_person_id , ban ) ;
blocking ( context . pool ( ) , ban_person )
. await ?
. map_err ( | e | ApiError ::err ( "couldnt_update_user" , e ) ) ? ;
. map_err ( LemmyError ::from )
. map_err ( | e | e . with_message ( "couldnt_update_user" ) ) ? ;
// Remove their data if that's desired
if data . remove_data . unwrap_or ( false ) {
@ -503,6 +522,7 @@ impl Perform for BanPerson {
impl Perform for BlockPerson {
type Response = BlockPersonResponse ;
#[ tracing::instrument(skip(context, _websocket_id)) ]
async fn perform (
& self ,
context : & Data < LemmyContext > ,
@ -517,7 +537,7 @@ impl Perform for BlockPerson {
// Don't let a person block themselves
if target_id = = person_id {
return Err ( ApiError::err_plain ( "cant_block_yourself" ) . into ( ) ) ;
return Err ( LemmyError::from_message ( "cant_block_yourself" ) ) ;
}
let person_block_form = PersonBlockForm {
@ -529,12 +549,14 @@ impl Perform for BlockPerson {
let block = move | conn : & ' _ _ | PersonBlock ::block ( conn , & person_block_form ) ;
blocking ( context . pool ( ) , block )
. await ?
. map_err ( | e | ApiError ::err ( "person_block_already_exists" , e ) ) ? ;
. map_err ( LemmyError ::from )
. map_err ( | e | e . with_message ( "person_block_already_exists" ) ) ? ;
} else {
let unblock = move | conn : & ' _ _ | PersonBlock ::unblock ( conn , & person_block_form ) ;
blocking ( context . pool ( ) , unblock )
. await ?
. map_err ( | e | ApiError ::err ( "person_block_already_exists" , e ) ) ? ;
. map_err ( LemmyError ::from )
. map_err ( | e | e . with_message ( "person_block_already_exists" ) ) ? ;
}
// TODO does any federated stuff need to be done here?
@ -557,6 +579,7 @@ impl Perform for BlockPerson {
impl Perform for GetReplies {
type Response = GetRepliesResponse ;
#[ tracing::instrument(skip(context, _websocket_id)) ]
async fn perform (
& self ,
context : & Data < LemmyContext > ,
@ -595,6 +618,7 @@ impl Perform for GetReplies {
impl Perform for GetPersonMentions {
type Response = GetPersonMentionsResponse ;
#[ tracing::instrument(skip(context, _websocket_id)) ]
async fn perform (
& self ,
context : & Data < LemmyContext > ,
@ -630,6 +654,7 @@ impl Perform for GetPersonMentions {
impl Perform for MarkPersonMentionAsRead {
type Response = PersonMentionResponse ;
#[ tracing::instrument(skip(context, _websocket_id)) ]
async fn perform (
& self ,
context : & Data < LemmyContext > ,
@ -646,7 +671,7 @@ impl Perform for MarkPersonMentionAsRead {
. await ? ? ;
if local_user_view . person . id ! = read_person_mention . recipient_id {
return Err ( ApiError::err_plain ( "couldnt_update_comment" ) . into ( ) ) ;
return Err ( LemmyError::from_message ( "couldnt_update_comment" ) ) ;
}
let person_mention_id = read_person_mention . id ;
@ -655,7 +680,8 @@ impl Perform for MarkPersonMentionAsRead {
move | conn : & ' _ _ | PersonMention ::update_read ( conn , person_mention_id , read ) ;
blocking ( context . pool ( ) , update_mention )
. await ?
. map_err ( | e | ApiError ::err ( "couldnt_update_comment" , e ) ) ? ;
. map_err ( LemmyError ::from )
. map_err ( | e | e . with_message ( "couldnt_update_comment" ) ) ? ;
let person_mention_id = read_person_mention . id ;
let person_id = local_user_view . person . id ;
@ -674,6 +700,7 @@ impl Perform for MarkPersonMentionAsRead {
impl Perform for MarkAllAsRead {
type Response = GetRepliesResponse ;
#[ tracing::instrument(skip(context, _websocket_id)) ]
async fn perform (
& self ,
context : & Data < LemmyContext > ,
@ -703,7 +730,8 @@ impl Perform for MarkAllAsRead {
let mark_as_read = move | conn : & ' _ _ | Comment ::update_read ( conn , reply_id , true ) ;
blocking ( context . pool ( ) , mark_as_read )
. await ?
. map_err ( | e | ApiError ::err ( "couldnt_update_comment" , e ) ) ? ;
. map_err ( LemmyError ::from )
. map_err ( | e | e . with_message ( "couldnt_update_comment" ) ) ? ;
}
// Mark all user mentions as read
@ -711,13 +739,15 @@ impl Perform for MarkAllAsRead {
move | conn : & ' _ _ | PersonMention ::mark_all_as_read ( conn , person_id ) ;
blocking ( context . pool ( ) , update_person_mentions )
. await ?
. map_err ( | e | ApiError ::err ( "couldnt_update_comment" , e ) ) ? ;
. map_err ( LemmyError ::from )
. map_err ( | e | e . with_message ( "couldnt_update_comment" ) ) ? ;
// Mark all private_messages as read
let update_pm = move | conn : & ' _ _ | PrivateMessage ::mark_all_as_read ( conn , person_id ) ;
blocking ( context . pool ( ) , update_pm )
. await ?
. map_err ( | e | ApiError ::err ( "couldnt_update_private_message" , e ) ) ? ;
. map_err ( LemmyError ::from )
. map_err ( | e | e . with_message ( "couldnt_update_private_message" ) ) ? ;
Ok ( GetRepliesResponse { replies : vec ! [ ] } )
}
@ -727,6 +757,7 @@ impl Perform for MarkAllAsRead {
impl Perform for PasswordReset {
type Response = PasswordResetResponse ;
#[ tracing::instrument(skip(self, context, _websocket_id)) ]
async fn perform (
& self ,
context : & Data < LemmyContext > ,
@ -740,7 +771,8 @@ impl Perform for PasswordReset {
LocalUserView ::find_by_email ( conn , & email )
} )
. await ?
. map_err ( | e | ApiError ::err ( "couldnt_find_that_username_or_email" , e ) ) ? ;
. map_err ( LemmyError ::from )
. map_err ( | e | e . with_message ( "couldnt_find_that_username_or_email" ) ) ? ;
// Generate a random token
let token = generate_random_string ( ) ;
@ -765,8 +797,7 @@ impl Perform for PasswordReset {
& local_user_view . person . name ,
html ,
& context . settings ( ) ,
)
. map_err ( | e | ApiError ::err ( "email_send_failed" , e ) ) ? ;
) ? ;
Ok ( PasswordResetResponse { } )
}
@ -776,6 +807,7 @@ impl Perform for PasswordReset {
impl Perform for PasswordChange {
type Response = LoginResponse ;
#[ tracing::instrument(skip(self, context, _websocket_id)) ]
async fn perform (
& self ,
context : & Data < LemmyContext > ,
@ -794,7 +826,7 @@ impl Perform for PasswordChange {
// Make sure passwords match
if data . password ! = data . password_verify {
return Err ( ApiError::err_plain ( "passwords_dont_match" ) . into ( ) ) ;
return Err ( LemmyError::from_message ( "passwords_dont_match" ) ) ;
}
// Update the user with the new password
@ -803,15 +835,19 @@ impl Perform for PasswordChange {
LocalUser ::update_password ( conn , local_user_id , & password )
} )
. await ?
. map_err ( | e | ApiError ::err ( "couldnt_update_user" , e ) ) ? ;
. map_err ( LemmyError ::from )
. map_err ( | e | e . with_message ( "couldnt_update_user" ) ) ? ;
// Return the jwt
Ok ( LoginResponse {
jwt : Some ( Claims ::jwt (
updated_local_user . id . 0 ,
& context . secret ( ) . jwt_secret ,
& context . settings ( ) . hostname ,
) ? ) ,
jwt : Some (
Claims ::jwt (
updated_local_user . id . 0 ,
& context . secret ( ) . jwt_secret ,
& context . settings ( ) . hostname ,
) ?
. into ( ) ,
) ,
verify_email_sent : false ,
registration_created : false ,
} )
@ -822,6 +858,7 @@ impl Perform for PasswordChange {
impl Perform for GetReportCount {
type Response = GetReportCountResponse ;
#[ tracing::instrument(skip(context, _websocket_id)) ]
async fn perform (
& self ,
context : & Data < LemmyContext > ,
@ -859,6 +896,7 @@ impl Perform for GetReportCount {
impl Perform for GetUnreadCount {
type Response = GetUnreadCountResponse ;
#[ tracing::instrument(skip(context, _websocket_id)) ]
async fn perform (
& self ,
context : & Data < LemmyContext > ,
@ -909,7 +947,8 @@ impl Perform for VerifyEmail {
EmailVerification ::read_for_token ( conn , & token )
} )
. await ?
. map_err ( | e | ApiError ::err ( "token_not_found" , e ) ) ? ;
. map_err ( LemmyError ::from )
. map_err ( | e | e . with_message ( "token_not_found" ) ) ? ;
let form = LocalUserForm {
// necessary in case this is a new signup