mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-12-22 19:01:32 +00:00
* Adding a post_view mode. Fixes #3730 * Fix test. * Addressing PR comments. * Adding a post_view mode. Fixes #3730 * Fix test. * Addressing PR comments. * Fixing column order. * Fix default Ok returns. * Removing return Err(... where feasible.
This commit is contained in:
parent
fed6542055
commit
56e26fc3d4
53 changed files with 198 additions and 155 deletions
|
@ -29,7 +29,7 @@ pub async fn add_mod_to_community(
|
|||
is_mod_or_admin(&mut context.pool(), local_user_view.person.id, community_id).await?;
|
||||
let community = Community::read(&mut context.pool(), community_id).await?;
|
||||
if local_user_view.local_user.admin && !community.local {
|
||||
return Err(LemmyErrorType::NotAModerator)?;
|
||||
Err(LemmyErrorType::NotAModerator)?
|
||||
}
|
||||
|
||||
// Update in local database
|
||||
|
|
|
@ -42,7 +42,7 @@ impl Perform for TransferCommunity {
|
|||
if !(is_top_mod(&local_user_view, &community_mods).is_ok()
|
||||
|| is_admin(&local_user_view).is_ok())
|
||||
{
|
||||
return Err(LemmyErrorType::NotAnAdmin)?;
|
||||
Err(LemmyErrorType::NotAnAdmin)?
|
||||
}
|
||||
|
||||
// You have to re-do the community_moderator table, reordering it.
|
||||
|
|
|
@ -41,24 +41,24 @@ pub(crate) fn captcha_as_wav_base64(captcha: &Captcha) -> Result<String, LemmyEr
|
|||
if let Some(samples16) = samples.as_sixteen() {
|
||||
concat_samples.extend(samples16);
|
||||
} else {
|
||||
Err(LemmyErrorType::CouldntCreateAudioCaptcha)?;
|
||||
Err(LemmyErrorType::CouldntCreateAudioCaptcha)?
|
||||
}
|
||||
}
|
||||
|
||||
// Encode the concatenated result as a wav file
|
||||
let mut output_buffer = Cursor::new(vec![]);
|
||||
let header = match any_header {
|
||||
Some(header) => header,
|
||||
None => return Err(LemmyErrorType::CouldntCreateAudioCaptcha)?,
|
||||
};
|
||||
wav::write(
|
||||
header,
|
||||
&wav::BitDepth::Sixteen(concat_samples),
|
||||
&mut output_buffer,
|
||||
)
|
||||
.with_lemmy_type(LemmyErrorType::CouldntCreateAudioCaptcha)?;
|
||||
if let Some(header) = any_header {
|
||||
wav::write(
|
||||
header,
|
||||
&wav::BitDepth::Sixteen(concat_samples),
|
||||
&mut output_buffer,
|
||||
)
|
||||
.with_lemmy_type(LemmyErrorType::CouldntCreateAudioCaptcha)?;
|
||||
|
||||
Ok(base64.encode(output_buffer.into_inner()))
|
||||
Ok(base64.encode(output_buffer.into_inner()))
|
||||
} else {
|
||||
Err(LemmyErrorType::CouldntCreateAudioCaptcha)?
|
||||
}
|
||||
}
|
||||
|
||||
/// Check size of report
|
||||
|
@ -67,12 +67,12 @@ pub(crate) fn check_report_reason(reason: &str, local_site: &LocalSite) -> Resul
|
|||
|
||||
check_slurs(reason, slur_regex)?;
|
||||
if reason.is_empty() {
|
||||
Err(LemmyErrorType::ReportReasonRequired)?;
|
||||
Err(LemmyErrorType::ReportReasonRequired)?
|
||||
} else if reason.chars().count() > 1000 {
|
||||
Err(LemmyErrorType::ReportTooLong)?
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
if reason.chars().count() > 1000 {
|
||||
Err(LemmyErrorType::ReportTooLong)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -27,7 +27,7 @@ impl Perform for BlockPerson {
|
|||
|
||||
// Don't let a person block themselves
|
||||
if target_id == person_id {
|
||||
return Err(LemmyErrorType::CantBlockYourself)?;
|
||||
Err(LemmyErrorType::CantBlockYourself)?
|
||||
}
|
||||
|
||||
let person_block_form = PersonBlockForm {
|
||||
|
@ -37,7 +37,7 @@ impl Perform for BlockPerson {
|
|||
|
||||
let target_user = LocalUserView::read_person(&mut context.pool(), target_id).await;
|
||||
if target_user.map(|t| t.local_user.admin) == Ok(true) {
|
||||
return Err(LemmyErrorType::CantBlockAdmin)?;
|
||||
Err(LemmyErrorType::CantBlockAdmin)?
|
||||
}
|
||||
|
||||
if data.block {
|
||||
|
|
|
@ -25,7 +25,7 @@ impl Perform for ChangePassword {
|
|||
|
||||
// Make sure passwords match
|
||||
if data.new_password != data.new_password_verify {
|
||||
return Err(LemmyErrorType::PasswordsDoNotMatch)?;
|
||||
Err(LemmyErrorType::PasswordsDoNotMatch)?
|
||||
}
|
||||
|
||||
// Check the old password
|
||||
|
@ -35,7 +35,7 @@ impl Perform for ChangePassword {
|
|||
)
|
||||
.unwrap_or(false);
|
||||
if !valid {
|
||||
return Err(LemmyErrorType::IncorrectLogin)?;
|
||||
Err(LemmyErrorType::IncorrectLogin)?
|
||||
}
|
||||
|
||||
let local_user_id = local_user_view.local_user.id;
|
||||
|
|
|
@ -29,7 +29,7 @@ impl Perform for PasswordChangeAfterReset {
|
|||
|
||||
// Make sure passwords match
|
||||
if data.password != data.password_verify {
|
||||
return Err(LemmyErrorType::PasswordsDoNotMatch)?;
|
||||
Err(LemmyErrorType::PasswordsDoNotMatch)?
|
||||
}
|
||||
|
||||
// Update the user with the new password
|
||||
|
|
|
@ -37,7 +37,7 @@ impl Perform for Login {
|
|||
)
|
||||
.unwrap_or(false);
|
||||
if !valid {
|
||||
return Err(LemmyErrorType::IncorrectLogin)?;
|
||||
Err(LemmyErrorType::IncorrectLogin)?
|
||||
}
|
||||
check_user_valid(
|
||||
local_user_view.person.banned,
|
||||
|
@ -51,7 +51,7 @@ impl Perform for Login {
|
|||
&& site_view.local_site.require_email_verification
|
||||
&& !local_user_view.local_user.email_verified
|
||||
{
|
||||
return Err(LemmyErrorType::EmailNotVerified)?;
|
||||
Err(LemmyErrorType::EmailNotVerified)?
|
||||
}
|
||||
|
||||
check_registration_application(&local_user_view, &site_view.local_site, &mut context.pool())
|
||||
|
|
|
@ -28,7 +28,7 @@ impl Perform for MarkPersonMentionAsRead {
|
|||
let read_person_mention = PersonMention::read(&mut context.pool(), person_mention_id).await?;
|
||||
|
||||
if local_user_view.person.id != read_person_mention.recipient_id {
|
||||
return Err(LemmyErrorType::CouldntUpdateComment)?;
|
||||
Err(LemmyErrorType::CouldntUpdateComment)?
|
||||
}
|
||||
|
||||
let person_mention_id = read_person_mention.id;
|
||||
|
|
|
@ -22,7 +22,7 @@ pub async fn mark_reply_as_read(
|
|||
let read_comment_reply = CommentReply::read(&mut context.pool(), comment_reply_id).await?;
|
||||
|
||||
if local_user_view.person.id != read_comment_reply.recipient_id {
|
||||
return Err(LemmyErrorType::CouldntUpdateComment)?;
|
||||
Err(LemmyErrorType::CouldntUpdateComment)?
|
||||
}
|
||||
|
||||
let comment_reply_id = read_comment_reply.id;
|
||||
|
|
|
@ -33,7 +33,7 @@ impl Perform for PasswordReset {
|
|||
)
|
||||
.await?;
|
||||
if recent_resets_count >= 3 {
|
||||
return Err(LemmyErrorType::PasswordResetLimitReached)?;
|
||||
Err(LemmyErrorType::PasswordResetLimitReached)?
|
||||
}
|
||||
|
||||
// Email the pure token to the user.
|
||||
|
|
|
@ -65,7 +65,7 @@ impl Perform for SaveUserSettings {
|
|||
// 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 email.is_none() && site_view.local_site.require_email_verification {
|
||||
return Err(LemmyErrorType::EmailRequired)?;
|
||||
Err(LemmyErrorType::EmailRequired)?
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ impl Perform for MarkPrivateMessageAsRead {
|
|||
let orig_private_message =
|
||||
PrivateMessage::read(&mut context.pool(), private_message_id).await?;
|
||||
if local_user_view.person.id != orig_private_message.recipient_id {
|
||||
return Err(LemmyErrorType::CouldntUpdatePrivateMessage)?;
|
||||
Err(LemmyErrorType::CouldntUpdatePrivateMessage)?
|
||||
}
|
||||
|
||||
// Doing the update
|
||||
|
|
|
@ -36,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)
|
||||
let admins = PersonView::admins(&mut context.pool()).await?;
|
||||
if admins.len() == 1 {
|
||||
return Err(LemmyErrorType::CannotLeaveAdmin)?;
|
||||
Err(LemmyErrorType::CannotLeaveAdmin)?
|
||||
}
|
||||
|
||||
LocalUser::update(
|
||||
|
|
|
@ -44,7 +44,7 @@ fn html_to_site_metadata(html_bytes: &[u8], url: &Url) -> Result<SiteMetadata, L
|
|||
.to_lowercase();
|
||||
|
||||
if !first_line.starts_with("<!doctype html>") {
|
||||
Err(LemmyErrorType::SiteMetadataPageIsNotDoctypeHtml)?;
|
||||
Err(LemmyErrorType::SiteMetadataPageIsNotDoctypeHtml)?
|
||||
}
|
||||
|
||||
let mut page = HTML::from_string(html.to_string(), None)?;
|
||||
|
|
|
@ -54,9 +54,10 @@ pub async fn is_mod_or_admin(
|
|||
) -> Result<(), LemmyError> {
|
||||
let is_mod_or_admin = CommunityView::is_mod_or_admin(pool, person_id, community_id).await?;
|
||||
if !is_mod_or_admin {
|
||||
return Err(LemmyErrorType::NotAModOrAdmin)?;
|
||||
Err(LemmyErrorType::NotAModOrAdmin)?
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
|
@ -78,9 +79,10 @@ pub async fn is_mod_or_admin_opt(
|
|||
|
||||
pub fn is_admin(local_user_view: &LocalUserView) -> Result<(), LemmyError> {
|
||||
if !local_user_view.local_user.admin {
|
||||
return Err(LemmyErrorType::NotAnAdmin)?;
|
||||
Err(LemmyErrorType::NotAnAdmin)?
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn is_top_mod(
|
||||
|
@ -93,9 +95,10 @@ pub fn is_top_mod(
|
|||
.map(|cm| cm.moderator.id)
|
||||
.unwrap_or(PersonId(0))
|
||||
{
|
||||
Err(LemmyErrorType::NotTopMod)?;
|
||||
Err(LemmyErrorType::NotTopMod)?
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
|
@ -190,15 +193,14 @@ pub fn check_user_valid(
|
|||
) -> Result<(), LemmyError> {
|
||||
// Check for a site ban
|
||||
if is_banned(banned, ban_expires) {
|
||||
Err(LemmyErrorType::SiteBan)?;
|
||||
Err(LemmyErrorType::SiteBan)?
|
||||
}
|
||||
|
||||
// check for account deletion
|
||||
if deleted {
|
||||
Err(LemmyErrorType::Deleted)?;
|
||||
else if deleted {
|
||||
Err(LemmyErrorType::Deleted)?
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
|
@ -259,9 +261,10 @@ pub async fn check_person_block(
|
|||
#[tracing::instrument(skip_all)]
|
||||
pub fn check_downvotes_enabled(score: i16, local_site: &LocalSite) -> Result<(), LemmyError> {
|
||||
if score == -1 && !local_site.enable_downvotes {
|
||||
Err(LemmyErrorType::DownvotesAreDisabled)?;
|
||||
Err(LemmyErrorType::DownvotesAreDisabled)?
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
|
@ -270,9 +273,10 @@ pub fn check_private_instance(
|
|||
local_site: &LocalSite,
|
||||
) -> Result<(), LemmyError> {
|
||||
if local_user_view.is_none() && local_site.private_instance {
|
||||
Err(LemmyErrorType::InstanceIsPrivate)?;
|
||||
Err(LemmyErrorType::InstanceIsPrivate)?
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
|
@ -517,11 +521,11 @@ pub async fn check_registration_application(
|
|||
if let Some(deny_reason) = registration.deny_reason {
|
||||
let lang = get_interface_language(local_user_view);
|
||||
let registration_denied_message = format!("{}: {}", lang.registration_denied(), deny_reason);
|
||||
return Err(LemmyErrorType::RegistrationDenied(
|
||||
Err(LemmyErrorType::RegistrationDenied(
|
||||
registration_denied_message,
|
||||
))?;
|
||||
))?
|
||||
} else {
|
||||
return Err(LemmyErrorType::RegistrationApplicationIsPending)?;
|
||||
Err(LemmyErrorType::RegistrationApplicationIsPending)?
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
@ -531,9 +535,10 @@ pub fn check_private_instance_and_federation_enabled(
|
|||
local_site: &LocalSite,
|
||||
) -> Result<(), LemmyError> {
|
||||
if local_site.private_instance && local_site.federation_enabled {
|
||||
Err(LemmyErrorType::CantEnablePrivateInstanceAndFederationTogether)?;
|
||||
Err(LemmyErrorType::CantEnablePrivateInstanceAndFederationTogether)?
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn purge_image_posts_for_person(
|
||||
|
|
|
@ -65,7 +65,7 @@ pub async fn create_comment(
|
|||
|
||||
// Check if post is locked, no new comments
|
||||
if post.locked {
|
||||
return Err(LemmyErrorType::Locked)?;
|
||||
Err(LemmyErrorType::Locked)?
|
||||
}
|
||||
|
||||
// Fetch the parent, if it exists
|
||||
|
@ -79,7 +79,7 @@ pub async fn create_comment(
|
|||
// Strange issue where sometimes the post ID of the parent comment is incorrect
|
||||
if let Some(parent) = parent_opt.as_ref() {
|
||||
if parent.post_id != post_id {
|
||||
return Err(LemmyErrorType::CouldntCreateComment)?;
|
||||
Err(LemmyErrorType::CouldntCreateComment)?
|
||||
}
|
||||
check_comment_depth(parent)?;
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ pub async fn delete_comment(
|
|||
|
||||
// Dont delete it if its already been deleted.
|
||||
if orig_comment.comment.deleted == data.deleted {
|
||||
return Err(LemmyErrorType::CouldntUpdateComment)?;
|
||||
Err(LemmyErrorType::CouldntUpdateComment)?
|
||||
}
|
||||
|
||||
check_community_ban(
|
||||
|
@ -41,7 +41,7 @@ pub async fn delete_comment(
|
|||
|
||||
// Verify that only the creator can delete
|
||||
if local_user_view.person.id != orig_comment.creator.id {
|
||||
return Err(LemmyErrorType::NoCommentEditAllowed)?;
|
||||
Err(LemmyErrorType::NoCommentEditAllowed)?
|
||||
}
|
||||
|
||||
// Do the delete
|
||||
|
|
|
@ -51,7 +51,7 @@ pub async fn update_comment(
|
|||
|
||||
// Verify that only the creator can edit
|
||||
if local_user_view.person.id != orig_comment.creator.id {
|
||||
return Err(LemmyErrorType::NoCommentEditAllowed)?;
|
||||
Err(LemmyErrorType::NoCommentEditAllowed)?
|
||||
}
|
||||
|
||||
let language_id = data.language_id;
|
||||
|
|
|
@ -51,7 +51,7 @@ pub async fn create_community(
|
|||
let local_site = site_view.local_site;
|
||||
|
||||
if local_site.community_creation_admin_only && is_admin(&local_user_view).is_err() {
|
||||
return Err(LemmyErrorType::OnlyAdminsCanCreateCommunities)?;
|
||||
Err(LemmyErrorType::OnlyAdminsCanCreateCommunities)?
|
||||
}
|
||||
|
||||
// Check to make sure the icon and banners are urls
|
||||
|
@ -79,7 +79,7 @@ pub async fn create_community(
|
|||
let community_dupe =
|
||||
Community::read_from_apub_id(&mut context.pool(), &community_actor_id).await?;
|
||||
if community_dupe.is_some() {
|
||||
return Err(LemmyErrorType::CommunityAlreadyExists)?;
|
||||
Err(LemmyErrorType::CommunityAlreadyExists)?
|
||||
}
|
||||
|
||||
// When you create a community, make sure the user becomes a moderator and a follower
|
||||
|
@ -135,7 +135,7 @@ pub async fn create_community(
|
|||
// https://stackoverflow.com/a/64227550
|
||||
let is_subset = languages.iter().all(|item| site_languages.contains(item));
|
||||
if !is_subset {
|
||||
return Err(LemmyErrorType::LanguageNotAllowed)?;
|
||||
Err(LemmyErrorType::LanguageNotAllowed)?
|
||||
}
|
||||
CommunityLanguage::update(&mut context.pool(), languages, community_id).await?;
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ pub async fn update_community(
|
|||
.await
|
||||
.map(|v| v.into_iter().map(|m| m.moderator.id).collect())?;
|
||||
if !mods.contains(&local_user_view.person.id) {
|
||||
return Err(LemmyErrorType::NotAModerator)?;
|
||||
Err(LemmyErrorType::NotAModerator)?
|
||||
}
|
||||
|
||||
let community_id = data.community_id;
|
||||
|
@ -60,7 +60,7 @@ pub async fn update_community(
|
|||
// https://stackoverflow.com/a/64227550
|
||||
let is_subset = languages.iter().all(|item| site_languages.contains(item));
|
||||
if !is_subset {
|
||||
return Err(LemmyErrorType::LanguageNotAllowed)?;
|
||||
Err(LemmyErrorType::LanguageNotAllowed)?
|
||||
}
|
||||
CommunityLanguage::update(&mut context.pool(), languages, community_id).await?;
|
||||
}
|
||||
|
|
|
@ -82,7 +82,7 @@ pub async fn create_post(
|
|||
)
|
||||
.await?;
|
||||
if !is_mod {
|
||||
return Err(LemmyErrorType::OnlyModsCanPostInCommunity)?;
|
||||
Err(LemmyErrorType::OnlyModsCanPostInCommunity)?
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ pub async fn delete_post(
|
|||
|
||||
// Dont delete it if its already been deleted.
|
||||
if orig_post.deleted == data.deleted {
|
||||
return Err(LemmyErrorType::CouldntUpdatePost)?;
|
||||
Err(LemmyErrorType::CouldntUpdatePost)?
|
||||
}
|
||||
|
||||
check_community_ban(
|
||||
|
@ -38,7 +38,7 @@ pub async fn delete_post(
|
|||
|
||||
// Verify that only the creator can delete
|
||||
if !Post::is_post_creator(local_user_view.person.id, orig_post.creator_id) {
|
||||
return Err(LemmyErrorType::NoPostEditAllowed)?;
|
||||
Err(LemmyErrorType::NoPostEditAllowed)?
|
||||
}
|
||||
|
||||
// Update the post
|
||||
|
|
|
@ -68,7 +68,7 @@ pub async fn update_post(
|
|||
|
||||
// Verify that only the creator can edit
|
||||
if !Post::is_post_creator(local_user_view.person.id, orig_post.creator_id) {
|
||||
return Err(LemmyErrorType::NoPostEditAllowed)?;
|
||||
Err(LemmyErrorType::NoPostEditAllowed)?
|
||||
}
|
||||
|
||||
// Fetch post links and Pictrs cached image
|
||||
|
|
|
@ -24,7 +24,7 @@ pub async fn delete_private_message(
|
|||
let private_message_id = data.private_message_id;
|
||||
let orig_private_message = PrivateMessage::read(&mut context.pool(), private_message_id).await?;
|
||||
if local_user_view.person.id != orig_private_message.creator_id {
|
||||
return Err(LemmyErrorType::EditPrivateMessageNotAllowed)?;
|
||||
Err(LemmyErrorType::EditPrivateMessageNotAllowed)?
|
||||
}
|
||||
|
||||
// Doing the update
|
||||
|
|
|
@ -32,7 +32,7 @@ pub async fn update_private_message(
|
|||
let private_message_id = data.private_message_id;
|
||||
let orig_private_message = PrivateMessage::read(&mut context.pool(), private_message_id).await?;
|
||||
if local_user_view.person.id != orig_private_message.creator_id {
|
||||
return Err(LemmyErrorType::EditPrivateMessageNotAllowed)?;
|
||||
Err(LemmyErrorType::EditPrivateMessageNotAllowed)?
|
||||
}
|
||||
|
||||
// Doing the update
|
||||
|
|
|
@ -147,7 +147,7 @@ pub async fn create_site(
|
|||
fn validate_create_payload(local_site: &LocalSite, create_site: &CreateSite) -> LemmyResult<()> {
|
||||
// Make sure the site hasn't already been set up...
|
||||
if local_site.site_setup {
|
||||
Err(LemmyErrorType::SiteAlreadyExists)?;
|
||||
Err(LemmyErrorType::SiteAlreadyExists)?
|
||||
};
|
||||
|
||||
// Check that the slur regex compiles, and returns the regex if valid...
|
||||
|
|
|
@ -48,23 +48,23 @@ pub async fn register(
|
|||
local_site.registration_mode == RegistrationMode::RequireApplication;
|
||||
|
||||
if local_site.registration_mode == RegistrationMode::Closed {
|
||||
return Err(LemmyErrorType::RegistrationClosed)?;
|
||||
Err(LemmyErrorType::RegistrationClosed)?
|
||||
}
|
||||
|
||||
password_length_check(&data.password)?;
|
||||
honeypot_check(&data.honeypot)?;
|
||||
|
||||
if local_site.require_email_verification && data.email.is_none() {
|
||||
return Err(LemmyErrorType::EmailRequired)?;
|
||||
Err(LemmyErrorType::EmailRequired)?
|
||||
}
|
||||
|
||||
if local_site.site_setup && require_registration_application && data.answer.is_none() {
|
||||
return Err(LemmyErrorType::RegistrationApplicationAnswerRequired)?;
|
||||
Err(LemmyErrorType::RegistrationApplicationAnswerRequired)?
|
||||
}
|
||||
|
||||
// Make sure passwords match
|
||||
if data.password != data.password_verify {
|
||||
return Err(LemmyErrorType::PasswordsDoNotMatch)?;
|
||||
Err(LemmyErrorType::PasswordsDoNotMatch)?
|
||||
}
|
||||
|
||||
if local_site.site_setup && local_site.captcha_enabled {
|
||||
|
@ -79,10 +79,10 @@ pub async fn register(
|
|||
)
|
||||
.await?;
|
||||
if !check {
|
||||
return Err(LemmyErrorType::CaptchaIncorrect)?;
|
||||
Err(LemmyErrorType::CaptchaIncorrect)?
|
||||
}
|
||||
} else {
|
||||
return Err(LemmyErrorType::CaptchaIncorrect)?;
|
||||
Err(LemmyErrorType::CaptchaIncorrect)?
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,7 +101,7 @@ pub async fn register(
|
|||
|
||||
if let Some(email) = &data.email {
|
||||
if LocalUser::is_email_taken(&mut context.pool(), email).await? {
|
||||
return Err(LemmyErrorType::EmailAlreadyExists)?;
|
||||
Err(LemmyErrorType::EmailAlreadyExists)?
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ pub async fn delete_account(
|
|||
)
|
||||
.unwrap_or(false);
|
||||
if !valid {
|
||||
return Err(LemmyErrorType::IncorrectLogin)?;
|
||||
Err(LemmyErrorType::IncorrectLogin)?
|
||||
}
|
||||
|
||||
if data.delete_content {
|
||||
|
|
|
@ -48,7 +48,7 @@ impl ActivityHandler for RawAnnouncableActivities {
|
|||
let activity: AnnouncableActivities = self.clone().try_into()?;
|
||||
// This is only for sending, not receiving so we reject it.
|
||||
if let AnnouncableActivities::Page(_) = activity {
|
||||
return Err(LemmyErrorType::CannotReceivePage)?;
|
||||
Err(LemmyErrorType::CannotReceivePage)?
|
||||
}
|
||||
|
||||
// verify and receive activity
|
||||
|
@ -146,7 +146,7 @@ impl ActivityHandler for AnnounceActivity {
|
|||
let object: AnnouncableActivities = self.object.object(context).await?.try_into()?;
|
||||
// This is only for sending, not receiving so we reject it.
|
||||
if let AnnouncableActivities::Page(_) = object {
|
||||
return Err(LemmyErrorType::CannotReceivePage)?;
|
||||
Err(LemmyErrorType::CannotReceivePage)?
|
||||
}
|
||||
|
||||
// verify here in order to avoid fetching the object twice over http
|
||||
|
|
|
@ -120,7 +120,7 @@ impl ActivityHandler for CreateOrUpdatePage {
|
|||
// because then we will definitely receive all create and update activities separately.
|
||||
let is_locked = self.object.comments_enabled == Some(false);
|
||||
if community.local && is_locked {
|
||||
return Err(LemmyErrorType::NewPostCannotBeLocked)?;
|
||||
Err(LemmyErrorType::NewPostCannotBeLocked)?
|
||||
}
|
||||
}
|
||||
CreateOrUpdateType::Update => {
|
||||
|
|
|
@ -112,7 +112,7 @@ pub(in crate::activities) async fn receive_remove_action(
|
|||
match DeletableObjects::read_from_db(object, context).await? {
|
||||
DeletableObjects::Community(community) => {
|
||||
if community.local {
|
||||
return Err(LemmyErrorType::OnlyLocalAdminCanRemoveCommunity)?;
|
||||
Err(LemmyErrorType::OnlyLocalAdminCanRemoveCommunity)?
|
||||
}
|
||||
let form = ModRemoveCommunityForm {
|
||||
mod_person_id: actor.id,
|
||||
|
|
|
@ -100,7 +100,7 @@ impl UndoDelete {
|
|||
match DeletableObjects::read_from_db(object, context).await? {
|
||||
DeletableObjects::Community(community) => {
|
||||
if community.local {
|
||||
return Err(LemmyErrorType::OnlyLocalAdminCanRestoreCommunity)?;
|
||||
Err(LemmyErrorType::OnlyLocalAdminCanRestoreCommunity)?
|
||||
}
|
||||
let form = ModRemoveCommunityForm {
|
||||
mod_person_id: actor.id,
|
||||
|
|
|
@ -81,10 +81,11 @@ async fn verify_person(
|
|||
) -> Result<(), LemmyError> {
|
||||
let person = person_id.dereference(context).await?;
|
||||
if person.banned {
|
||||
return Err(anyhow!("Person {} is banned", person_id))
|
||||
.with_lemmy_type(LemmyErrorType::CouldntUpdateComment);
|
||||
Err(anyhow!("Person {} is banned", person_id))
|
||||
.with_lemmy_type(LemmyErrorType::CouldntUpdateComment)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Fetches the person and community to verify their type, then checks if person is banned from site
|
||||
|
@ -97,9 +98,9 @@ pub(crate) async fn verify_person_in_community(
|
|||
) -> Result<(), LemmyError> {
|
||||
let person = person_id.dereference(context).await?;
|
||||
if person.banned {
|
||||
return Err(LemmyErrorType::PersonIsBannedFromSite(
|
||||
Err(LemmyErrorType::PersonIsBannedFromSite(
|
||||
person.actor_id.to_string(),
|
||||
))?;
|
||||
))?
|
||||
}
|
||||
let person_id = person.id;
|
||||
let community_id = community.id;
|
||||
|
@ -107,10 +108,10 @@ pub(crate) async fn verify_person_in_community(
|
|||
.await
|
||||
.is_ok();
|
||||
if is_banned {
|
||||
return Err(LemmyErrorType::PersonIsBannedFromCommunity)?;
|
||||
Err(LemmyErrorType::PersonIsBannedFromCommunity)?
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Verify that mod action in community was performed by a moderator.
|
||||
|
@ -145,9 +146,10 @@ pub(crate) async fn verify_mod_action(
|
|||
|
||||
pub(crate) fn verify_is_public(to: &[Url], cc: &[Url]) -> Result<(), LemmyError> {
|
||||
if ![to, cc].iter().any(|set| set.contains(&public())) {
|
||||
Err(LemmyErrorType::ObjectIsNotPublic)?;
|
||||
Err(LemmyErrorType::ObjectIsNotPublic)?
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn verify_community_matches<T>(
|
||||
|
@ -159,9 +161,10 @@ where
|
|||
{
|
||||
let b: ObjectId<ApubCommunity> = b.into();
|
||||
if a != &b {
|
||||
Err(LemmyErrorType::InvalidCommunity)?;
|
||||
Err(LemmyErrorType::InvalidCommunity)?
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn check_community_deleted_or_removed(community: &Community) -> Result<(), LemmyError> {
|
||||
|
|
|
@ -64,9 +64,10 @@ impl ActivityHandler for Vote {
|
|||
.map(|l| l.enable_downvotes)
|
||||
.unwrap_or(true);
|
||||
if self.kind == VoteType::Dislike && !enable_downvotes {
|
||||
return Err(anyhow!("Downvotes disabled").into());
|
||||
Err(anyhow!("Downvotes disabled").into())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
|
|
|
@ -26,7 +26,7 @@ pub async fn get_community(
|
|||
let local_site = LocalSite::read(&mut context.pool()).await?;
|
||||
|
||||
if data.name.is_none() && data.id.is_none() {
|
||||
return Err(LemmyErrorType::NoIdGiven)?;
|
||||
Err(LemmyErrorType::NoIdGiven)?
|
||||
}
|
||||
|
||||
check_private_instance(&local_user_view, &local_site)?;
|
||||
|
|
|
@ -22,7 +22,7 @@ pub async fn read_person(
|
|||
) -> Result<Json<GetPersonDetailsResponse>, LemmyError> {
|
||||
// Check to make sure a person name or an id is given
|
||||
if data.username.is_none() && data.person_id.is_none() {
|
||||
return Err(LemmyErrorType::NoIdGiven)?;
|
||||
Err(LemmyErrorType::NoIdGiven)?
|
||||
}
|
||||
|
||||
local_user_view_from_jwt_opt_new(&mut local_user_view, data.auth.as_ref(), &context).await;
|
||||
|
@ -39,7 +39,7 @@ pub async fn read_person(
|
|||
.with_lemmy_type(LemmyErrorType::CouldntFindPerson)?
|
||||
.id
|
||||
} else {
|
||||
return Err(LemmyErrorType::CouldntFindPerson)?;
|
||||
Err(LemmyErrorType::CouldntFindPerson)?
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -72,7 +72,8 @@ async fn convert_response(
|
|||
};
|
||||
// if the object was deleted from database, dont return it
|
||||
if removed_or_deleted {
|
||||
return Err(NotFound {}.into());
|
||||
Err(NotFound {}.into())
|
||||
} else {
|
||||
Ok(Json(res))
|
||||
}
|
||||
Ok(Json(res))
|
||||
}
|
||||
|
|
|
@ -23,10 +23,8 @@ pub(crate) async fn get_apub_comment(
|
|||
let id = CommentId(info.comment_id.parse::<i32>()?);
|
||||
let comment: ApubComment = Comment::read(&mut context.pool(), id).await?.into();
|
||||
if !comment.local {
|
||||
return Err(err_object_not_local());
|
||||
}
|
||||
|
||||
if !comment.deleted && !comment.removed {
|
||||
Err(err_object_not_local())
|
||||
} else if !comment.deleted && !comment.removed {
|
||||
create_apub_response(&comment.into_json(&context).await?)
|
||||
} else {
|
||||
create_apub_tombstone_response(comment.ap_id.clone())
|
||||
|
|
|
@ -81,7 +81,7 @@ pub(crate) async fn get_apub_community_outbox(
|
|||
.await?
|
||||
.into();
|
||||
if community.deleted || community.removed {
|
||||
return Err(LemmyErrorType::Deleted)?;
|
||||
Err(LemmyErrorType::Deleted)?
|
||||
}
|
||||
let outbox = ApubCommunityOutbox::read_local(&community, &context).await?;
|
||||
create_apub_response(&outbox)
|
||||
|
@ -97,7 +97,7 @@ pub(crate) async fn get_apub_community_moderators(
|
|||
.await?
|
||||
.into();
|
||||
if community.deleted || community.removed {
|
||||
return Err(LemmyErrorType::Deleted)?;
|
||||
Err(LemmyErrorType::Deleted)?
|
||||
}
|
||||
let moderators = ApubCommunityModerators::read_local(&community, &context).await?;
|
||||
create_apub_response(&moderators)
|
||||
|
@ -113,7 +113,7 @@ pub(crate) async fn get_apub_community_featured(
|
|||
.await?
|
||||
.into();
|
||||
if community.deleted || community.removed {
|
||||
return Err(LemmyErrorType::Deleted)?;
|
||||
Err(LemmyErrorType::Deleted)?
|
||||
}
|
||||
let featured = ApubCommunityFeatured::read_local(&community, &context).await?;
|
||||
create_apub_response(&featured)
|
||||
|
|
|
@ -23,10 +23,8 @@ pub(crate) async fn get_apub_post(
|
|||
let id = PostId(info.post_id.parse::<i32>()?);
|
||||
let post: ApubPost = Post::read(&mut context.pool(), id).await?.into();
|
||||
if !post.local {
|
||||
return Err(err_object_not_local());
|
||||
}
|
||||
|
||||
if !post.deleted && !post.removed {
|
||||
Err(err_object_not_local())
|
||||
} else if !post.deleted && !post.removed {
|
||||
create_apub_response(&post.into_json(&context).await?)
|
||||
} else {
|
||||
create_apub_tombstone_response(post.ap_id.clone())
|
||||
|
|
|
@ -79,7 +79,7 @@ fn check_apub_id_valid(apub_id: &Url, local_site_data: &LocalSiteData) -> Result
|
|||
.map(|l| l.federation_enabled)
|
||||
.unwrap_or(true)
|
||||
{
|
||||
Err(LemmyErrorType::FederationDisabled)?;
|
||||
Err(LemmyErrorType::FederationDisabled)?
|
||||
}
|
||||
|
||||
if local_site_data
|
||||
|
@ -87,7 +87,7 @@ fn check_apub_id_valid(apub_id: &Url, local_site_data: &LocalSiteData) -> Result
|
|||
.iter()
|
||||
.any(|i| domain.to_lowercase().eq(&i.domain.to_lowercase()))
|
||||
{
|
||||
Err(LemmyErrorType::DomainBlocked(domain.clone()))?;
|
||||
Err(LemmyErrorType::DomainBlocked(domain.clone()))?
|
||||
}
|
||||
|
||||
// Only check this if there are instances in the allowlist
|
||||
|
@ -97,7 +97,7 @@ fn check_apub_id_valid(apub_id: &Url, local_site_data: &LocalSiteData) -> Result
|
|||
.iter()
|
||||
.any(|i| domain.to_lowercase().eq(&i.domain.to_lowercase()))
|
||||
{
|
||||
Err(LemmyErrorType::DomainNotInAllowList(domain))?;
|
||||
Err(LemmyErrorType::DomainNotInAllowList(domain))?
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -176,7 +176,7 @@ pub(crate) async fn check_apub_id_valid_with_strictness(
|
|||
|
||||
let domain = apub_id.domain().expect("apud id has domain").to_string();
|
||||
if !allowed_and_local.contains(&domain) {
|
||||
return Err(LemmyErrorType::FederationDisabledByStrictAllowList)?;
|
||||
Err(LemmyErrorType::FederationDisabledByStrictAllowList)?
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
@ -143,9 +143,10 @@ impl Object for ApubComment {
|
|||
verify_person_in_community(¬e.attributed_to, &community, context).await?;
|
||||
let (post, _) = note.get_parents(context).await?;
|
||||
if post.locked {
|
||||
return Err(LemmyErrorType::PostIsLocked)?;
|
||||
Err(LemmyErrorType::PostIsLocked)?
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Converts a `Note` to `Comment`.
|
||||
|
|
|
@ -107,11 +107,12 @@ impl Object for ApubPrivateMessage {
|
|||
check_apub_id_valid_with_strictness(note.id.inner(), false, context).await?;
|
||||
let person = note.attributed_to.dereference(context).await?;
|
||||
if person.banned {
|
||||
return Err(LemmyErrorType::PersonIsBannedFromSite(
|
||||
Err(LemmyErrorType::PersonIsBannedFromSite(
|
||||
person.actor_id.to_string(),
|
||||
))?;
|
||||
))?
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
|
|
|
@ -208,7 +208,7 @@ impl InCommunity for Page {
|
|||
break c;
|
||||
}
|
||||
} else {
|
||||
return Err(LemmyErrorType::NoCommunityFoundInCc)?;
|
||||
Err(LemmyErrorType::NoCommunityFoundInCc)?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,23 +2,6 @@ diff --git a/crates/db_schema/src/schema.rs b/crates/db_schema/src/schema.rs
|
|||
index 255c6422..f2ccf5e2 100644
|
||||
--- a/crates/db_schema/src/schema.rs
|
||||
+++ b/crates/db_schema/src/schema.rs
|
||||
@@ -2,16 +2,12 @@
|
||||
|
||||
pub mod sql_types {
|
||||
#[derive(diesel::sql_types::SqlType)]
|
||||
#[diesel(postgres_type(name = "listing_type_enum"))]
|
||||
pub struct ListingTypeEnum;
|
||||
|
||||
- #[derive(diesel::sql_types::SqlType)]
|
||||
- #[diesel(postgres_type(name = "ltree"))]
|
||||
- pub struct Ltree;
|
||||
-
|
||||
#[derive(diesel::sql_types::SqlType)]
|
||||
#[diesel(postgres_type(name = "registration_mode_enum"))]
|
||||
pub struct RegistrationModeEnum;
|
||||
|
||||
#[derive(diesel::sql_types::SqlType)]
|
||||
#[diesel(postgres_type(name = "sort_type_enum"))]
|
||||
@@ -76,13 +76,13 @@ diesel::table! {
|
||||
published -> Timestamptz,
|
||||
}
|
||||
|
|
|
@ -143,6 +143,24 @@ pub enum RegistrationMode {
|
|||
Open,
|
||||
}
|
||||
|
||||
#[derive(EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "full", derive(DbEnum, TS))]
|
||||
#[cfg_attr(
|
||||
feature = "full",
|
||||
ExistingTypePath = "crate::schema::sql_types::PostListingModeEnum"
|
||||
)]
|
||||
#[cfg_attr(feature = "full", DbValueStyle = "verbatim")]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// A post-view mode that changes how multiple post listings look.
|
||||
pub enum PostListingMode {
|
||||
/// A compact, list-type view.
|
||||
List,
|
||||
/// A larger card-type view.
|
||||
Card,
|
||||
/// A smaller card-type view, usually with images as thumbnails
|
||||
SmallCard,
|
||||
}
|
||||
|
||||
#[derive(EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
|
|
|
@ -5,6 +5,14 @@ pub mod sql_types {
|
|||
#[diesel(postgres_type(name = "listing_type_enum"))]
|
||||
pub struct ListingTypeEnum;
|
||||
|
||||
#[derive(diesel::sql_types::SqlType)]
|
||||
#[diesel(postgres_type(name = "ltree"))]
|
||||
pub struct Ltree;
|
||||
|
||||
#[derive(diesel::sql_types::SqlType)]
|
||||
#[diesel(postgres_type(name = "post_listing_mode_enum"))]
|
||||
pub struct PostListingModeEnum;
|
||||
|
||||
#[derive(diesel::sql_types::SqlType)]
|
||||
#[diesel(postgres_type(name = "registration_mode_enum"))]
|
||||
pub struct RegistrationModeEnum;
|
||||
|
@ -372,6 +380,7 @@ diesel::table! {
|
|||
use diesel::sql_types::*;
|
||||
use super::sql_types::SortTypeEnum;
|
||||
use super::sql_types::ListingTypeEnum;
|
||||
use super::sql_types::PostListingModeEnum;
|
||||
|
||||
local_user (id) {
|
||||
id -> Int4,
|
||||
|
@ -400,6 +409,7 @@ diesel::table! {
|
|||
auto_expand -> Bool,
|
||||
infinite_scroll_enabled -> Bool,
|
||||
admin -> Bool,
|
||||
post_listing_mode -> PostListingModeEnum,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ use crate::schema::local_user;
|
|||
use crate::{
|
||||
newtypes::{LocalUserId, PersonId},
|
||||
ListingType,
|
||||
PostListingMode,
|
||||
SortType,
|
||||
};
|
||||
use chrono::{DateTime, Utc};
|
||||
|
@ -60,6 +61,7 @@ pub struct LocalUser {
|
|||
pub infinite_scroll_enabled: bool,
|
||||
/// Whether the person is an admin.
|
||||
pub admin: bool,
|
||||
pub post_listing_mode: PostListingMode,
|
||||
}
|
||||
|
||||
#[derive(Clone, TypedBuilder)]
|
||||
|
@ -92,6 +94,7 @@ pub struct LocalUserInsertForm {
|
|||
pub auto_expand: Option<bool>,
|
||||
pub infinite_scroll_enabled: Option<bool>,
|
||||
pub admin: Option<bool>,
|
||||
pub post_listing_mode: Option<PostListingMode>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
|
@ -120,4 +123,5 @@ pub struct LocalUserUpdateForm {
|
|||
pub auto_expand: Option<bool>,
|
||||
pub infinite_scroll_enabled: Option<bool>,
|
||||
pub admin: Option<bool>,
|
||||
pub post_listing_mode: Option<PostListingMode>,
|
||||
}
|
||||
|
|
|
@ -290,6 +290,7 @@ mod tests {
|
|||
open_links_in_new_tab: inserted_sara_local_user.open_links_in_new_tab,
|
||||
infinite_scroll_enabled: inserted_sara_local_user.infinite_scroll_enabled,
|
||||
admin: false,
|
||||
post_listing_mode: inserted_sara_local_user.post_listing_mode,
|
||||
},
|
||||
creator: Person {
|
||||
id: inserted_sara_person.id,
|
||||
|
|
|
@ -38,10 +38,10 @@ impl Settings {
|
|||
let config = from_str::<Settings>(&Self::read_config_file()?)?;
|
||||
|
||||
if config.hostname == "unset" {
|
||||
return Err(anyhow!("Hostname variable is not set!").into());
|
||||
Err(anyhow!("Hostname variable is not set!").into())
|
||||
} else {
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
pub fn get_database_url(&self) -> String {
|
||||
|
|
|
@ -216,10 +216,10 @@ pub fn build_and_check_regex(regex_str_opt: &Option<&str>) -> LemmyResult<Option
|
|||
// against an innocuous string - a single number - which should help catch a regex
|
||||
// that accidentally matches against all strings.
|
||||
if regex.is_match("1") {
|
||||
return Err(LemmyErrorType::PermissiveRegex.into());
|
||||
Err(LemmyErrorType::PermissiveRegex.into())
|
||||
} else {
|
||||
Ok(Some(regex))
|
||||
}
|
||||
|
||||
Ok(Some(regex))
|
||||
})
|
||||
},
|
||||
)
|
||||
|
@ -255,11 +255,13 @@ pub fn check_totp_2fa_valid(
|
|||
|
||||
let check_passed = totp.check_current(token)?;
|
||||
if !check_passed {
|
||||
return Err(LemmyErrorType::IncorrectTotpToken.into());
|
||||
Err(LemmyErrorType::IncorrectTotpToken.into())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn generate_totp_2fa_secret() -> String {
|
||||
|
@ -294,19 +296,22 @@ pub fn check_site_visibility_valid(
|
|||
let federation_enabled = new_federation_enabled.unwrap_or(current_federation_enabled);
|
||||
|
||||
if private_instance && federation_enabled {
|
||||
return Err(LemmyErrorType::CantEnablePrivateInstanceAndFederationTogether.into());
|
||||
Err(LemmyErrorType::CantEnablePrivateInstanceAndFederationTogether.into())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn check_url_scheme(url: &Option<Url>) -> LemmyResult<()> {
|
||||
if let Some(url) = url {
|
||||
if url.scheme() != "http" && url.scheme() != "https" {
|
||||
return Err(LemmyErrorType::InvalidUrlScheme.into());
|
||||
Err(LemmyErrorType::InvalidUrlScheme.into())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
ALTER TABLE local_user
|
||||
DROP COLUMN post_listing_mode;
|
||||
|
||||
DROP TYPE post_listing_mode_enum;
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
CREATE TYPE post_listing_mode_enum AS enum (
|
||||
'List',
|
||||
'Card',
|
||||
'SmallCard'
|
||||
);
|
||||
|
||||
ALTER TABLE local_user
|
||||
ADD COLUMN post_listing_mode post_listing_mode_enum DEFAULT 'List' NOT NULL;
|
||||
|
Loading…
Reference in a new issue