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 <dessalines@users.noreply.github.com>
This commit is contained in:
Nutomic 2023-08-24 11:40:08 +02:00 committed by GitHub
parent 51ccf318e8
commit 6047257bfc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 140 additions and 81 deletions

View file

@ -27,7 +27,7 @@ pub async fn list_comment_reports(
page, page,
limit, limit,
} }
.list(&mut context.pool(), &local_user_view.person) .list(&mut context.pool(), &local_user_view)
.await?; .await?;
Ok(Json(ListCommentReportsResponse { comment_reports })) Ok(Json(ListCommentReportsResponse { comment_reports }))

View file

@ -28,7 +28,7 @@ pub async fn add_mod_to_community(
// Verify that only mods or admins can add mod // Verify that only mods or admins can add mod
is_mod_or_admin(&mut context.pool(), local_user_view.person.id, community_id).await?; 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?; 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)?; return Err(LemmyErrorType::NotAModerator)?;
} }

View file

@ -7,8 +7,8 @@ use lemmy_api_common::{
}; };
use lemmy_db_schema::{ use lemmy_db_schema::{
source::{ source::{
local_user::{LocalUser, LocalUserUpdateForm},
moderator::{ModAdd, ModAddForm}, moderator::{ModAdd, ModAddForm},
person::{Person, PersonUpdateForm},
}, },
traits::Crud, traits::Crud,
}; };
@ -27,13 +27,11 @@ impl Perform for AddAdmin {
// Make sure user is an admin // Make sure user is an admin
is_admin(&local_user_view)?; is_admin(&local_user_view)?;
let added = data.added; let added_admin = LocalUser::update(
let added_person_id = data.person_id;
let added_admin = Person::update(
&mut context.pool(), &mut context.pool(),
added_person_id, data.local_user_id,
&PersonUpdateForm { &LocalUserUpdateForm {
admin: Some(added), admin: Some(data.added),
..Default::default() ..Default::default()
}, },
) )
@ -43,7 +41,7 @@ impl Perform for AddAdmin {
// Mod tables // Mod tables
let form = ModAddForm { let form = ModAddForm {
mod_person_id: local_user_view.person.id, 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), removed: Some(!data.added),
}; };

View file

@ -9,6 +9,7 @@ use lemmy_db_schema::{
source::person_block::{PersonBlock, PersonBlockForm}, source::person_block::{PersonBlock, PersonBlockForm},
traits::Blockable, traits::Blockable,
}; };
use lemmy_db_views::structs::LocalUserView;
use lemmy_db_views_actor::structs::PersonView; use lemmy_db_views_actor::structs::PersonView;
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType};
@ -34,9 +35,8 @@ impl Perform for BlockPerson {
target_id, target_id,
}; };
let target_person_view = PersonView::read(&mut context.pool(), target_id).await?; let target_user = LocalUserView::read_person(&mut context.pool(), target_id).await;
if target_user.map(|t| t.local_user.admin) == Ok(true) {
if target_person_view.person.admin {
return Err(LemmyErrorType::CantBlockAdmin)?; return Err(LemmyErrorType::CantBlockAdmin)?;
} }
@ -50,8 +50,9 @@ impl Perform for BlockPerson {
.with_lemmy_type(LemmyErrorType::PersonBlockAlreadyExists)?; .with_lemmy_type(LemmyErrorType::PersonBlockAlreadyExists)?;
} }
let person_view = PersonView::read(&mut context.pool(), target_id).await?;
Ok(BlockPersonResponse { Ok(BlockPersonResponse {
person_view: target_person_view, person_view,
blocked: data.block, blocked: data.block,
}) })
} }

View file

