From 6047257bfced900c805be4cb965d81caaa7fab4f Mon Sep 17 00:00:00 2001 From: Nutomic Date: Thu, 24 Aug 2023 11:40:08 +0200 Subject: [PATCH] Move admin flag from person to local_user (fixes #3060) (#3403) * Move admin flag from person to local_user (fixes #3060) The person table is for federated data, but admin flag can only apply to local users. Thats why it really belongs in the local_user table. This will also prevent the federation code from accidentally overwriting the admin flag * fmt * try to fix api tests * lint * fix person view * ci * ci --------- Co-authored-by: Dessalines --- crates/api/src/comment_report/list.rs | 2 +- crates/api/src/community/add_mod.rs | 2 +- crates/api/src/local_user/add_admin.rs | 14 +++---- crates/api/src/local_user/block.rs | 9 ++-- crates/api/src/local_user/login.rs | 2 +- crates/api/src/local_user/report_count.rs | 2 +- crates/api/src/post_report/list.rs | 2 +- crates/api/src/site/leave_admin.rs | 10 ++--- crates/api_common/src/person.rs | 4 +- crates/api_common/src/utils.rs | 6 +-- crates/api_crud/src/user/create.rs | 4 +- crates/apub/src/objects/person.rs | 1 - crates/db_schema/src/impls/person.rs | 1 - crates/db_schema/src/schema.rs | 4 +- crates/db_schema/src/source/local_user.rs | 4 ++ crates/db_schema/src/source/person.rs | 4 -- crates/db_views/src/comment_report_view.rs | 42 ++++++++++++------- crates/db_views/src/comment_view.rs | 6 ++- crates/db_views/src/local_user_view.rs | 2 +- crates/db_views/src/post_report_view.rs | 41 +++++++++++------- crates/db_views/src/post_view.rs | 8 ++-- crates/db_views/src/private_message_view.rs | 1 - .../src/registration_application_view.rs | 5 +-- crates/db_views_actor/src/person_view.rs | 11 +++-- .../down.sql | 16 +++++++ .../up.sql | 16 +++++++ src/code_migrations.rs | 2 +- 27 files changed, 140 insertions(+), 81 deletions(-) create mode 100644 migrations/2023-08-01-101826_admin_flag_local_user/down.sql create mode 100644 migrations/2023-08-01-101826_admin_flag_local_user/up.sql diff --git a/crates/api/src/comment_report/list.rs b/crates/api/src/comment_report/list.rs index 3f6f160c8..839288521 100644 --- a/crates/api/src/comment_report/list.rs +++ b/crates/api/src/comment_report/list.rs @@ -27,7 +27,7 @@ pub async fn list_comment_reports( page, limit, } - .list(&mut context.pool(), &local_user_view.person) + .list(&mut context.pool(), &local_user_view) .await?; Ok(Json(ListCommentReportsResponse { comment_reports })) diff --git a/crates/api/src/community/add_mod.rs b/crates/api/src/community/add_mod.rs index 2d7b88750..937af22df 100644 --- a/crates/api/src/community/add_mod.rs +++ b/crates/api/src/community/add_mod.rs @@ -28,7 +28,7 @@ pub async fn add_mod_to_community( // Verify that only mods or admins can add mod 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.person.admin && !community.local { + if local_user_view.local_user.admin && !community.local { return Err(LemmyErrorType::NotAModerator)?; } diff --git a/crates/api/src/local_user/add_admin.rs b/crates/api/src/local_user/add_admin.rs index 81ec588f0..6800b75a5 100644 --- a/crates/api/src/local_user/add_admin.rs +++ b/crates/api/src/local_user/add_admin.rs @@ -7,8 +7,8 @@ use lemmy_api_common::{ }; use lemmy_db_schema::{ source::{ + local_user::{LocalUser, LocalUserUpdateForm}, moderator::{ModAdd, ModAddForm}, - person::{Person, PersonUpdateForm}, }, traits::Crud, }; @@ -27,13 +27,11 @@ impl Perform for AddAdmin { // Make sure user is an admin is_admin(&local_user_view)?; - let added = data.added; - let added_person_id = data.person_id; - let added_admin = Person::update( + let added_admin = LocalUser::update( &mut context.pool(), - added_person_id, - &PersonUpdateForm { - admin: Some(added), + data.local_user_id, + &LocalUserUpdateForm { + admin: Some(data.added), ..Default::default() }, ) @@ -43,7 +41,7 @@ impl Perform for AddAdmin { // Mod tables let form = ModAddForm { mod_person_id: local_user_view.person.id, - other_person_id: added_admin.id, + other_person_id: added_admin.person_id, removed: Some(!data.added), }; diff --git a/crates/api/src/local_user/block.rs b/crates/api/src/local_user/block.rs index 604219d4e..395ab0a15 100644 --- a/crates/api/src/local_user/block.rs +++ b/crates/api/src/local_user/block.rs @@ -9,6 +9,7 @@ use lemmy_db_schema::{ source::person_block::{PersonBlock, PersonBlockForm}, traits::Blockable, }; +use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::structs::PersonView; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; @@ -34,9 +35,8 @@ impl Perform for BlockPerson { target_id, }; - let target_person_view = PersonView::read(&mut context.pool(), target_id).await?; - - if target_person_view.person.admin { + 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)?; } @@ -50,8 +50,9 @@ impl Perform for BlockPerson { .with_lemmy_type(LemmyErrorType::PersonBlockAlreadyExists)?; } + let person_view = PersonView::read(&mut context.pool(), target_id).await?; Ok(BlockPersonResponse { - person_view: target_person_view, + person_view, blocked: data.block, }) } diff --git a/crates/api/src/local_user/login.rs b/crates/api/src/local_user/login.rs index 4b5ea0faf..62449c424 100644 --- a/crates/api/src/local_user/login.rs +++ b/crates/api/src/local_user/login.rs @@ -47,7 +47,7 @@ impl Perform for Login { // Check if the user's email is verified if email verification is turned on // However, skip checking verification if the user is an admin - if !local_user_view.person.admin + if !local_user_view.local_user.admin && site_view.local_site.require_email_verification && !local_user_view.local_user.email_verified { diff --git a/crates/api/src/local_user/report_count.rs b/crates/api/src/local_user/report_count.rs index 89bedc262..061372960 100644 --- a/crates/api/src/local_user/report_count.rs +++ b/crates/api/src/local_user/report_count.rs @@ -21,7 +21,7 @@ impl Perform for GetReportCount { let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; let person_id = local_user_view.person.id; - let admin = local_user_view.person.admin; + let admin = local_user_view.local_user.admin; let community_id = data.community_id; let comment_reports = diff --git a/crates/api/src/post_report/list.rs b/crates/api/src/post_report/list.rs index f5edab703..01a59aa84 100644 --- a/crates/api/src/post_report/list.rs +++ b/crates/api/src/post_report/list.rs @@ -33,7 +33,7 @@ impl Perform for ListPostReports { page, limit, } - .list(&mut context.pool(), &local_user_view.person) + .list(&mut context.pool(), &local_user_view) .await?; Ok(ListPostReportsResponse { post_reports }) diff --git a/crates/api/src/site/leave_admin.rs b/crates/api/src/site/leave_admin.rs index 570f9d52c..13e1c05dd 100644 --- a/crates/api/src/site/leave_admin.rs +++ b/crates/api/src/site/leave_admin.rs @@ -9,8 +9,8 @@ use lemmy_db_schema::{ source::{ actor_language::SiteLanguage, language::Language, + local_user::{LocalUser, LocalUserUpdateForm}, moderator::{ModAdd, ModAddForm}, - person::{Person, PersonUpdateForm}, tagline::Tagline, }, traits::Crud, @@ -39,11 +39,10 @@ impl Perform for LeaveAdmin { return Err(LemmyErrorType::CannotLeaveAdmin)?; } - let person_id = local_user_view.person.id; - Person::update( + LocalUser::update( &mut context.pool(), - person_id, - &PersonUpdateForm { + local_user_view.local_user.id, + &LocalUserUpdateForm { admin: Some(false), ..Default::default() }, @@ -51,6 +50,7 @@ impl Perform for LeaveAdmin { .await?; // Mod tables + let person_id = local_user_view.person.id; let form = ModAddForm { mod_person_id: person_id, other_person_id: person_id, diff --git a/crates/api_common/src/person.rs b/crates/api_common/src/person.rs index 79a0aa377..ef970f1bc 100644 --- a/crates/api_common/src/person.rs +++ b/crates/api_common/src/person.rs @@ -1,6 +1,6 @@ use crate::sensitive::Sensitive; use lemmy_db_schema::{ - newtypes::{CommentReplyId, CommunityId, LanguageId, PersonId, PersonMentionId}, + newtypes::{CommentReplyId, CommunityId, LanguageId, LocalUserId, PersonId, PersonMentionId}, CommentSortType, ListingType, SortType, @@ -207,7 +207,7 @@ pub struct MarkAllAsRead { #[cfg_attr(feature = "full", ts(export))] /// Adds an admin to a site. pub struct AddAdmin { - pub person_id: PersonId, + pub local_user_id: LocalUserId, pub added: bool, pub auth: Sensitive, } diff --git a/crates/api_common/src/utils.rs b/crates/api_common/src/utils.rs index 4d434afcd..fa84962d8 100644 --- a/crates/api_common/src/utils.rs +++ b/crates/api_common/src/utils.rs @@ -78,8 +78,8 @@ pub async fn is_mod_or_admin_opt( } pub fn is_admin(local_user_view: &LocalUserView) -> Result<(), LemmyError> { - if !local_user_view.person.admin { - Err(LemmyErrorType::NotAnAdmin)?; + if !local_user_view.local_user.admin { + return Err(LemmyErrorType::NotAnAdmin)?; } Ok(()) } @@ -500,7 +500,7 @@ pub async fn check_registration_application( if (local_site.registration_mode == RegistrationMode::RequireApplication || local_site.registration_mode == RegistrationMode::Closed) && !local_user_view.local_user.accepted_application - && !local_user_view.person.admin + && !local_user_view.local_user.admin { // Fetch the registration, see if its denied let local_user_id = local_user_view.local_user.id; diff --git a/crates/api_crud/src/user/create.rs b/crates/api_crud/src/user/create.rs index 1665ba191..8475dfa9d 100644 --- a/crates/api_crud/src/user/create.rs +++ b/crates/api_crud/src/user/create.rs @@ -115,8 +115,6 @@ pub async fn register( .public_key(actor_keypair.public_key) .inbox_url(Some(generate_inbox_url(&actor_id)?)) .shared_inbox_url(Some(generate_shared_inbox_url(&actor_id)?)) - // If its the initial site setup, they are an admin - .admin(Some(!local_site.site_setup)) .instance_id(site_view.site.instance_id) .build(); @@ -137,6 +135,8 @@ pub async fn register( .show_nsfw(Some(data.show_nsfw)) .accepted_application(accepted_application) .default_listing_type(Some(local_site.default_post_listing_type)) + // If its the initial site setup, they are an admin + .admin(Some(!local_site.site_setup)) .build(); let inserted_local_user = LocalUser::create(&mut context.pool(), &local_user_form).await?; diff --git a/crates/apub/src/objects/person.rs b/crates/apub/src/objects/person.rs index 907fd5f8f..3c98ce735 100644 --- a/crates/apub/src/objects/person.rs +++ b/crates/apub/src/objects/person.rs @@ -163,7 +163,6 @@ impl Object for ApubPerson { actor_id: Some(person.id.into()), bio, local: Some(false), - admin: Some(false), bot_account: Some(person.kind == UserTypes::Service), private_key: None, public_key: person.public_key.public_key_pem, diff --git a/crates/db_schema/src/impls/person.rs b/crates/db_schema/src/impls/person.rs index d8a80596f..6616970d8 100644 --- a/crates/db_schema/src/impls/person.rs +++ b/crates/db_schema/src/impls/person.rs @@ -240,7 +240,6 @@ mod tests { bio: None, local: true, bot_account: false, - admin: false, private_key: None, public_key: "nada".to_owned(), last_refreshed_at: inserted_person.published, diff --git a/crates/db_schema/src/schema.rs b/crates/db_schema/src/schema.rs index 7106b1c90..77224f9fe 100644 --- a/crates/db_schema/src/schema.rs +++ b/crates/db_schema/src/schema.rs @@ -396,9 +396,10 @@ diesel::table! { totp_2fa_secret -> Nullable, totp_2fa_url -> Nullable, open_links_in_new_tab -> Bool, + infinite_scroll_enabled -> Bool, blur_nsfw -> Bool, auto_expand -> Bool, - infinite_scroll_enabled -> Bool, + admin -> Bool, } } @@ -566,7 +567,6 @@ diesel::table! { #[max_length = 255] shared_inbox_url -> Nullable, matrix_user_id -> Nullable, - admin -> Bool, bot_account -> Bool, ban_expires -> Nullable, instance_id -> Int4, diff --git a/crates/db_schema/src/source/local_user.rs b/crates/db_schema/src/source/local_user.rs index 4e668bddf..d9e03c35f 100644 --- a/crates/db_schema/src/source/local_user.rs +++ b/crates/db_schema/src/source/local_user.rs @@ -57,6 +57,8 @@ pub struct LocalUser { pub auto_expand: bool, /// Whether infinite scroll is enabled. pub infinite_scroll_enabled: bool, + /// Whether the person is an admin. + pub admin: bool, } #[derive(Clone, TypedBuilder)] @@ -88,6 +90,7 @@ pub struct LocalUserInsertForm { pub blur_nsfw: Option, pub auto_expand: Option, pub infinite_scroll_enabled: Option, + pub admin: Option, } #[derive(Clone, Default)] @@ -115,4 +118,5 @@ pub struct LocalUserUpdateForm { pub blur_nsfw: Option, pub auto_expand: Option, pub infinite_scroll_enabled: Option, + pub admin: Option, } diff --git a/crates/db_schema/src/source/person.rs b/crates/db_schema/src/source/person.rs index 7772bb118..9ff3972d4 100644 --- a/crates/db_schema/src/source/person.rs +++ b/crates/db_schema/src/source/person.rs @@ -49,8 +49,6 @@ pub struct Person { pub shared_inbox_url: Option, /// A matrix id, usually given an @person:matrix.org pub matrix_user_id: Option, - /// Whether the person is an admin. - pub admin: bool, /// Whether the person is a bot account. pub bot_account: bool, /// When their ban, if it exists, expires, if at all. @@ -84,7 +82,6 @@ pub struct PersonInsertForm { pub inbox_url: Option, pub shared_inbox_url: Option, pub matrix_user_id: Option, - pub admin: Option, pub bot_account: Option, pub ban_expires: Option, } @@ -108,7 +105,6 @@ pub struct PersonUpdateForm { pub inbox_url: Option, pub shared_inbox_url: Option>, pub matrix_user_id: Option>, - pub admin: Option, pub bot_account: Option, pub ban_expires: Option>, } diff --git a/crates/db_views/src/comment_report_view.rs b/crates/db_views/src/comment_report_view.rs index 98ff555b7..c8f4e3e41 100644 --- a/crates/db_views/src/comment_report_view.rs +++ b/crates/db_views/src/comment_report_view.rs @@ -1,4 +1,4 @@ -use crate::structs::CommentReportView; +use crate::structs::{CommentReportView, LocalUserView}; use diesel::{ dsl::now, pg::Pg, @@ -38,7 +38,7 @@ use lemmy_db_schema::{ fn queries<'a>() -> Queries< impl ReadFn<'a, CommentReportView, (CommentReportId, PersonId)>, - impl ListFn<'a, CommentReportView, (CommentReportQuery, &'a Person)>, + impl ListFn<'a, CommentReportView, (CommentReportQuery, &'a LocalUserView)>, > { let all_joins = |query: comment_report::BoxedQuery<'a, Pg>, my_person_id: PersonId| { query @@ -93,8 +93,9 @@ fn queries<'a>() -> Queries< .await }; - let list = move |mut conn: DbConn<'a>, (options, my_person): (CommentReportQuery, &'a Person)| async move { - let mut query = all_joins(comment_report::table.into_boxed(), my_person.id) + let list = move |mut conn: DbConn<'a>, + (options, user): (CommentReportQuery, &'a LocalUserView)| async move { + let mut query = all_joins(comment_report::table.into_boxed(), user.person.id) .left_join( community_person_ban::table.on( community::id @@ -125,13 +126,13 @@ fn queries<'a>() -> Queries< .offset(offset); // If its not an admin, get only the ones you mod - if !my_person.admin { + if !user.local_user.admin { query .inner_join( community_moderator::table.on( community_moderator::community_id .eq(post::community_id) - .and(community_moderator::person_id.eq(my_person.id)), + .and(community_moderator::person_id.eq(user.person.id)), ), ) .load::<::JoinTuple>(&mut conn) @@ -213,9 +214,9 @@ impl CommentReportQuery { pub async fn list( self, pool: &mut DbPool<'_>, - my_person: &Person, + user: &LocalUserView, ) -> Result, Error> { - queries().list(pool, (self, my_person)).await + queries().list(pool, (self, user)).await } } @@ -254,7 +255,10 @@ mod tests { #![allow(clippy::unwrap_used)] #![allow(clippy::indexing_slicing)] - use crate::comment_report_view::{CommentReportQuery, CommentReportView}; + use crate::{ + comment_report_view::{CommentReportQuery, CommentReportView}, + structs::LocalUserView, + }; use lemmy_db_schema::{ aggregates::structs::CommentAggregates, source::{ @@ -262,6 +266,7 @@ mod tests { comment_report::{CommentReport, CommentReportForm}, community::{Community, CommunityInsertForm, CommunityModerator, CommunityModeratorForm}, instance::Instance, + local_user::{LocalUser, LocalUserInsertForm}, person::{Person, PersonInsertForm}, post::{Post, PostInsertForm}, }, @@ -288,6 +293,17 @@ mod tests { let inserted_timmy = Person::create(pool, &new_person).await.unwrap(); + let new_local_user = LocalUserInsertForm::builder() + .person_id(inserted_timmy.id) + .password_encrypted("123".to_string()) + .build(); + let timmy_local_user = LocalUser::create(pool, &new_local_user).await.unwrap(); + let timmy_view = LocalUserView { + local_user: timmy_local_user, + person: inserted_timmy.clone(), + counts: Default::default(), + }; + let new_person_2 = PersonInsertForm::builder() .name("sara_crv".into()) .public_key("pubkey".to_string()) @@ -412,7 +428,6 @@ mod tests { local: true, banned: false, deleted: false, - admin: false, bot_account: false, bio: None, banner: None, @@ -436,7 +451,6 @@ mod tests { local: true, banned: false, deleted: false, - admin: false, bot_account: false, bio: None, banner: None, @@ -480,7 +494,6 @@ mod tests { local: true, banned: false, deleted: false, - admin: false, bot_account: false, bio: None, banner: None, @@ -497,7 +510,7 @@ mod tests { // Do a batch read of timmys reports let reports = CommentReportQuery::default() - .list(pool, &inserted_timmy) + .list(pool, &timmy_view) .await .unwrap(); @@ -546,7 +559,6 @@ mod tests { local: true, banned: false, deleted: false, - admin: false, bot_account: false, bio: None, banner: None, @@ -572,7 +584,7 @@ mod tests { unresolved_only: (true), ..Default::default() } - .list(pool, &inserted_timmy) + .list(pool, &timmy_view) .await .unwrap(); assert_eq!(reports_after_resolve[0], expected_sara_report_view); diff --git a/crates/db_views/src/comment_view.rs b/crates/db_views/src/comment_view.rs index be7e043a2..716d563a7 100644 --- a/crates/db_views/src/comment_view.rs +++ b/crates/db_views/src/comment_view.rs @@ -205,7 +205,10 @@ fn queries<'a>() -> Queries< query = query.filter(comment::deleted.eq(false)); } - let is_admin = options.local_user.map(|l| l.person.admin).unwrap_or(false); + let is_admin = options + .local_user + .map(|l| l.local_user.admin) + .unwrap_or(false); // only show removed comments to admin when viewing user profile if !(options.is_profile_view && is_admin) { query = query.filter(comment::removed.eq(false)); @@ -847,7 +850,6 @@ mod tests { local: true, banned: false, deleted: false, - admin: false, bot_account: false, bio: None, banner: None, diff --git a/crates/db_views/src/local_user_view.rs b/crates/db_views/src/local_user_view.rs index 23a8b8f05..d0d461545 100644 --- a/crates/db_views/src/local_user_view.rs +++ b/crates/db_views/src/local_user_view.rs @@ -62,7 +62,7 @@ fn queries<'a>( ListMode::AdminsWithEmails => { local_user::table .filter(local_user::email.is_not_null()) - .filter(person::admin.eq(true)) + .filter(local_user::admin.eq(true)) .inner_join(person::table) .inner_join(person_aggregates::table.on(person::id.eq(person_aggregates::person_id))) .select(selection) diff --git a/crates/db_views/src/post_report_view.rs b/crates/db_views/src/post_report_view.rs index 07037f940..da264a79c 100644 --- a/crates/db_views/src/post_report_view.rs +++ b/crates/db_views/src/post_report_view.rs @@ -1,4 +1,4 @@ -use crate::structs::PostReportView; +use crate::structs::{LocalUserView, PostReportView}; use diesel::{ pg::Pg, result::Error, @@ -42,7 +42,7 @@ type PostReportViewTuple = ( fn queries<'a>() -> Queries< impl ReadFn<'a, PostReportView, (PostReportId, PersonId)>, - impl ListFn<'a, PostReportView, (PostReportQuery, &'a Person)>, + impl ListFn<'a, PostReportView, (PostReportQuery, &'a LocalUserView)>, > { let all_joins = |query: post_report::BoxedQuery<'a, Pg>, my_person_id: PersonId| { query @@ -91,8 +91,8 @@ fn queries<'a>() -> Queries< .await }; - let list = move |mut conn: DbConn<'a>, (options, my_person): (PostReportQuery, &'a Person)| async move { - let mut query = all_joins(post_report::table.into_boxed(), my_person.id); + let list = move |mut conn: DbConn<'a>, (options, user): (PostReportQuery, &'a LocalUserView)| async move { + let mut query = all_joins(post_report::table.into_boxed(), user.person.id); if let Some(community_id) = options.community_id { query = query.filter(post::community_id.eq(community_id)); @@ -110,13 +110,13 @@ fn queries<'a>() -> Queries< .offset(offset); // If its not an admin, get only the ones you mod - if !my_person.admin { + if !user.local_user.admin { query .inner_join( community_moderator::table.on( community_moderator::community_id .eq(post::community_id) - .and(community_moderator::person_id.eq(my_person.id)), + .and(community_moderator::person_id.eq(user.person.id)), ), ) .load::(&mut conn) @@ -193,9 +193,9 @@ impl PostReportQuery { pub async fn list( self, pool: &mut DbPool<'_>, - my_person: &Person, + user: &LocalUserView, ) -> Result, Error> { - queries().list(pool, (self, my_person)).await + queries().list(pool, (self, user)).await } } @@ -221,12 +221,16 @@ mod tests { #![allow(clippy::unwrap_used)] #![allow(clippy::indexing_slicing)] - use crate::post_report_view::{PostReportQuery, PostReportView}; + use crate::{ + post_report_view::{PostReportQuery, PostReportView}, + structs::LocalUserView, + }; use lemmy_db_schema::{ aggregates::structs::PostAggregates, source::{ community::{Community, CommunityInsertForm, CommunityModerator, CommunityModeratorForm}, instance::Instance, + local_user::{LocalUser, LocalUserInsertForm}, person::{Person, PersonInsertForm}, post::{Post, PostInsertForm}, post_report::{PostReport, PostReportForm}, @@ -254,6 +258,17 @@ mod tests { let inserted_timmy = Person::create(pool, &new_person).await.unwrap(); + let new_local_user = LocalUserInsertForm::builder() + .person_id(inserted_timmy.id) + .password_encrypted("123".to_string()) + .build(); + let timmy_local_user = LocalUser::create(pool, &new_local_user).await.unwrap(); + let timmy_view = LocalUserView { + local_user: timmy_local_user, + person: inserted_timmy.clone(), + counts: Default::default(), + }; + let new_person_2 = PersonInsertForm::builder() .name("sara_prv".into()) .public_key("pubkey".to_string()) @@ -369,7 +384,6 @@ mod tests { local: true, banned: false, deleted: false, - admin: false, bot_account: false, bio: None, banner: None, @@ -393,7 +407,6 @@ mod tests { local: true, banned: false, deleted: false, - admin: false, bot_account: false, bio: None, banner: None, @@ -445,7 +458,6 @@ mod tests { local: true, banned: false, deleted: false, - admin: false, bot_account: false, bio: None, banner: None, @@ -462,7 +474,7 @@ mod tests { // Do a batch read of timmys reports let reports = PostReportQuery::default() - .list(pool, &inserted_timmy) + .list(pool, &timmy_view) .await .unwrap(); @@ -509,7 +521,6 @@ mod tests { local: true, banned: false, deleted: false, - admin: false, bot_account: false, bio: None, banner: None, @@ -535,7 +546,7 @@ mod tests { unresolved_only: (true), ..Default::default() } - .list(pool, &inserted_timmy) + .list(pool, &timmy_view) .await .unwrap(); assert_eq!(reports_after_resolve[0], expected_sara_report_view); diff --git a/crates/db_views/src/post_view.rs b/crates/db_views/src/post_view.rs index f7add4cec..f859a6ad9 100644 --- a/crates/db_views/src/post_view.rs +++ b/crates/db_views/src/post_view.rs @@ -217,7 +217,10 @@ fn queries<'a>() -> Queries< .filter(post::deleted.eq(false)); } - let is_admin = options.local_user.map(|l| l.person.admin).unwrap_or(false); + let is_admin = options + .local_user + .map(|l| l.local_user.admin) + .unwrap_or(false); // only show removed posts to admin when viewing user profile if !(options.is_profile_view && is_admin) { query = query @@ -945,7 +948,7 @@ mod tests { assert_eq!(1, post_listings_no_admin.len()); // Removed post is shown to admins on profile page - data.local_user_view.person.admin = true; + data.local_user_view.local_user.admin = true; let post_listings_is_admin = PostQuery { sort: Some(SortType::New), local_user: Some(&data.local_user_view), @@ -1071,7 +1074,6 @@ mod tests { avatar: None, actor_id: inserted_person.actor_id.clone(), local: true, - admin: false, bot_account: false, banned: false, deleted: false, diff --git a/crates/db_views/src/private_message_view.rs b/crates/db_views/src/private_message_view.rs index 58f1f3f8a..c1eeabab8 100644 --- a/crates/db_views/src/private_message_view.rs +++ b/crates/db_views/src/private_message_view.rs @@ -178,7 +178,6 @@ mod tests { let timmy_form = PersonInsertForm::builder() .name("timmy_rav".into()) - .admin(Some(true)) .public_key("pubkey".to_string()) .instance_id(instance.id) .build(); diff --git a/crates/db_views/src/registration_application_view.rs b/crates/db_views/src/registration_application_view.rs index 46556317f..13317ad1f 100644 --- a/crates/db_views/src/registration_application_view.rs +++ b/crates/db_views/src/registration_application_view.rs @@ -184,7 +184,6 @@ mod tests { let timmy_person_form = PersonInsertForm::builder() .name("timmy_rav".into()) - .admin(Some(true)) .public_key("pubkey".to_string()) .instance_id(inserted_instance.id) .build(); @@ -194,6 +193,7 @@ mod tests { let timmy_local_user_form = LocalUserInsertForm::builder() .person_id(inserted_timmy_person.id) .password_encrypted("nada".to_string()) + .admin(Some(true)) .build(); let _inserted_timmy_local_user = LocalUser::create(pool, &timmy_local_user_form) @@ -289,6 +289,7 @@ mod tests { password_encrypted: inserted_sara_local_user.password_encrypted, 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, }, creator: Person { id: inserted_sara_person.id, @@ -301,7 +302,6 @@ mod tests { banned: false, ban_expires: None, deleted: false, - admin: false, bot_account: false, bio: None, banner: None, @@ -380,7 +380,6 @@ mod tests { banned: false, ban_expires: None, deleted: false, - admin: true, bot_account: false, bio: None, banner: None, diff --git a/crates/db_views_actor/src/person_view.rs b/crates/db_views_actor/src/person_view.rs index dd4edcaf0..b9fbf9a01 100644 --- a/crates/db_views_actor/src/person_view.rs +++ b/crates/db_views_actor/src/person_view.rs @@ -13,7 +13,7 @@ use lemmy_db_schema::{ aggregates::structs::PersonAggregates, newtypes::PersonId, schema, - schema::{person, person_aggregates}, + schema::{local_user, person, person_aggregates}, source::person::Person, traits::JoinView, utils::{fuzzy_search, get_conn, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn}, @@ -33,6 +33,7 @@ fn queries<'a>( let all_joins = |query: person::BoxedQuery<'a, Pg>| { query .inner_join(person_aggregates::table) + .left_join(local_user::table) .select((person::all_columns, person_aggregates::all_columns)) }; @@ -47,7 +48,7 @@ fn queries<'a>( match mode { ListMode::Admins => { query = query - .filter(person::admin.eq(true)) + .filter(local_user::admin.eq(true)) .filter(person::deleted.eq(false)) .order_by(person::published); } @@ -95,9 +96,13 @@ impl PersonView { } pub async fn is_admin(pool: &mut DbPool<'_>, person_id: PersonId) -> Result { - use schema::person::dsl::{admin, id, person}; + use schema::{ + local_user::dsl::admin, + person::dsl::{id, person}, + }; let conn = &mut get_conn(pool).await?; let is_admin = person + .inner_join(local_user::table) .filter(id.eq(person_id)) .select(admin) .first::(conn) diff --git a/migrations/2023-08-01-101826_admin_flag_local_user/down.sql b/migrations/2023-08-01-101826_admin_flag_local_user/down.sql new file mode 100644 index 000000000..8ec229be7 --- /dev/null +++ b/migrations/2023-08-01-101826_admin_flag_local_user/down.sql @@ -0,0 +1,16 @@ +ALTER TABLE person + ADD COLUMN admin boolean DEFAULT FALSE NOT NULL; + +UPDATE + person +SET + admin = TRUE +FROM + local_user +WHERE + local_user.person_id = person.id + AND local_user.admin; + +ALTER TABLE local_user + DROP COLUMN admin; + diff --git a/migrations/2023-08-01-101826_admin_flag_local_user/up.sql b/migrations/2023-08-01-101826_admin_flag_local_user/up.sql new file mode 100644 index 000000000..be5bdf4dc --- /dev/null +++ b/migrations/2023-08-01-101826_admin_flag_local_user/up.sql @@ -0,0 +1,16 @@ +ALTER TABLE local_user + ADD COLUMN admin boolean DEFAULT FALSE NOT NULL; + +UPDATE + local_user +SET + admin = TRUE +FROM + person +WHERE + local_user.person_id = person.id + AND person.admin; + +ALTER TABLE person + DROP COLUMN admin; + diff --git a/src/code_migrations.rs b/src/code_migrations.rs index 51302524f..e274ca940 100644 --- a/src/code_migrations.rs +++ b/src/code_migrations.rs @@ -457,7 +457,6 @@ async fn initialize_local_site_2022_10_10( // Register the user if there's a site setup let person_form = PersonInsertForm::builder() .name(setup.admin_username.clone()) - .admin(Some(true)) .instance_id(instance.id) .actor_id(Some(person_actor_id.clone())) .private_key(Some(person_keypair.private_key)) @@ -471,6 +470,7 @@ async fn initialize_local_site_2022_10_10( .person_id(person_inserted.id) .password_encrypted(setup.admin_password.clone()) .email(setup.admin_email.clone()) + .admin(Some(true)) .build(); LocalUser::create(pool, &local_user_form).await?; };