Adding checks for higher admin and mod. (#4860)
* Adding checks for higher admin and mod. * Adding admin/mod checks for ban and comment removal. * Combining mod or admin check with an SQL union. * Making community ban or add mod also allow higher admins. * Making sure remove post also checks higher mods or admins. * Add unit test for is_higher_mod_or_admin_check * Fixing comment. * Addressing PR comments. * Get rid of pointless wrapper functions, return lemmyresult directly.
This commit is contained in:
parent
6ff128341c
commit
ba044c7d98
28 changed files with 475 additions and 211 deletions
|
@ -9,6 +9,7 @@ use lemmy_api_common::{
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::{
|
source::{
|
||||||
community::{Community, CommunityModerator, CommunityModeratorForm},
|
community::{Community, CommunityModerator, CommunityModeratorForm},
|
||||||
|
local_user::LocalUser,
|
||||||
moderator::{ModAddCommunity, ModAddCommunityForm},
|
moderator::{ModAddCommunity, ModAddCommunityForm},
|
||||||
},
|
},
|
||||||
traits::{Crud, Joinable},
|
traits::{Crud, Joinable},
|
||||||
|
@ -33,6 +34,18 @@ pub async fn add_mod_to_community(
|
||||||
&mut context.pool(),
|
&mut context.pool(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
// If its a mod removal, also check that you're a higher mod.
|
||||||
|
if !data.added {
|
||||||
|
LocalUser::is_higher_mod_or_admin_check(
|
||||||
|
&mut context.pool(),
|
||||||
|
community_id,
|
||||||
|
local_user_view.person.id,
|
||||||
|
vec![data.person_id],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
let community = Community::read(&mut context.pool(), community_id)
|
let community = Community::read(&mut context.pool(), community_id)
|
||||||
.await?
|
.await?
|
||||||
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
|
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
|
||||||
|
|
|
@ -14,6 +14,7 @@ use lemmy_db_schema::{
|
||||||
CommunityPersonBan,
|
CommunityPersonBan,
|
||||||
CommunityPersonBanForm,
|
CommunityPersonBanForm,
|
||||||
},
|
},
|
||||||
|
local_user::LocalUser,
|
||||||
moderator::{ModBanFromCommunity, ModBanFromCommunityForm},
|
moderator::{ModBanFromCommunity, ModBanFromCommunityForm},
|
||||||
},
|
},
|
||||||
traits::{Bannable, Crud, Followable},
|
traits::{Bannable, Crud, Followable},
|
||||||
|
@ -44,6 +45,14 @@ pub async fn ban_from_community(
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
LocalUser::is_higher_mod_or_admin_check(
|
||||||
|
&mut context.pool(),
|
||||||
|
data.community_id,
|
||||||
|
local_user_view.person.id,
|
||||||
|
vec![data.person_id],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
if let Some(reason) = &data.reason {
|
if let Some(reason) = &data.reason {
|
||||||
is_valid_body_field(reason, false)?;
|
is_valid_body_field(reason, false)?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,16 @@ pub async fn add_admin(
|
||||||
// Make sure user is an admin
|
// Make sure user is an admin
|
||||||
is_admin(&local_user_view)?;
|
is_admin(&local_user_view)?;
|
||||||
|
|
||||||
|
// If its an admin removal, also check that you're a higher admin
|
||||||
|
if !data.added {
|
||||||
|
LocalUser::is_higher_admin_check(
|
||||||
|
&mut context.pool(),
|
||||||
|
local_user_view.person.id,
|
||||||
|
vec![data.person_id],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure that the person_id added is local
|
// Make sure that the person_id added is local
|
||||||
let added_local_user = LocalUserView::read_person(&mut context.pool(), data.person_id)
|
let added_local_user = LocalUserView::read_person(&mut context.pool(), data.person_id)
|
||||||
.await?
|
.await?
|
||||||
|
|
|
@ -9,6 +9,7 @@ use lemmy_api_common::{
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::{
|
source::{
|
||||||
|
local_user::LocalUser,
|
||||||
login_token::LoginToken,
|
login_token::LoginToken,
|
||||||
moderator::{ModBan, ModBanForm},
|
moderator::{ModBan, ModBanForm},
|
||||||
person::{Person, PersonUpdateForm},
|
person::{Person, PersonUpdateForm},
|
||||||
|
@ -31,6 +32,14 @@ pub async fn ban_from_site(
|
||||||
// Make sure user is an admin
|
// Make sure user is an admin
|
||||||
is_admin(&local_user_view)?;
|
is_admin(&local_user_view)?;
|
||||||
|
|
||||||
|
// Also make sure you're a higher admin than the target
|
||||||
|
LocalUser::is_higher_admin_check(
|
||||||
|
&mut context.pool(),
|
||||||
|
local_user_view.person.id,
|
||||||
|
vec![data.person_id],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
if let Some(reason) = &data.reason {
|
if let Some(reason) = &data.reason {
|
||||||
is_valid_body_field(reason, false)?;
|
is_valid_body_field(reason, false)?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ use lemmy_api_common::{
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::{
|
source::{
|
||||||
comment::Comment,
|
comment::Comment,
|
||||||
|
local_user::LocalUser,
|
||||||
moderator::{AdminPurgeComment, AdminPurgeCommentForm},
|
moderator::{AdminPurgeComment, AdminPurgeCommentForm},
|
||||||
},
|
},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
|
@ -37,6 +38,14 @@ pub async fn purge_comment(
|
||||||
.await?
|
.await?
|
||||||
.ok_or(LemmyErrorType::CouldntFindComment)?;
|
.ok_or(LemmyErrorType::CouldntFindComment)?;
|
||||||
|
|
||||||
|
// Also check that you're a higher admin
|
||||||
|
LocalUser::is_higher_admin_check(
|
||||||
|
&mut context.pool(),
|
||||||
|
local_user_view.person.id,
|
||||||
|
vec![comment_view.creator.id],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
let post_id = comment_view.comment.post_id;
|
let post_id = comment_view.comment.post_id;
|
||||||
|
|
||||||
// TODO read comments for pictrs images and purge them
|
// TODO read comments for pictrs images and purge them
|
||||||
|
|
|
@ -9,13 +9,16 @@ use lemmy_api_common::{
|
||||||
SuccessResponse,
|
SuccessResponse,
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
|
newtypes::PersonId,
|
||||||
source::{
|
source::{
|
||||||
community::Community,
|
community::Community,
|
||||||
|
local_user::LocalUser,
|
||||||
moderator::{AdminPurgeCommunity, AdminPurgeCommunityForm},
|
moderator::{AdminPurgeCommunity, AdminPurgeCommunityForm},
|
||||||
},
|
},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::LocalUserView;
|
use lemmy_db_views::structs::LocalUserView;
|
||||||
|
use lemmy_db_views_actor::structs::CommunityModeratorView;
|
||||||
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
||||||
|
|
||||||
#[tracing::instrument(skip(context))]
|
#[tracing::instrument(skip(context))]
|
||||||
|
@ -32,6 +35,21 @@ pub async fn purge_community(
|
||||||
.await?
|
.await?
|
||||||
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
|
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
|
||||||
|
|
||||||
|
// Also check that you're a higher admin than all the mods
|
||||||
|
let community_mod_person_ids =
|
||||||
|
CommunityModeratorView::for_community(&mut context.pool(), community.id)
|
||||||
|
.await?
|
||||||
|
.iter()
|
||||||
|
.map(|cmv| cmv.moderator.id)
|
||||||
|
.collect::<Vec<PersonId>>();
|
||||||
|
|
||||||
|
LocalUser::is_higher_admin_check(
|
||||||
|
&mut context.pool(),
|
||||||
|
local_user_view.person.id,
|
||||||
|
community_mod_person_ids,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
if let Some(banner) = &community.banner {
|
if let Some(banner) = &community.banner {
|
||||||
purge_image_from_pictrs(banner, &context).await.ok();
|
purge_image_from_pictrs(banner, &context).await.ok();
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ use lemmy_api_common::{
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::{
|
source::{
|
||||||
|
local_user::LocalUser,
|
||||||
moderator::{AdminPurgePerson, AdminPurgePersonForm},
|
moderator::{AdminPurgePerson, AdminPurgePersonForm},
|
||||||
person::{Person, PersonUpdateForm},
|
person::{Person, PersonUpdateForm},
|
||||||
},
|
},
|
||||||
|
@ -27,9 +28,18 @@ pub async fn purge_person(
|
||||||
// Only let admin purge an item
|
// Only let admin purge an item
|
||||||
is_admin(&local_user_view)?;
|
is_admin(&local_user_view)?;
|
||||||
|
|
||||||
|
// Also check that you're a higher admin
|
||||||
|
LocalUser::is_higher_admin_check(
|
||||||
|
&mut context.pool(),
|
||||||
|
local_user_view.person.id,
|
||||||
|
vec![data.person_id],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
let person = Person::read(&mut context.pool(), data.person_id)
|
let person = Person::read(&mut context.pool(), data.person_id)
|
||||||
.await?
|
.await?
|
||||||
.ok_or(LemmyErrorType::CouldntFindPerson)?;
|
.ok_or(LemmyErrorType::CouldntFindPerson)?;
|
||||||
|
|
||||||
ban_nonlocal_user_from_local_communities(
|
ban_nonlocal_user_from_local_communities(
|
||||||
&local_user_view,
|
&local_user_view,
|
||||||
&person,
|
&person,
|
||||||
|
|
|
@ -10,6 +10,7 @@ use lemmy_api_common::{
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::{
|
source::{
|
||||||
|
local_user::LocalUser,
|
||||||
moderator::{AdminPurgePost, AdminPurgePostForm},
|
moderator::{AdminPurgePost, AdminPurgePostForm},
|
||||||
post::Post,
|
post::Post,
|
||||||
},
|
},
|
||||||
|
@ -32,6 +33,14 @@ pub async fn purge_post(
|
||||||
.await?
|
.await?
|
||||||
.ok_or(LemmyErrorType::CouldntFindPost)?;
|
.ok_or(LemmyErrorType::CouldntFindPost)?;
|
||||||
|
|
||||||
|
// Also check that you're a higher admin
|
||||||
|
LocalUser::is_higher_admin_check(
|
||||||
|
&mut context.pool(),
|
||||||
|
local_user_view.person.id,
|
||||||
|
vec![post.creator_id],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
// Purge image
|
// Purge image
|
||||||
if let Some(url) = &post.url {
|
if let Some(url) = &post.url {
|
||||||
purge_image_from_pictrs(url, &context).await.ok();
|
purge_image_from_pictrs(url, &context).await.ok();
|
||||||
|
|
|
@ -116,10 +116,7 @@ mod tests {
|
||||||
|
|
||||||
let inserted_person = Person::create(pool, &new_person).await.unwrap();
|
let inserted_person = Person::create(pool, &new_person).await.unwrap();
|
||||||
|
|
||||||
let local_user_form = LocalUserInsertForm::builder()
|
let local_user_form = LocalUserInsertForm::test_form(inserted_person.id);
|
||||||
.person_id(inserted_person.id)
|
|
||||||
.password_encrypted("123456".to_string())
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let inserted_local_user = LocalUser::create(pool, &local_user_form, vec![])
|
let inserted_local_user = LocalUser::create(pool, &local_user_form, vec![])
|
||||||
.await
|
.await
|
||||||
|
|
|
@ -11,6 +11,7 @@ use lemmy_db_schema::{
|
||||||
source::{
|
source::{
|
||||||
comment::{Comment, CommentUpdateForm},
|
comment::{Comment, CommentUpdateForm},
|
||||||
comment_report::CommentReport,
|
comment_report::CommentReport,
|
||||||
|
local_user::LocalUser,
|
||||||
moderator::{ModRemoveComment, ModRemoveCommentForm},
|
moderator::{ModRemoveComment, ModRemoveCommentForm},
|
||||||
},
|
},
|
||||||
traits::{Crud, Reportable},
|
traits::{Crud, Reportable},
|
||||||
|
@ -41,6 +42,14 @@ pub async fn remove_comment(
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
LocalUser::is_higher_mod_or_admin_check(
|
||||||
|
&mut context.pool(),
|
||||||
|
orig_comment.community.id,
|
||||||
|
local_user_view.person.id,
|
||||||
|
vec![orig_comment.creator.id],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
// Don't allow removing or restoring comment which was deleted by user, as it would reveal
|
// Don't allow removing or restoring comment which was deleted by user, as it would reveal
|
||||||
// the comment text in mod log.
|
// the comment text in mod log.
|
||||||
if orig_comment.comment.deleted {
|
if orig_comment.comment.deleted {
|
||||||
|
|
|
@ -9,6 +9,7 @@ use lemmy_api_common::{
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::{
|
source::{
|
||||||
|
local_user::LocalUser,
|
||||||
moderator::{ModRemovePost, ModRemovePostForm},
|
moderator::{ModRemovePost, ModRemovePostForm},
|
||||||
post::{Post, PostUpdateForm},
|
post::{Post, PostUpdateForm},
|
||||||
post_report::PostReport,
|
post_report::PostReport,
|
||||||
|
@ -37,6 +38,14 @@ pub async fn remove_post(
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
LocalUser::is_higher_mod_or_admin_check(
|
||||||
|
&mut context.pool(),
|
||||||
|
orig_post.community_id,
|
||||||
|
local_user_view.person.id,
|
||||||
|
vec![orig_post.creator_id],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
// Update the post
|
// Update the post
|
||||||
let post_id = data.post_id;
|
let post_id = data.post_id;
|
||||||
let removed = data.removed;
|
let removed = data.removed;
|
||||||
|
|
|
@ -150,18 +150,18 @@ pub async fn register(
|
||||||
.unwrap_or(site_view.site.content_warning.is_some());
|
.unwrap_or(site_view.site.content_warning.is_some());
|
||||||
|
|
||||||
// Create the local user
|
// Create the local user
|
||||||
let local_user_form = LocalUserInsertForm::builder()
|
let local_user_form = LocalUserInsertForm {
|
||||||
.person_id(inserted_person.id)
|
email: data.email.as_deref().map(str::to_lowercase),
|
||||||
.email(data.email.as_deref().map(str::to_lowercase))
|
password_encrypted: data.password.to_string(),
|
||||||
.password_encrypted(data.password.to_string())
|
show_nsfw: Some(show_nsfw),
|
||||||
.show_nsfw(Some(show_nsfw))
|
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))
|
post_listing_mode: Some(local_site.default_post_listing_mode),
|
||||||
.post_listing_mode(Some(local_site.default_post_listing_mode))
|
interface_language: language_tags.first().cloned(),
|
||||||
.interface_language(language_tags.first().cloned())
|
|
||||||
// If its the initial site setup, they are an admin
|
// If its the initial site setup, they are an admin
|
||||||
.admin(Some(!local_site.site_setup))
|
admin: Some(!local_site.site_setup),
|
||||||
.build();
|
..LocalUserInsertForm::new(inserted_person.id, data.password.to_string())
|
||||||
|
};
|
||||||
|
|
||||||
let all_languages = Language::read_all(&mut context.pool()).await?;
|
let all_languages = Language::read_all(&mut context.pool()).await?;
|
||||||
// use hashset to avoid duplicates
|
// use hashset to avoid duplicates
|
||||||
|
|
|
@ -345,10 +345,7 @@ mod tests {
|
||||||
};
|
};
|
||||||
let person = Person::create(&mut context.pool(), &person_form).await?;
|
let person = Person::create(&mut context.pool(), &person_form).await?;
|
||||||
|
|
||||||
let user_form = LocalUserInsertForm::builder()
|
let user_form = LocalUserInsertForm::test_form(person.id);
|
||||||
.person_id(person.id)
|
|
||||||
.password_encrypted("pass".to_string())
|
|
||||||
.build();
|
|
||||||
let local_user = LocalUser::create(&mut context.pool(), &user_form, vec![]).await?;
|
let local_user = LocalUser::create(&mut context.pool(), &user_form, vec![]).await?;
|
||||||
|
|
||||||
Ok(
|
Ok(
|
||||||
|
|
|
@ -533,10 +533,7 @@ mod tests {
|
||||||
|
|
||||||
let person_form = PersonInsertForm::test_form(instance.id, "my test person");
|
let person_form = PersonInsertForm::test_form(instance.id, "my test person");
|
||||||
let person = Person::create(pool, &person_form).await.unwrap();
|
let person = Person::create(pool, &person_form).await.unwrap();
|
||||||
let local_user_form = LocalUserInsertForm::builder()
|
let local_user_form = LocalUserInsertForm::test_form(person.id);
|
||||||
.person_id(person.id)
|
|
||||||
.password_encrypted("my_pw".to_string())
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let local_user = LocalUser::create(pool, &local_user_form, vec![])
|
let local_user = LocalUser::create(pool, &local_user_form, vec![])
|
||||||
.await
|
.await
|
||||||
|
@ -645,10 +642,7 @@ mod tests {
|
||||||
|
|
||||||
let person_form = PersonInsertForm::test_form(instance.id, "my test person");
|
let person_form = PersonInsertForm::test_form(instance.id, "my test person");
|
||||||
let person = Person::create(pool, &person_form).await.unwrap();
|
let person = Person::create(pool, &person_form).await.unwrap();
|
||||||
let local_user_form = LocalUserInsertForm::builder()
|
let local_user_form = LocalUserInsertForm::test_form(person.id);
|
||||||
.person_id(person.id)
|
|
||||||
.password_encrypted("my_pw".to_string())
|
|
||||||
.build();
|
|
||||||
let local_user = LocalUser::create(pool, &local_user_form, vec![])
|
let local_user = LocalUser::create(pool, &local_user_form, vec![])
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
@ -1,7 +1,14 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
diesel::{DecoratableTarget, OptionalExtension},
|
diesel::{DecoratableTarget, OptionalExtension},
|
||||||
newtypes::{CommunityId, DbUrl, PersonId},
|
newtypes::{CommunityId, DbUrl, PersonId},
|
||||||
schema::{community, community_follower, instance},
|
schema::{
|
||||||
|
community,
|
||||||
|
community_follower,
|
||||||
|
community_moderator,
|
||||||
|
community_person_ban,
|
||||||
|
instance,
|
||||||
|
post,
|
||||||
|
},
|
||||||
source::{
|
source::{
|
||||||
actor_language::CommunityLanguage,
|
actor_language::CommunityLanguage,
|
||||||
community::{
|
community::{
|
||||||
|
@ -42,6 +49,7 @@ use diesel::{
|
||||||
Queryable,
|
Queryable,
|
||||||
};
|
};
|
||||||
use diesel_async::RunQueryDsl;
|
use diesel_async::RunQueryDsl;
|
||||||
|
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl Crud for Community {
|
impl Crud for Community {
|
||||||
|
@ -83,9 +91,8 @@ impl Joinable for CommunityModerator {
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
community_moderator_form: &CommunityModeratorForm,
|
community_moderator_form: &CommunityModeratorForm,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
use crate::schema::community_moderator::dsl::community_moderator;
|
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
insert_into(community_moderator)
|
insert_into(community_moderator::table)
|
||||||
.values(community_moderator_form)
|
.values(community_moderator_form)
|
||||||
.get_result::<Self>(conn)
|
.get_result::<Self>(conn)
|
||||||
.await
|
.await
|
||||||
|
@ -95,9 +102,8 @@ impl Joinable for CommunityModerator {
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
community_moderator_form: &CommunityModeratorForm,
|
community_moderator_form: &CommunityModeratorForm,
|
||||||
) -> Result<usize, Error> {
|
) -> Result<usize, Error> {
|
||||||
use crate::schema::community_moderator::dsl::community_moderator;
|
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
diesel::delete(community_moderator.find((
|
diesel::delete(community_moderator::table.find((
|
||||||
community_moderator_form.person_id,
|
community_moderator_form.person_id,
|
||||||
community_moderator_form.community_id,
|
community_moderator_form.community_id,
|
||||||
)))
|
)))
|
||||||
|
@ -147,25 +153,23 @@ impl Community {
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
url: &DbUrl,
|
url: &DbUrl,
|
||||||
) -> Result<Option<(Community, CollectionType)>, Error> {
|
) -> Result<Option<(Community, CollectionType)>, Error> {
|
||||||
use crate::schema::community::dsl::{featured_url, moderators_url};
|
|
||||||
use CollectionType::*;
|
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
let res = community::table
|
let res = community::table
|
||||||
.filter(moderators_url.eq(url))
|
.filter(community::moderators_url.eq(url))
|
||||||
.first(conn)
|
.first(conn)
|
||||||
.await
|
.await
|
||||||
.optional()?;
|
.optional()?;
|
||||||
|
|
||||||
if let Some(c) = res {
|
if let Some(c) = res {
|
||||||
Ok(Some((c, Moderators)))
|
Ok(Some((c, CollectionType::Moderators)))
|
||||||
} else {
|
} else {
|
||||||
let res = community::table
|
let res = community::table
|
||||||
.filter(featured_url.eq(url))
|
.filter(community::featured_url.eq(url))
|
||||||
.first(conn)
|
.first(conn)
|
||||||
.await
|
.await
|
||||||
.optional()?;
|
.optional()?;
|
||||||
if let Some(c) = res {
|
if let Some(c) = res {
|
||||||
Ok(Some((c, Featured)))
|
Ok(Some((c, CollectionType::Featured)))
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
@ -177,7 +181,6 @@ impl Community {
|
||||||
posts: Vec<Post>,
|
posts: Vec<Post>,
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
use crate::schema::post;
|
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
for p in &posts {
|
for p in &posts {
|
||||||
debug_assert!(p.community_id == community_id);
|
debug_assert!(p.community_id == community_id);
|
||||||
|
@ -185,10 +188,10 @@ impl Community {
|
||||||
// Mark the given posts as featured and all other posts as not featured.
|
// Mark the given posts as featured and all other posts as not featured.
|
||||||
let post_ids = posts.iter().map(|p| p.id);
|
let post_ids = posts.iter().map(|p| p.id);
|
||||||
update(post::table)
|
update(post::table)
|
||||||
.filter(post::dsl::community_id.eq(community_id))
|
.filter(post::community_id.eq(community_id))
|
||||||
// This filter is just for performance
|
// This filter is just for performance
|
||||||
.filter(post::dsl::featured_community.or(post::dsl::id.eq_any(post_ids.clone())))
|
.filter(post::featured_community.or(post::id.eq_any(post_ids.clone())))
|
||||||
.set(post::dsl::featured_community.eq(post::dsl::id.eq_any(post_ids)))
|
.set(post::featured_community.eq(post::id.eq_any(post_ids)))
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -200,37 +203,68 @@ impl CommunityModerator {
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
for_community_id: CommunityId,
|
for_community_id: CommunityId,
|
||||||
) -> Result<usize, Error> {
|
) -> Result<usize, Error> {
|
||||||
use crate::schema::community_moderator::dsl::{community_id, community_moderator};
|
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
|
|
||||||
diesel::delete(community_moderator.filter(community_id.eq(for_community_id)))
|
diesel::delete(
|
||||||
.execute(conn)
|
community_moderator::table.filter(community_moderator::community_id.eq(for_community_id)),
|
||||||
.await
|
)
|
||||||
|
.execute(conn)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn leave_all_communities(
|
pub async fn leave_all_communities(
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
for_person_id: PersonId,
|
for_person_id: PersonId,
|
||||||
) -> Result<usize, Error> {
|
) -> Result<usize, Error> {
|
||||||
use crate::schema::community_moderator::dsl::{community_moderator, person_id};
|
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
diesel::delete(community_moderator.filter(person_id.eq(for_person_id)))
|
diesel::delete(
|
||||||
.execute(conn)
|
community_moderator::table.filter(community_moderator::person_id.eq(for_person_id)),
|
||||||
.await
|
)
|
||||||
|
.execute(conn)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_person_moderated_communities(
|
pub async fn get_person_moderated_communities(
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
for_person_id: PersonId,
|
for_person_id: PersonId,
|
||||||
) -> Result<Vec<CommunityId>, Error> {
|
) -> Result<Vec<CommunityId>, Error> {
|
||||||
use crate::schema::community_moderator::dsl::{community_id, community_moderator, person_id};
|
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
community_moderator
|
community_moderator::table
|
||||||
.filter(person_id.eq(for_person_id))
|
.filter(community_moderator::person_id.eq(for_person_id))
|
||||||
.select(community_id)
|
.select(community_moderator::community_id)
|
||||||
.load::<CommunityId>(conn)
|
.load::<CommunityId>(conn)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks to make sure the acting moderator was added earlier than the target moderator
|
||||||
|
pub async fn is_higher_mod_check(
|
||||||
|
pool: &mut DbPool<'_>,
|
||||||
|
for_community_id: CommunityId,
|
||||||
|
mod_person_id: PersonId,
|
||||||
|
target_person_ids: Vec<PersonId>,
|
||||||
|
) -> LemmyResult<()> {
|
||||||
|
let conn = &mut get_conn(pool).await?;
|
||||||
|
|
||||||
|
// Build the list of persons
|
||||||
|
let mut persons = target_person_ids;
|
||||||
|
persons.push(mod_person_id);
|
||||||
|
persons.dedup();
|
||||||
|
|
||||||
|
let res = community_moderator::table
|
||||||
|
.filter(community_moderator::community_id.eq(for_community_id))
|
||||||
|
.filter(community_moderator::person_id.eq_any(persons))
|
||||||
|
.order_by(community_moderator::published)
|
||||||
|
// This does a limit 1 select first
|
||||||
|
.first::<CommunityModerator>(conn)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// If the first result sorted by published is the acting mod
|
||||||
|
if res.person_id == mod_person_id {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(LemmyErrorType::NotHigherMod)?
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
@ -240,11 +274,13 @@ impl Bannable for CommunityPersonBan {
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
community_person_ban_form: &CommunityPersonBanForm,
|
community_person_ban_form: &CommunityPersonBanForm,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
use crate::schema::community_person_ban::dsl::{community_id, community_person_ban, person_id};
|
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
insert_into(community_person_ban)
|
insert_into(community_person_ban::table)
|
||||||
.values(community_person_ban_form)
|
.values(community_person_ban_form)
|
||||||
.on_conflict((community_id, person_id))
|
.on_conflict((
|
||||||
|
community_person_ban::community_id,
|
||||||
|
community_person_ban::person_id,
|
||||||
|
))
|
||||||
.do_update()
|
.do_update()
|
||||||
.set(community_person_ban_form)
|
.set(community_person_ban_form)
|
||||||
.get_result::<Self>(conn)
|
.get_result::<Self>(conn)
|
||||||
|
@ -255,9 +291,8 @@ impl Bannable for CommunityPersonBan {
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
community_person_ban_form: &CommunityPersonBanForm,
|
community_person_ban_form: &CommunityPersonBanForm,
|
||||||
) -> Result<usize, Error> {
|
) -> Result<usize, Error> {
|
||||||
use crate::schema::community_person_ban::dsl::community_person_ban;
|
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
diesel::delete(community_person_ban.find((
|
diesel::delete(community_person_ban::table.find((
|
||||||
community_person_ban_form.person_id,
|
community_person_ban_form.person_id,
|
||||||
community_person_ban_form.community_id,
|
community_person_ban_form.community_id,
|
||||||
)))
|
)))
|
||||||
|
@ -291,11 +326,10 @@ impl CommunityFollower {
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
remote_community_id: CommunityId,
|
remote_community_id: CommunityId,
|
||||||
) -> Result<bool, Error> {
|
) -> Result<bool, Error> {
|
||||||
use crate::schema::community_follower::dsl::{community_follower, community_id};
|
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
select(exists(
|
select(exists(community_follower::table.filter(
|
||||||
community_follower.filter(community_id.eq(remote_community_id)),
|
community_follower::community_id.eq(remote_community_id),
|
||||||
))
|
)))
|
||||||
.get_result(conn)
|
.get_result(conn)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
@ -316,11 +350,13 @@ impl Queryable<sql_types::Nullable<sql_types::Bool>, Pg> for SubscribedType {
|
||||||
impl Followable for CommunityFollower {
|
impl Followable for CommunityFollower {
|
||||||
type Form = CommunityFollowerForm;
|
type Form = CommunityFollowerForm;
|
||||||
async fn follow(pool: &mut DbPool<'_>, form: &CommunityFollowerForm) -> Result<Self, Error> {
|
async fn follow(pool: &mut DbPool<'_>, form: &CommunityFollowerForm) -> Result<Self, Error> {
|
||||||
use crate::schema::community_follower::dsl::{community_follower, community_id, person_id};
|
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
insert_into(community_follower)
|
insert_into(community_follower::table)
|
||||||
.values(form)
|
.values(form)
|
||||||
.on_conflict((community_id, person_id))
|
.on_conflict((
|
||||||
|
community_follower::community_id,
|
||||||
|
community_follower::person_id,
|
||||||
|
))
|
||||||
.do_update()
|
.do_update()
|
||||||
.set(form)
|
.set(form)
|
||||||
.get_result::<Self>(conn)
|
.get_result::<Self>(conn)
|
||||||
|
@ -331,17 +367,16 @@ impl Followable for CommunityFollower {
|
||||||
community_id: CommunityId,
|
community_id: CommunityId,
|
||||||
person_id: PersonId,
|
person_id: PersonId,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
use crate::schema::community_follower::dsl::{community_follower, pending};
|
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
diesel::update(community_follower.find((person_id, community_id)))
|
diesel::update(community_follower::table.find((person_id, community_id)))
|
||||||
.set(pending.eq(false))
|
.set(community_follower::pending.eq(false))
|
||||||
.get_result::<Self>(conn)
|
.get_result::<Self>(conn)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn unfollow(pool: &mut DbPool<'_>, form: &CommunityFollowerForm) -> Result<usize, Error> {
|
async fn unfollow(pool: &mut DbPool<'_>, form: &CommunityFollowerForm) -> Result<usize, Error> {
|
||||||
use crate::schema::community_follower::dsl::community_follower;
|
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
diesel::delete(community_follower.find((form.person_id, form.community_id)))
|
diesel::delete(community_follower::table.find((form.person_id, form.community_id)))
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
@ -397,10 +432,8 @@ impl ApubActor for Community {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[allow(clippy::unwrap_used)]
|
|
||||||
#[allow(clippy::indexing_slicing)]
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
source::{
|
source::{
|
||||||
community::{
|
community::{
|
||||||
|
@ -415,28 +448,30 @@ mod tests {
|
||||||
CommunityUpdateForm,
|
CommunityUpdateForm,
|
||||||
},
|
},
|
||||||
instance::Instance,
|
instance::Instance,
|
||||||
|
local_user::LocalUser,
|
||||||
person::{Person, PersonInsertForm},
|
person::{Person, PersonInsertForm},
|
||||||
},
|
},
|
||||||
traits::{Bannable, Crud, Followable, Joinable},
|
traits::{Bannable, Crud, Followable, Joinable},
|
||||||
utils::build_db_pool_for_tests,
|
utils::build_db_pool_for_tests,
|
||||||
CommunityVisibility,
|
CommunityVisibility,
|
||||||
};
|
};
|
||||||
|
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[serial]
|
#[serial]
|
||||||
async fn test_crud() {
|
async fn test_crud() -> LemmyResult<()> {
|
||||||
let pool = &build_db_pool_for_tests().await;
|
let pool = &build_db_pool_for_tests().await;
|
||||||
let pool = &mut pool.into();
|
let pool = &mut pool.into();
|
||||||
|
|
||||||
let inserted_instance = Instance::read_or_create(pool, "my_domain.tld".to_string())
|
let inserted_instance = Instance::read_or_create(pool, "my_domain.tld".to_string()).await?;
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let new_person = PersonInsertForm::test_form(inserted_instance.id, "bobbee");
|
let bobby_person = PersonInsertForm::test_form(inserted_instance.id, "bobby");
|
||||||
|
let inserted_bobby = Person::create(pool, &bobby_person).await?;
|
||||||
|
|
||||||
let inserted_person = Person::create(pool, &new_person).await.unwrap();
|
let artemis_person = PersonInsertForm::test_form(inserted_instance.id, "artemis");
|
||||||
|
let inserted_artemis = Person::create(pool, &artemis_person).await?;
|
||||||
|
|
||||||
let new_community = CommunityInsertForm::builder()
|
let new_community = CommunityInsertForm::builder()
|
||||||
.name("TIL".into())
|
.name("TIL".into())
|
||||||
|
@ -445,7 +480,7 @@ mod tests {
|
||||||
.instance_id(inserted_instance.id)
|
.instance_id(inserted_instance.id)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let inserted_community = Community::create(pool, &new_community).await.unwrap();
|
let inserted_community = Community::create(pool, &new_community).await?;
|
||||||
|
|
||||||
let expected_community = Community {
|
let expected_community = Community {
|
||||||
id: inserted_community.id,
|
id: inserted_community.id,
|
||||||
|
@ -477,91 +512,120 @@ mod tests {
|
||||||
|
|
||||||
let community_follower_form = CommunityFollowerForm {
|
let community_follower_form = CommunityFollowerForm {
|
||||||
community_id: inserted_community.id,
|
community_id: inserted_community.id,
|
||||||
person_id: inserted_person.id,
|
person_id: inserted_bobby.id,
|
||||||
pending: false,
|
pending: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let inserted_community_follower = CommunityFollower::follow(pool, &community_follower_form)
|
let inserted_community_follower =
|
||||||
.await
|
CommunityFollower::follow(pool, &community_follower_form).await?;
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let expected_community_follower = CommunityFollower {
|
let expected_community_follower = CommunityFollower {
|
||||||
community_id: inserted_community.id,
|
community_id: inserted_community.id,
|
||||||
person_id: inserted_person.id,
|
person_id: inserted_bobby.id,
|
||||||
pending: false,
|
pending: false,
|
||||||
published: inserted_community_follower.published,
|
published: inserted_community_follower.published,
|
||||||
};
|
};
|
||||||
|
|
||||||
let community_moderator_form = CommunityModeratorForm {
|
let bobby_moderator_form = CommunityModeratorForm {
|
||||||
community_id: inserted_community.id,
|
community_id: inserted_community.id,
|
||||||
person_id: inserted_person.id,
|
person_id: inserted_bobby.id,
|
||||||
};
|
};
|
||||||
|
|
||||||
let inserted_community_moderator = CommunityModerator::join(pool, &community_moderator_form)
|
let inserted_bobby_moderator = CommunityModerator::join(pool, &bobby_moderator_form).await?;
|
||||||
.await
|
|
||||||
.unwrap();
|
let artemis_moderator_form = CommunityModeratorForm {
|
||||||
|
community_id: inserted_community.id,
|
||||||
|
person_id: inserted_artemis.id,
|
||||||
|
};
|
||||||
|
|
||||||
|
let _inserted_artemis_moderator =
|
||||||
|
CommunityModerator::join(pool, &artemis_moderator_form).await?;
|
||||||
|
|
||||||
let expected_community_moderator = CommunityModerator {
|
let expected_community_moderator = CommunityModerator {
|
||||||
community_id: inserted_community.id,
|
community_id: inserted_community.id,
|
||||||
person_id: inserted_person.id,
|
person_id: inserted_bobby.id,
|
||||||
published: inserted_community_moderator.published,
|
published: inserted_bobby_moderator.published,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let moderator_person_ids = vec![inserted_bobby.id, inserted_artemis.id];
|
||||||
|
|
||||||
|
// Make sure bobby is marked as a higher mod than artemis, and vice versa
|
||||||
|
let bobby_higher_check = CommunityModerator::is_higher_mod_check(
|
||||||
|
pool,
|
||||||
|
inserted_community.id,
|
||||||
|
inserted_bobby.id,
|
||||||
|
moderator_person_ids.clone(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
assert!(bobby_higher_check.is_ok());
|
||||||
|
|
||||||
|
// Also check the other is_higher_mod_or_admin function just in case
|
||||||
|
let bobby_higher_check_2 = LocalUser::is_higher_mod_or_admin_check(
|
||||||
|
pool,
|
||||||
|
inserted_community.id,
|
||||||
|
inserted_bobby.id,
|
||||||
|
moderator_person_ids.clone(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
assert!(bobby_higher_check_2.is_ok());
|
||||||
|
|
||||||
|
// This should throw an error, since artemis was added later
|
||||||
|
let artemis_higher_check = CommunityModerator::is_higher_mod_check(
|
||||||
|
pool,
|
||||||
|
inserted_community.id,
|
||||||
|
inserted_artemis.id,
|
||||||
|
moderator_person_ids,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
assert!(artemis_higher_check.is_err());
|
||||||
|
|
||||||
let community_person_ban_form = CommunityPersonBanForm {
|
let community_person_ban_form = CommunityPersonBanForm {
|
||||||
community_id: inserted_community.id,
|
community_id: inserted_community.id,
|
||||||
person_id: inserted_person.id,
|
person_id: inserted_bobby.id,
|
||||||
expires: None,
|
expires: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let inserted_community_person_ban = CommunityPersonBan::ban(pool, &community_person_ban_form)
|
let inserted_community_person_ban =
|
||||||
.await
|
CommunityPersonBan::ban(pool, &community_person_ban_form).await?;
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let expected_community_person_ban = CommunityPersonBan {
|
let expected_community_person_ban = CommunityPersonBan {
|
||||||
community_id: inserted_community.id,
|
community_id: inserted_community.id,
|
||||||
person_id: inserted_person.id,
|
person_id: inserted_bobby.id,
|
||||||
published: inserted_community_person_ban.published,
|
published: inserted_community_person_ban.published,
|
||||||
expires: None,
|
expires: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let read_community = Community::read(pool, inserted_community.id)
|
let read_community = Community::read(pool, inserted_community.id)
|
||||||
.await
|
.await?
|
||||||
.unwrap()
|
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let update_community_form = CommunityUpdateForm {
|
let update_community_form = CommunityUpdateForm {
|
||||||
title: Some("nada".to_owned()),
|
title: Some("nada".to_owned()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let updated_community = Community::update(pool, inserted_community.id, &update_community_form)
|
let updated_community =
|
||||||
.await
|
Community::update(pool, inserted_community.id, &update_community_form).await?;
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let ignored_community = CommunityFollower::unfollow(pool, &community_follower_form)
|
let ignored_community = CommunityFollower::unfollow(pool, &community_follower_form).await?;
|
||||||
.await
|
let left_community = CommunityModerator::leave(pool, &bobby_moderator_form).await?;
|
||||||
.unwrap();
|
let unban = CommunityPersonBan::unban(pool, &community_person_ban_form).await?;
|
||||||
let left_community = CommunityModerator::leave(pool, &community_moderator_form)
|
let num_deleted = Community::delete(pool, inserted_community.id).await?;
|
||||||
.await
|
Person::delete(pool, inserted_bobby.id).await?;
|
||||||
.unwrap();
|
Person::delete(pool, inserted_artemis.id).await?;
|
||||||
let unban = CommunityPersonBan::unban(pool, &community_person_ban_form)
|
Instance::delete(pool, inserted_instance.id).await?;
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
let num_deleted = Community::delete(pool, inserted_community.id)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
Person::delete(pool, inserted_person.id).await.unwrap();
|
|
||||||
Instance::delete(pool, inserted_instance.id).await.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(expected_community, read_community);
|
assert_eq!(expected_community, read_community);
|
||||||
assert_eq!(expected_community, inserted_community);
|
assert_eq!(expected_community, inserted_community);
|
||||||
assert_eq!(expected_community, updated_community);
|
assert_eq!(expected_community, updated_community);
|
||||||
assert_eq!(expected_community_follower, inserted_community_follower);
|
assert_eq!(expected_community_follower, inserted_community_follower);
|
||||||
assert_eq!(expected_community_moderator, inserted_community_moderator);
|
assert_eq!(expected_community_moderator, inserted_bobby_moderator);
|
||||||
assert_eq!(expected_community_person_ban, inserted_community_person_ban);
|
assert_eq!(expected_community_person_ban, inserted_community_person_ban);
|
||||||
assert_eq!(1, ignored_community);
|
assert_eq!(1, ignored_community);
|
||||||
assert_eq!(1, left_community);
|
assert_eq!(1, left_community);
|
||||||
assert_eq!(1, unban);
|
assert_eq!(1, unban);
|
||||||
// assert_eq!(2, loaded_count);
|
// assert_eq!(2, loaded_count);
|
||||||
assert_eq!(1, num_deleted);
|
assert_eq!(1, num_deleted);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
newtypes::{DbUrl, LanguageId, LocalUserId, PersonId},
|
newtypes::{CommunityId, DbUrl, LanguageId, LocalUserId, PersonId},
|
||||||
schema::{community, local_user, person, registration_application},
|
schema::{community, community_moderator, local_user, person, registration_application},
|
||||||
source::{
|
source::{
|
||||||
actor_language::LocalUserLanguage,
|
actor_language::LocalUserLanguage,
|
||||||
local_user::{LocalUser, LocalUserInsertForm, LocalUserUpdateForm},
|
local_user::{LocalUser, LocalUserInsertForm, LocalUserUpdateForm},
|
||||||
|
@ -19,11 +19,13 @@ use bcrypt::{hash, DEFAULT_COST};
|
||||||
use diesel::{
|
use diesel::{
|
||||||
dsl::{insert_into, not, IntervalDsl},
|
dsl::{insert_into, not, IntervalDsl},
|
||||||
result::Error,
|
result::Error,
|
||||||
|
CombineDsl,
|
||||||
ExpressionMethods,
|
ExpressionMethods,
|
||||||
JoinOnDsl,
|
JoinOnDsl,
|
||||||
QueryDsl,
|
QueryDsl,
|
||||||
};
|
};
|
||||||
use diesel_async::RunQueryDsl;
|
use diesel_async::RunQueryDsl;
|
||||||
|
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
|
||||||
|
|
||||||
impl LocalUser {
|
impl LocalUser {
|
||||||
pub async fn create(
|
pub async fn create(
|
||||||
|
@ -216,6 +218,72 @@ impl LocalUser {
|
||||||
blocked_instances,
|
blocked_instances,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks to make sure the acting admin is higher than the target admin
|
||||||
|
pub async fn is_higher_admin_check(
|
||||||
|
pool: &mut DbPool<'_>,
|
||||||
|
admin_person_id: PersonId,
|
||||||
|
target_person_ids: Vec<PersonId>,
|
||||||
|
) -> LemmyResult<()> {
|
||||||
|
let conn = &mut get_conn(pool).await?;
|
||||||
|
|
||||||
|
// Build the list of persons
|
||||||
|
let mut persons = target_person_ids;
|
||||||
|
persons.push(admin_person_id);
|
||||||
|
persons.dedup();
|
||||||
|
|
||||||
|
let res = local_user::table
|
||||||
|
.filter(local_user::admin.eq(true))
|
||||||
|
.filter(local_user::person_id.eq_any(persons))
|
||||||
|
.order_by(local_user::id)
|
||||||
|
// This does a limit 1 select first
|
||||||
|
.first::<LocalUser>(conn)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// If the first result sorted by published is the acting admin
|
||||||
|
if res.person_id == admin_person_id {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(LemmyErrorType::NotHigherAdmin)?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks to make sure the acting moderator is higher than the target moderator
|
||||||
|
pub async fn is_higher_mod_or_admin_check(
|
||||||
|
pool: &mut DbPool<'_>,
|
||||||
|
for_community_id: CommunityId,
|
||||||
|
admin_person_id: PersonId,
|
||||||
|
target_person_ids: Vec<PersonId>,
|
||||||
|
) -> LemmyResult<()> {
|
||||||
|
let conn = &mut get_conn(pool).await?;
|
||||||
|
|
||||||
|
// Build the list of persons
|
||||||
|
let mut persons = target_person_ids;
|
||||||
|
persons.push(admin_person_id);
|
||||||
|
persons.dedup();
|
||||||
|
|
||||||
|
let admins = local_user::table
|
||||||
|
.filter(local_user::admin.eq(true))
|
||||||
|
.filter(local_user::person_id.eq_any(&persons))
|
||||||
|
.order_by(local_user::id)
|
||||||
|
.select(local_user::person_id);
|
||||||
|
|
||||||
|
let mods = community_moderator::table
|
||||||
|
.filter(community_moderator::community_id.eq(for_community_id))
|
||||||
|
.filter(community_moderator::person_id.eq_any(&persons))
|
||||||
|
.order_by(community_moderator::published)
|
||||||
|
.select(community_moderator::person_id);
|
||||||
|
|
||||||
|
let res = admins.union_all(mods).get_results::<PersonId>(conn).await?;
|
||||||
|
let first_person = res.as_slice().first().ok_or(LemmyErrorType::NotHigherMod)?;
|
||||||
|
|
||||||
|
// If the first result sorted by published is the acting mod
|
||||||
|
if *first_person == admin_person_id {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(LemmyErrorType::NotHigherMod)?
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds some helper functions for an optional LocalUser
|
/// Adds some helper functions for an optional LocalUser
|
||||||
|
@ -278,10 +346,14 @@ impl LocalUserOptionHelper for Option<&LocalUser> {
|
||||||
|
|
||||||
impl LocalUserInsertForm {
|
impl LocalUserInsertForm {
|
||||||
pub fn test_form(person_id: PersonId) -> Self {
|
pub fn test_form(person_id: PersonId) -> Self {
|
||||||
Self::builder()
|
Self::new(person_id, String::new())
|
||||||
.person_id(person_id)
|
}
|
||||||
.password_encrypted(String::new())
|
|
||||||
.build()
|
pub fn test_form_admin(person_id: PersonId) -> Self {
|
||||||
|
LocalUserInsertForm {
|
||||||
|
admin: Some(true),
|
||||||
|
..Self::test_form(person_id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,3 +365,58 @@ pub struct UserBackupLists {
|
||||||
pub blocked_users: Vec<DbUrl>,
|
pub blocked_users: Vec<DbUrl>,
|
||||||
pub blocked_instances: Vec<String>,
|
pub blocked_instances: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
|
mod tests {
|
||||||
|
use crate::{
|
||||||
|
source::{
|
||||||
|
instance::Instance,
|
||||||
|
local_user::{LocalUser, LocalUserInsertForm},
|
||||||
|
person::{Person, PersonInsertForm},
|
||||||
|
},
|
||||||
|
traits::Crud,
|
||||||
|
utils::build_db_pool_for_tests,
|
||||||
|
};
|
||||||
|
use lemmy_utils::error::LemmyResult;
|
||||||
|
use serial_test::serial;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
#[serial]
|
||||||
|
async fn test_admin_higher_check() -> LemmyResult<()> {
|
||||||
|
let pool = &build_db_pool_for_tests().await;
|
||||||
|
let pool = &mut pool.into();
|
||||||
|
|
||||||
|
let inserted_instance = Instance::read_or_create(pool, "my_domain.tld".to_string()).await?;
|
||||||
|
|
||||||
|
let fiona_person = PersonInsertForm::test_form(inserted_instance.id, "fiona");
|
||||||
|
let inserted_fiona_person = Person::create(pool, &fiona_person).await?;
|
||||||
|
|
||||||
|
let fiona_local_user_form = LocalUserInsertForm::test_form_admin(inserted_fiona_person.id);
|
||||||
|
let _inserted_fiona_local_user =
|
||||||
|
LocalUser::create(pool, &fiona_local_user_form, vec![]).await?;
|
||||||
|
|
||||||
|
let delores_person = PersonInsertForm::test_form(inserted_instance.id, "delores");
|
||||||
|
let inserted_delores_person = Person::create(pool, &delores_person).await?;
|
||||||
|
let delores_local_user_form = LocalUserInsertForm::test_form_admin(inserted_delores_person.id);
|
||||||
|
let _inserted_delores_local_user =
|
||||||
|
LocalUser::create(pool, &delores_local_user_form, vec![]).await?;
|
||||||
|
|
||||||
|
let admin_person_ids = vec![inserted_fiona_person.id, inserted_delores_person.id];
|
||||||
|
|
||||||
|
// Make sure fiona is marked as a higher admin than delores, and vice versa
|
||||||
|
let fiona_higher_check =
|
||||||
|
LocalUser::is_higher_admin_check(pool, inserted_fiona_person.id, admin_person_ids.clone())
|
||||||
|
.await;
|
||||||
|
assert!(fiona_higher_check.is_ok());
|
||||||
|
|
||||||
|
// This should throw an error, since delores was added later
|
||||||
|
let delores_higher_check =
|
||||||
|
LocalUser::is_higher_admin_check(pool, inserted_delores_person.id, admin_person_ids).await;
|
||||||
|
assert!(delores_higher_check.is_err());
|
||||||
|
|
||||||
|
Instance::delete(pool, inserted_instance.id).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -72,10 +72,7 @@ mod tests {
|
||||||
let inserted_instance = Instance::read_or_create(pool, "my_domain.tld".to_string()).await?;
|
let inserted_instance = Instance::read_or_create(pool, "my_domain.tld".to_string()).await?;
|
||||||
let new_person = PersonInsertForm::test_form(inserted_instance.id, "thommy prw");
|
let new_person = PersonInsertForm::test_form(inserted_instance.id, "thommy prw");
|
||||||
let inserted_person = Person::create(pool, &new_person).await?;
|
let inserted_person = Person::create(pool, &new_person).await?;
|
||||||
let new_local_user = LocalUserInsertForm::builder()
|
let new_local_user = LocalUserInsertForm::test_form(inserted_person.id);
|
||||||
.person_id(inserted_person.id)
|
|
||||||
.password_encrypted("pass".to_string())
|
|
||||||
.build();
|
|
||||||
let inserted_local_user = LocalUser::create(pool, &new_local_user, vec![]).await?;
|
let inserted_local_user = LocalUser::create(pool, &new_local_user, vec![]).await?;
|
||||||
|
|
||||||
// Create password reset token
|
// Create password reset token
|
||||||
|
|
|
@ -182,11 +182,10 @@ impl ApubActor for Person {
|
||||||
impl Followable for PersonFollower {
|
impl Followable for PersonFollower {
|
||||||
type Form = PersonFollowerForm;
|
type Form = PersonFollowerForm;
|
||||||
async fn follow(pool: &mut DbPool<'_>, form: &PersonFollowerForm) -> Result<Self, Error> {
|
async fn follow(pool: &mut DbPool<'_>, form: &PersonFollowerForm) -> Result<Self, Error> {
|
||||||
use crate::schema::person_follower::dsl::{follower_id, person_follower, person_id};
|
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
insert_into(person_follower)
|
insert_into(person_follower::table)
|
||||||
.values(form)
|
.values(form)
|
||||||
.on_conflict((follower_id, person_id))
|
.on_conflict((person_follower::follower_id, person_follower::person_id))
|
||||||
.do_update()
|
.do_update()
|
||||||
.set(form)
|
.set(form)
|
||||||
.get_result::<Self>(conn)
|
.get_result::<Self>(conn)
|
||||||
|
@ -196,9 +195,8 @@ impl Followable for PersonFollower {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
async fn unfollow(pool: &mut DbPool<'_>, form: &PersonFollowerForm) -> Result<usize, Error> {
|
async fn unfollow(pool: &mut DbPool<'_>, form: &PersonFollowerForm) -> Result<usize, Error> {
|
||||||
use crate::schema::person_follower::dsl::person_follower;
|
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
diesel::delete(person_follower.find((form.follower_id, form.person_id)))
|
diesel::delete(person_follower::table.find((form.follower_id, form.person_id)))
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
@ -220,7 +218,6 @@ impl PersonFollower {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[allow(clippy::unwrap_used)]
|
|
||||||
#[allow(clippy::indexing_slicing)]
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
|
@ -232,22 +229,21 @@ mod tests {
|
||||||
traits::{Crud, Followable},
|
traits::{Crud, Followable},
|
||||||
utils::build_db_pool_for_tests,
|
utils::build_db_pool_for_tests,
|
||||||
};
|
};
|
||||||
|
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[serial]
|
#[serial]
|
||||||
async fn test_crud() {
|
async fn test_crud() -> LemmyResult<()> {
|
||||||
let pool = &build_db_pool_for_tests().await;
|
let pool = &build_db_pool_for_tests().await;
|
||||||
let pool = &mut pool.into();
|
let pool = &mut pool.into();
|
||||||
|
|
||||||
let inserted_instance = Instance::read_or_create(pool, "my_domain.tld".to_string())
|
let inserted_instance = Instance::read_or_create(pool, "my_domain.tld".to_string()).await?;
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let new_person = PersonInsertForm::test_form(inserted_instance.id, "holly");
|
let new_person = PersonInsertForm::test_form(inserted_instance.id, "holly");
|
||||||
|
|
||||||
let inserted_person = Person::create(pool, &new_person).await.unwrap();
|
let inserted_person = Person::create(pool, &new_person).await?;
|
||||||
|
|
||||||
let expected_person = Person {
|
let expected_person = Person {
|
||||||
id: inserted_person.id,
|
id: inserted_person.id,
|
||||||
|
@ -274,57 +270,54 @@ mod tests {
|
||||||
};
|
};
|
||||||
|
|
||||||
let read_person = Person::read(pool, inserted_person.id)
|
let read_person = Person::read(pool, inserted_person.id)
|
||||||
.await
|
.await?
|
||||||
.unwrap()
|
.ok_or(LemmyErrorType::CouldntFindPerson)?;
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let update_person_form = PersonUpdateForm {
|
let update_person_form = PersonUpdateForm {
|
||||||
actor_id: Some(inserted_person.actor_id.clone()),
|
actor_id: Some(inserted_person.actor_id.clone()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let updated_person = Person::update(pool, inserted_person.id, &update_person_form)
|
let updated_person = Person::update(pool, inserted_person.id, &update_person_form).await?;
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let num_deleted = Person::delete(pool, inserted_person.id).await.unwrap();
|
let num_deleted = Person::delete(pool, inserted_person.id).await?;
|
||||||
Instance::delete(pool, inserted_instance.id).await.unwrap();
|
Instance::delete(pool, inserted_instance.id).await?;
|
||||||
|
|
||||||
assert_eq!(expected_person, read_person);
|
assert_eq!(expected_person, read_person);
|
||||||
assert_eq!(expected_person, inserted_person);
|
assert_eq!(expected_person, inserted_person);
|
||||||
assert_eq!(expected_person, updated_person);
|
assert_eq!(expected_person, updated_person);
|
||||||
assert_eq!(1, num_deleted);
|
assert_eq!(1, num_deleted);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[serial]
|
#[serial]
|
||||||
async fn follow() {
|
async fn follow() -> LemmyResult<()> {
|
||||||
let pool = &build_db_pool_for_tests().await;
|
let pool = &build_db_pool_for_tests().await;
|
||||||
let pool = &mut pool.into();
|
let pool = &mut pool.into();
|
||||||
let inserted_instance = Instance::read_or_create(pool, "my_domain.tld".to_string())
|
let inserted_instance = Instance::read_or_create(pool, "my_domain.tld".to_string()).await?;
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let person_form_1 = PersonInsertForm::test_form(inserted_instance.id, "erich");
|
let person_form_1 = PersonInsertForm::test_form(inserted_instance.id, "erich");
|
||||||
let person_1 = Person::create(pool, &person_form_1).await.unwrap();
|
let person_1 = Person::create(pool, &person_form_1).await?;
|
||||||
let person_form_2 = PersonInsertForm::test_form(inserted_instance.id, "michele");
|
let person_form_2 = PersonInsertForm::test_form(inserted_instance.id, "michele");
|
||||||
let person_2 = Person::create(pool, &person_form_2).await.unwrap();
|
let person_2 = Person::create(pool, &person_form_2).await?;
|
||||||
|
|
||||||
let follow_form = PersonFollowerForm {
|
let follow_form = PersonFollowerForm {
|
||||||
person_id: person_1.id,
|
person_id: person_1.id,
|
||||||
follower_id: person_2.id,
|
follower_id: person_2.id,
|
||||||
pending: false,
|
pending: false,
|
||||||
};
|
};
|
||||||
let person_follower = PersonFollower::follow(pool, &follow_form).await.unwrap();
|
let person_follower = PersonFollower::follow(pool, &follow_form).await?;
|
||||||
assert_eq!(person_1.id, person_follower.person_id);
|
assert_eq!(person_1.id, person_follower.person_id);
|
||||||
assert_eq!(person_2.id, person_follower.follower_id);
|
assert_eq!(person_2.id, person_follower.follower_id);
|
||||||
assert!(!person_follower.pending);
|
assert!(!person_follower.pending);
|
||||||
|
|
||||||
let followers = PersonFollower::list_followers(pool, person_1.id)
|
let followers = PersonFollower::list_followers(pool, person_1.id).await?;
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(vec![person_2], followers);
|
assert_eq!(vec![person_2], followers);
|
||||||
|
|
||||||
let unfollow = PersonFollower::unfollow(pool, &follow_form).await.unwrap();
|
let unfollow = PersonFollower::unfollow(pool, &follow_form).await?;
|
||||||
assert_eq!(1, unfollow);
|
assert_eq!(1, unfollow);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ use serde::{Deserialize, Serialize};
|
||||||
use serde_with::skip_serializing_none;
|
use serde_with::skip_serializing_none;
|
||||||
#[cfg(feature = "full")]
|
#[cfg(feature = "full")]
|
||||||
use ts_rs::TS;
|
use ts_rs::TS;
|
||||||
use typed_builder::TypedBuilder;
|
|
||||||
|
|
||||||
#[skip_serializing_none]
|
#[skip_serializing_none]
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
|
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
|
||||||
|
@ -69,38 +68,59 @@ pub struct LocalUser {
|
||||||
pub collapse_bot_comments: bool,
|
pub collapse_bot_comments: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, TypedBuilder)]
|
#[derive(Clone, derive_new::new)]
|
||||||
#[builder(field_defaults(default))]
|
|
||||||
#[cfg_attr(feature = "full", derive(Insertable))]
|
#[cfg_attr(feature = "full", derive(Insertable))]
|
||||||
#[cfg_attr(feature = "full", diesel(table_name = local_user))]
|
#[cfg_attr(feature = "full", diesel(table_name = local_user))]
|
||||||
pub struct LocalUserInsertForm {
|
pub struct LocalUserInsertForm {
|
||||||
#[builder(!default)]
|
|
||||||
pub person_id: PersonId,
|
pub person_id: PersonId,
|
||||||
#[builder(!default)]
|
|
||||||
pub password_encrypted: String,
|
pub password_encrypted: String,
|
||||||
|
#[new(default)]
|
||||||
pub email: Option<String>,
|
pub email: Option<String>,
|
||||||
|
#[new(default)]
|
||||||
pub show_nsfw: Option<bool>,
|
pub show_nsfw: Option<bool>,
|
||||||
|
#[new(default)]
|
||||||
pub theme: Option<String>,
|
pub theme: Option<String>,
|
||||||
|
#[new(default)]
|
||||||
pub default_sort_type: Option<SortType>,
|
pub default_sort_type: Option<SortType>,
|
||||||
|
#[new(default)]
|
||||||
pub default_listing_type: Option<ListingType>,
|
pub default_listing_type: Option<ListingType>,
|
||||||
|
#[new(default)]
|
||||||
pub interface_language: Option<String>,
|
pub interface_language: Option<String>,
|
||||||
|
#[new(default)]
|
||||||
pub show_avatars: Option<bool>,
|
pub show_avatars: Option<bool>,
|
||||||
|
#[new(default)]
|
||||||
pub send_notifications_to_email: Option<bool>,
|
pub send_notifications_to_email: Option<bool>,
|
||||||
|
#[new(default)]
|
||||||
pub show_bot_accounts: Option<bool>,
|
pub show_bot_accounts: Option<bool>,
|
||||||
|
#[new(default)]
|
||||||
pub show_scores: Option<bool>,
|
pub show_scores: Option<bool>,
|
||||||
|
#[new(default)]
|
||||||
pub show_read_posts: Option<bool>,
|
pub show_read_posts: Option<bool>,
|
||||||
|
#[new(default)]
|
||||||
pub email_verified: Option<bool>,
|
pub email_verified: Option<bool>,
|
||||||
|
#[new(default)]
|
||||||
pub accepted_application: Option<bool>,
|
pub accepted_application: Option<bool>,
|
||||||
|
#[new(default)]
|
||||||
pub totp_2fa_secret: Option<Option<String>>,
|
pub totp_2fa_secret: Option<Option<String>>,
|
||||||
|
#[new(default)]
|
||||||
pub open_links_in_new_tab: Option<bool>,
|
pub open_links_in_new_tab: Option<bool>,
|
||||||
|
#[new(default)]
|
||||||
pub blur_nsfw: Option<bool>,
|
pub blur_nsfw: Option<bool>,
|
||||||
|
#[new(default)]
|
||||||
pub auto_expand: Option<bool>,
|
pub auto_expand: Option<bool>,
|
||||||
|
#[new(default)]
|
||||||
pub infinite_scroll_enabled: Option<bool>,
|
pub infinite_scroll_enabled: Option<bool>,
|
||||||
|
#[new(default)]
|
||||||
pub admin: Option<bool>,
|
pub admin: Option<bool>,
|
||||||
|
#[new(default)]
|
||||||
pub post_listing_mode: Option<PostListingMode>,
|
pub post_listing_mode: Option<PostListingMode>,
|
||||||
|
#[new(default)]
|
||||||
pub totp_2fa_enabled: Option<bool>,
|
pub totp_2fa_enabled: Option<bool>,
|
||||||
|
#[new(default)]
|
||||||
pub enable_keyboard_navigation: Option<bool>,
|
pub enable_keyboard_navigation: Option<bool>,
|
||||||
|
#[new(default)]
|
||||||
pub enable_animated_images: Option<bool>,
|
pub enable_animated_images: Option<bool>,
|
||||||
|
#[new(default)]
|
||||||
pub collapse_bot_comments: Option<bool>,
|
pub collapse_bot_comments: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -301,10 +301,7 @@ 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()
|
let new_local_user = LocalUserInsertForm::test_form(inserted_timmy.id);
|
||||||
.person_id(inserted_timmy.id)
|
|
||||||
.password_encrypted("123".to_string())
|
|
||||||
.build();
|
|
||||||
let timmy_local_user = LocalUser::create(pool, &new_local_user, vec![])
|
let timmy_local_user = LocalUser::create(pool, &new_local_user, vec![])
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
@ -484,11 +484,8 @@ mod tests {
|
||||||
|
|
||||||
let timmy_person_form = PersonInsertForm::test_form(inserted_instance.id, "timmy");
|
let timmy_person_form = PersonInsertForm::test_form(inserted_instance.id, "timmy");
|
||||||
let inserted_timmy_person = Person::create(pool, &timmy_person_form).await?;
|
let inserted_timmy_person = Person::create(pool, &timmy_person_form).await?;
|
||||||
let timmy_local_user_form = LocalUserInsertForm::builder()
|
let timmy_local_user_form = LocalUserInsertForm::test_form_admin(inserted_timmy_person.id);
|
||||||
.person_id(inserted_timmy_person.id)
|
|
||||||
.admin(Some(true))
|
|
||||||
.password_encrypted(String::new())
|
|
||||||
.build();
|
|
||||||
let inserted_timmy_local_user = LocalUser::create(pool, &timmy_local_user_form, vec![]).await?;
|
let inserted_timmy_local_user = LocalUser::create(pool, &timmy_local_user_form, vec![]).await?;
|
||||||
|
|
||||||
let sara_person_form = PersonInsertForm::test_form(inserted_instance.id, "sara");
|
let sara_person_form = PersonInsertForm::test_form(inserted_instance.id, "sara");
|
||||||
|
|
|
@ -323,10 +323,7 @@ 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()
|
let new_local_user = LocalUserInsertForm::test_form(inserted_timmy.id);
|
||||||
.person_id(inserted_timmy.id)
|
|
||||||
.password_encrypted("123".to_string())
|
|
||||||
.build();
|
|
||||||
let timmy_local_user = LocalUser::create(pool, &new_local_user, vec![])
|
let timmy_local_user = LocalUser::create(pool, &new_local_user, vec![])
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
@ -167,11 +167,7 @@ mod tests {
|
||||||
|
|
||||||
let inserted_timmy_person = Person::create(pool, &timmy_person_form).await.unwrap();
|
let inserted_timmy_person = Person::create(pool, &timmy_person_form).await.unwrap();
|
||||||
|
|
||||||
let timmy_local_user_form = LocalUserInsertForm::builder()
|
let timmy_local_user_form = LocalUserInsertForm::test_form_admin(inserted_timmy_person.id);
|
||||||
.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, vec![])
|
let _inserted_timmy_local_user = LocalUser::create(pool, &timmy_local_user_form, vec![])
|
||||||
.await
|
.await
|
||||||
|
@ -181,10 +177,7 @@ mod tests {
|
||||||
|
|
||||||
let inserted_sara_person = Person::create(pool, &sara_person_form).await.unwrap();
|
let inserted_sara_person = Person::create(pool, &sara_person_form).await.unwrap();
|
||||||
|
|
||||||
let sara_local_user_form = LocalUserInsertForm::builder()
|
let sara_local_user_form = LocalUserInsertForm::test_form(inserted_sara_person.id);
|
||||||
.person_id(inserted_sara_person.id)
|
|
||||||
.password_encrypted("nada".to_string())
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let inserted_sara_local_user = LocalUser::create(pool, &sara_local_user_form, vec![])
|
let inserted_sara_local_user = LocalUser::create(pool, &sara_local_user_form, vec![])
|
||||||
.await
|
.await
|
||||||
|
@ -209,10 +202,7 @@ mod tests {
|
||||||
|
|
||||||
let inserted_jess_person = Person::create(pool, &jess_person_form).await.unwrap();
|
let inserted_jess_person = Person::create(pool, &jess_person_form).await.unwrap();
|
||||||
|
|
||||||
let jess_local_user_form = LocalUserInsertForm::builder()
|
let jess_local_user_form = LocalUserInsertForm::test_form(inserted_jess_person.id);
|
||||||
.person_id(inserted_jess_person.id)
|
|
||||||
.password_encrypted("nada".to_string())
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let inserted_jess_local_user = LocalUser::create(pool, &jess_local_user_form, vec![])
|
let inserted_jess_local_user = LocalUser::create(pool, &jess_local_user_form, vec![])
|
||||||
.await
|
.await
|
||||||
|
|
|
@ -275,10 +275,7 @@ mod tests {
|
||||||
|
|
||||||
let inserted_person = Person::create(pool, &new_person).await.unwrap();
|
let inserted_person = Person::create(pool, &new_person).await.unwrap();
|
||||||
|
|
||||||
let local_user_form = LocalUserInsertForm::builder()
|
let local_user_form = LocalUserInsertForm::test_form(inserted_person.id);
|
||||||
.person_id(inserted_person.id)
|
|
||||||
.password_encrypted(String::new())
|
|
||||||
.build();
|
|
||||||
let local_user = LocalUser::create(pool, &local_user_form, vec![])
|
let local_user = LocalUser::create(pool, &local_user_form, vec![])
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
@ -196,10 +196,7 @@ mod tests {
|
||||||
..PersonInsertForm::test_form(inserted_instance.id, "alice")
|
..PersonInsertForm::test_form(inserted_instance.id, "alice")
|
||||||
};
|
};
|
||||||
let alice = Person::create(pool, &alice_form).await?;
|
let alice = Person::create(pool, &alice_form).await?;
|
||||||
let alice_local_user_form = LocalUserInsertForm::builder()
|
let alice_local_user_form = LocalUserInsertForm::test_form(alice.id);
|
||||||
.person_id(alice.id)
|
|
||||||
.password_encrypted(String::new())
|
|
||||||
.build();
|
|
||||||
let alice_local_user = LocalUser::create(pool, &alice_local_user_form, vec![]).await?;
|
let alice_local_user = LocalUser::create(pool, &alice_local_user_form, vec![]).await?;
|
||||||
|
|
||||||
let bob_form = PersonInsertForm {
|
let bob_form = PersonInsertForm {
|
||||||
|
@ -208,10 +205,7 @@ mod tests {
|
||||||
..PersonInsertForm::test_form(inserted_instance.id, "bob")
|
..PersonInsertForm::test_form(inserted_instance.id, "bob")
|
||||||
};
|
};
|
||||||
let bob = Person::create(pool, &bob_form).await?;
|
let bob = Person::create(pool, &bob_form).await?;
|
||||||
let bob_local_user_form = LocalUserInsertForm::builder()
|
let bob_local_user_form = LocalUserInsertForm::test_form(bob.id);
|
||||||
.person_id(bob.id)
|
|
||||||
.password_encrypted(String::new())
|
|
||||||
.build();
|
|
||||||
let bob_local_user = LocalUser::create(pool, &bob_local_user_form, vec![]).await?;
|
let bob_local_user = LocalUser::create(pool, &bob_local_user_form, vec![]).await?;
|
||||||
|
|
||||||
Ok(Data {
|
Ok(Data {
|
||||||
|
|
|
@ -38,6 +38,8 @@ pub enum LemmyErrorType {
|
||||||
NotTopAdmin,
|
NotTopAdmin,
|
||||||
NotTopMod,
|
NotTopMod,
|
||||||
NotLoggedIn,
|
NotLoggedIn,
|
||||||
|
NotHigherMod,
|
||||||
|
NotHigherAdmin,
|
||||||
SiteBan,
|
SiteBan,
|
||||||
Deleted,
|
Deleted,
|
||||||
BannedFromCommunity,
|
BannedFromCommunity,
|
||||||
|
|
|
@ -468,12 +468,11 @@ async fn initialize_local_site_2022_10_10(
|
||||||
};
|
};
|
||||||
let person_inserted = Person::create(pool, &person_form).await?;
|
let person_inserted = Person::create(pool, &person_form).await?;
|
||||||
|
|
||||||
let local_user_form = LocalUserInsertForm::builder()
|
let local_user_form = LocalUserInsertForm {
|
||||||
.person_id(person_inserted.id)
|
email: setup.admin_email.clone(),
|
||||||
.password_encrypted(setup.admin_password.clone())
|
admin: Some(true),
|
||||||
.email(setup.admin_email.clone())
|
..LocalUserInsertForm::new(person_inserted.id, setup.admin_password.clone())
|
||||||
.admin(Some(true))
|
};
|
||||||
.build();
|
|
||||||
LocalUser::create(pool, &local_user_form, vec![]).await?;
|
LocalUser::create(pool, &local_user_form, vec![]).await?;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -146,10 +146,7 @@ mod tests {
|
||||||
|
|
||||||
let inserted_person = Person::create(pool, &new_person).await.unwrap();
|
let inserted_person = Person::create(pool, &new_person).await.unwrap();
|
||||||
|
|
||||||
let local_user_form = LocalUserInsertForm::builder()
|
let local_user_form = LocalUserInsertForm::test_form(inserted_person.id);
|
||||||
.person_id(inserted_person.id)
|
|
||||||
.password_encrypted("123456".to_string())
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let inserted_local_user = LocalUser::create(pool, &local_user_form, vec![])
|
let inserted_local_user = LocalUser::create(pool, &local_user_form, vec![])
|
||||||
.await
|
.await
|
||||||
|
|
Loading…
Reference in a new issue