@ -47,7 +47,7 @@ impl Perform for Login {
// Check if the user's email is verified if email verification is turned on // Check if the user's email is verified if email verification is turned on
// However, skip checking verification if the user is an admin // 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 && site_view.local_site.require_email_verification
&& !local_user_view.local_user.email_verified && !local_user_view.local_user.email_verified
{ {

View file

@ -21,7 +21,7 @@ impl Perform for GetReportCount {
let local_user_view = local_user_view_from_jwt(&data.auth, context).await?; let local_user_view = local_user_view_from_jwt(&data.auth, context).await?;
let person_id = local_user_view.person.id; 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 community_id = data.community_id;
let comment_reports = let comment_reports =

View file

@ -33,7 +33,7 @@ impl Perform for ListPostReports {
page, page,
limit, limit,
} }
.list(&mut context.pool(), &local_user_view.person) .list(&mut context.pool(), &local_user_view)
.await?; .await?;
Ok(ListPostReportsResponse { post_reports }) Ok(ListPostReportsResponse { post_reports })

View file

@ -9,8 +9,8 @@ use lemmy_db_schema::{
source::{ source::{
actor_language::SiteLanguage, actor_language::SiteLanguage,
language::Language, language::Language,
local_user::{LocalUser, LocalUserUpdateForm},
moderator::{ModAdd, ModAddForm}, moderator::{ModAdd, ModAddForm},
person::{Person, PersonUpdateForm},
tagline::Tagline, tagline::Tagline,
}, },
traits::Crud, traits::Crud,
@ -39,11 +39,10 @@ impl Perform for LeaveAdmin {
return Err(LemmyErrorType::CannotLeaveAdmin)?; return Err(LemmyErrorType::CannotLeaveAdmin)?;
} }
let person_id = local_user_view.person.id; LocalUser::update(
Person::update(
&mut context.pool(), &mut context.pool(),
person_id, local_user_view.local_user.id,
&PersonUpdateForm { &LocalUserUpdateForm {
admin: Some(false), admin: Some(false),
..Default::default() ..Default::default()
}, },
@ -51,6 +50,7 @@ impl Perform for LeaveAdmin {
.await?; .await?;
// Mod tables // Mod tables
let person_id = local_user_view.person.id;
let form = ModAddForm { let form = ModAddForm {
mod_person_id: person_id, mod_person_id: person_id,
other_person_id: person_id, other_person_id: person_id,

View file

@ -1,6 +1,6 @@
use crate::sensitive::Sensitive; use crate::sensitive::Sensitive;
use lemmy_db_schema::{ use lemmy_db_schema::{
newtypes::{CommentReplyId, CommunityId, LanguageId, PersonId, PersonMentionId}, newtypes::{CommentReplyId, CommunityId, LanguageId, LocalUserId, PersonId, PersonMentionId},
CommentSortType, CommentSortType,
ListingType, ListingType,
SortType, SortType,
@ -207,7 +207,7 @@ pub struct MarkAllAsRead {
#[cfg_attr(feature = "full", ts(export))] #[cfg_attr(feature = "full", ts(export))]
/// Adds an admin to a site. /// Adds an admin to a site.
pub struct AddAdmin { pub struct AddAdmin {
pub person_id: PersonId, pub local_user_id: LocalUserId,
pub added: bool, pub added: bool,
pub auth: Sensitive<String>, pub auth: Sensitive<String>,
} }

View file

@ -78,8 +78,8 @@ pub async fn is_mod_or_admin_opt(
} }
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.local_user.admin {
Err(LemmyErrorType::NotAnAdmin)?; return Err(LemmyErrorType::NotAnAdmin)?;
} }
Ok(()) Ok(())
} }
@ -500,7 +500,7 @@ pub async fn check_registration_application(
if (local_site.registration_mode == RegistrationMode::RequireApplication if (local_site.registration_mode == RegistrationMode::RequireApplication
|| local_site.registration_mode == RegistrationMode::Closed) || local_site.registration_mode == RegistrationMode::Closed)
&& !local_user_view.local_user.accepted_application && !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 // Fetch the registration, see if its denied
let local_user_id = local_user_view.local_user.id; let local_user_id = local_user_view.local_user.id;

View file

@ -115,8 +115,6 @@ pub async fn register(
.public_key(actor_keypair.public_key) .public_key(actor_keypair.public_key)
.inbox_url(Some(generate_inbox_url(&actor_id)?)) .inbox_url(Some(generate_inbox_url(&actor_id)?))
.shared_inbox_url(Some(generate_shared_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) .instance_id(site_view.site.instance_id)
.build(); .build();
@ -137,6 +135,8 @@ pub async fn register(
.show_nsfw(Some(data.show_nsfw)) .show_nsfw(Some(data.show_nsfw))
.accepted_application(accepted_application) .accepted_application(accepted_application)
.default_listing_type(Some(local_site.default_post_listing_type)) .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(); .build();
let inserted_local_user = LocalUser::create(&mut context.pool(), &local_user_form).await?; let inserted_local_user = LocalUser::create(&mut context.pool(), &local_user_form).await?;

View file

@ -163,7 +163,6 @@ impl Object for ApubPerson {
actor_id: Some(person.id.into()), actor_id: Some(person.id.into()),
bio, bio,
local: Some(false), local: Some(false),
admin: Some(false),
bot_account: Some(person.kind == UserTypes::Service), bot_account: Some(person.kind == UserTypes::Service),
private_key: None, private_key: None,
public_key: person.public_key.public_key_pem, public_key: person.public_key.public_key_pem,

View file

@ -240,7 +240,6 @@ mod tests {
bio: None, bio: None,
local: true, local: true,
bot_account: false, bot_account: false,
admin: false,
private_key: None, private_key: None,
public_key: "nada".to_owned(), public_key: "nada".to_owned(),
last_refreshed_at: inserted_person.published, last_refreshed_at: inserted_person.published,

View file

@ -396,9 +396,10 @@ diesel::table! {
totp_2fa_secret -> Nullable<Text>, totp_2fa_secret -> Nullable<Text>,
totp_2fa_url -> Nullable<Text>, totp_2fa_url -> Nullable<Text>,
open_links_in_new_tab -> Bool, open_links_in_new_tab -> Bool,
infinite_scroll_enabled -> Bool,
blur_nsfw -> Bool, blur_nsfw -> Bool,
auto_expand -> Bool, auto_expand -> Bool,
infinite_scroll_enabled -> Bool, admin -> Bool,
} }
} }
@ -566,7 +567,6 @@ diesel::table! {
#[max_length = 255] #[max_length = 255]
shared_inbox_url -> Nullable<Varchar>, shared_inbox_url -> Nullable<Varchar>,
matrix_user_id -> Nullable<Text>, matrix_user_id -> Nullable<Text>,
admin -> Bool,
bot_account -> Bool, bot_account -> Bool,
ban_expires -> Nullable<Timestamp>, ban_expires -> Nullable<Timestamp>,
instance_id -> Int4, instance_id -> Int4,

View file

@ -57,6 +57,8 @@ pub struct LocalUser {
pub auto_expand: bool, pub auto_expand: bool,
/// Whether infinite scroll is enabled. /// Whether infinite scroll is enabled.
pub infinite_scroll_enabled: bool, pub infinite_scroll_enabled: bool,
/// Whether the person is an admin.
pub admin: bool,
} }
#[derive(Clone, TypedBuilder)] #[derive(Clone, TypedBuilder)]
@ -88,6 +90,7 @@ pub struct LocalUserInsertForm {
pub blur_nsfw: Option<bool>, pub blur_nsfw: Option<bool>,
pub auto_expand: Option<bool>, pub auto_expand: Option<bool>,
pub infinite_scroll_enabled: Option<bool>, pub infinite_scroll_enabled: Option<bool>,
pub admin: Option<bool>,
} }
#[derive(Clone, Default)] #[derive(Clone, Default)]
@ -115,4 +118,5 @@ pub struct LocalUserUpdateForm {
pub blur_nsfw: Option<bool>, pub blur_nsfw: Option<bool>,
pub auto_expand: Option<bool>, pub auto_expand: Option<bool>,
pub infinite_scroll_enabled: Option<bool>, pub infinite_scroll_enabled: Option<bool>,
pub admin: Option<bool>,
} }

View file

@ -49,8 +49,6 @@ pub struct Person {
pub shared_inbox_url: Option<DbUrl>, pub shared_inbox_url: Option<DbUrl>,
/// A matrix id, usually given an @person:matrix.org /// A matrix id, usually given an @person:matrix.org
pub matrix_user_id: Option<String>, pub matrix_user_id: Option<String>,
/// Whether the person is an admin.
pub admin: bool,
/// Whether the person is a bot account. /// Whether the person is a bot account.
pub bot_account: bool, pub bot_account: bool,
/// When their ban, if it exists, expires, if at all. /// When their ban, if it exists, expires, if at all.
@ -84,7 +82,6 @@ pub struct PersonInsertForm {
pub inbox_url: Option<DbUrl>, pub inbox_url: Option<DbUrl>,
pub shared_inbox_url: Option<DbUrl>, pub shared_inbox_url: Option<DbUrl>,
pub matrix_user_id: Option<String>, pub matrix_user_id: Option<String>,
pub admin: Option<bool>,
pub bot_account: Option<bool>, pub bot_account: Option<bool>,
pub ban_expires: Option<chrono::NaiveDateTime>, pub ban_expires: Option<chrono::NaiveDateTime>,
} }
@ -108,7 +105,6 @@ pub struct PersonUpdateForm {
pub inbox_url: Option<DbUrl>, pub inbox_url: Option<DbUrl>,
pub shared_inbox_url: Option<Option<DbUrl>>, pub shared_inbox_url: Option<Option<DbUrl>>,
pub matrix_user_id: Option<Option<String>>, pub matrix_user_id: Option<Option<String>>,
pub admin: Option<bool>,
pub bot_account: Option<bool>, pub bot_account: Option<bool>,
pub ban_expires: Option<Option<chrono::NaiveDateTime>>, pub ban_expires: Option<Option<chrono::NaiveDateTime>>,
} }

View file

@ -1,4 +1,4 @@
use crate::structs::CommentReportView; use crate::structs::{CommentReportView, LocalUserView};
use diesel::{ use diesel::{
dsl::now, dsl::now,
pg::Pg, pg::Pg,
@ -38,7 +38,7 @@ use lemmy_db_schema::{
fn queries<'a>() -> Queries< fn queries<'a>() -> Queries<
impl ReadFn<'a, CommentReportView, (CommentReportId, PersonId)>, 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| { let all_joins = |query: comment_report::BoxedQuery<'a, Pg>, my_person_id: PersonId| {
query query
@ -93,8 +93,9 @@ fn queries<'a>() -> Queries<
.await .await
}; };
let list = move |mut conn: DbConn<'a>, (options, my_person): (CommentReportQuery, &'a Person)| async move { let list = move |mut conn: DbConn<'a>,
let mut query = all_joins(comment_report::table.into_boxed(), my_person.id) (options, user): (CommentReportQuery, &'a LocalUserView)| async move {
let mut query = all_joins(comment_report::table.into_boxed(), user.person.id)
.left_join( .left_join(
community_person_ban::table.on( community_person_ban::table.on(
community::id community::id
@ -125,13 +126,13 @@ fn queries<'a>() -> Queries<
.offset(offset); .offset(offset);
// If its not an admin, get only the ones you mod // If its not an admin, get only the ones you mod
if !my_person.admin { if !user.local_user.admin {
query query
.inner_join( .inner_join(
community_moderator::table.on( community_moderator::table.on(
community_moderator::community_id community_moderator::community_id
.eq(post::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::<<CommentReportView as JoinView>::JoinTuple>(&mut conn) .load::<<CommentReportView as JoinView>::JoinTuple>(&mut conn)
@ -213,9 +214,9 @@ impl CommentReportQuery {
pub async fn list( pub async fn list(
self, self,
pool: &mut DbPool<'_>, pool: &mut DbPool<'_>,
my_person: &Person, user: &LocalUserView,
) -> Result<Vec<CommentReportView>, Error> { ) -> Result<Vec<CommentReportView>, 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::unwrap_used)]
#![allow(clippy::indexing_slicing)] #![allow(clippy::indexing_slicing)]
use crate::comment_report_view::{CommentReportQuery, CommentReportView}; use crate::{
comment_report_view::{CommentReportQuery, CommentReportView},
structs::LocalUserView,
};
use lemmy_db_schema::{ use lemmy_db_schema::{
aggregates::structs::CommentAggregates, aggregates::structs::CommentAggregates,
source::{ source::{
@ -262,6 +266,7 @@ mod tests {
comment_report::{CommentReport, CommentReportForm}, comment_report::{CommentReport, CommentReportForm},
community::{Community, CommunityInsertForm, CommunityModerator, CommunityModeratorForm}, community::{Community, CommunityInsertForm, CommunityModerator, CommunityModeratorForm},
instance::Instance, instance::Instance,
local_user::{LocalUser, LocalUserInsertForm},
person::{Person, PersonInsertForm}, person::{Person, PersonInsertForm},
post::{Post, PostInsertForm}, post::{Post, PostInsertForm},
}, },
@ -288,6 +293,17 @@ mod tests {
let inserted_timmy = Person::create(pool, &new_person).await.unwrap(); 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() let new_person_2 = PersonInsertForm::builder()
.name("sara_crv".into()) .name("sara_crv".into())
.public_key("pubkey".to_string()) .public_key("pubkey".to_string())
@ -412,7 +428,6 @@ mod tests {
local: true, local: true,
banned: false, banned: false,
deleted: false, deleted: false,
admin: false,
bot_account: false, bot_account: false,
bio: None, bio: None,
banner: None, banner: None,
@ -436,7 +451,6 @@ mod tests {
local: true, local: true,
banned: false, banned: false,
deleted: false, deleted: false,
admin: false,
bot_account: false, bot_account: false,
bio: None, bio: None,
banner: None, banner: None,
@ -480,7 +494,6 @@ mod tests {
local: true, local: true,
banned: false, banned: false,
deleted: false, deleted: false,
admin: false,
bot_account: false, bot_account: false,
bio: None, bio: None,
banner: None, banner: None,
@ -497,7 +510,7 @@ mod tests {
// Do a batch read of timmys reports // Do a batch read of timmys reports
let reports = CommentReportQuery::default() let reports = CommentReportQuery::default()
.list(pool, &inserted_timmy) .list(pool, &timmy_view)
.await .await
.unwrap(); .unwrap();
@ -546,7 +559,6 @@ mod tests {
local: true, local: true,
banned: false, banned: false,
deleted: false, deleted: false,
admin: false,
bot_account: false, bot_account: false,
bio: None, bio: None,
banner: None, banner: None,
@ -572,7 +584,7 @@ mod tests {
unresolved_only: (true), unresolved_only: (true),
..Default::default() ..Default::default()
} }
.list(pool, &inserted_timmy) .list(pool, &timmy_view)
.await .await
.unwrap(); .unwrap();
assert_eq!(reports_after_resolve[0], expected_sara_report_view); assert_eq!(reports_after_resolve[0], expected_sara_report_view);

View file

@ -205,7 +205,10 @@ fn queries<'a>() -> Queries<
query = query.filter(comment::deleted.eq(false)); 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 // only show removed comments to admin when viewing user profile
if !(options.is_profile_view && is_admin) { if !(options.is_profile_view && is_admin) {
query = query.filter(comment::removed.eq(false)); query = query.filter(comment::removed.eq(false));
@ -847,7 +850,6 @@ mod tests {
local: true, local: true,
banned: false, banned: false,
deleted: false, deleted: false,
admin: false,
bot_account: false, bot_account: false,
bio: None, bio: None,
banner: None, banner: None,

View file

@ -62,7 +62,7 @@ fn queries<'a>(
ListMode::AdminsWithEmails => { ListMode::AdminsWithEmails => {
local_user::table local_user::table
.filter(local_user::email.is_not_null()) .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::table)
.inner_join(person_aggregates::table.on(person::id.eq(person_aggregates::person_id))) .inner_join(person_aggregates::table.on(person::id.eq(person_aggregates::person_id)))
.select(selection) .select(selection)

View file

@ -1,4 +1,4 @@
use crate::structs::PostReportView; use crate::structs::{LocalUserView, PostReportView};
use diesel::{ use diesel::{
pg::Pg, pg::Pg,
result::Error, result::Error,
@ -42,7 +42,7 @@ type PostReportViewTuple = (
fn queries<'a>() -> Queries< fn queries<'a>() -> Queries<
impl ReadFn<'a, PostReportView, (PostReportId, PersonId)>, 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| { let all_joins = |query: post_report::BoxedQuery<'a, Pg>, my_person_id: PersonId| {
query query
@ -91,8 +91,8 @@ fn queries<'a>() -> Queries<
.await .await
}; };
let list = move |mut conn: DbConn<'a>, (options, my_person): (PostReportQuery, &'a Person)| async move { let list = move |mut conn: DbConn<'a>, (options, user): (PostReportQuery, &'a LocalUserView)| async move {
let mut query = all_joins(post_report::table.into_boxed(), my_person.id); let mut query = all_joins(post_report::table.into_boxed(), user.person.id);
if let Some(community_id) = options.community_id { if let Some(community_id) = options.community_id {
query = query.filter(post::community_id.eq(community_id)); query = query.filter(post::community_id.eq(community_id));
@ -110,13 +110,13 @@ fn queries<'a>() -> Queries<
.offset(offset); .offset(offset);
// If its not an admin, get only the ones you mod // If its not an admin, get only the ones you mod
if !my_person.admin { if !user.local_user.admin {
query query
.inner_join( .inner_join(
community_moderator::table.on( community_moderator::table.on(
community_moderator::community_id community_moderator::community_id
.eq(post::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::<PostReportViewTuple>(&mut conn) .load::<PostReportViewTuple>(&mut conn)
@ -193,9 +193,9 @@ impl PostReportQuery {
pub async fn list( pub async fn list(
self, self,
pool: &mut DbPool<'_>, pool: &mut DbPool<'_>,
my_person: &Person, user: &LocalUserView,
) -> Result<Vec<PostReportView>, Error> { ) -> Result<Vec<PostReportView>, 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::unwrap_used)]
#![allow(clippy::indexing_slicing)] #![allow(clippy::indexing_slicing)]
use crate::post_report_view::{PostReportQuery, PostReportView}; use crate::{
post_report_view::{PostReportQuery, PostReportView},
structs::LocalUserView,
};
use lemmy_db_schema::{ use lemmy_db_schema::{
aggregates::structs::PostAggregates, aggregates::structs::PostAggregates,
source::{ source::{
community::{Community, CommunityInsertForm, CommunityModerator, CommunityModeratorForm}, community::{Community, CommunityInsertForm, CommunityModerator, CommunityModeratorForm},
instance::Instance, instance::Instance,
local_user::{LocalUser, LocalUserInsertForm},
person::{Person, PersonInsertForm}, person::{Person, PersonInsertForm},
post::{Post, PostInsertForm}, post::{Post, PostInsertForm},
post_report::{PostReport, PostReportForm}, post_report::{PostReport, PostReportForm},
@ -254,6 +258,17 @@ mod tests {
let inserted_timmy = Person::create(pool, &new_person).await.unwrap(); 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() let new_person_2 = PersonInsertForm::builder()
.name("sara_prv".into()) .name("sara_prv".into())
.public_key("pubkey".to_string()) .public_key("pubkey".to_string())
@ -369,7 +384,6 @@ mod tests {
local: true, local: true,
banned: false, banned: false,
deleted: false, deleted: false,
admin: false,
bot_account: false, bot_account: false,
bio: None, bio: None,
banner: None, banner: None,
@ -393,7 +407,6 @@ mod tests {
local: true, local: true,
banned: false, banned: false,
deleted: false, deleted: false,
admin: false,
bot_account: false, bot_account: false,
bio: None, bio: None,
banner: None, banner: None,
@ -445,7 +458,6 @@ mod tests {
local: true, local: true,
banned: false, banned: false,
deleted: false, deleted: false,
admin: false,
bot_account: false, bot_account: false,
bio: None, bio: None,
banner: None, banner: None,
@ -462,7 +474,7 @@ mod tests {
// Do a batch read of timmys reports // Do a batch read of timmys reports
let reports = PostReportQuery::default() let reports = PostReportQuery::default()
.list(pool, &inserted_timmy) .list(pool, &timmy_view)
.await .await
.unwrap(); .unwrap();
@ -509,7 +521,6 @@ mod tests {
local: true, local: true,
banned: false, banned: false,
deleted: false, deleted: false,
admin: false,
bot_account: false, bot_account: false,
bio: None, bio: None,
banner: None, banner: None,
@ -535,7 +546,7 @@ mod tests {
unresolved_only: (true), unresolved_only: (true),
..Default::default() ..Default::default()
} }
.list(pool, &inserted_timmy) .list(pool, &timmy_view)
.await .await
.unwrap(); .unwrap();
assert_eq!(reports_after_resolve[0], expected_sara_report_view); assert_eq!(reports_after_resolve[0], expected_sara_report_view);

View file

@ -217,7 +217,10 @@ fn queries<'a>() -> Queries<
.filter(post::deleted.eq(false)); .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 // only show removed posts to admin when viewing user profile
if !(options.is_profile_view && is_admin) { if !(options.is_profile_view && is_admin) {
query = query query = query
@ -945,7 +948,7 @@ mod tests {
assert_eq!(1, post_listings_no_admin.len()); assert_eq!(1, post_listings_no_admin.len());
// Removed post is shown to admins on profile page // 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 { let post_listings_is_admin = PostQuery {
sort: Some(SortType::New), sort: Some(SortType::New),
local_user: Some(&data.local_user_view), local_user: Some(&data.local_user_view),
@ -1071,7 +1074,6 @@ mod tests {
avatar: None, avatar: None,
actor_id: inserted_person.actor_id.clone(), actor_id: inserted_person.actor_id.clone(),
local: true, local: true,
admin: false,
bot_account: false, bot_account: false,
banned: false, banned: false,
deleted: false, deleted: false,

View file

@ -178,7 +178,6 @@ mod tests {
let timmy_form = PersonInsertForm::builder() let timmy_form = PersonInsertForm::builder()
.name("timmy_rav".into()) .name("timmy_rav".into())
.admin(Some(true))
.public_key("pubkey".to_string()) .public_key("pubkey".to_string())
.instance_id(instance.id) .instance_id(instance.id)
.build(); .build();

View file

@ -184,7 +184,6 @@ mod tests {
let timmy_person_form = PersonInsertForm::builder() let timmy_person_form = PersonInsertForm::builder()
.name("timmy_rav".into()) .name("timmy_rav".into())
.admin(Some(true))
.public_key("pubkey".to_string()) .public_key("pubkey".to_string())
.instance_id(inserted_instance.id) .instance_id(inserted_instance.id)
.build(); .build();
@ -194,6 +193,7 @@ mod tests {
let timmy_local_user_form = LocalUserInsertForm::builder() let timmy_local_user_form = LocalUserInsertForm::builder()
.person_id(inserted_timmy_person.id) .person_id(inserted_timmy_person.id)
.password_encrypted("nada".to_string()) .password_encrypted("nada".to_string())
.admin(Some(true))
.build(); .build();
let _inserted_timmy_local_user = LocalUser::create(pool, &timmy_local_user_form) 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, password_encrypted: inserted_sara_local_user.password_encrypted,
open_links_in_new_tab: inserted_sara_local_user.open_links_in_new_tab, open_links_in_new_tab: inserted_sara_local_user.open_links_in_new_tab,
infinite_scroll_enabled: inserted_sara_local_user.infinite_scroll_enabled, infinite_scroll_enabled: inserted_sara_local_user.infinite_scroll_enabled,
admin: false,
}, },
creator: Person { creator: Person {
id: inserted_sara_person.id, id: inserted_sara_person.id,
@ -301,7 +302,6 @@ mod tests {
banned: false, banned: false,
ban_expires: None, ban_expires: None,
deleted: false, deleted: false,
admin: false,
bot_account: false, bot_account: false,
bio: None, bio: None,
banner: None, banner: None,
@ -380,7 +380,6 @@ mod tests {
banned: false, banned: false,
ban_expires: None, ban_expires: None,
deleted: false, deleted: false,
admin: true,
bot_account: false, bot_account: false,
bio: None, bio: None,
banner: None, banner: None,

View file

@ -13,7 +13,7 @@ use lemmy_db_schema::{
aggregates::structs::PersonAggregates, aggregates::structs::PersonAggregates,
newtypes::PersonId, newtypes::PersonId,
schema, schema,
schema::{person, person_aggregates}, schema::{local_user, person, person_aggregates},
source::person::Person, source::person::Person,
traits::JoinView, traits::JoinView,
utils::{fuzzy_search, get_conn, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn}, 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>| { let all_joins = |query: person::BoxedQuery<'a, Pg>| {
query query
.inner_join(person_aggregates::table) .inner_join(person_aggregates::table)
.left_join(local_user::table)
.select((person::all_columns, person_aggregates::all_columns)) .select((person::all_columns, person_aggregates::all_columns))
}; };
@ -47,7 +48,7 @@ fn queries<'a>(
match mode { match mode {
ListMode::Admins => { ListMode::Admins => {
query = query query = query
.filter(person::admin.eq(true)) .filter(local_user::admin.eq(true))
.filter(person::deleted.eq(false)) .filter(person::deleted.eq(false))
.order_by(person::published); .order_by(person::published);
} }
@ -95,9 +96,13 @@ impl PersonView {
} }
pub async fn is_admin(pool: &mut DbPool<'_>, person_id: PersonId) -> Result<bool, Error> { pub async fn is_admin(pool: &mut DbPool<'_>, person_id: PersonId) -> Result<bool, Error> {
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 conn = &mut get_conn(pool).await?;
let is_admin = person let is_admin = person
.inner_join(local_user::table)
.filter(id.eq(person_id)) .filter(id.eq(person_id))
.select(admin) .select(admin)
.first::<bool>(conn) .first::<bool>(conn)

View file

@ -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;

View file

@ -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;

View file

@ -457,7 +457,6 @@ async fn initialize_local_site_2022_10_10(
// Register the user if there's a site setup // Register the user if there's a site setup
let person_form = PersonInsertForm::builder() let person_form = PersonInsertForm::builder()
.name(setup.admin_username.clone()) .name(setup.admin_username.clone())
.admin(Some(true))
.instance_id(instance.id) .instance_id(instance.id)
.actor_id(Some(person_actor_id.clone())) .actor_id(Some(person_actor_id.clone()))
.private_key(Some(person_keypair.private_key)) .private_key(Some(person_keypair.private_key))
@ -471,6 +470,7 @@ async fn initialize_local_site_2022_10_10(
.person_id(person_inserted.id) .person_id(person_inserted.id)
.password_encrypted(setup.admin_password.clone()) .password_encrypted(setup.admin_password.clone())
.email(setup.admin_email.clone()) .email(setup.admin_email.clone())
.admin(Some(true))
.build(); .build();
LocalUser::create(pool, &local_user_form).await?; LocalUser::create(pool, &local_user_form).await?;
}; };