mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-10-01 01:36:12 -04:00
Compare commits
No commits in common. "a5eaad7afd1fd27a7432beff67ae10182db20b93" and "622ce6c976adf69667abf8ad5b9dfbd0897d9998" have entirely different histories.
a5eaad7afd
...
622ce6c976
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -2538,7 +2538,6 @@ dependencies = [
|
|||||||
"actix-web",
|
"actix-web",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bcrypt",
|
"bcrypt",
|
||||||
"chrono",
|
|
||||||
"futures",
|
"futures",
|
||||||
"lemmy_api_common",
|
"lemmy_api_common",
|
||||||
"lemmy_db_schema",
|
"lemmy_db_schema",
|
||||||
|
@ -21,16 +21,16 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^29.5.12",
|
"@types/jest": "^29.5.12",
|
||||||
"@types/node": "^22.3.0",
|
"@types/node": "^22.0.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.1.0",
|
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
||||||
"@typescript-eslint/parser": "^8.1.0",
|
"@typescript-eslint/parser": "^8.0.0",
|
||||||
"eslint": "^9.9.0",
|
"eslint": "^9.8.0",
|
||||||
"eslint-plugin-prettier": "^5.1.3",
|
"eslint-plugin-prettier": "^5.1.3",
|
||||||
"jest": "^29.5.0",
|
"jest": "^29.5.0",
|
||||||
"lemmy-js-client": "0.20.0-alpha.12",
|
"lemmy-js-client": "0.20.0-alpha.12",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.2.5",
|
||||||
"ts-jest": "^29.1.0",
|
"ts-jest": "^29.1.0",
|
||||||
"typescript": "^5.5.4",
|
"typescript": "^5.5.4",
|
||||||
"typescript-eslint": "^8.1.0"
|
"typescript-eslint": "^8.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,16 +12,16 @@ importers:
|
|||||||
specifier: ^29.5.12
|
specifier: ^29.5.12
|
||||||
version: 29.5.12
|
version: 29.5.12
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^22.3.0
|
specifier: ^22.0.2
|
||||||
version: 22.3.0
|
version: 22.3.0
|
||||||
'@typescript-eslint/eslint-plugin':
|
'@typescript-eslint/eslint-plugin':
|
||||||
specifier: ^8.1.0
|
specifier: ^8.0.0
|
||||||
version: 8.1.0(@typescript-eslint/parser@8.1.0(eslint@9.9.0)(typescript@5.5.4))(eslint@9.9.0)(typescript@5.5.4)
|
version: 8.1.0(@typescript-eslint/parser@8.1.0(eslint@9.9.0)(typescript@5.5.4))(eslint@9.9.0)(typescript@5.5.4)
|
||||||
'@typescript-eslint/parser':
|
'@typescript-eslint/parser':
|
||||||
specifier: ^8.1.0
|
specifier: ^8.0.0
|
||||||
version: 8.1.0(eslint@9.9.0)(typescript@5.5.4)
|
version: 8.1.0(eslint@9.9.0)(typescript@5.5.4)
|
||||||
eslint:
|
eslint:
|
||||||
specifier: ^9.9.0
|
specifier: ^9.8.0
|
||||||
version: 9.9.0
|
version: 9.9.0
|
||||||
eslint-plugin-prettier:
|
eslint-plugin-prettier:
|
||||||
specifier: ^5.1.3
|
specifier: ^5.1.3
|
||||||
@ -42,7 +42,7 @@ importers:
|
|||||||
specifier: ^5.5.4
|
specifier: ^5.5.4
|
||||||
version: 5.5.4
|
version: 5.5.4
|
||||||
typescript-eslint:
|
typescript-eslint:
|
||||||
specifier: ^8.1.0
|
specifier: ^8.0.0
|
||||||
version: 8.1.0(eslint@9.9.0)(typescript@5.5.4)
|
version: 8.1.0(eslint@9.9.0)(typescript@5.5.4)
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
@ -628,7 +628,7 @@ test("Enforce community ban for federated user", async () => {
|
|||||||
// Alpha tries to make post on beta, but it fails because of ban
|
// Alpha tries to make post on beta, but it fails because of ban
|
||||||
await expect(
|
await expect(
|
||||||
createPost(alpha, betaCommunity.community.id),
|
createPost(alpha, betaCommunity.community.id),
|
||||||
).rejects.toStrictEqual(Error("person_is_banned_from_community"));
|
).rejects.toStrictEqual(Error("banned_from_community"));
|
||||||
|
|
||||||
// Unban alpha
|
// Unban alpha
|
||||||
let unBanAlpha = await banPersonFromCommunity(
|
let unBanAlpha = await banPersonFromCommunity(
|
||||||
|
@ -52,12 +52,15 @@ pub async fn add_mod_to_community(
|
|||||||
// moderator. This is necessary because otherwise the action would be rejected
|
// moderator. This is necessary because otherwise the action would be rejected
|
||||||
// by the community's home instance.
|
// by the community's home instance.
|
||||||
if local_user_view.local_user.admin && !community.local {
|
if local_user_view.local_user.admin && !community.local {
|
||||||
CommunityModeratorView::check_is_community_moderator(
|
let is_mod = CommunityModeratorView::is_community_moderator(
|
||||||
&mut context.pool(),
|
&mut context.pool(),
|
||||||
community.id,
|
community.id,
|
||||||
local_user_view.person.id,
|
local_user_view.person.id,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
if !is_mod {
|
||||||
|
Err(LemmyErrorType::NotAModerator)?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update in local database
|
// Update in local database
|
||||||
|
@ -265,6 +265,8 @@ pub async fn local_user_view_from_jwt(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
#[allow(clippy::unwrap_used)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -63,7 +63,9 @@ pub async fn save_user_settings(
|
|||||||
let previous_email = local_user_view.local_user.email.clone().unwrap_or_default();
|
let previous_email = local_user_view.local_user.email.clone().unwrap_or_default();
|
||||||
// if email was changed, check that it is not taken and send verification mail
|
// if email was changed, check that it is not taken and send verification mail
|
||||||
if previous_email.deref() != email {
|
if previous_email.deref() != email {
|
||||||
LocalUser::check_is_email_taken(&mut context.pool(), email).await?;
|
if LocalUser::is_email_taken(&mut context.pool(), email).await? {
|
||||||
|
return Err(LemmyErrorType::EmailAlreadyExists)?;
|
||||||
|
}
|
||||||
send_verification_email(
|
send_verification_email(
|
||||||
&local_user_view,
|
&local_user_view,
|
||||||
email,
|
email,
|
||||||
@ -130,6 +132,7 @@ pub async fn save_user_settings(
|
|||||||
send_notifications_to_email: data.send_notifications_to_email,
|
send_notifications_to_email: data.send_notifications_to_email,
|
||||||
show_nsfw: data.show_nsfw,
|
show_nsfw: data.show_nsfw,
|
||||||
blur_nsfw: data.blur_nsfw,
|
blur_nsfw: data.blur_nsfw,
|
||||||
|
auto_expand: data.auto_expand,
|
||||||
show_bot_accounts: data.show_bot_accounts,
|
show_bot_accounts: data.show_bot_accounts,
|
||||||
default_post_sort_type,
|
default_post_sort_type,
|
||||||
default_comment_sort_type,
|
default_comment_sort_type,
|
||||||
|
@ -34,7 +34,7 @@ use lemmy_db_views::structs::LocalUserView;
|
|||||||
use lemmy_utils::{error::LemmyResult, LemmyErrorType, CACHE_DURATION_API};
|
use lemmy_utils::{error::LemmyResult, LemmyErrorType, CACHE_DURATION_API};
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
async fn create_test_site(context: &Data<LemmyContext>) -> LemmyResult<(Instance, LocalUserView)> {
|
async fn create_test_site(context: &Data<LemmyContext>) -> LemmyResult<(Instance, LocalUserView)> {
|
||||||
let pool = &mut context.pool();
|
let pool = &mut context.pool();
|
||||||
|
|
||||||
@ -109,7 +109,7 @@ async fn signup(
|
|||||||
Ok((local_user, application))
|
Ok((local_user, application))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
async fn get_application_statuses(
|
async fn get_application_statuses(
|
||||||
context: &Data<LemmyContext>,
|
context: &Data<LemmyContext>,
|
||||||
admin: LocalUserView,
|
admin: LocalUserView,
|
||||||
@ -138,9 +138,10 @@ async fn get_application_statuses(
|
|||||||
Ok((application_count, unread_applications, all_applications))
|
Ok((application_count, unread_applications, all_applications))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[serial]
|
#[allow(clippy::indexing_slicing)]
|
||||||
|
#[allow(clippy::unwrap_used)]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[expect(clippy::indexing_slicing)]
|
#[serial]
|
||||||
async fn test_application_approval() -> LemmyResult<()> {
|
async fn test_application_approval() -> LemmyResult<()> {
|
||||||
let context = LemmyContext::init_test_context().await;
|
let context = LemmyContext::init_test_context().await;
|
||||||
let pool = &mut context.pool();
|
let pool = &mut context.pool();
|
||||||
|
@ -42,7 +42,7 @@ pub async fn get_sitemap(context: Data<LemmyContext>) -> LemmyResult<HttpRespons
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
pub(crate) mod tests {
|
pub(crate) mod tests {
|
||||||
|
|
||||||
use crate::sitemap::generate_urlset;
|
use crate::sitemap::generate_urlset;
|
||||||
|
@ -29,8 +29,12 @@ impl Claims {
|
|||||||
let claims =
|
let claims =
|
||||||
decode::<Claims>(jwt, &key, &validation).with_lemmy_type(LemmyErrorType::NotLoggedIn)?;
|
decode::<Claims>(jwt, &key, &validation).with_lemmy_type(LemmyErrorType::NotLoggedIn)?;
|
||||||
let user_id = LocalUserId(claims.claims.sub.parse()?);
|
let user_id = LocalUserId(claims.claims.sub.parse()?);
|
||||||
LoginToken::validate(&mut context.pool(), user_id, jwt).await?;
|
let is_valid = LoginToken::validate(&mut context.pool(), user_id, jwt).await?;
|
||||||
Ok(user_id)
|
if !is_valid {
|
||||||
|
Err(LemmyErrorType::NotLoggedIn)?
|
||||||
|
} else {
|
||||||
|
Ok(user_id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn generate(
|
pub async fn generate(
|
||||||
@ -69,7 +73,8 @@ impl Claims {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::{claims::Claims, context::LemmyContext};
|
use crate::{claims::Claims, context::LemmyContext};
|
||||||
|
@ -19,12 +19,11 @@ pub struct CreateOAuthProvider {
|
|||||||
pub client_id: String,
|
pub client_id: String,
|
||||||
pub client_secret: String,
|
pub client_secret: String,
|
||||||
pub scopes: String,
|
pub scopes: String,
|
||||||
pub auto_verify_email: Option<bool>,
|
pub auto_verify_email: bool,
|
||||||
pub account_linking_enabled: Option<bool>,
|
pub account_linking_enabled: bool,
|
||||||
pub enabled: Option<bool>,
|
pub enabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[skip_serializing_none]
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
#[cfg_attr(feature = "full", derive(TS))]
|
#[cfg_attr(feature = "full", derive(TS))]
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
|
@ -84,8 +84,8 @@ pub struct CaptchaResponse {
|
|||||||
pub struct SaveUserSettings {
|
pub struct SaveUserSettings {
|
||||||
/// Show nsfw posts.
|
/// Show nsfw posts.
|
||||||
pub show_nsfw: Option<bool>,
|
pub show_nsfw: Option<bool>,
|
||||||
/// Blur nsfw posts.
|
|
||||||
pub blur_nsfw: Option<bool>,
|
pub blur_nsfw: Option<bool>,
|
||||||
|
pub auto_expand: Option<bool>,
|
||||||
/// Your user's theme.
|
/// Your user's theme.
|
||||||
pub theme: Option<String>,
|
pub theme: Option<String>,
|
||||||
/// The default post listing type, usually "local"
|
/// The default post listing type, usually "local"
|
||||||
|
@ -30,8 +30,6 @@ pub struct CreatePost {
|
|||||||
pub language_id: Option<LanguageId>,
|
pub language_id: Option<LanguageId>,
|
||||||
/// Instead of fetching a thumbnail, use a custom one.
|
/// Instead of fetching a thumbnail, use a custom one.
|
||||||
pub custom_thumbnail: Option<String>,
|
pub custom_thumbnail: Option<String>,
|
||||||
/// Time when this post should be scheduled. Null means publish immediately.
|
|
||||||
pub scheduled_publish_time: Option<i64>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
@ -126,8 +124,6 @@ pub struct EditPost {
|
|||||||
pub language_id: Option<LanguageId>,
|
pub language_id: Option<LanguageId>,
|
||||||
/// Instead of fetching a thumbnail, use a custom one.
|
/// Instead of fetching a thumbnail, use a custom one.
|
||||||
pub custom_thumbnail: Option<String>,
|
pub custom_thumbnail: Option<String>,
|
||||||
/// Time when this post should be scheduled. Null means publish immediately.
|
|
||||||
pub scheduled_publish_time: Option<i64>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
|
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default, PartialEq, Eq, Hash)]
|
||||||
|
@ -471,7 +471,8 @@ pub async fn replace_image(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -78,7 +78,7 @@ pub struct Search {
|
|||||||
pub listing_type: Option<ListingType>,
|
pub listing_type: Option<ListingType>,
|
||||||
pub page: Option<i64>,
|
pub page: Option<i64>,
|
||||||
pub limit: Option<i64>,
|
pub limit: Option<i64>,
|
||||||
pub title_only: Option<bool>,
|
pub post_title_only: Option<bool>,
|
||||||
pub post_url_only: Option<bool>,
|
pub post_url_only: Option<bool>,
|
||||||
pub saved_only: Option<bool>,
|
pub saved_only: Option<bool>,
|
||||||
pub liked_only: Option<bool>,
|
pub liked_only: Option<bool>,
|
||||||
|
@ -73,7 +73,13 @@ pub async fn is_mod_or_admin(
|
|||||||
community_id: CommunityId,
|
community_id: CommunityId,
|
||||||
) -> LemmyResult<()> {
|
) -> LemmyResult<()> {
|
||||||
check_user_valid(person)?;
|
check_user_valid(person)?;
|
||||||
CommunityView::check_is_mod_or_admin(pool, person.id, community_id).await
|
|
||||||
|
let is_mod_or_admin = CommunityView::is_mod_or_admin(pool, person.id, community_id).await?;
|
||||||
|
if !is_mod_or_admin {
|
||||||
|
Err(LemmyErrorType::NotAModOrAdmin)?
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
@ -104,7 +110,13 @@ pub async fn check_community_mod_of_any_or_admin_action(
|
|||||||
let person = &local_user_view.person;
|
let person = &local_user_view.person;
|
||||||
|
|
||||||
check_user_valid(person)?;
|
check_user_valid(person)?;
|
||||||
CommunityView::check_is_mod_of_any_or_admin(pool, person.id).await
|
|
||||||
|
let is_mod_of_any_or_admin = CommunityView::is_mod_of_any_or_admin(pool, person.id).await?;
|
||||||
|
if !is_mod_of_any_or_admin {
|
||||||
|
Err(LemmyErrorType::NotAModOrAdmin)?
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_admin(local_user_view: &LocalUserView) -> LemmyResult<()> {
|
pub fn is_admin(local_user_view: &LocalUserView) -> LemmyResult<()> {
|
||||||
@ -230,7 +242,7 @@ pub async fn check_community_user_action(
|
|||||||
) -> LemmyResult<()> {
|
) -> LemmyResult<()> {
|
||||||
check_user_valid(person)?;
|
check_user_valid(person)?;
|
||||||
check_community_deleted_removed(community_id, pool).await?;
|
check_community_deleted_removed(community_id, pool).await?;
|
||||||
CommunityPersonBanView::check(pool, person.id, community_id).await?;
|
check_community_ban(person, community_id, pool).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,6 +257,19 @@ async fn check_community_deleted_removed(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn check_community_ban(
|
||||||
|
person: &Person,
|
||||||
|
community_id: CommunityId,
|
||||||
|
pool: &mut DbPool<'_>,
|
||||||
|
) -> LemmyResult<()> {
|
||||||
|
// check if user was banned from site or community
|
||||||
|
let is_banned = CommunityPersonBanView::get(pool, person.id, community_id).await?;
|
||||||
|
if is_banned {
|
||||||
|
Err(LemmyErrorType::BannedFromCommunity)?
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Check that the given user can perform a mod action in the community.
|
/// Check that the given user can perform a mod action in the community.
|
||||||
///
|
///
|
||||||
/// In particular it checks that he is an admin or mod, wasn't banned and the community isn't
|
/// In particular it checks that he is an admin or mod, wasn't banned and the community isn't
|
||||||
@ -256,7 +281,7 @@ pub async fn check_community_mod_action(
|
|||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
) -> LemmyResult<()> {
|
) -> LemmyResult<()> {
|
||||||
is_mod_or_admin(pool, person, community_id).await?;
|
is_mod_or_admin(pool, person, community_id).await?;
|
||||||
CommunityPersonBanView::check(pool, person.id, community_id).await?;
|
check_community_ban(person, community_id, pool).await?;
|
||||||
|
|
||||||
// it must be possible to restore deleted community
|
// it must be possible to restore deleted community
|
||||||
if !allow_deleted {
|
if !allow_deleted {
|
||||||
@ -282,6 +307,51 @@ pub fn check_comment_deleted_or_removed(comment: &Comment) -> LemmyResult<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Throws an error if a recipient has blocked a person.
|
||||||
|
#[tracing::instrument(skip_all)]
|
||||||
|
pub async fn check_person_block(
|
||||||
|
my_id: PersonId,
|
||||||
|
potential_blocker_id: PersonId,
|
||||||
|
pool: &mut DbPool<'_>,
|
||||||
|
) -> LemmyResult<()> {
|
||||||
|
let is_blocked = PersonBlock::read(pool, potential_blocker_id, my_id).await?;
|
||||||
|
if is_blocked {
|
||||||
|
Err(LemmyErrorType::PersonIsBlocked)?
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Throws an error if a recipient has blocked a community.
|
||||||
|
#[tracing::instrument(skip_all)]
|
||||||
|
async fn check_community_block(
|
||||||
|
community_id: CommunityId,
|
||||||
|
person_id: PersonId,
|
||||||
|
pool: &mut DbPool<'_>,
|
||||||
|
) -> LemmyResult<()> {
|
||||||
|
let is_blocked = CommunityBlock::read(pool, person_id, community_id).await?;
|
||||||
|
if is_blocked {
|
||||||
|
Err(LemmyErrorType::CommunityIsBlocked)?
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Throws an error if a recipient has blocked an instance.
|
||||||
|
#[tracing::instrument(skip_all)]
|
||||||
|
async fn check_instance_block(
|
||||||
|
instance_id: InstanceId,
|
||||||
|
person_id: PersonId,
|
||||||
|
pool: &mut DbPool<'_>,
|
||||||
|
) -> LemmyResult<()> {
|
||||||
|
let is_blocked = InstanceBlock::read(pool, person_id, instance_id).await?;
|
||||||
|
if is_blocked {
|
||||||
|
Err(LemmyErrorType::InstanceIsBlocked)?
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub async fn check_person_instance_community_block(
|
pub async fn check_person_instance_community_block(
|
||||||
my_id: PersonId,
|
my_id: PersonId,
|
||||||
@ -290,9 +360,9 @@ pub async fn check_person_instance_community_block(
|
|||||||
community_id: CommunityId,
|
community_id: CommunityId,
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
) -> LemmyResult<()> {
|
) -> LemmyResult<()> {
|
||||||
PersonBlock::read(pool, potential_blocker_id, my_id).await?;
|
check_person_block(my_id, potential_blocker_id, pool).await?;
|
||||||
InstanceBlock::read(pool, potential_blocker_id, community_instance_id).await?;
|
check_instance_block(community_instance_id, potential_blocker_id, pool).await?;
|
||||||
CommunityBlock::read(pool, potential_blocker_id, community_id).await?;
|
check_community_block(community_id, potential_blocker_id, pool).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -776,13 +846,12 @@ pub async fn remove_or_restore_user_data_in_community(
|
|||||||
|
|
||||||
// Comments
|
// Comments
|
||||||
// TODO Diesel doesn't allow updates with joins, so this has to be a loop
|
// TODO Diesel doesn't allow updates with joins, so this has to be a loop
|
||||||
let site = Site::read_local(pool).await?;
|
|
||||||
let comments = CommentQuery {
|
let comments = CommentQuery {
|
||||||
creator_id: Some(banned_person_id),
|
creator_id: Some(banned_person_id),
|
||||||
community_id: Some(community_id),
|
community_id: Some(community_id),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&site, pool)
|
.list(pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
for comment_view in &comments {
|
for comment_view in &comments {
|
||||||
@ -1067,7 +1136,8 @@ fn build_proxied_image_url(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -27,7 +27,6 @@ futures.workspace = true
|
|||||||
uuid = { workspace = true }
|
uuid = { workspace = true }
|
||||||
moka.workspace = true
|
moka.workspace = true
|
||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
chrono.workspace = true
|
|
||||||
webmention = "0.6.0"
|
webmention = "0.6.0"
|
||||||
accept-language = "3.1.0"
|
accept-language = "3.1.0"
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
use super::convert_published_time;
|
|
||||||
use activitypub_federation::config::Data;
|
use activitypub_federation::config::Data;
|
||||||
use actix_web::web::Json;
|
use actix_web::web::Json;
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
@ -96,12 +95,15 @@ pub async fn create_post(
|
|||||||
let community = Community::read(&mut context.pool(), community_id).await?;
|
let community = Community::read(&mut context.pool(), community_id).await?;
|
||||||
if community.posting_restricted_to_mods {
|
if community.posting_restricted_to_mods {
|
||||||
let community_id = data.community_id;
|
let community_id = data.community_id;
|
||||||
CommunityModeratorView::check_is_community_moderator(
|
let is_mod = CommunityModeratorView::is_community_moderator(
|
||||||
&mut context.pool(),
|
&mut context.pool(),
|
||||||
community_id,
|
community_id,
|
||||||
local_user_view.local_user.person_id,
|
local_user_view.local_user.person_id,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
if !is_mod {
|
||||||
|
Err(LemmyErrorType::OnlyModsCanPostInCommunity)?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only need to check if language is allowed in case user set it explicitly. When using default
|
// Only need to check if language is allowed in case user set it explicitly. When using default
|
||||||
@ -126,15 +128,12 @@ pub async fn create_post(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let scheduled_publish_time =
|
|
||||||
convert_published_time(data.scheduled_publish_time, &local_user_view, &context).await?;
|
|
||||||
let post_form = PostInsertForm {
|
let post_form = PostInsertForm {
|
||||||
url: url.map(Into::into),
|
url: url.map(Into::into),
|
||||||
body,
|
body,
|
||||||
alt_text: data.alt_text.clone(),
|
alt_text: data.alt_text.clone(),
|
||||||
nsfw: data.nsfw,
|
nsfw: data.nsfw,
|
||||||
language_id,
|
language_id,
|
||||||
scheduled_publish_time,
|
|
||||||
..PostInsertForm::new(
|
..PostInsertForm::new(
|
||||||
data.name.trim().to_string(),
|
data.name.trim().to_string(),
|
||||||
local_user_view.person.id,
|
local_user_view.person.id,
|
||||||
@ -146,16 +145,10 @@ pub async fn create_post(
|
|||||||
.await
|
.await
|
||||||
.with_lemmy_type(LemmyErrorType::CouldntCreatePost)?;
|
.with_lemmy_type(LemmyErrorType::CouldntCreatePost)?;
|
||||||
|
|
||||||
let federate_post = if scheduled_publish_time.is_none() {
|
|
||||||
send_webmention(inserted_post.clone(), community);
|
|
||||||
|post| Some(SendActivityData::CreatePost(post))
|
|
||||||
} else {
|
|
||||||
|_| None
|
|
||||||
};
|
|
||||||
generate_post_link_metadata(
|
generate_post_link_metadata(
|
||||||
inserted_post.clone(),
|
inserted_post.clone(),
|
||||||
custom_thumbnail.map(Into::into),
|
custom_thumbnail.map(Into::into),
|
||||||
federate_post,
|
|post| Some(SendActivityData::CreatePost(post)),
|
||||||
context.reset_request_count(),
|
context.reset_request_count(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
@ -175,14 +168,11 @@ pub async fn create_post(
|
|||||||
|
|
||||||
mark_post_as_read(person_id, post_id, &mut context.pool()).await?;
|
mark_post_as_read(person_id, post_id, &mut context.pool()).await?;
|
||||||
|
|
||||||
build_post_response(&context, community_id, local_user_view, post_id).await
|
if let Some(url) = inserted_post.url.clone() {
|
||||||
}
|
|
||||||
|
|
||||||
pub fn send_webmention(post: Post, community: Community) {
|
|
||||||
if let Some(url) = post.url.clone() {
|
|
||||||
if community.visibility == CommunityVisibility::Public {
|
if community.visibility == CommunityVisibility::Public {
|
||||||
spawn_try_task(async move {
|
spawn_try_task(async move {
|
||||||
let mut webmention = Webmention::new::<Url>(post.ap_id.clone().into(), url.clone().into())?;
|
let mut webmention =
|
||||||
|
Webmention::new::<Url>(inserted_post.ap_id.clone().into(), url.clone().into())?;
|
||||||
webmention.set_checked(true);
|
webmention.set_checked(true);
|
||||||
match webmention
|
match webmention
|
||||||
.send()
|
.send()
|
||||||
@ -196,4 +186,6 @@ pub fn send_webmention(post: Post, community: Community) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
build_post_response(&context, community_id, local_user_view, post_id).await
|
||||||
}
|
}
|
||||||
|
@ -1,38 +1,5 @@
|
|||||||
use chrono::{DateTime, TimeZone, Utc};
|
|
||||||
use lemmy_api_common::context::LemmyContext;
|
|
||||||
use lemmy_db_schema::source::post::Post;
|
|
||||||
use lemmy_db_views::structs::LocalUserView;
|
|
||||||
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
|
||||||
|
|
||||||
pub mod create;
|
pub mod create;
|
||||||
pub mod delete;
|
pub mod delete;
|
||||||
pub mod read;
|
pub mod read;
|
||||||
pub mod remove;
|
pub mod remove;
|
||||||
pub mod update;
|
pub mod update;
|
||||||
|
|
||||||
async fn convert_published_time(
|
|
||||||
scheduled_publish_time: Option<i64>,
|
|
||||||
local_user_view: &LocalUserView,
|
|
||||||
context: &LemmyContext,
|
|
||||||
) -> LemmyResult<Option<DateTime<Utc>>> {
|
|
||||||
const MAX_SCHEDULED_POSTS: i64 = 10;
|
|
||||||
if let Some(scheduled_publish_time) = scheduled_publish_time {
|
|
||||||
let converted = Utc
|
|
||||||
.timestamp_opt(scheduled_publish_time, 0)
|
|
||||||
.single()
|
|
||||||
.ok_or(LemmyErrorType::InvalidUnixTime)?;
|
|
||||||
if converted < Utc::now() {
|
|
||||||
Err(LemmyErrorType::PostScheduleTimeMustBeInFuture)?;
|
|
||||||
}
|
|
||||||
if !local_user_view.local_user.admin {
|
|
||||||
let count =
|
|
||||||
Post::user_scheduled_post_count(local_user_view.person.id, &mut context.pool()).await?;
|
|
||||||
if count >= MAX_SCHEDULED_POSTS {
|
|
||||||
Err(LemmyErrorType::TooManyScheduledPosts)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(Some(converted))
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
use super::{convert_published_time, create::send_webmention};
|
|
||||||
use activitypub_federation::config::Data;
|
use activitypub_federation::config::Data;
|
||||||
use actix_web::web::Json;
|
use actix_web::web::Json;
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
@ -17,7 +16,6 @@ use lemmy_api_common::{
|
|||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::{
|
source::{
|
||||||
actor_language::CommunityLanguage,
|
actor_language::CommunityLanguage,
|
||||||
community::Community,
|
|
||||||
local_site::LocalSite,
|
local_site::LocalSite,
|
||||||
post::{Post, PostUpdateForm},
|
post::{Post, PostUpdateForm},
|
||||||
},
|
},
|
||||||
@ -109,21 +107,6 @@ pub async fn update_post(
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// handle changes to scheduled_publish_time
|
|
||||||
let scheduled_publish_time = match (
|
|
||||||
orig_post.scheduled_publish_time,
|
|
||||||
data.scheduled_publish_time,
|
|
||||||
) {
|
|
||||||
// schedule time can be changed if post is still scheduled (and not published yet)
|
|
||||||
(Some(_), Some(_)) => {
|
|
||||||
Some(convert_published_time(data.scheduled_publish_time, &local_user_view, &context).await?)
|
|
||||||
}
|
|
||||||
// post was scheduled, gets changed to publish immediately
|
|
||||||
(Some(_), None) => Some(None),
|
|
||||||
// unchanged
|
|
||||||
(_, _) => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let post_form = PostUpdateForm {
|
let post_form = PostUpdateForm {
|
||||||
name: data.name.clone(),
|
name: data.name.clone(),
|
||||||
url,
|
url,
|
||||||
@ -132,7 +115,6 @@ pub async fn update_post(
|
|||||||
nsfw: data.nsfw,
|
nsfw: data.nsfw,
|
||||||
language_id: data.language_id,
|
language_id: data.language_id,
|
||||||
updated: Some(Some(naive_now())),
|
updated: Some(Some(naive_now())),
|
||||||
scheduled_publish_time,
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -141,36 +123,13 @@ pub async fn update_post(
|
|||||||
.await
|
.await
|
||||||
.with_lemmy_type(LemmyErrorType::CouldntUpdatePost)?;
|
.with_lemmy_type(LemmyErrorType::CouldntUpdatePost)?;
|
||||||
|
|
||||||
// send out federation/webmention if necessary
|
generate_post_link_metadata(
|
||||||
match (
|
updated_post.clone(),
|
||||||
orig_post.scheduled_publish_time,
|
custom_thumbnail.flatten().map(Into::into),
|
||||||
data.scheduled_publish_time,
|
|post| Some(SendActivityData::UpdatePost(post)),
|
||||||
) {
|
context.reset_request_count(),
|
||||||
// schedule was removed, send create activity and webmention
|
)
|
||||||
(Some(_), None) => {
|
.await?;
|
||||||
let community = Community::read(&mut context.pool(), orig_post.community_id).await?;
|
|
||||||
send_webmention(updated_post.clone(), community);
|
|
||||||
generate_post_link_metadata(
|
|
||||||
updated_post.clone(),
|
|
||||||
custom_thumbnail.flatten().map(Into::into),
|
|
||||||
|post| Some(SendActivityData::CreatePost(post)),
|
|
||||||
context.reset_request_count(),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
// post was already public, send update
|
|
||||||
(None, _) => {
|
|
||||||
generate_post_link_metadata(
|
|
||||||
updated_post.clone(),
|
|
||||||
custom_thumbnail.flatten().map(Into::into),
|
|
||||||
|post| Some(SendActivityData::UpdatePost(post)),
|
|
||||||
context.reset_request_count(),
|
|
||||||
)
|
|
||||||
.await?
|
|
||||||
}
|
|
||||||
// schedule was changed, do nothing
|
|
||||||
(Some(_), Some(_)) => {}
|
|
||||||
};
|
|
||||||
|
|
||||||
build_post_response(
|
build_post_response(
|
||||||
context.deref(),
|
context.deref(),
|
||||||
|
@ -5,6 +5,7 @@ use lemmy_api_common::{
|
|||||||
private_message::{CreatePrivateMessage, PrivateMessageResponse},
|
private_message::{CreatePrivateMessage, PrivateMessageResponse},
|
||||||
send_activity::{ActivityChannel, SendActivityData},
|
send_activity::{ActivityChannel, SendActivityData},
|
||||||
utils::{
|
utils::{
|
||||||
|
check_person_block,
|
||||||
get_interface_language,
|
get_interface_language,
|
||||||
get_url_blocklist,
|
get_url_blocklist,
|
||||||
local_site_to_slur_regex,
|
local_site_to_slur_regex,
|
||||||
@ -15,7 +16,6 @@ use lemmy_api_common::{
|
|||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::{
|
source::{
|
||||||
local_site::LocalSite,
|
local_site::LocalSite,
|
||||||
person_block::PersonBlock,
|
|
||||||
private_message::{PrivateMessage, PrivateMessageInsertForm},
|
private_message::{PrivateMessage, PrivateMessageInsertForm},
|
||||||
},
|
},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
@ -39,10 +39,10 @@ pub async fn create_private_message(
|
|||||||
let content = process_markdown(&data.content, &slur_regex, &url_blocklist, &context).await?;
|
let content = process_markdown(&data.content, &slur_regex, &url_blocklist, &context).await?;
|
||||||
is_valid_body_field(&content, false)?;
|
is_valid_body_field(&content, false)?;
|
||||||
|
|
||||||
PersonBlock::read(
|
check_person_block(
|
||||||
&mut context.pool(),
|
|
||||||
data.recipient_id,
|
|
||||||
local_user_view.person.id,
|
local_user_view.person.id,
|
||||||
|
data.recipient_id,
|
||||||
|
&mut context.pool(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
@ -189,6 +189,8 @@ fn validate_create_payload(local_site: &LocalSite, create_site: &CreateSite) ->
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
#[allow(clippy::unwrap_used)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::site::create::validate_create_payload;
|
use crate::site::create::validate_create_payload;
|
||||||
|
@ -48,6 +48,8 @@ fn not_zero(val: Option<i32>) -> Option<i32> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
#[allow(clippy::unwrap_used)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::site::{application_question_check, not_zero, site_default_post_listing_type_check};
|
use crate::site::{application_question_check, not_zero, site_default_post_listing_type_check};
|
||||||
|
@ -241,6 +241,8 @@ fn validate_update_payload(local_site: &LocalSite, edit_site: &EditSite) -> Lemm
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
#[allow(clippy::unwrap_used)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::site::update::validate_update_payload;
|
use crate::site::update::validate_update_payload;
|
||||||
|
@ -92,25 +92,36 @@ pub async fn register(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if local_site.site_setup && local_site.captcha_enabled {
|
if local_site.site_setup && local_site.captcha_enabled {
|
||||||
let uuid = uuid::Uuid::parse_str(&data.captcha_uuid.clone().unwrap_or_default())?;
|
if let Some(captcha_uuid) = &data.captcha_uuid {
|
||||||
CaptchaAnswer::check_captcha(
|
let uuid = uuid::Uuid::parse_str(captcha_uuid)?;
|
||||||
&mut context.pool(),
|
let check = CaptchaAnswer::check_captcha(
|
||||||
CheckCaptchaAnswer {
|
&mut context.pool(),
|
||||||
uuid,
|
CheckCaptchaAnswer {
|
||||||
answer: data.captcha_answer.clone().unwrap_or_default(),
|
uuid,
|
||||||
},
|
answer: data.captcha_answer.clone().unwrap_or_default(),
|
||||||
)
|
},
|
||||||
.await?;
|
)
|
||||||
|
.await?;
|
||||||
|
if !check {
|
||||||
|
Err(LemmyErrorType::CaptchaIncorrect)?
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(LemmyErrorType::CaptchaIncorrect)?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let slur_regex = local_site_to_slur_regex(&local_site);
|
let slur_regex = local_site_to_slur_regex(&local_site);
|
||||||
check_slurs(&data.username, &slur_regex)?;
|
check_slurs(&data.username, &slur_regex)?;
|
||||||
check_slurs_opt(&data.answer, &slur_regex)?;
|
check_slurs_opt(&data.answer, &slur_regex)?;
|
||||||
|
|
||||||
Person::check_username_taken(&mut context.pool(), &data.username).await?;
|
if Person::is_username_taken(&mut context.pool(), &data.username).await? {
|
||||||
|
return Err(LemmyErrorType::UsernameAlreadyExists)?;
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(email) = &data.email {
|
if let Some(email) = &data.email {
|
||||||
LocalUser::check_is_email_taken(&mut context.pool(), email).await?;
|
if LocalUser::is_email_taken(&mut context.pool(), email).await? {
|
||||||
|
Err(LemmyErrorType::EmailAlreadyExists)?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have to create both a person, and local_user
|
// We have to create both a person, and local_user
|
||||||
@ -327,7 +338,9 @@ pub async fn authenticate_with_oauth(
|
|||||||
check_slurs(username, &slur_regex)?;
|
check_slurs(username, &slur_regex)?;
|
||||||
check_slurs_opt(&data.answer, &slur_regex)?;
|
check_slurs_opt(&data.answer, &slur_regex)?;
|
||||||
|
|
||||||
Person::check_username_taken(&mut context.pool(), username).await?;
|
if Person::is_username_taken(&mut context.pool(), username).await? {
|
||||||
|
return Err(LemmyErrorType::UsernameAlreadyExists)?;
|
||||||
|
}
|
||||||
|
|
||||||
// We have to create a person, a local_user, and an oauth_account
|
// We have to create a person, a local_user, and an oauth_account
|
||||||
person = create_person(
|
person = create_person(
|
||||||
|
@ -213,13 +213,15 @@ async fn can_accept_activity_in_community(
|
|||||||
context: &Data<LemmyContext>,
|
context: &Data<LemmyContext>,
|
||||||
) -> LemmyResult<()> {
|
) -> LemmyResult<()> {
|
||||||
if let Some(community) = community {
|
if let Some(community) = community {
|
||||||
|
if !community.local
|
||||||
|
&& !CommunityFollower::has_local_followers(&mut context.pool(), community.id).await?
|
||||||
|
{
|
||||||
|
Err(LemmyErrorType::CommunityHasNoFollowers)?
|
||||||
|
}
|
||||||
// Local only community can't federate
|
// Local only community can't federate
|
||||||
if community.visibility != CommunityVisibility::Public {
|
if community.visibility != CommunityVisibility::Public {
|
||||||
return Err(LemmyErrorType::NotFound.into());
|
return Err(LemmyErrorType::NotFound.into());
|
||||||
}
|
}
|
||||||
if !community.local {
|
|
||||||
CommunityFollower::check_has_local_followers(&mut context.pool(), community.id).await?
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,12 @@ pub(crate) async fn verify_person_in_community(
|
|||||||
}
|
}
|
||||||
let person_id = person.id;
|
let person_id = person.id;
|
||||||
let community_id = community.id;
|
let community_id = community.id;
|
||||||
CommunityPersonBanView::check(&mut context.pool(), person_id, community_id).await
|
let is_banned = CommunityPersonBanView::get(&mut context.pool(), person_id, community_id).await?;
|
||||||
|
if is_banned {
|
||||||
|
Err(LemmyErrorType::PersonIsBannedFromCommunity)?
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verify that mod action in community was performed by a moderator.
|
/// Verify that mod action in community was performed by a moderator.
|
||||||
@ -101,6 +106,14 @@ pub(crate) async fn verify_mod_action(
|
|||||||
community: &Community,
|
community: &Community,
|
||||||
context: &Data<LemmyContext>,
|
context: &Data<LemmyContext>,
|
||||||
) -> LemmyResult<()> {
|
) -> LemmyResult<()> {
|
||||||
|
let mod_ = mod_id.dereference(context).await?;
|
||||||
|
|
||||||
|
let is_mod_or_admin =
|
||||||
|
CommunityView::is_mod_or_admin(&mut context.pool(), mod_.id, community.id).await?;
|
||||||
|
if is_mod_or_admin {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
// mod action comes from the same instance as the community, so it was presumably done
|
// mod action comes from the same instance as the community, so it was presumably done
|
||||||
// by an instance admin.
|
// by an instance admin.
|
||||||
// TODO: federate instance admin status and check it here
|
// TODO: federate instance admin status and check it here
|
||||||
@ -108,8 +121,7 @@ pub(crate) async fn verify_mod_action(
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mod_ = mod_id.dereference(context).await?;
|
Err(LemmyErrorType::NotAModerator)?
|
||||||
CommunityView::check_is_mod_or_admin(&mut context.pool(), mod_.id, community.id).await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn verify_is_public(to: &[Url], cc: &[Url]) -> LemmyResult<()> {
|
pub(crate) fn verify_is_public(to: &[Url], cc: &[Url]) -> LemmyResult<()> {
|
||||||
|
@ -123,6 +123,7 @@ impl InCommunity for AnnouncableActivities {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -12,13 +12,10 @@ use lemmy_api_common::{
|
|||||||
utils::check_private_instance,
|
utils::check_private_instance,
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::{comment::Comment, community::Community},
|
source::{comment::Comment, community::Community, local_site::LocalSite},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
};
|
};
|
||||||
use lemmy_db_views::{
|
use lemmy_db_views::{comment_view::CommentQuery, structs::LocalUserView};
|
||||||
comment_view::CommentQuery,
|
|
||||||
structs::{LocalUserView, SiteView},
|
|
||||||
};
|
|
||||||
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType, LemmyResult};
|
use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType, LemmyResult};
|
||||||
|
|
||||||
#[tracing::instrument(skip(context))]
|
#[tracing::instrument(skip(context))]
|
||||||
@ -27,8 +24,8 @@ pub async fn list_comments(
|
|||||||
context: Data<LemmyContext>,
|
context: Data<LemmyContext>,
|
||||||
local_user_view: Option<LocalUserView>,
|
local_user_view: Option<LocalUserView>,
|
||||||
) -> LemmyResult<Json<GetCommentsResponse>> {
|
) -> LemmyResult<Json<GetCommentsResponse>> {
|
||||||
let site_view = SiteView::read_local(&mut context.pool()).await?;
|
let local_site = LocalSite::read(&mut context.pool()).await?;
|
||||||
check_private_instance(&local_user_view, &site_view.local_site)?;
|
check_private_instance(&local_user_view, &local_site)?;
|
||||||
|
|
||||||
let community_id = if let Some(name) = &data.community_name {
|
let community_id = if let Some(name) = &data.community_name {
|
||||||
Some(
|
Some(
|
||||||
@ -43,7 +40,7 @@ pub async fn list_comments(
|
|||||||
let sort = Some(comment_sort_type_with_default(
|
let sort = Some(comment_sort_type_with_default(
|
||||||
data.sort,
|
data.sort,
|
||||||
local_user_ref,
|
local_user_ref,
|
||||||
&site_view.local_site,
|
&local_site,
|
||||||
));
|
));
|
||||||
let max_depth = data.max_depth;
|
let max_depth = data.max_depth;
|
||||||
let saved_only = data.saved_only;
|
let saved_only = data.saved_only;
|
||||||
@ -61,7 +58,7 @@ pub async fn list_comments(
|
|||||||
let listing_type = Some(listing_type_with_default(
|
let listing_type = Some(listing_type_with_default(
|
||||||
data.type_,
|
data.type_,
|
||||||
local_user_view.as_ref().map(|u| &u.local_user),
|
local_user_view.as_ref().map(|u| &u.local_user),
|
||||||
&site_view.local_site,
|
&local_site,
|
||||||
community_id,
|
community_id,
|
||||||
));
|
));
|
||||||
|
|
||||||
@ -91,7 +88,7 @@ pub async fn list_comments(
|
|||||||
limit,
|
limit,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&site_view.site, &mut context.pool())
|
.list(&mut context.pool())
|
||||||
.await
|
.await
|
||||||
.with_lemmy_type(LemmyErrorType::CouldntGetComments)?;
|
.with_lemmy_type(LemmyErrorType::CouldntGetComments)?;
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ pub async fn read_person(
|
|||||||
creator_id,
|
creator_id,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&local_site.site, &mut context.pool())
|
.list(&mut context.pool())
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let moderates = CommunityModeratorView::for_person(
|
let moderates = CommunityModeratorView::for_person(
|
||||||
|
@ -47,7 +47,7 @@ pub async fn search(
|
|||||||
listing_type,
|
listing_type,
|
||||||
page,
|
page,
|
||||||
limit,
|
limit,
|
||||||
title_only,
|
post_title_only,
|
||||||
post_url_only,
|
post_url_only,
|
||||||
saved_only,
|
saved_only,
|
||||||
liked_only,
|
liked_only,
|
||||||
@ -78,7 +78,7 @@ pub async fn search(
|
|||||||
search_term: Some(q.clone()),
|
search_term: Some(q.clone()),
|
||||||
page,
|
page,
|
||||||
limit,
|
limit,
|
||||||
title_only,
|
title_only: post_title_only,
|
||||||
url_only: post_url_only,
|
url_only: post_url_only,
|
||||||
liked_only,
|
liked_only,
|
||||||
disliked_only,
|
disliked_only,
|
||||||
@ -105,7 +105,6 @@ pub async fn search(
|
|||||||
sort,
|
sort,
|
||||||
listing_type,
|
listing_type,
|
||||||
search_term: Some(q.clone()),
|
search_term: Some(q.clone()),
|
||||||
title_only,
|
|
||||||
local_user,
|
local_user,
|
||||||
is_mod_or_admin: is_admin,
|
is_mod_or_admin: is_admin,
|
||||||
page,
|
page,
|
||||||
@ -128,9 +127,7 @@ pub async fn search(
|
|||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
SearchType::Comments => {
|
SearchType::Comments => {
|
||||||
comments = comment_query
|
comments = comment_query.list(&mut context.pool()).await?;
|
||||||
.list(&local_site.site, &mut context.pool())
|
|
||||||
.await?;
|
|
||||||
}
|
}
|
||||||
SearchType::Communities => {
|
SearchType::Communities => {
|
||||||
communities = community_query
|
communities = community_query
|
||||||
@ -149,9 +146,7 @@ pub async fn search(
|
|||||||
.list(&local_site.site, &mut context.pool())
|
.list(&local_site.site, &mut context.pool())
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
comments = comment_query
|
comments = comment_query.list(&mut context.pool()).await?;
|
||||||
.list(&local_site.site, &mut context.pool())
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
communities = if community_or_creator_included {
|
communities = if community_or_creator_included {
|
||||||
vec![]
|
vec![]
|
||||||
|
@ -127,6 +127,7 @@ pub async fn import_settings(
|
|||||||
show_read_posts: data.settings.as_ref().map(|s| s.show_read_posts),
|
show_read_posts: data.settings.as_ref().map(|s| s.show_read_posts),
|
||||||
open_links_in_new_tab: data.settings.as_ref().map(|s| s.open_links_in_new_tab),
|
open_links_in_new_tab: data.settings.as_ref().map(|s| s.open_links_in_new_tab),
|
||||||
blur_nsfw: data.settings.as_ref().map(|s| s.blur_nsfw),
|
blur_nsfw: data.settings.as_ref().map(|s| s.blur_nsfw),
|
||||||
|
auto_expand: data.settings.as_ref().map(|s| s.auto_expand),
|
||||||
infinite_scroll_enabled: data.settings.as_ref().map(|s| s.infinite_scroll_enabled),
|
infinite_scroll_enabled: data.settings.as_ref().map(|s| s.infinite_scroll_enabled),
|
||||||
post_listing_mode: data.settings.as_ref().map(|s| s.post_listing_mode),
|
post_listing_mode: data.settings.as_ref().map(|s| s.post_listing_mode),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@ -307,9 +308,8 @@ where
|
|||||||
});
|
});
|
||||||
Ok(failed_items.into_iter().join(","))
|
Ok(failed_items.into_iter().join(","))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::indexing_slicing)]
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::api::user_settings_backup::{export_settings, import_settings, UserSettingsBackup};
|
use crate::api::user_settings_backup::{export_settings, import_settings, UserSettingsBackup};
|
||||||
|
@ -98,7 +98,7 @@ impl Collection for ApubCommunityModerators {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::indexing_slicing)]
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -120,7 +120,8 @@ pub(crate) async fn get_apub_community_featured(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
pub(crate) mod tests {
|
pub(crate) mod tests {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -39,7 +39,7 @@ use lemmy_db_schema::{
|
|||||||
};
|
};
|
||||||
use lemmy_db_views_actor::structs::CommunityModeratorView;
|
use lemmy_db_views_actor::structs::CommunityModeratorView;
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
error::{LemmyError, LemmyResult},
|
error::{LemmyError, LemmyErrorType, LemmyResult},
|
||||||
spawn_try_task,
|
spawn_try_task,
|
||||||
utils::{
|
utils::{
|
||||||
markdown::markdown_to_html,
|
markdown::markdown_to_html,
|
||||||
@ -180,12 +180,15 @@ impl Object for ApubPost {
|
|||||||
let creator = page.creator()?.dereference(context).await?;
|
let creator = page.creator()?.dereference(context).await?;
|
||||||
let community = page.community(context).await?;
|
let community = page.community(context).await?;
|
||||||
if community.posting_restricted_to_mods {
|
if community.posting_restricted_to_mods {
|
||||||
CommunityModeratorView::check_is_community_moderator(
|
let is_mod = CommunityModeratorView::is_community_moderator(
|
||||||
&mut context.pool(),
|
&mut context.pool(),
|
||||||
community.id,
|
community.id,
|
||||||
creator.id,
|
creator.id,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
if !is_mod {
|
||||||
|
Err(LemmyErrorType::OnlyModsCanPostInCommunity)?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let mut name = page
|
let mut name = page
|
||||||
.name
|
.name
|
||||||
|
@ -15,13 +15,12 @@ use activitypub_federation::{
|
|||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
utils::{get_url_blocklist, local_site_opt_to_slur_regex, process_markdown},
|
utils::{check_person_block, get_url_blocklist, local_site_opt_to_slur_regex, process_markdown},
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::{
|
source::{
|
||||||
local_site::LocalSite,
|
local_site::LocalSite,
|
||||||
person::Person,
|
person::Person,
|
||||||
person_block::PersonBlock,
|
|
||||||
private_message::{PrivateMessage, PrivateMessageInsertForm},
|
private_message::{PrivateMessage, PrivateMessageInsertForm},
|
||||||
},
|
},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
@ -127,7 +126,7 @@ impl Object for ApubPrivateMessage {
|
|||||||
) -> LemmyResult<ApubPrivateMessage> {
|
) -> LemmyResult<ApubPrivateMessage> {
|
||||||
let creator = note.attributed_to.dereference(context).await?;
|
let creator = note.attributed_to.dereference(context).await?;
|
||||||
let recipient = note.to[0].dereference(context).await?;
|
let recipient = note.to[0].dereference(context).await?;
|
||||||
PersonBlock::read(&mut context.pool(), recipient.id, creator.id).await?;
|
check_person_block(creator.id, recipient.id, &mut context.pool()).await?;
|
||||||
|
|
||||||
let local_site = LocalSite::read(&mut context.pool()).await.ok();
|
let local_site = LocalSite::read(&mut context.pool()).await.ok();
|
||||||
let slur_regex = &local_site_opt_to_slur_regex(&local_site);
|
let slur_regex = &local_site_opt_to_slur_regex(&local_site);
|
||||||
|
@ -75,7 +75,7 @@ impl<S: ValidGrouping<(), IsAggregate = is_aggregate::No>> ValidGrouping<()>
|
|||||||
type IsAggregate = is_aggregate::No;
|
type IsAggregate = is_aggregate::No;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
#[derive(QueryId, Clone, Copy, Debug)]
|
#[derive(QueryId, Clone, Copy, Debug)]
|
||||||
pub struct current_value;
|
pub struct current_value;
|
||||||
|
|
||||||
|
@ -30,7 +30,8 @@ impl CommentAggregates {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -36,7 +36,8 @@ impl CommunityAggregates {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -20,7 +20,8 @@ impl PersonAggregates {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -49,8 +49,8 @@ impl PostAggregates {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -15,8 +15,8 @@ impl SiteAggregates {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -58,7 +58,8 @@ impl ReceivedActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -392,8 +392,8 @@ async fn convert_read_languages(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
#[expect(clippy::indexing_slicing)]
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -13,7 +13,6 @@ use diesel::{
|
|||||||
QueryDsl,
|
QueryDsl,
|
||||||
};
|
};
|
||||||
use diesel_async::RunQueryDsl;
|
use diesel_async::RunQueryDsl;
|
||||||
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
|
||||||
|
|
||||||
impl CaptchaAnswer {
|
impl CaptchaAnswer {
|
||||||
pub async fn insert(pool: &mut DbPool<'_>, captcha: &CaptchaAnswerForm) -> Result<Self, Error> {
|
pub async fn insert(pool: &mut DbPool<'_>, captcha: &CaptchaAnswerForm) -> Result<Self, Error> {
|
||||||
@ -28,7 +27,7 @@ impl CaptchaAnswer {
|
|||||||
pub async fn check_captcha(
|
pub async fn check_captcha(
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
to_check: CheckCaptchaAnswer,
|
to_check: CheckCaptchaAnswer,
|
||||||
) -> LemmyResult<()> {
|
) -> Result<bool, Error> {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
|
|
||||||
// fetch requested captcha
|
// fetch requested captcha
|
||||||
@ -44,13 +43,13 @@ impl CaptchaAnswer {
|
|||||||
.execute(conn)
|
.execute(conn)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
captcha_exists
|
Ok(captcha_exists)
|
||||||
.then_some(())
|
|
||||||
.ok_or(LemmyErrorType::CaptchaIncorrect.into())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
#[allow(clippy::unwrap_used)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -84,6 +83,7 @@ mod tests {
|
|||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
|
assert!(result.unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@ -119,6 +119,7 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(result_repeat.is_err());
|
assert!(result_repeat.is_ok());
|
||||||
|
assert!(!result_repeat.unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -196,7 +196,8 @@ impl Saveable for CommentSaved {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -35,7 +35,8 @@ use crate::{
|
|||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use diesel::{
|
use diesel::{
|
||||||
deserialize,
|
deserialize,
|
||||||
dsl::{self, exists, insert_into},
|
dsl,
|
||||||
|
dsl::{exists, insert_into},
|
||||||
pg::Pg,
|
pg::Pg,
|
||||||
result::Error,
|
result::Error,
|
||||||
select,
|
select,
|
||||||
@ -319,18 +320,16 @@ impl CommunityFollower {
|
|||||||
|
|
||||||
/// Check if a remote instance has any followers on local instance. For this it is enough to check
|
/// Check if a remote instance has any followers on local instance. For this it is enough to check
|
||||||
/// if any follow relation is stored. Dont use this for local community.
|
/// if any follow relation is stored. Dont use this for local community.
|
||||||
pub async fn check_has_local_followers(
|
pub async fn has_local_followers(
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
remote_community_id: CommunityId,
|
remote_community_id: CommunityId,
|
||||||
) -> LemmyResult<()> {
|
) -> Result<bool, Error> {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
select(exists(community_follower::table.filter(
|
select(exists(community_follower::table.filter(
|
||||||
community_follower::community_id.eq(remote_community_id),
|
community_follower::community_id.eq(remote_community_id),
|
||||||
)))
|
)))
|
||||||
.get_result::<bool>(conn)
|
.get_result(conn)
|
||||||
.await?
|
.await
|
||||||
.then_some(())
|
|
||||||
.ok_or(LemmyErrorType::CommunityHasNoFollowers.into())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -431,6 +430,7 @@ impl ApubActor for Community {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
source::{
|
source::{
|
||||||
|
@ -9,29 +9,26 @@ use crate::{
|
|||||||
utils::{get_conn, DbPool},
|
utils::{get_conn, DbPool},
|
||||||
};
|
};
|
||||||
use diesel::{
|
use diesel::{
|
||||||
dsl::{exists, insert_into, not},
|
dsl::{exists, insert_into},
|
||||||
result::Error,
|
result::Error,
|
||||||
select,
|
select,
|
||||||
ExpressionMethods,
|
ExpressionMethods,
|
||||||
QueryDsl,
|
QueryDsl,
|
||||||
};
|
};
|
||||||
use diesel_async::RunQueryDsl;
|
use diesel_async::RunQueryDsl;
|
||||||
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
|
||||||
|
|
||||||
impl CommunityBlock {
|
impl CommunityBlock {
|
||||||
pub async fn read(
|
pub async fn read(
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
for_person_id: PersonId,
|
for_person_id: PersonId,
|
||||||
for_community_id: CommunityId,
|
for_community_id: CommunityId,
|
||||||
) -> LemmyResult<()> {
|
) -> Result<bool, Error> {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
select(not(exists(
|
select(exists(
|
||||||
community_block::table.find((for_person_id, for_community_id)),
|
community_block::table.find((for_person_id, for_community_id)),
|
||||||
)))
|
))
|
||||||
.get_result::<bool>(conn)
|
.get_result(conn)
|
||||||
.await?
|
.await
|
||||||
.then_some(())
|
|
||||||
.ok_or(LemmyErrorType::CommunityIsBlocked.into())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn for_person(
|
pub async fn for_person(
|
||||||
|
@ -48,7 +48,8 @@ impl FederationAllowList {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -9,29 +9,26 @@ use crate::{
|
|||||||
utils::{get_conn, DbPool},
|
utils::{get_conn, DbPool},
|
||||||
};
|
};
|
||||||
use diesel::{
|
use diesel::{
|
||||||
dsl::{exists, insert_into, not},
|
dsl::{exists, insert_into},
|
||||||
result::Error,
|
result::Error,
|
||||||
select,
|
select,
|
||||||
ExpressionMethods,
|
ExpressionMethods,
|
||||||
QueryDsl,
|
QueryDsl,
|
||||||
};
|
};
|
||||||
use diesel_async::RunQueryDsl;
|
use diesel_async::RunQueryDsl;
|
||||||
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
|
||||||
|
|
||||||
impl InstanceBlock {
|
impl InstanceBlock {
|
||||||
pub async fn read(
|
pub async fn read(
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
for_person_id: PersonId,
|
for_person_id: PersonId,
|
||||||
for_instance_id: InstanceId,
|
for_instance_id: InstanceId,
|
||||||
) -> LemmyResult<()> {
|
) -> Result<bool, Error> {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
select(not(exists(
|
select(exists(
|
||||||
instance_block::table.find((for_person_id, for_instance_id)),
|
instance_block::table.find((for_person_id, for_instance_id)),
|
||||||
)))
|
))
|
||||||
.get_result::<bool>(conn)
|
.get_result(conn)
|
||||||
.await?
|
.await
|
||||||
.then_some(())
|
|
||||||
.ok_or(LemmyErrorType::InstanceIsBlocked.into())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn for_person(
|
pub async fn for_person(
|
||||||
|
@ -41,8 +41,8 @@ impl Language {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
#[expect(clippy::indexing_slicing)]
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::{source::language::Language, utils::build_db_pool_for_tests};
|
use crate::{source::language::Language, utils::build_db_pool_for_tests};
|
||||||
|
@ -136,16 +136,14 @@ impl LocalUser {
|
|||||||
diesel::delete(persons).execute(conn).await
|
diesel::delete(persons).execute(conn).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn check_is_email_taken(pool: &mut DbPool<'_>, email: &str) -> LemmyResult<()> {
|
pub async fn is_email_taken(pool: &mut DbPool<'_>, email: &str) -> Result<bool, Error> {
|
||||||
use diesel::dsl::{exists, select};
|
use diesel::dsl::{exists, select};
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
select(not(exists(local_user::table.filter(
|
select(exists(local_user::table.filter(
|
||||||
lower(coalesce(local_user::email, "")).eq(email.to_lowercase()),
|
lower(coalesce(local_user::email, "")).eq(email.to_lowercase()),
|
||||||
))))
|
)))
|
||||||
.get_result::<bool>(conn)
|
.get_result(conn)
|
||||||
.await?
|
.await
|
||||||
.then_some(())
|
|
||||||
.ok_or(LemmyErrorType::EmailAlreadyExists.into())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: maybe move this and pass in LocalUserView
|
// TODO: maybe move this and pass in LocalUserView
|
||||||
@ -369,6 +367,7 @@ pub struct UserBackupLists {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
source::{
|
source::{
|
||||||
@ -420,32 +419,4 @@ mod tests {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
#[serial]
|
|
||||||
async fn test_email_taken() -> LemmyResult<()> {
|
|
||||||
let pool = &build_db_pool_for_tests().await;
|
|
||||||
let pool = &mut pool.into();
|
|
||||||
|
|
||||||
let darwin_email = "charles.darwin@gmail.com";
|
|
||||||
|
|
||||||
let inserted_instance = Instance::read_or_create(pool, "my_domain.tld".to_string()).await?;
|
|
||||||
|
|
||||||
let darwin_person = PersonInsertForm::test_form(inserted_instance.id, "darwin");
|
|
||||||
let inserted_darwin_person = Person::create(pool, &darwin_person).await?;
|
|
||||||
|
|
||||||
let mut darwin_local_user_form =
|
|
||||||
LocalUserInsertForm::test_form_admin(inserted_darwin_person.id);
|
|
||||||
darwin_local_user_form.email = Some(darwin_email.into());
|
|
||||||
let _inserted_darwin_local_user =
|
|
||||||
LocalUser::create(pool, &darwin_local_user_form, vec![]).await?;
|
|
||||||
|
|
||||||
let check = LocalUser::check_is_email_taken(pool, darwin_email).await;
|
|
||||||
assert!(check.is_err());
|
|
||||||
|
|
||||||
let passed_check = LocalUser::check_is_email_taken(pool, "not_charles@gmail.com").await;
|
|
||||||
assert!(passed_check.is_ok());
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use diesel::{delete, dsl::exists, insert_into, result::Error, select};
|
use diesel::{delete, dsl::exists, insert_into, result::Error, select};
|
||||||
use diesel_async::RunQueryDsl;
|
use diesel_async::RunQueryDsl;
|
||||||
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
|
||||||
|
|
||||||
impl LoginToken {
|
impl LoginToken {
|
||||||
pub async fn create(pool: &mut DbPool<'_>, form: LoginTokenCreateForm) -> Result<Self, Error> {
|
pub async fn create(pool: &mut DbPool<'_>, form: LoginTokenCreateForm) -> Result<Self, Error> {
|
||||||
@ -23,15 +22,13 @@ impl LoginToken {
|
|||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
user_id_: LocalUserId,
|
user_id_: LocalUserId,
|
||||||
token_: &str,
|
token_: &str,
|
||||||
) -> LemmyResult<()> {
|
) -> Result<bool, Error> {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
select(exists(
|
select(exists(
|
||||||
login_token.find(token_).filter(user_id.eq(user_id_)),
|
login_token.find(token_).filter(user_id.eq(user_id_)),
|
||||||
))
|
))
|
||||||
.get_result::<bool>(conn)
|
.get_result(conn)
|
||||||
.await?
|
.await
|
||||||
.then_some(())
|
|
||||||
.ok_or(LemmyErrorType::NotLoggedIn.into())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn list(
|
pub async fn list(
|
||||||
|
@ -465,7 +465,8 @@ impl Crud for AdminPurgeComment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -1,13 +1,32 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
newtypes::LocalUserId,
|
newtypes::{LocalUserId, OAuthProviderId},
|
||||||
schema::{oauth_account, oauth_account::dsl::local_user_id},
|
schema::{oauth_account, oauth_account::dsl::local_user_id},
|
||||||
source::oauth_account::{OAuthAccount, OAuthAccountInsertForm},
|
source::oauth_account::{OAuthAccount, OAuthAccountInsertForm},
|
||||||
utils::{get_conn, DbPool},
|
utils::{get_conn, DbPool},
|
||||||
};
|
};
|
||||||
use diesel::{insert_into, result::Error, ExpressionMethods, QueryDsl};
|
use diesel::{
|
||||||
|
dsl::{exists, insert_into},
|
||||||
|
result::Error,
|
||||||
|
select,
|
||||||
|
ExpressionMethods,
|
||||||
|
QueryDsl,
|
||||||
|
};
|
||||||
use diesel_async::RunQueryDsl;
|
use diesel_async::RunQueryDsl;
|
||||||
|
|
||||||
impl OAuthAccount {
|
impl OAuthAccount {
|
||||||
|
pub async fn read(
|
||||||
|
pool: &mut DbPool<'_>,
|
||||||
|
for_oauth_provider_id: OAuthProviderId,
|
||||||
|
for_local_user_id: LocalUserId,
|
||||||
|
) -> Result<bool, Error> {
|
||||||
|
let conn = &mut get_conn(pool).await?;
|
||||||
|
select(exists(
|
||||||
|
oauth_account::table.find((for_oauth_provider_id, for_local_user_id)),
|
||||||
|
))
|
||||||
|
.get_result(conn)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn create(pool: &mut DbPool<'_>, form: &OAuthAccountInsertForm) -> Result<Self, Error> {
|
pub async fn create(pool: &mut DbPool<'_>, form: &OAuthAccountInsertForm) -> Result<Self, Error> {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
insert_into(oauth_account::table)
|
insert_into(oauth_account::table)
|
||||||
@ -16,6 +35,17 @@ impl OAuthAccount {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn delete(
|
||||||
|
pool: &mut DbPool<'_>,
|
||||||
|
for_oauth_provider_id: OAuthProviderId,
|
||||||
|
for_local_user_id: LocalUserId,
|
||||||
|
) -> Result<usize, Error> {
|
||||||
|
let conn = &mut get_conn(pool).await?;
|
||||||
|
diesel::delete(oauth_account::table.find((for_oauth_provider_id, for_local_user_id)))
|
||||||
|
.execute(conn)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn delete_user_accounts(
|
pub async fn delete_user_accounts(
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
for_local_user_id: LocalUserId,
|
for_local_user_id: LocalUserId,
|
||||||
|
@ -42,6 +42,8 @@ impl PasswordResetRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
#[allow(clippy::unwrap_used)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -21,7 +21,6 @@ use diesel::{
|
|||||||
QueryDsl,
|
QueryDsl,
|
||||||
};
|
};
|
||||||
use diesel_async::RunQueryDsl;
|
use diesel_async::RunQueryDsl;
|
||||||
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl Crud for Person {
|
impl Crud for Person {
|
||||||
@ -122,18 +121,16 @@ impl Person {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn check_username_taken(pool: &mut DbPool<'_>, username: &str) -> LemmyResult<()> {
|
pub async fn is_username_taken(pool: &mut DbPool<'_>, username: &str) -> Result<bool, Error> {
|
||||||
use diesel::dsl::{exists, select};
|
use diesel::dsl::{exists, select};
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
select(not(exists(
|
select(exists(
|
||||||
person::table
|
person::table
|
||||||
.filter(lower(person::name).eq(username.to_lowercase()))
|
.filter(lower(person::name).eq(username.to_lowercase()))
|
||||||
.filter(person::local.eq(true)),
|
.filter(person::local.eq(true)),
|
||||||
)))
|
))
|
||||||
.get_result::<bool>(conn)
|
.get_result(conn)
|
||||||
.await?
|
.await
|
||||||
.then_some(())
|
|
||||||
.ok_or(LemmyErrorType::UsernameAlreadyExists.into())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,6 +232,7 @@ impl PersonFollower {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -9,7 +9,7 @@ use crate::{
|
|||||||
utils::{get_conn, DbPool},
|
utils::{get_conn, DbPool},
|
||||||
};
|
};
|
||||||
use diesel::{
|
use diesel::{
|
||||||
dsl::{exists, insert_into, not},
|
dsl::{exists, insert_into},
|
||||||
result::Error,
|
result::Error,
|
||||||
select,
|
select,
|
||||||
ExpressionMethods,
|
ExpressionMethods,
|
||||||
@ -17,22 +17,19 @@ use diesel::{
|
|||||||
QueryDsl,
|
QueryDsl,
|
||||||
};
|
};
|
||||||
use diesel_async::RunQueryDsl;
|
use diesel_async::RunQueryDsl;
|
||||||
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
|
||||||
|
|
||||||
impl PersonBlock {
|
impl PersonBlock {
|
||||||
pub async fn read(
|
pub async fn read(
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
for_person_id: PersonId,
|
for_person_id: PersonId,
|
||||||
for_recipient_id: PersonId,
|
for_recipient_id: PersonId,
|
||||||
) -> LemmyResult<()> {
|
) -> Result<bool, Error> {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
select(not(exists(
|
select(exists(
|
||||||
person_block::table.find((for_person_id, for_recipient_id)),
|
person_block::table.find((for_person_id, for_recipient_id)),
|
||||||
)))
|
))
|
||||||
.get_result::<bool>(conn)
|
.get_result(conn)
|
||||||
.await?
|
.await
|
||||||
.then_some(())
|
|
||||||
.ok_or(LemmyErrorType::PersonIsBlocked.into())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn for_person(
|
pub async fn for_person(
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
diesel::{BoolExpressionMethods, OptionalExtension},
|
diesel::OptionalExtension,
|
||||||
newtypes::{CommunityId, DbUrl, PersonId, PostId},
|
newtypes::{CommunityId, DbUrl, PersonId, PostId},
|
||||||
schema::{community, person, post, post_hide, post_like, post_read, post_saved},
|
schema::{post, post_hide, post_like, post_read, post_saved},
|
||||||
source::post::{
|
source::post::{
|
||||||
Post,
|
Post,
|
||||||
PostHide,
|
PostHide,
|
||||||
@ -20,7 +20,6 @@ use crate::{
|
|||||||
functions::coalesce,
|
functions::coalesce,
|
||||||
get_conn,
|
get_conn,
|
||||||
naive_now,
|
naive_now,
|
||||||
now,
|
|
||||||
DbPool,
|
DbPool,
|
||||||
DELETED_REPLACEMENT_TEXT,
|
DELETED_REPLACEMENT_TEXT,
|
||||||
FETCH_LIMIT_MAX,
|
FETCH_LIMIT_MAX,
|
||||||
@ -31,7 +30,7 @@ use crate::{
|
|||||||
use ::url::Url;
|
use ::url::Url;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use diesel::{
|
use diesel::{
|
||||||
dsl::{count, insert_into, not},
|
dsl::insert_into,
|
||||||
result::Error,
|
result::Error,
|
||||||
DecoratableTarget,
|
DecoratableTarget,
|
||||||
ExpressionMethods,
|
ExpressionMethods,
|
||||||
@ -173,7 +172,6 @@ impl Post {
|
|||||||
let object_id: DbUrl = object_id.into();
|
let object_id: DbUrl = object_id.into();
|
||||||
post::table
|
post::table
|
||||||
.filter(post::ap_id.eq(object_id))
|
.filter(post::ap_id.eq(object_id))
|
||||||
.filter(post::scheduled_publish_time.is_null())
|
|
||||||
.first(conn)
|
.first(conn)
|
||||||
.await
|
.await
|
||||||
.optional()
|
.optional()
|
||||||
@ -247,28 +245,6 @@ impl Post {
|
|||||||
.get_results::<Self>(conn)
|
.get_results::<Self>(conn)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn user_scheduled_post_count(
|
|
||||||
person_id: PersonId,
|
|
||||||
pool: &mut DbPool<'_>,
|
|
||||||
) -> Result<i64, Error> {
|
|
||||||
let conn = &mut get_conn(pool).await?;
|
|
||||||
|
|
||||||
post::table
|
|
||||||
.inner_join(person::table)
|
|
||||||
.inner_join(community::table)
|
|
||||||
// find all posts which have scheduled_publish_time that is in the past
|
|
||||||
.filter(post::scheduled_publish_time.is_not_null())
|
|
||||||
.filter(coalesce(post::scheduled_publish_time, now()).lt(now()))
|
|
||||||
// make sure the post and community are still around
|
|
||||||
.filter(not(post::deleted.or(post::removed)))
|
|
||||||
.filter(not(community::removed.or(community::deleted)))
|
|
||||||
// only posts by specified user
|
|
||||||
.filter(post::creator_id.eq(person_id))
|
|
||||||
.select(count(post::id))
|
|
||||||
.first::<i64>(conn)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
@ -468,7 +444,6 @@ mod tests {
|
|||||||
featured_community: false,
|
featured_community: false,
|
||||||
featured_local: false,
|
featured_local: false,
|
||||||
url_content_type: None,
|
url_content_type: None,
|
||||||
scheduled_publish_time: None,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Post Like
|
// Post Like
|
||||||
|
@ -80,7 +80,8 @@ impl Reportable for PostReport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -85,7 +85,8 @@ impl PrivateMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -27,6 +27,7 @@ pub mod newtypes;
|
|||||||
pub mod sensitive;
|
pub mod sensitive;
|
||||||
#[cfg(feature = "full")]
|
#[cfg(feature = "full")]
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
|
#[allow(clippy::wildcard_imports)]
|
||||||
pub mod schema;
|
pub mod schema;
|
||||||
#[cfg(feature = "full")]
|
#[cfg(feature = "full")]
|
||||||
pub mod aliases {
|
pub mod aliases {
|
||||||
|
@ -191,13 +191,13 @@ impl Display for DbUrl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// the project doesn't compile with From
|
// the project doesn't compile with From
|
||||||
#[expect(clippy::from_over_into)]
|
#[allow(clippy::from_over_into)]
|
||||||
impl Into<DbUrl> for Url {
|
impl Into<DbUrl> for Url {
|
||||||
fn into(self) -> DbUrl {
|
fn into(self) -> DbUrl {
|
||||||
DbUrl(Box::new(self))
|
DbUrl(Box::new(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[expect(clippy::from_over_into)]
|
#[allow(clippy::from_over_into)]
|
||||||
impl Into<Url> for DbUrl {
|
impl Into<Url> for DbUrl {
|
||||||
fn into(self) -> Url {
|
fn into(self) -> Url {
|
||||||
*self.0
|
*self.0
|
||||||
|
@ -459,6 +459,7 @@ diesel::table! {
|
|||||||
totp_2fa_secret -> Nullable<Text>,
|
totp_2fa_secret -> Nullable<Text>,
|
||||||
open_links_in_new_tab -> Bool,
|
open_links_in_new_tab -> Bool,
|
||||||
blur_nsfw -> Bool,
|
blur_nsfw -> Bool,
|
||||||
|
auto_expand -> Bool,
|
||||||
infinite_scroll_enabled -> Bool,
|
infinite_scroll_enabled -> Bool,
|
||||||
admin -> Bool,
|
admin -> Bool,
|
||||||
post_listing_mode -> PostListingModeEnum,
|
post_listing_mode -> PostListingModeEnum,
|
||||||
@ -769,7 +770,6 @@ diesel::table! {
|
|||||||
featured_local -> Bool,
|
featured_local -> Bool,
|
||||||
url_content_type -> Nullable<Text>,
|
url_content_type -> Nullable<Text>,
|
||||||
alt_text -> Nullable<Text>,
|
alt_text -> Nullable<Text>,
|
||||||
scheduled_publish_time -> Nullable<Timestamptz>
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,6 +49,7 @@ pub struct LocalUser {
|
|||||||
/// Open links in a new tab.
|
/// Open links in a new tab.
|
||||||
pub open_links_in_new_tab: bool,
|
pub open_links_in_new_tab: bool,
|
||||||
pub blur_nsfw: bool,
|
pub blur_nsfw: 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.
|
/// Whether the person is an admin.
|
||||||
@ -103,6 +104,8 @@ pub struct LocalUserInsertForm {
|
|||||||
#[new(default)]
|
#[new(default)]
|
||||||
pub blur_nsfw: Option<bool>,
|
pub blur_nsfw: Option<bool>,
|
||||||
#[new(default)]
|
#[new(default)]
|
||||||
|
pub auto_expand: Option<bool>,
|
||||||
|
#[new(default)]
|
||||||
pub infinite_scroll_enabled: Option<bool>,
|
pub infinite_scroll_enabled: Option<bool>,
|
||||||
#[new(default)]
|
#[new(default)]
|
||||||
pub admin: Option<bool>,
|
pub admin: Option<bool>,
|
||||||
@ -140,6 +143,7 @@ pub struct LocalUserUpdateForm {
|
|||||||
pub totp_2fa_secret: Option<Option<String>>,
|
pub totp_2fa_secret: Option<Option<String>>,
|
||||||
pub open_links_in_new_tab: Option<bool>,
|
pub open_links_in_new_tab: Option<bool>,
|
||||||
pub blur_nsfw: Option<bool>,
|
pub blur_nsfw: Option<bool>,
|
||||||
|
pub auto_expand: Option<bool>,
|
||||||
pub infinite_scroll_enabled: Option<bool>,
|
pub infinite_scroll_enabled: Option<bool>,
|
||||||
pub admin: Option<bool>,
|
pub admin: Option<bool>,
|
||||||
pub post_listing_mode: Option<PostListingMode>,
|
pub post_listing_mode: Option<PostListingMode>,
|
||||||
|
@ -87,30 +87,39 @@ impl Serialize for PublicOAuthProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
|
#[cfg_attr(feature = "full", derive(Insertable, AsChangeset, TS))]
|
||||||
#[cfg_attr(feature = "full", diesel(table_name = oauth_provider))]
|
#[cfg_attr(feature = "full", diesel(table_name = oauth_provider))]
|
||||||
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
pub struct OAuthProviderInsertForm {
|
pub struct OAuthProviderInsertForm {
|
||||||
pub display_name: String,
|
pub display_name: String,
|
||||||
|
#[cfg_attr(feature = "full", ts(type = "string"))]
|
||||||
pub issuer: DbUrl,
|
pub issuer: DbUrl,
|
||||||
|
#[cfg_attr(feature = "full", ts(type = "string"))]
|
||||||
pub authorization_endpoint: DbUrl,
|
pub authorization_endpoint: DbUrl,
|
||||||
|
#[cfg_attr(feature = "full", ts(type = "string"))]
|
||||||
pub token_endpoint: DbUrl,
|
pub token_endpoint: DbUrl,
|
||||||
|
#[cfg_attr(feature = "full", ts(type = "string"))]
|
||||||
pub userinfo_endpoint: DbUrl,
|
pub userinfo_endpoint: DbUrl,
|
||||||
pub id_claim: String,
|
pub id_claim: String,
|
||||||
pub client_id: String,
|
pub client_id: String,
|
||||||
pub client_secret: String,
|
pub client_secret: String,
|
||||||
pub scopes: String,
|
pub scopes: String,
|
||||||
pub auto_verify_email: Option<bool>,
|
pub auto_verify_email: bool,
|
||||||
pub account_linking_enabled: Option<bool>,
|
pub account_linking_enabled: bool,
|
||||||
pub enabled: Option<bool>,
|
pub enabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
|
#[cfg_attr(feature = "full", derive(Insertable, AsChangeset, TS))]
|
||||||
#[cfg_attr(feature = "full", diesel(table_name = oauth_provider))]
|
#[cfg_attr(feature = "full", diesel(table_name = oauth_provider))]
|
||||||
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
pub struct OAuthProviderUpdateForm {
|
pub struct OAuthProviderUpdateForm {
|
||||||
pub display_name: Option<String>,
|
pub display_name: Option<String>,
|
||||||
|
#[cfg_attr(feature = "full", ts(type = "string"))]
|
||||||
pub authorization_endpoint: Option<DbUrl>,
|
pub authorization_endpoint: Option<DbUrl>,
|
||||||
|
#[cfg_attr(feature = "full", ts(type = "string"))]
|
||||||
pub token_endpoint: Option<DbUrl>,
|
pub token_endpoint: Option<DbUrl>,
|
||||||
|
#[cfg_attr(feature = "full", ts(type = "string"))]
|
||||||
pub userinfo_endpoint: Option<DbUrl>,
|
pub userinfo_endpoint: Option<DbUrl>,
|
||||||
pub id_claim: Option<String>,
|
pub id_claim: Option<String>,
|
||||||
pub client_secret: Option<String>,
|
pub client_secret: Option<String>,
|
||||||
|
@ -57,8 +57,6 @@ pub struct Post {
|
|||||||
pub url_content_type: Option<String>,
|
pub url_content_type: Option<String>,
|
||||||
/// An optional alt_text, usable for image posts.
|
/// An optional alt_text, usable for image posts.
|
||||||
pub alt_text: Option<String>,
|
pub alt_text: Option<String>,
|
||||||
/// Time at which the post will be published. None means publish immediately.
|
|
||||||
pub scheduled_publish_time: Option<DateTime<Utc>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, derive_new::new)]
|
#[derive(Debug, Clone, derive_new::new)]
|
||||||
@ -106,8 +104,6 @@ pub struct PostInsertForm {
|
|||||||
pub url_content_type: Option<String>,
|
pub url_content_type: Option<String>,
|
||||||
#[new(default)]
|
#[new(default)]
|
||||||
pub alt_text: Option<String>,
|
pub alt_text: Option<String>,
|
||||||
#[new(default)]
|
|
||||||
pub scheduled_publish_time: Option<DateTime<Utc>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
@ -134,7 +130,6 @@ pub struct PostUpdateForm {
|
|||||||
pub featured_local: Option<bool>,
|
pub featured_local: Option<bool>,
|
||||||
pub url_content_type: Option<Option<String>>,
|
pub url_content_type: Option<Option<String>>,
|
||||||
pub alt_text: Option<Option<String>>,
|
pub alt_text: Option<Option<String>>,
|
||||||
pub scheduled_publish_time: Option<Option<DateTime<Utc>>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug)]
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
|
@ -595,6 +595,7 @@ impl<RF, LF> Queries<RF, LF> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -259,8 +259,8 @@ impl CommentReportQuery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
#[expect(clippy::indexing_slicing)]
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -35,7 +35,7 @@ use lemmy_db_schema::{
|
|||||||
person_block,
|
person_block,
|
||||||
post,
|
post,
|
||||||
},
|
},
|
||||||
source::{local_user::LocalUser, site::Site},
|
source::local_user::LocalUser,
|
||||||
utils::{fuzzy_search, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn},
|
utils::{fuzzy_search, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn},
|
||||||
CommentSortType,
|
CommentSortType,
|
||||||
ListingType,
|
ListingType,
|
||||||
@ -43,7 +43,7 @@ use lemmy_db_schema::{
|
|||||||
|
|
||||||
fn queries<'a>() -> Queries<
|
fn queries<'a>() -> Queries<
|
||||||
impl ReadFn<'a, CommentView, (CommentId, Option<&'a LocalUser>)>,
|
impl ReadFn<'a, CommentView, (CommentId, Option<&'a LocalUser>)>,
|
||||||
impl ListFn<'a, CommentView, (CommentQuery<'a>, &'a Site)>,
|
impl ListFn<'a, CommentView, CommentQuery<'a>>,
|
||||||
> {
|
> {
|
||||||
let is_creator_banned_from_community = exists(
|
let is_creator_banned_from_community = exists(
|
||||||
community_person_ban::table.filter(
|
community_person_ban::table.filter(
|
||||||
@ -182,7 +182,7 @@ fn queries<'a>() -> Queries<
|
|||||||
query.first(&mut conn).await
|
query.first(&mut conn).await
|
||||||
};
|
};
|
||||||
|
|
||||||
let list = move |mut conn: DbConn<'a>, (options, site): (CommentQuery<'a>, &'a Site)| async move {
|
let list = move |mut conn: DbConn<'a>, options: CommentQuery<'a>| async move {
|
||||||
// The left join below will return None in this case
|
// The left join below will return None in this case
|
||||||
let person_id_join = options.local_user.person_id().unwrap_or(PersonId(-1));
|
let person_id_join = options.local_user.person_id().unwrap_or(PersonId(-1));
|
||||||
let local_user_id_join = options
|
let local_user_id_join = options
|
||||||
@ -295,12 +295,6 @@ fn queries<'a>() -> Queries<
|
|||||||
query = query.filter(not(is_creator_blocked(person_id_join)));
|
query = query.filter(not(is_creator_blocked(person_id_join)));
|
||||||
};
|
};
|
||||||
|
|
||||||
if !options.local_user.show_nsfw(site) {
|
|
||||||
query = query
|
|
||||||
.filter(post::nsfw.eq(false))
|
|
||||||
.filter(community::nsfw.eq(false));
|
|
||||||
};
|
|
||||||
|
|
||||||
query = options.local_user.visible_communities_only(query);
|
query = options.local_user.visible_communities_only(query);
|
||||||
|
|
||||||
// A Max depth given means its a tree fetch
|
// A Max depth given means its a tree fetch
|
||||||
@ -404,10 +398,10 @@ pub struct CommentQuery<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CommentQuery<'a> {
|
impl<'a> CommentQuery<'a> {
|
||||||
pub async fn list(self, site: &Site, pool: &mut DbPool<'_>) -> Result<Vec<CommentView>, Error> {
|
pub async fn list(self, pool: &mut DbPool<'_>) -> Result<Vec<CommentView>, Error> {
|
||||||
Ok(
|
Ok(
|
||||||
queries()
|
queries()
|
||||||
.list(pool, (self, site))
|
.list(pool, self)
|
||||||
.await?
|
.await?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|mut c| {
|
.map(|mut c| {
|
||||||
@ -422,8 +416,8 @@ impl<'a> CommentQuery<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::indexing_slicing)]
|
#[allow(clippy::indexing_slicing)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -461,8 +455,7 @@ mod tests {
|
|||||||
local_user_vote_display_mode::LocalUserVoteDisplayMode,
|
local_user_vote_display_mode::LocalUserVoteDisplayMode,
|
||||||
person::{Person, PersonInsertForm},
|
person::{Person, PersonInsertForm},
|
||||||
person_block::{PersonBlock, PersonBlockForm},
|
person_block::{PersonBlock, PersonBlockForm},
|
||||||
post::{Post, PostInsertForm, PostUpdateForm},
|
post::{Post, PostInsertForm},
|
||||||
site::{Site, SiteInsertForm},
|
|
||||||
},
|
},
|
||||||
traits::{Bannable, Blockable, Crud, Joinable, Likeable, Saveable},
|
traits::{Bannable, Blockable, Crud, Joinable, Likeable, Saveable},
|
||||||
utils::{build_db_pool_for_tests, RANK_DEFAULT},
|
utils::{build_db_pool_for_tests, RANK_DEFAULT},
|
||||||
@ -482,7 +475,6 @@ mod tests {
|
|||||||
timmy_local_user_view: LocalUserView,
|
timmy_local_user_view: LocalUserView,
|
||||||
inserted_sara_person: Person,
|
inserted_sara_person: Person,
|
||||||
inserted_community: Community,
|
inserted_community: Community,
|
||||||
site: Site,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn init_data(pool: &mut DbPool<'_>) -> LemmyResult<Data> {
|
async fn init_data(pool: &mut DbPool<'_>) -> LemmyResult<Data> {
|
||||||
@ -619,8 +611,6 @@ mod tests {
|
|||||||
person: inserted_timmy_person.clone(),
|
person: inserted_timmy_person.clone(),
|
||||||
counts: Default::default(),
|
counts: Default::default(),
|
||||||
};
|
};
|
||||||
let site_form = SiteInsertForm::new("test site".to_string(), inserted_instance.id);
|
|
||||||
let site = Site::create(pool, &site_form).await?;
|
|
||||||
Ok(Data {
|
Ok(Data {
|
||||||
inserted_instance,
|
inserted_instance,
|
||||||
inserted_comment_0,
|
inserted_comment_0,
|
||||||
@ -630,7 +620,6 @@ mod tests {
|
|||||||
timmy_local_user_view,
|
timmy_local_user_view,
|
||||||
inserted_sara_person,
|
inserted_sara_person,
|
||||||
inserted_community,
|
inserted_community,
|
||||||
site,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -651,7 +640,7 @@ mod tests {
|
|||||||
post_id: (Some(data.inserted_post.id)),
|
post_id: (Some(data.inserted_post.id)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&data.site, pool)
|
.list(pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -665,7 +654,7 @@ mod tests {
|
|||||||
local_user: (Some(&data.timmy_local_user_view.local_user)),
|
local_user: (Some(&data.timmy_local_user_view.local_user)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&data.site, pool)
|
.list(pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -717,7 +706,7 @@ mod tests {
|
|||||||
liked_only: Some(true),
|
liked_only: Some(true),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&data.site, pool)
|
.list(pool)
|
||||||
.await?
|
.await?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|c| c.comment.content)
|
.map(|c| c.comment.content)
|
||||||
@ -733,7 +722,7 @@ mod tests {
|
|||||||
disliked_only: Some(true),
|
disliked_only: Some(true),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&data.site, pool)
|
.list(pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
assert!(read_disliked_comment_views.is_empty());
|
assert!(read_disliked_comment_views.is_empty());
|
||||||
@ -754,7 +743,7 @@ mod tests {
|
|||||||
parent_path: (Some(top_path)),
|
parent_path: (Some(top_path)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&data.site, pool)
|
.list(pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let child_path = data.inserted_comment_1.path.clone();
|
let child_path = data.inserted_comment_1.path.clone();
|
||||||
@ -763,7 +752,7 @@ mod tests {
|
|||||||
parent_path: (Some(child_path)),
|
parent_path: (Some(child_path)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&data.site, pool)
|
.list(pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// Make sure the comment parent-limited fetch is correct
|
// Make sure the comment parent-limited fetch is correct
|
||||||
@ -783,7 +772,7 @@ mod tests {
|
|||||||
max_depth: (Some(1)),
|
max_depth: (Some(1)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&data.site, pool)
|
.list(pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// Make sure a depth limited one only has the top comment
|
// Make sure a depth limited one only has the top comment
|
||||||
@ -801,7 +790,7 @@ mod tests {
|
|||||||
sort: (Some(CommentSortType::New)),
|
sort: (Some(CommentSortType::New)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&data.site, pool)
|
.list(pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// Make sure a depth limited one, and given child comment 1, has 3
|
// Make sure a depth limited one, and given child comment 1, has 3
|
||||||
@ -827,7 +816,7 @@ mod tests {
|
|||||||
local_user: (Some(&data.timmy_local_user_view.local_user)),
|
local_user: (Some(&data.timmy_local_user_view.local_user)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&data.site, pool)
|
.list(pool)
|
||||||
.await?;
|
.await?;
|
||||||
assert_length!(5, all_languages);
|
assert_length!(5, all_languages);
|
||||||
|
|
||||||
@ -845,7 +834,7 @@ mod tests {
|
|||||||
local_user: (Some(&data.timmy_local_user_view.local_user)),
|
local_user: (Some(&data.timmy_local_user_view.local_user)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&data.site, pool)
|
.list(pool)
|
||||||
.await?;
|
.await?;
|
||||||
assert_length!(2, finnish_comments);
|
assert_length!(2, finnish_comments);
|
||||||
let finnish_comment = finnish_comments
|
let finnish_comment = finnish_comments
|
||||||
@ -868,7 +857,7 @@ mod tests {
|
|||||||
local_user: (Some(&data.timmy_local_user_view.local_user)),
|
local_user: (Some(&data.timmy_local_user_view.local_user)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&data.site, pool)
|
.list(pool)
|
||||||
.await?;
|
.await?;
|
||||||
assert_length!(1, undetermined_comment);
|
assert_length!(1, undetermined_comment);
|
||||||
|
|
||||||
@ -892,7 +881,7 @@ mod tests {
|
|||||||
post_id: Some(data.inserted_comment_2.post_id),
|
post_id: Some(data.inserted_comment_2.post_id),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&data.site, pool)
|
.list(pool)
|
||||||
.await?;
|
.await?;
|
||||||
assert_eq!(comments[0].comment.id, data.inserted_comment_2.id);
|
assert_eq!(comments[0].comment.id, data.inserted_comment_2.id);
|
||||||
assert!(comments[0].comment.distinguished);
|
assert!(comments[0].comment.distinguished);
|
||||||
@ -921,7 +910,7 @@ mod tests {
|
|||||||
sort: (Some(CommentSortType::Old)),
|
sort: (Some(CommentSortType::Old)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&data.site, pool)
|
.list(pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
assert_eq!(comments[1].creator.name, "sara");
|
assert_eq!(comments[1].creator.name, "sara");
|
||||||
@ -942,7 +931,7 @@ mod tests {
|
|||||||
sort: (Some(CommentSortType::Old)),
|
sort: (Some(CommentSortType::Old)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&data.site, pool)
|
.list(pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// Timmy is an admin, and make sure that field is true
|
// Timmy is an admin, and make sure that field is true
|
||||||
@ -982,7 +971,7 @@ mod tests {
|
|||||||
saved_only: Some(true),
|
saved_only: Some(true),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&data.site, pool)
|
.list(pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// There should only be two comments
|
// There should only be two comments
|
||||||
@ -1012,7 +1001,6 @@ mod tests {
|
|||||||
LocalUser::delete(pool, data.timmy_local_user_view.local_user.id).await?;
|
LocalUser::delete(pool, data.timmy_local_user_view.local_user.id).await?;
|
||||||
Person::delete(pool, data.inserted_sara_person.id).await?;
|
Person::delete(pool, data.inserted_sara_person.id).await?;
|
||||||
Instance::delete(pool, data.inserted_instance.id).await?;
|
Instance::delete(pool, data.inserted_instance.id).await?;
|
||||||
Site::delete(pool, data.site.id).await?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -1090,7 +1078,6 @@ mod tests {
|
|||||||
featured_community: false,
|
featured_community: false,
|
||||||
featured_local: false,
|
featured_local: false,
|
||||||
url_content_type: None,
|
url_content_type: None,
|
||||||
scheduled_publish_time: None,
|
|
||||||
},
|
},
|
||||||
community: Community {
|
community: Community {
|
||||||
id: data.inserted_community.id,
|
id: data.inserted_community.id,
|
||||||
@ -1152,7 +1139,7 @@ mod tests {
|
|||||||
let unauthenticated_query = CommentQuery {
|
let unauthenticated_query = CommentQuery {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&data.site, pool)
|
.list(pool)
|
||||||
.await?;
|
.await?;
|
||||||
assert_eq!(0, unauthenticated_query.len());
|
assert_eq!(0, unauthenticated_query.len());
|
||||||
|
|
||||||
@ -1160,7 +1147,7 @@ mod tests {
|
|||||||
local_user: Some(&data.timmy_local_user_view.local_user),
|
local_user: Some(&data.timmy_local_user_view.local_user),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.list(&data.site, pool)
|
.list(pool)
|
||||||
.await?;
|
.await?;
|
||||||
assert_eq!(5, authenticated_query.len());
|
assert_eq!(5, authenticated_query.len());
|
||||||
|
|
||||||
@ -1238,33 +1225,4 @@ mod tests {
|
|||||||
|
|
||||||
cleanup(data, pool).await
|
cleanup(data, pool).await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
#[serial]
|
|
||||||
async fn comment_listings_hide_nsfw() -> LemmyResult<()> {
|
|
||||||
let pool = &build_db_pool_for_tests().await;
|
|
||||||
let pool = &mut pool.into();
|
|
||||||
let data = init_data(pool).await?;
|
|
||||||
|
|
||||||
// Mark a post as nsfw
|
|
||||||
let update_form = PostUpdateForm {
|
|
||||||
nsfw: Some(true),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
Post::update(pool, data.inserted_post.id, &update_form).await?;
|
|
||||||
|
|
||||||
// Make sure comments of this post are not returned
|
|
||||||
let comments = CommentQuery::default().list(&data.site, pool).await?;
|
|
||||||
assert_eq!(0, comments.len());
|
|
||||||
|
|
||||||
// Mark site as nsfw
|
|
||||||
let mut site = data.site.clone();
|
|
||||||
site.content_warning = Some("nsfw".to_string());
|
|
||||||
|
|
||||||
// Now comments of nsfw post are returned
|
|
||||||
let comments = CommentQuery::default().list(&site, pool).await?;
|
|
||||||
assert_eq!(6, comments.len());
|
|
||||||
|
|
||||||
cleanup(data, pool).await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -284,8 +284,8 @@ impl PostReportQuery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
#[expect(clippy::indexing_slicing)]
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -318,18 +318,11 @@ fn queries<'a>() -> Queries<
|
|||||||
// hide posts from deleted communities
|
// hide posts from deleted communities
|
||||||
query = query.filter(community::deleted.eq(false));
|
query = query.filter(community::deleted.eq(false));
|
||||||
|
|
||||||
// only creator can see deleted posts and unpublished scheduled posts
|
// only show deleted posts to creator
|
||||||
if let Some(person_id) = options.local_user.person_id() {
|
if let Some(person_id) = options.local_user.person_id() {
|
||||||
query = query.filter(post::deleted.eq(false).or(post::creator_id.eq(person_id)));
|
query = query.filter(post::deleted.eq(false).or(post::creator_id.eq(person_id)));
|
||||||
query = query.filter(
|
|
||||||
post::scheduled_publish_time
|
|
||||||
.is_null()
|
|
||||||
.or(post::creator_id.eq(person_id)),
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
query = query
|
query = query.filter(post::deleted.eq(false));
|
||||||
.filter(post::deleted.eq(false))
|
|
||||||
.filter(post::scheduled_publish_time.is_null());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// only show removed posts to admin when viewing user profile
|
// only show removed posts to admin when viewing user profile
|
||||||
@ -394,12 +387,14 @@ fn queries<'a>() -> Queries<
|
|||||||
query = query.filter(post::url.eq(search_term));
|
query = query.filter(post::url.eq(search_term));
|
||||||
} else {
|
} else {
|
||||||
let searcher = fuzzy_search(search_term);
|
let searcher = fuzzy_search(search_term);
|
||||||
let name_filter = post::name.ilike(searcher.clone());
|
|
||||||
let body_filter = post::body.ilike(searcher.clone());
|
|
||||||
query = if options.title_only.unwrap_or_default() {
|
query = if options.title_only.unwrap_or_default() {
|
||||||
query.filter(name_filter)
|
query.filter(post::name.ilike(searcher))
|
||||||
} else {
|
} else {
|
||||||
query.filter(name_filter.or(body_filter))
|
query.filter(
|
||||||
|
post::name
|
||||||
|
.ilike(searcher.clone())
|
||||||
|
.or(post::body.ilike(searcher)),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
.filter(not(post::removed.or(post::deleted)));
|
.filter(not(post::removed.or(post::deleted)));
|
||||||
}
|
}
|
||||||
@ -739,7 +734,7 @@ impl<'a> PostQuery<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
post_view::{PaginationCursorData, PostQuery, PostView},
|
post_view::{PaginationCursorData, PostQuery, PostView},
|
||||||
@ -1776,7 +1771,6 @@ mod tests {
|
|||||||
featured_community: false,
|
featured_community: false,
|
||||||
featured_local: false,
|
featured_local: false,
|
||||||
url_content_type: None,
|
url_content_type: None,
|
||||||
scheduled_publish_time: None,
|
|
||||||
},
|
},
|
||||||
my_vote: None,
|
my_vote: None,
|
||||||
unread_comments: 0,
|
unread_comments: 0,
|
||||||
|
@ -111,8 +111,8 @@ impl PrivateMessageReportQuery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
#[expect(clippy::indexing_slicing)]
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::private_message_report_view::PrivateMessageReportQuery;
|
use crate::private_message_report_view::PrivateMessageReportQuery;
|
||||||
|
@ -173,8 +173,8 @@ impl PrivateMessageQuery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
#[expect(clippy::indexing_slicing)]
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::{private_message_view::PrivateMessageQuery, structs::PrivateMessageView};
|
use crate::{private_message_view::PrivateMessageQuery, structs::PrivateMessageView};
|
||||||
|
@ -135,7 +135,8 @@ impl RegistrationApplicationQuery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::registration_application_view::{
|
use crate::registration_application_view::{
|
||||||
@ -234,6 +235,7 @@ mod tests {
|
|||||||
person_id: inserted_sara_local_user.person_id,
|
person_id: inserted_sara_local_user.person_id,
|
||||||
email: inserted_sara_local_user.email,
|
email: inserted_sara_local_user.email,
|
||||||
show_nsfw: inserted_sara_local_user.show_nsfw,
|
show_nsfw: inserted_sara_local_user.show_nsfw,
|
||||||
|
auto_expand: inserted_sara_local_user.auto_expand,
|
||||||
blur_nsfw: inserted_sara_local_user.blur_nsfw,
|
blur_nsfw: inserted_sara_local_user.blur_nsfw,
|
||||||
theme: inserted_sara_local_user.theme,
|
theme: inserted_sara_local_user.theme,
|
||||||
default_post_sort_type: inserted_sara_local_user.default_post_sort_type,
|
default_post_sort_type: inserted_sara_local_user.default_post_sort_type,
|
||||||
|
@ -83,7 +83,8 @@ impl VoteView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::structs::VoteView;
|
use crate::structs::VoteView;
|
||||||
|
@ -15,13 +15,7 @@ doctest = false
|
|||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
full = [
|
full = ["lemmy_db_schema/full", "diesel", "diesel-async", "ts-rs"]
|
||||||
"lemmy_db_schema/full",
|
|
||||||
"lemmy_utils/full",
|
|
||||||
"diesel",
|
|
||||||
"diesel-async",
|
|
||||||
"ts-rs",
|
|
||||||
]
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
lemmy_db_schema = { workspace = true }
|
lemmy_db_schema = { workspace = true }
|
||||||
@ -39,7 +33,6 @@ serde_with = { workspace = true }
|
|||||||
ts-rs = { workspace = true, optional = true }
|
ts-rs = { workspace = true, optional = true }
|
||||||
chrono.workspace = true
|
chrono.workspace = true
|
||||||
strum = { workspace = true }
|
strum = { workspace = true }
|
||||||
lemmy_utils = { workspace = true, optional = true }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serial_test = { workspace = true }
|
serial_test = { workspace = true }
|
||||||
|
@ -303,6 +303,7 @@ impl CommentReplyQuery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::{comment_reply_view::CommentReplyQuery, structs::CommentReplyView};
|
use crate::{comment_reply_view::CommentReplyQuery, structs::CommentReplyView};
|
||||||
|
@ -8,14 +8,13 @@ use lemmy_db_schema::{
|
|||||||
source::local_user::LocalUser,
|
source::local_user::LocalUser,
|
||||||
utils::{get_conn, DbPool},
|
utils::{get_conn, DbPool},
|
||||||
};
|
};
|
||||||
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
|
||||||
|
|
||||||
impl CommunityModeratorView {
|
impl CommunityModeratorView {
|
||||||
pub async fn check_is_community_moderator(
|
pub async fn is_community_moderator(
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
find_community_id: CommunityId,
|
find_community_id: CommunityId,
|
||||||
find_person_id: PersonId,
|
find_person_id: PersonId,
|
||||||
) -> LemmyResult<()> {
|
) -> Result<bool, Error> {
|
||||||
use lemmy_db_schema::schema::community_moderator::dsl::{
|
use lemmy_db_schema::schema::community_moderator::dsl::{
|
||||||
community_id,
|
community_id,
|
||||||
community_moderator,
|
community_moderator,
|
||||||
@ -28,24 +27,20 @@ impl CommunityModeratorView {
|
|||||||
.filter(person_id.eq(find_person_id)),
|
.filter(person_id.eq(find_person_id)),
|
||||||
))
|
))
|
||||||
.get_result::<bool>(conn)
|
.get_result::<bool>(conn)
|
||||||
.await?
|
.await
|
||||||
.then_some(())
|
|
||||||
.ok_or(LemmyErrorType::NotAModerator.into())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn is_community_moderator_of_any(
|
pub(crate) async fn is_community_moderator_of_any(
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
find_person_id: PersonId,
|
find_person_id: PersonId,
|
||||||
) -> LemmyResult<()> {
|
) -> Result<bool, Error> {
|
||||||
use lemmy_db_schema::schema::community_moderator::dsl::{community_moderator, person_id};
|
use lemmy_db_schema::schema::community_moderator::dsl::{community_moderator, person_id};
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
select(exists(
|
select(exists(
|
||||||
community_moderator.filter(person_id.eq(find_person_id)),
|
community_moderator.filter(person_id.eq(find_person_id)),
|
||||||
))
|
))
|
||||||
.get_result::<bool>(conn)
|
.get_result::<bool>(conn)
|
||||||
.await?
|
.await
|
||||||
.then_some(())
|
|
||||||
.ok_or(LemmyErrorType::NotAModerator.into())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn for_community(
|
pub async fn for_community(
|
||||||
|
@ -1,33 +1,25 @@
|
|||||||
use crate::structs::CommunityPersonBanView;
|
use crate::structs::CommunityPersonBanView;
|
||||||
use diesel::{
|
use diesel::{dsl::exists, result::Error, select, ExpressionMethods, QueryDsl};
|
||||||
dsl::{exists, not},
|
|
||||||
select,
|
|
||||||
ExpressionMethods,
|
|
||||||
QueryDsl,
|
|
||||||
};
|
|
||||||
use diesel_async::RunQueryDsl;
|
use diesel_async::RunQueryDsl;
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
newtypes::{CommunityId, PersonId},
|
newtypes::{CommunityId, PersonId},
|
||||||
schema::community_person_ban,
|
schema::community_person_ban,
|
||||||
utils::{get_conn, DbPool},
|
utils::{get_conn, DbPool},
|
||||||
};
|
};
|
||||||
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
|
||||||
|
|
||||||
impl CommunityPersonBanView {
|
impl CommunityPersonBanView {
|
||||||
pub async fn check(
|
pub async fn get(
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
from_person_id: PersonId,
|
from_person_id: PersonId,
|
||||||
from_community_id: CommunityId,
|
from_community_id: CommunityId,
|
||||||
) -> LemmyResult<()> {
|
) -> Result<bool, Error> {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
select(not(exists(
|
select(exists(
|
||||||
community_person_ban::table
|
community_person_ban::table
|
||||||
.filter(community_person_ban::community_id.eq(from_community_id))
|
.filter(community_person_ban::community_id.eq(from_community_id))
|
||||||
.filter(community_person_ban::person_id.eq(from_person_id)),
|
.filter(community_person_ban::person_id.eq(from_person_id)),
|
||||||
)))
|
))
|
||||||
.get_result::<bool>(conn)
|
.get_result::<bool>(conn)
|
||||||
.await?
|
.await
|
||||||
.then_some(())
|
|
||||||
.ok_or(LemmyErrorType::PersonIsBannedFromCommunity.into())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,6 @@ use lemmy_db_schema::{
|
|||||||
ListingType,
|
ListingType,
|
||||||
PostSortType,
|
PostSortType,
|
||||||
};
|
};
|
||||||
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
|
||||||
|
|
||||||
fn queries<'a>() -> Queries<
|
fn queries<'a>() -> Queries<
|
||||||
impl ReadFn<'a, CommunityView, (CommunityId, Option<&'a LocalUser>, bool)>,
|
impl ReadFn<'a, CommunityView, (CommunityId, Option<&'a LocalUser>, bool)>,
|
||||||
@ -112,14 +111,9 @@ fn queries<'a>() -> Queries<
|
|||||||
|
|
||||||
if let Some(search_term) = options.search_term {
|
if let Some(search_term) = options.search_term {
|
||||||
let searcher = fuzzy_search(&search_term);
|
let searcher = fuzzy_search(&search_term);
|
||||||
let name_filter = community::name.ilike(searcher.clone());
|
query = query
|
||||||
let title_filter = community::title.ilike(searcher.clone());
|
.filter(community::name.ilike(searcher.clone()))
|
||||||
let description_filter = community::description.ilike(searcher.clone());
|
.or_filter(community::title.ilike(searcher))
|
||||||
query = if options.title_only.unwrap_or_default() {
|
|
||||||
query.filter(name_filter.or(title_filter))
|
|
||||||
} else {
|
|
||||||
query.filter(name_filter.or(title_filter.or(description_filter)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hide deleted and removed for non-admins or mods
|
// Hide deleted and removed for non-admins or mods
|
||||||
@ -191,39 +185,35 @@ impl CommunityView {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn check_is_mod_or_admin(
|
pub async fn is_mod_or_admin(
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
person_id: PersonId,
|
person_id: PersonId,
|
||||||
community_id: CommunityId,
|
community_id: CommunityId,
|
||||||
) -> LemmyResult<()> {
|
) -> Result<bool, Error> {
|
||||||
let is_mod =
|
let is_mod =
|
||||||
CommunityModeratorView::check_is_community_moderator(pool, community_id, person_id).await;
|
CommunityModeratorView::is_community_moderator(pool, community_id, person_id).await?;
|
||||||
if is_mod.is_ok()
|
if is_mod {
|
||||||
|| PersonView::read(pool, person_id)
|
Ok(true)
|
||||||
.await
|
} else if let Ok(person_view) = PersonView::read(pool, person_id).await {
|
||||||
.is_ok_and(|t| t.is_admin)
|
Ok(person_view.is_admin)
|
||||||
{
|
|
||||||
Ok(())
|
|
||||||
} else {
|
} else {
|
||||||
Err(LemmyErrorType::NotAModOrAdmin)?
|
Ok(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if a person is an admin, or moderator of any community.
|
/// Checks if a person is an admin, or moderator of any community.
|
||||||
pub async fn check_is_mod_of_any_or_admin(
|
pub async fn is_mod_of_any_or_admin(
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
person_id: PersonId,
|
person_id: PersonId,
|
||||||
) -> LemmyResult<()> {
|
) -> Result<bool, Error> {
|
||||||
let is_mod_of_any =
|
let is_mod_of_any =
|
||||||
CommunityModeratorView::is_community_moderator_of_any(pool, person_id).await;
|
CommunityModeratorView::is_community_moderator_of_any(pool, person_id).await?;
|
||||||
if is_mod_of_any.is_ok()
|
if is_mod_of_any {
|
||||||
|| PersonView::read(pool, person_id)
|
Ok(true)
|
||||||
.await
|
} else if let Ok(person_view) = PersonView::read(pool, person_id).await {
|
||||||
.is_ok_and(|t| t.is_admin)
|
Ok(person_view.is_admin)
|
||||||
{
|
|
||||||
Ok(())
|
|
||||||
} else {
|
} else {
|
||||||
Err(LemmyErrorType::NotAModOrAdmin)?
|
Ok(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -234,7 +224,6 @@ pub struct CommunityQuery<'a> {
|
|||||||
pub sort: Option<PostSortType>,
|
pub sort: Option<PostSortType>,
|
||||||
pub local_user: Option<&'a LocalUser>,
|
pub local_user: Option<&'a LocalUser>,
|
||||||
pub search_term: Option<String>,
|
pub search_term: Option<String>,
|
||||||
pub title_only: Option<bool>,
|
|
||||||
pub is_mod_or_admin: bool,
|
pub is_mod_or_admin: bool,
|
||||||
pub show_nsfw: bool,
|
pub show_nsfw: bool,
|
||||||
pub page: Option<i64>,
|
pub page: Option<i64>,
|
||||||
@ -248,7 +237,8 @@ impl<'a> CommunityQuery<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::{community_view::CommunityQuery, structs::CommunityView};
|
use crate::{community_view::CommunityQuery, structs::CommunityView};
|
||||||
|
@ -303,6 +303,7 @@ impl PersonMentionQuery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::{person_mention_view::PersonMentionQuery, structs::PersonMentionView};
|
use crate::{person_mention_view::PersonMentionQuery, structs::PersonMentionView};
|
||||||
|
@ -164,7 +164,7 @@ impl PersonQuery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::indexing_slicing)]
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -222,8 +222,8 @@ impl<T: DataSource> CommunityInboxCollector<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
#[expect(clippy::indexing_slicing)]
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
|
@ -192,8 +192,8 @@ impl SendManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
#[expect(clippy::indexing_slicing)]
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod test {
|
mod test {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -439,8 +439,8 @@ impl InstanceWorker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
#[expect(clippy::indexing_slicing)]
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod test {
|
mod test {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -172,8 +172,6 @@ pub enum LemmyErrorType {
|
|||||||
Unknown(String),
|
Unknown(String),
|
||||||
CantDeleteSite,
|
CantDeleteSite,
|
||||||
UrlLengthOverflow,
|
UrlLengthOverflow,
|
||||||
PostScheduleTimeMustBeInFuture,
|
|
||||||
TooManyScheduledPosts,
|
|
||||||
NotFound,
|
NotFound,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,6 +221,8 @@ fn parse_ip(addr: &str) -> Option<IpAddr> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
#[allow(clippy::unwrap_used)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -136,6 +136,7 @@ impl<K: Eq + Hash, C: MapLevel> MapLevel for Map<K, C> {
|
|||||||
.entry(addr_part)
|
.entry(addr_part)
|
||||||
.or_insert(RateLimitedGroup::new(now, adjusted_configs));
|
.or_insert(RateLimitedGroup::new(now, adjusted_configs));
|
||||||
|
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
let total_passes = group.check_total(action_type, now, adjusted_configs[action_type]);
|
let total_passes = group.check_total(action_type, now, adjusted_configs[action_type]);
|
||||||
|
|
||||||
let children_pass = group.children.check(
|
let children_pass = group.children.check(
|
||||||
@ -160,6 +161,7 @@ impl<K: Eq + Hash, C: MapLevel> MapLevel for Map<K, C> {
|
|||||||
// Evaluated if `some_children_remaining` is false
|
// Evaluated if `some_children_remaining` is false
|
||||||
let total_has_refill_in_future = || {
|
let total_has_refill_in_future = || {
|
||||||
group.total.into_iter().any(|(action_type, bucket)| {
|
group.total.into_iter().any(|(action_type, bucket)| {
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
let config = configs[action_type];
|
let config = configs[action_type];
|
||||||
bucket.update(now, config).tokens != config.capacity
|
bucket.update(now, config).tokens != config.capacity
|
||||||
})
|
})
|
||||||
@ -212,6 +214,7 @@ impl<C: Default> RateLimitedGroup<C> {
|
|||||||
now: InstantSecs,
|
now: InstantSecs,
|
||||||
config: BucketConfig,
|
config: BucketConfig,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
#[allow(clippy::indexing_slicing)] // `EnumMap` has no `get` function
|
||||||
let bucket = &mut self.total[action_type];
|
let bucket = &mut self.total[action_type];
|
||||||
|
|
||||||
let new_bucket = bucket.update(now, config);
|
let new_bucket = bucket.update(now, config);
|
||||||
@ -308,7 +311,8 @@ fn split_ipv6(ip: Ipv6Addr) -> ([u8; 6], u8, u8) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use super::{ActionType, BucketConfig, InstantSecs, RateLimitState, RateLimitedGroup};
|
use super::{ActionType, BucketConfig, InstantSecs, RateLimitState, RateLimitedGroup};
|
||||||
@ -357,6 +361,7 @@ mod tests {
|
|||||||
assert!(post_passed);
|
assert!(post_passed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
let expected_buckets = |factor: u32, tokens_consumed: u32| {
|
let expected_buckets = |factor: u32, tokens_consumed: u32| {
|
||||||
let adjusted_configs = bucket_configs.map(|_, config| BucketConfig {
|
let adjusted_configs = bucket_configs.map(|_, config| BucketConfig {
|
||||||
capacity: config.capacity.saturating_mul(factor),
|
capacity: config.capacity.saturating_mul(factor),
|
||||||
|
@ -107,7 +107,8 @@ pub fn markdown_check_for_blocked_urls(text: &str, blocklist: &RegexSet) -> Lemm
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -134,6 +134,8 @@ pub fn add(markdown_parser: &mut MarkdownIt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
#[allow(clippy::unwrap_used)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::utils::markdown::spoiler_rule::add;
|
use crate::utils::markdown::spoiler_rule::add;
|
||||||
|
@ -34,7 +34,8 @@ pub fn scrape_text_for_mentions(text: &str) -> Vec<MentionData> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::indexing_slicing)]
|
#[allow(clippy::unwrap_used)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod test {
|
mod test {
|
||||||
|
|
||||||
use crate::utils::mention::scrape_text_for_mentions;
|
use crate::utils::mention::scrape_text_for_mentions;
|
||||||
|
@ -61,7 +61,8 @@ pub(crate) fn slurs_vec_to_str(slurs: &[&str]) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[expect(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod test {
|
mod test {
|
||||||
|
|
||||||
use crate::utils::slurs::{remove_slurs, slur_check, slurs_vec_to_str};
|
use crate::utils::slurs::{remove_slurs, slur_check, slurs_vec_to_str};
|
||||||
|
@ -351,6 +351,7 @@ pub fn build_url_str_without_scheme(url_str: &str) -> LemmyResult<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
ALTER TABLE post
|
|
||||||
DROP COLUMN scheduled_publish_time;
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
|||||||
ALTER TABLE post
|
|
||||||
ADD COLUMN scheduled_publish_time timestamptz;
|
|
||||||
|
|
||||||
CREATE INDEX idx_post_scheduled_publish_time ON post (scheduled_publish_time);
|
|
||||||
|
|
@ -14,7 +14,7 @@ CREATE TABLE oauth_provider (
|
|||||||
scopes text NOT NULL,
|
scopes text NOT NULL,
|
||||||
auto_verify_email boolean DEFAULT TRUE NOT NULL,
|
auto_verify_email boolean DEFAULT TRUE NOT NULL,
|
||||||
account_linking_enabled boolean DEFAULT FALSE NOT NULL,
|
account_linking_enabled boolean DEFAULT FALSE NOT NULL,
|
||||||
enabled boolean DEFAULT TRUE NOT NULL,
|
enabled boolean DEFAULT FALSE NOT NULL,
|
||||||
published timestamp with time zone DEFAULT now() NOT NULL,
|
published timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
updated timestamp with time zone
|
updated timestamp with time zone
|
||||||
);
|
);
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
ALTER TABLE local_user
|
|
||||||
ADD COLUMN auto_expand boolean NOT NULL DEFAULT FALSE;
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
|||||||
ALTER TABLE local_user
|
|
||||||
DROP COLUMN auto_expand;
|
|
||||||
|
|
14
src/lib.rs
14
src/lib.rs
@ -157,6 +157,11 @@ pub async fn start_lemmy_server(args: CmdArgs) -> LemmyResult<()> {
|
|||||||
rate_limit_cell.clone(),
|
rate_limit_cell.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let scheduled_tasks = (!args.disable_scheduled_tasks).then(|| {
|
||||||
|
// Schedules various cleanup tasks for the DB
|
||||||
|
tokio::task::spawn(scheduled_tasks::setup(context.clone()))
|
||||||
|
});
|
||||||
|
|
||||||
if let Some(prometheus) = SETTINGS.prometheus.clone() {
|
if let Some(prometheus) = SETTINGS.prometheus.clone() {
|
||||||
serve_prometheus(prometheus, context.clone())?;
|
serve_prometheus(prometheus, context.clone())?;
|
||||||
}
|
}
|
||||||
@ -182,14 +187,7 @@ pub async fn start_lemmy_server(args: CmdArgs) -> LemmyResult<()> {
|
|||||||
}))
|
}))
|
||||||
.expect("set function pointer");
|
.expect("set function pointer");
|
||||||
let request_data = federation_config.to_request_data();
|
let request_data = federation_config.to_request_data();
|
||||||
let outgoing_activities_task = tokio::task::spawn(handle_outgoing_activities(
|
let outgoing_activities_task = tokio::task::spawn(handle_outgoing_activities(request_data));
|
||||||
request_data.reset_request_count(),
|
|
||||||
));
|
|
||||||
|
|
||||||
let scheduled_tasks = (!args.disable_scheduled_tasks).then(|| {
|
|
||||||
// Schedules various cleanup tasks for the DB
|
|
||||||
tokio::task::spawn(scheduled_tasks::setup(request_data.reset_request_count()))
|
|
||||||
});
|
|
||||||
|
|
||||||
let server = if !args.disable_http_server {
|
let server = if !args.disable_http_server {
|
||||||
if let Some(startup_server_handle) = startup_server_handle {
|
if let Some(startup_server_handle) = startup_server_handle {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user