mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-10-01 01:36:12 -04:00
Compare commits
16 Commits
030001dfd7
...
9ca78e1bc9
Author | SHA1 | Date | |
---|---|---|---|
|
9ca78e1bc9 | ||
|
777992e829 | ||
|
0fcbd25ad5 | ||
|
ca8458a7db | ||
|
44dda08b13 | ||
|
5115ed4c09 | ||
|
f7d881ac78 | ||
|
e82f72d3c8 | ||
|
50ce7961d1 | ||
|
a5eaad7afd | ||
|
33cbd95b7e | ||
|
f6a24e133a | ||
|
61a02482ff | ||
|
0fab5bed24 | ||
|
622ce6c976 | ||
|
10079f8295 |
40
Cargo.lock
generated
40
Cargo.lock
generated
@ -42,7 +42,7 @@ dependencies = [
|
||||
"pin-project-lite",
|
||||
"rand",
|
||||
"regex",
|
||||
"reqwest 0.12.7",
|
||||
"reqwest 0.12.8",
|
||||
"reqwest-middleware",
|
||||
"rsa",
|
||||
"serde",
|
||||
@ -839,9 +839,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.17"
|
||||
version = "4.5.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac"
|
||||
checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@ -849,9 +849,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.17"
|
||||
version = "4.5.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73"
|
||||
checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@ -861,9 +861,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.13"
|
||||
version = "4.5.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
|
||||
checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
|
||||
dependencies = [
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
@ -1989,7 +1989,7 @@ dependencies = [
|
||||
"base64 0.22.1",
|
||||
"http-signature-normalization",
|
||||
"httpdate",
|
||||
"reqwest 0.12.7",
|
||||
"reqwest 0.12.8",
|
||||
"reqwest-middleware",
|
||||
"sha2",
|
||||
"thiserror",
|
||||
@ -2514,7 +2514,7 @@ dependencies = [
|
||||
"moka",
|
||||
"pretty_assertions",
|
||||
"regex",
|
||||
"reqwest 0.12.7",
|
||||
"reqwest 0.12.8",
|
||||
"reqwest-middleware",
|
||||
"rosetta-i18n",
|
||||
"serde",
|
||||
@ -2579,7 +2579,7 @@ dependencies = [
|
||||
"lemmy_utils",
|
||||
"moka",
|
||||
"pretty_assertions",
|
||||
"reqwest 0.12.7",
|
||||
"reqwest 0.12.8",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_with",
|
||||
@ -2718,7 +2718,7 @@ dependencies = [
|
||||
"lemmy_utils",
|
||||
"mockall",
|
||||
"moka",
|
||||
"reqwest 0.12.7",
|
||||
"reqwest 0.12.8",
|
||||
"serde_json",
|
||||
"serial_test",
|
||||
"test-context",
|
||||
@ -2745,7 +2745,7 @@ dependencies = [
|
||||
"lemmy_db_views",
|
||||
"lemmy_db_views_actor",
|
||||
"lemmy_utils",
|
||||
"reqwest 0.12.7",
|
||||
"reqwest 0.12.8",
|
||||
"reqwest-middleware",
|
||||
"rss",
|
||||
"serde",
|
||||
@ -2778,7 +2778,7 @@ dependencies = [
|
||||
"lemmy_utils",
|
||||
"pretty_assertions",
|
||||
"prometheus",
|
||||
"reqwest 0.12.7",
|
||||
"reqwest 0.12.8",
|
||||
"reqwest-middleware",
|
||||
"reqwest-tracing",
|
||||
"rustls 0.23.13",
|
||||
@ -2811,7 +2811,7 @@ dependencies = [
|
||||
"markdown-it",
|
||||
"pretty_assertions",
|
||||
"regex",
|
||||
"reqwest 0.12.7",
|
||||
"reqwest 0.12.8",
|
||||
"reqwest-middleware",
|
||||
"rosetta-build",
|
||||
"rosetta-i18n",
|
||||
@ -2870,7 +2870,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-targets 0.52.6",
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3966,9 +3966,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.12.7"
|
||||
version = "0.12.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63"
|
||||
checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b"
|
||||
dependencies = [
|
||||
"async-compression",
|
||||
"base64 0.22.1",
|
||||
@ -4019,7 +4019,7 @@ dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"http 1.1.0",
|
||||
"reqwest 0.12.7",
|
||||
"reqwest 0.12.8",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"tower-service",
|
||||
@ -4036,7 +4036,7 @@ dependencies = [
|
||||
"getrandom",
|
||||
"http 1.1.0",
|
||||
"matchit",
|
||||
"reqwest 0.12.7",
|
||||
"reqwest 0.12.8",
|
||||
"reqwest-middleware",
|
||||
"tracing",
|
||||
]
|
||||
@ -5579,7 +5579,7 @@ version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||
dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -90,7 +90,7 @@ lemmy_db_views = { version = "=0.19.6-beta.7", path = "./crates/db_views" }
|
||||
lemmy_db_views_actor = { version = "=0.19.6-beta.7", path = "./crates/db_views_actor" }
|
||||
lemmy_db_views_moderator = { version = "=0.19.6-beta.7", path = "./crates/db_views_moderator" }
|
||||
lemmy_federate = { version = "=0.19.6-beta.7", path = "./crates/federate" }
|
||||
activitypub_federation = { version = "0.6.0-alpha1", default-features = false, features = [
|
||||
activitypub_federation = { version = "0.6.0-alpha2", default-features = false, features = [
|
||||
"actix-web",
|
||||
] }
|
||||
diesel = "2.1.6"
|
||||
|
@ -27,7 +27,7 @@
|
||||
"eslint": "^9.9.0",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"jest": "^29.5.0",
|
||||
"lemmy-js-client": "0.20.0-alpha.11",
|
||||
"lemmy-js-client": "0.20.0-alpha.12",
|
||||
"prettier": "^3.2.5",
|
||||
"ts-jest": "^29.1.0",
|
||||
"typescript": "^5.5.4",
|
||||
|
@ -30,8 +30,8 @@ importers:
|
||||
specifier: ^29.5.0
|
||||
version: 29.7.0(@types/node@22.3.0)
|
||||
lemmy-js-client:
|
||||
specifier: 0.20.0-alpha.11
|
||||
version: 0.20.0-alpha.11
|
||||
specifier: 0.20.0-alpha.12
|
||||
version: 0.20.0-alpha.12
|
||||
prettier:
|
||||
specifier: ^3.2.5
|
||||
version: 3.3.3
|
||||
@ -1175,8 +1175,8 @@ packages:
|
||||
resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
lemmy-js-client@0.20.0-alpha.11:
|
||||
resolution: {integrity: sha512-iRSG4xHMjPDIreQqVIoJ5JrMY71uk07G0Zbgyf068xKbib22J3+i1x/XgCTs6tiHlqTnw1Ig/KRq7p7qJoA4uw==}
|
||||
lemmy-js-client@0.20.0-alpha.12:
|
||||
resolution: {integrity: sha512-+nknIpFAT25TnhObvPPCI0JhDxmTSfg3jbNm7f4RnwidRskjS8SraNFD4bXFfHf14lu61ZEiVe58+UhhRe2UdA==}
|
||||
|
||||
leven@3.1.0:
|
||||
resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==}
|
||||
@ -3107,7 +3107,7 @@ snapshots:
|
||||
|
||||
kleur@3.0.3: {}
|
||||
|
||||
lemmy-js-client@0.20.0-alpha.11: {}
|
||||
lemmy-js-client@0.20.0-alpha.12: {}
|
||||
|
||||
leven@3.1.0: {}
|
||||
|
||||
|
@ -858,3 +858,26 @@ test("Dont send a comment reply to a blocked community", async () => {
|
||||
blockRes = await blockCommunity(beta, newCommunityId, false);
|
||||
expect(blockRes.blocked).toBe(false);
|
||||
});
|
||||
|
||||
/// Fetching a deeply nested comment can lead to stack overflow as all parent comments are also
|
||||
/// fetched recursively. Ensure that it works properly.
|
||||
test("Fetch a deeply nested comment", async () => {
|
||||
let lastComment;
|
||||
for (let i = 0; i < 50; i++) {
|
||||
let commentRes = await createComment(
|
||||
alpha,
|
||||
postOnAlphaRes.post_view.post.id,
|
||||
lastComment?.comment_view.comment.id,
|
||||
);
|
||||
expect(commentRes.comment_view.comment).toBeDefined();
|
||||
lastComment = commentRes;
|
||||
}
|
||||
|
||||
let betaComment = await resolveComment(
|
||||
beta,
|
||||
lastComment!.comment_view.comment,
|
||||
);
|
||||
|
||||
expect(betaComment!.comment!.comment).toBeDefined();
|
||||
expect(betaComment?.comment?.post).toBeDefined();
|
||||
});
|
||||
|
@ -265,8 +265,6 @@ pub async fn local_user_view_from_jwt(
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
@ -1,34 +1,39 @@
|
||||
use actix_web::web::{Data, Json};
|
||||
use lemmy_api_common::{context::LemmyContext, post::HidePost, SuccessResponse};
|
||||
use lemmy_api_common::{
|
||||
context::LemmyContext,
|
||||
post::{HidePost, PostResponse},
|
||||
};
|
||||
use lemmy_db_schema::source::post::PostHide;
|
||||
use lemmy_db_views::structs::LocalUserView;
|
||||
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult, MAX_API_PARAM_ELEMENTS};
|
||||
use std::collections::HashSet;
|
||||
use lemmy_db_views::structs::{LocalUserView, PostView};
|
||||
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult};
|
||||
|
||||
#[tracing::instrument(skip(context))]
|
||||
pub async fn hide_post(
|
||||
data: Json<HidePost>,
|
||||
context: Data<LemmyContext>,
|
||||
local_user_view: LocalUserView,
|
||||
) -> LemmyResult<Json<SuccessResponse>> {
|
||||
let post_ids = HashSet::from_iter(data.post_ids.clone());
|
||||
|
||||
if post_ids.len() > MAX_API_PARAM_ELEMENTS {
|
||||
Err(LemmyErrorType::TooManyItems)?;
|
||||
}
|
||||
|
||||
) -> LemmyResult<Json<PostResponse>> {
|
||||
let person_id = local_user_view.person.id;
|
||||
let post_id = data.post_id;
|
||||
|
||||
// Mark the post as hidden / unhidden
|
||||
if data.hide {
|
||||
PostHide::hide(&mut context.pool(), post_ids, person_id)
|
||||
PostHide::hide(&mut context.pool(), post_id, person_id)
|
||||
.await
|
||||
.with_lemmy_type(LemmyErrorType::CouldntHidePost)?;
|
||||
} else {
|
||||
PostHide::unhide(&mut context.pool(), post_ids, person_id)
|
||||
PostHide::unhide(&mut context.pool(), post_id, person_id)
|
||||
.await
|
||||
.with_lemmy_type(LemmyErrorType::CouldntHidePost)?;
|
||||
}
|
||||
|
||||
Ok(Json(SuccessResponse::default()))
|
||||
let post_view = PostView::read(
|
||||
&mut context.pool(),
|
||||
post_id,
|
||||
Some(&local_user_view.local_user),
|
||||
false,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(Json(PostResponse { post_view }))
|
||||
}
|
||||
|
@ -1,34 +1,38 @@
|
||||
use actix_web::web::{Data, Json};
|
||||
use lemmy_api_common::{context::LemmyContext, post::MarkPostAsRead, SuccessResponse};
|
||||
use lemmy_api_common::{
|
||||
context::LemmyContext,
|
||||
post::{MarkPostAsRead, PostResponse},
|
||||
};
|
||||
use lemmy_db_schema::source::post::PostRead;
|
||||
use lemmy_db_views::structs::LocalUserView;
|
||||
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult, MAX_API_PARAM_ELEMENTS};
|
||||
use std::collections::HashSet;
|
||||
use lemmy_db_views::structs::{LocalUserView, PostView};
|
||||
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult};
|
||||
|
||||
#[tracing::instrument(skip(context))]
|
||||
pub async fn mark_post_as_read(
|
||||
data: Json<MarkPostAsRead>,
|
||||
context: Data<LemmyContext>,
|
||||
local_user_view: LocalUserView,
|
||||
) -> LemmyResult<Json<SuccessResponse>> {
|
||||
let post_ids = HashSet::from_iter(data.post_ids.clone());
|
||||
|
||||
if post_ids.len() > MAX_API_PARAM_ELEMENTS {
|
||||
Err(LemmyErrorType::TooManyItems)?;
|
||||
}
|
||||
|
||||
) -> LemmyResult<Json<PostResponse>> {
|
||||
let person_id = local_user_view.person.id;
|
||||
let post_id = data.post_id;
|
||||
|
||||
// Mark the post as read / unread
|
||||
if data.read {
|
||||
PostRead::mark_as_read(&mut context.pool(), post_ids, person_id)
|
||||
PostRead::mark_as_read(&mut context.pool(), post_id, person_id)
|
||||
.await
|
||||
.with_lemmy_type(LemmyErrorType::CouldntMarkPostAsRead)?;
|
||||
} else {
|
||||
PostRead::mark_as_unread(&mut context.pool(), post_ids, person_id)
|
||||
PostRead::mark_as_unread(&mut context.pool(), post_id, person_id)
|
||||
.await
|
||||
.with_lemmy_type(LemmyErrorType::CouldntMarkPostAsRead)?;
|
||||
}
|
||||
let post_view = PostView::read(
|
||||
&mut context.pool(),
|
||||
post_id,
|
||||
Some(&local_user_view.local_user),
|
||||
false,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(Json(SuccessResponse::default()))
|
||||
Ok(Json(PostResponse { post_view }))
|
||||
}
|
||||
|
@ -76,5 +76,7 @@ pub async fn leave_admin(
|
||||
admin_oauth_providers: None,
|
||||
blocked_urls,
|
||||
tagline,
|
||||
taglines: vec![],
|
||||
custom_emojis: vec![],
|
||||
}))
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ use lemmy_db_views::structs::LocalUserView;
|
||||
use lemmy_utils::{error::LemmyResult, LemmyErrorType, CACHE_DURATION_API};
|
||||
use serial_test::serial;
|
||||
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
async fn create_test_site(context: &Data<LemmyContext>) -> LemmyResult<(Instance, LocalUserView)> {
|
||||
let pool = &mut context.pool();
|
||||
|
||||
@ -109,7 +109,7 @@ async fn signup(
|
||||
Ok((local_user, application))
|
||||
}
|
||||
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
async fn get_application_statuses(
|
||||
context: &Data<LemmyContext>,
|
||||
admin: LocalUserView,
|
||||
@ -138,10 +138,9 @@ async fn get_application_statuses(
|
||||
Ok((application_count, unread_applications, all_applications))
|
||||
}
|
||||
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
#[tokio::test]
|
||||
#[expect(clippy::indexing_slicing)]
|
||||
async fn test_application_approval() -> LemmyResult<()> {
|
||||
let context = LemmyContext::init_test_context().await;
|
||||
let pool = &mut context.pool();
|
||||
|
@ -42,7 +42,7 @@ pub async fn get_sitemap(context: Data<LemmyContext>) -> LemmyResult<HttpRespons
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
pub(crate) mod tests {
|
||||
|
||||
use crate::sitemap::generate_urlset;
|
||||
|
@ -69,8 +69,7 @@ impl Claims {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
mod tests {
|
||||
|
||||
use crate::{claims::Claims, context::LemmyContext};
|
||||
|
@ -5,6 +5,7 @@ use serde_with::skip_serializing_none;
|
||||
use ts_rs::TS;
|
||||
use url::Url;
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
@ -19,11 +20,12 @@ pub struct CreateOAuthProvider {
|
||||
pub client_id: String,
|
||||
pub client_secret: String,
|
||||
pub scopes: String,
|
||||
pub auto_verify_email: bool,
|
||||
pub account_linking_enabled: bool,
|
||||
pub enabled: bool,
|
||||
pub auto_verify_email: Option<bool>,
|
||||
pub account_linking_enabled: Option<bool>,
|
||||
pub enabled: Option<bool>,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[cfg_attr(feature = "full", derive(TS))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
|
@ -156,7 +156,7 @@ pub struct RemovePost {
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// Mark a post as read.
|
||||
pub struct MarkPostAsRead {
|
||||
pub post_ids: Vec<PostId>,
|
||||
pub post_id: PostId,
|
||||
pub read: bool,
|
||||
}
|
||||
|
||||
@ -166,7 +166,7 @@ pub struct MarkPostAsRead {
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
/// Hide a post from list views
|
||||
pub struct HidePost {
|
||||
pub post_ids: Vec<PostId>,
|
||||
pub post_id: PostId,
|
||||
pub hide: bool,
|
||||
}
|
||||
|
||||
|
@ -471,8 +471,7 @@ pub async fn replace_image(
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
mod tests {
|
||||
|
||||
use crate::{
|
||||
|
@ -78,7 +78,7 @@ pub struct Search {
|
||||
pub listing_type: Option<ListingType>,
|
||||
pub page: Option<i64>,
|
||||
pub limit: Option<i64>,
|
||||
pub post_title_only: Option<bool>,
|
||||
pub title_only: Option<bool>,
|
||||
pub post_url_only: Option<bool>,
|
||||
pub saved_only: Option<bool>,
|
||||
pub liked_only: Option<bool>,
|
||||
@ -306,6 +306,8 @@ pub struct EditSite {
|
||||
/// The response for a site.
|
||||
pub struct SiteResponse {
|
||||
pub site_view: SiteView,
|
||||
/// deprecated, use field `tagline` or /api/v3/tagline/list
|
||||
pub taglines: Vec<()>,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
@ -320,6 +322,10 @@ pub struct GetSiteResponse {
|
||||
pub my_user: Option<MyUserInfo>,
|
||||
pub all_languages: Vec<Language>,
|
||||
pub discussion_languages: Vec<LanguageId>,
|
||||
/// deprecated, use field `tagline` or /api/v3/tagline/list
|
||||
pub taglines: Vec<()>,
|
||||
/// deprecated, use /api/v3/custom_emoji/list
|
||||
pub custom_emojis: Vec<()>,
|
||||
/// If the site has any taglines, a random one is included here for displaying
|
||||
pub tagline: Option<Tagline>,
|
||||
/// A list of external auth methods your site supports.
|
||||
|
@ -59,7 +59,7 @@ use lemmy_utils::{
|
||||
use moka::future::Cache;
|
||||
use regex::{escape, Regex, RegexSet};
|
||||
use rosetta_i18n::{Language, LanguageId};
|
||||
use std::{collections::HashSet, sync::LazyLock};
|
||||
use std::sync::LazyLock;
|
||||
use tracing::warn;
|
||||
use url::{ParseError, Url};
|
||||
use urlencoding::encode;
|
||||
@ -142,7 +142,7 @@ pub async fn mark_post_as_read(
|
||||
post_id: PostId,
|
||||
pool: &mut DbPool<'_>,
|
||||
) -> LemmyResult<()> {
|
||||
PostRead::mark_as_read(pool, HashSet::from([post_id]), person_id)
|
||||
PostRead::mark_as_read(pool, post_id, person_id)
|
||||
.await
|
||||
.with_lemmy_type(LemmyErrorType::CouldntMarkPostAsRead)?;
|
||||
Ok(())
|
||||
@ -1067,8 +1067,7 @@ fn build_proxied_image_url(
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
@ -30,10 +30,9 @@ use lemmy_db_views::structs::{LocalUserView, PostView};
|
||||
use lemmy_utils::{
|
||||
error::{LemmyErrorExt, LemmyErrorType, LemmyResult},
|
||||
utils::{mention::scrape_text_for_mentions, validation::is_valid_body_field},
|
||||
MAX_COMMENT_DEPTH_LIMIT,
|
||||
};
|
||||
|
||||
const MAX_COMMENT_DEPTH_LIMIT: usize = 100;
|
||||
|
||||
#[tracing::instrument(skip(context))]
|
||||
pub async fn create_comment(
|
||||
data: Json<CreateComment>,
|
||||
|
@ -139,7 +139,10 @@ pub async fn create_site(
|
||||
local_site_rate_limit_to_rate_limit_config(&site_view.local_site_rate_limit);
|
||||
context.rate_limit_cell().set_config(rate_limit_config);
|
||||
|
||||
Ok(Json(SiteResponse { site_view }))
|
||||
Ok(Json(SiteResponse {
|
||||
site_view,
|
||||
taglines: vec![],
|
||||
}))
|
||||
}
|
||||
|
||||
fn validate_create_payload(local_site: &LocalSite, create_site: &CreateSite) -> LemmyResult<()> {
|
||||
@ -189,8 +192,6 @@ fn validate_create_payload(local_site: &LocalSite, create_site: &CreateSite) ->
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
mod tests {
|
||||
|
||||
use crate::site::create::validate_create_payload;
|
||||
|
@ -48,8 +48,6 @@ fn not_zero(val: Option<i32>) -> Option<i32> {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
mod tests {
|
||||
|
||||
use crate::site::{application_question_check, not_zero, site_default_post_listing_type_check};
|
||||
|
@ -59,6 +59,8 @@ pub async fn get_site(
|
||||
tagline,
|
||||
oauth_providers: Some(oauth_providers),
|
||||
admin_oauth_providers: Some(admin_oauth_providers),
|
||||
taglines: vec![],
|
||||
custom_emojis: vec![],
|
||||
})
|
||||
})
|
||||
.await
|
||||
|
@ -193,7 +193,10 @@ pub async fn update_site(
|
||||
local_site_rate_limit_to_rate_limit_config(&site_view.local_site_rate_limit);
|
||||
context.rate_limit_cell().set_config(rate_limit_config);
|
||||
|
||||
Ok(Json(SiteResponse { site_view }))
|
||||
Ok(Json(SiteResponse {
|
||||
site_view,
|
||||
taglines: vec![],
|
||||
}))
|
||||
}
|
||||
|
||||
fn validate_update_payload(local_site: &LocalSite, edit_site: &EditSite) -> LemmyResult<()> {
|
||||
@ -241,8 +244,6 @@ fn validate_update_payload(local_site: &LocalSite, edit_site: &EditSite) -> Lemm
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
mod tests {
|
||||
|
||||
use crate::site::update::validate_update_payload;
|
||||
|
@ -107,9 +107,7 @@ pub async fn register(
|
||||
check_slurs(&data.username, &slur_regex)?;
|
||||
check_slurs_opt(&data.answer, &slur_regex)?;
|
||||
|
||||
if Person::is_username_taken(&mut context.pool(), &data.username).await? {
|
||||
return Err(LemmyErrorType::UsernameAlreadyExists)?;
|
||||
}
|
||||
Person::check_username_taken(&mut context.pool(), &data.username).await?;
|
||||
|
||||
if let Some(email) = &data.email {
|
||||
LocalUser::check_is_email_taken(&mut context.pool(), email).await?;
|
||||
@ -329,9 +327,7 @@ pub async fn authenticate_with_oauth(
|
||||
check_slurs(username, &slur_regex)?;
|
||||
check_slurs_opt(&data.answer, &slur_regex)?;
|
||||
|
||||
if Person::is_username_taken(&mut context.pool(), username).await? {
|
||||
return Err(LemmyErrorType::UsernameAlreadyExists)?;
|
||||
}
|
||||
Person::check_username_taken(&mut context.pool(), username).await?;
|
||||
|
||||
// We have to create a person, a local_user, and an oauth_account
|
||||
person = create_person(
|
||||
|
@ -123,7 +123,6 @@ impl InCommunity for AnnouncableActivities {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
mod tests {
|
||||
|
||||
use crate::{
|
||||
|
@ -47,7 +47,7 @@ pub async fn search(
|
||||
listing_type,
|
||||
page,
|
||||
limit,
|
||||
post_title_only,
|
||||
title_only,
|
||||
post_url_only,
|
||||
saved_only,
|
||||
liked_only,
|
||||
@ -78,7 +78,7 @@ pub async fn search(
|
||||
search_term: Some(q.clone()),
|
||||
page,
|
||||
limit,
|
||||
title_only: post_title_only,
|
||||
title_only,
|
||||
url_only: post_url_only,
|
||||
liked_only,
|
||||
disliked_only,
|
||||
@ -105,6 +105,7 @@ pub async fn search(
|
||||
sort,
|
||||
listing_type,
|
||||
search_term: Some(q.clone()),
|
||||
title_only,
|
||||
local_user,
|
||||
is_mod_or_admin: is_admin,
|
||||
page,
|
||||
|
@ -103,13 +103,16 @@ pub async fn import_settings(
|
||||
context: Data<LemmyContext>,
|
||||
) -> LemmyResult<Json<SuccessResponse>> {
|
||||
let person_form = PersonUpdateForm {
|
||||
display_name: Some(data.display_name.clone()),
|
||||
bio: Some(data.bio.clone()),
|
||||
matrix_user_id: Some(data.matrix_id.clone()),
|
||||
display_name: data.display_name.clone().map(Some),
|
||||
bio: data.bio.clone().map(Some),
|
||||
matrix_user_id: data.bio.clone().map(Some),
|
||||
bot_account: data.bot_account,
|
||||
..Default::default()
|
||||
};
|
||||
Person::update(&mut context.pool(), local_user_view.person.id, &person_form).await?;
|
||||
// ignore error in case form is empty
|
||||
Person::update(&mut context.pool(), local_user_view.person.id, &person_form)
|
||||
.await
|
||||
.ok();
|
||||
|
||||
let local_user_form = LocalUserUpdateForm {
|
||||
show_nsfw: data.settings.as_ref().map(|s| s.show_nsfw),
|
||||
@ -307,12 +310,14 @@ where
|
||||
});
|
||||
Ok(failed_items.into_iter().join(","))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::indexing_slicing)]
|
||||
mod tests {
|
||||
|
||||
use crate::api::user_settings_backup::{export_settings, import_settings, UserSettingsBackup};
|
||||
use crate::api::user_settings_backup::{export_settings, import_settings};
|
||||
use activitypub_federation::config::Data;
|
||||
use actix_web::web::Json;
|
||||
use lemmy_api_common::context::LemmyContext;
|
||||
use lemmy_db_schema::{
|
||||
source::{
|
||||
@ -400,45 +405,6 @@ mod tests {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
async fn test_settings_partial_import() -> LemmyResult<()> {
|
||||
let context = LemmyContext::init_test_context().await;
|
||||
|
||||
let export_user =
|
||||
create_user("hanna".to_string(), Some("my bio".to_string()), &context).await?;
|
||||
|
||||
let community_form = CommunityInsertForm::new(
|
||||
export_user.person.instance_id,
|
||||
"testcom".to_string(),
|
||||
"testcom".to_string(),
|
||||
"pubkey".to_string(),
|
||||
);
|
||||
let community = Community::create(&mut context.pool(), &community_form).await?;
|
||||
let follower_form = CommunityFollowerForm {
|
||||
community_id: community.id,
|
||||
person_id: export_user.person.id,
|
||||
pending: false,
|
||||
};
|
||||
CommunityFollower::follow(&mut context.pool(), &follower_form).await?;
|
||||
|
||||
let backup = export_settings(export_user.clone(), context.reset_request_count()).await?;
|
||||
|
||||
let import_user = create_user("charles".to_string(), None, &context).await?;
|
||||
|
||||
let backup2 = UserSettingsBackup {
|
||||
followed_communities: backup.followed_communities.clone(),
|
||||
..Default::default()
|
||||
};
|
||||
import_settings(
|
||||
actix_web::web::Json(backup2),
|
||||
import_user.clone(),
|
||||
context.reset_request_count(),
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
async fn disallow_large_backup() -> LemmyResult<()> {
|
||||
@ -474,4 +440,33 @@ mod tests {
|
||||
LocalUser::delete(&mut context.pool(), import_user.local_user.id).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
async fn import_partial_backup() -> LemmyResult<()> {
|
||||
let context = LemmyContext::init_test_context().await;
|
||||
|
||||
let import_user =
|
||||
create_user("hanna".to_string(), Some("my bio".to_string()), &context).await?;
|
||||
|
||||
let backup =
|
||||
serde_json::from_str("{\"bot_account\": true, \"settings\": {\"theme\": \"my_theme\"}}")?;
|
||||
import_settings(
|
||||
Json(backup),
|
||||
import_user.clone(),
|
||||
context.reset_request_count(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let import_user_updated =
|
||||
LocalUserView::read(&mut context.pool(), import_user.local_user.id).await?;
|
||||
// mark as bot account
|
||||
assert!(import_user_updated.person.bot_account);
|
||||
// dont remove existing bio
|
||||
assert_eq!(import_user.person.bio, import_user_updated.person.bio);
|
||||
// local_user can be deserialized without id/person_id fields
|
||||
assert_eq!("my_theme", import_user_updated.local_user.theme);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ impl Collection for ApubCommunityModerators {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::indexing_slicing)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
@ -120,8 +120,7 @@ pub(crate) async fn get_apub_community_featured(
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
pub(crate) mod tests {
|
||||
|
||||
use super::*;
|
||||
|
@ -20,10 +20,9 @@ use lemmy_db_schema::{
|
||||
source::{community::Community, post::Post},
|
||||
traits::Crud,
|
||||
};
|
||||
use lemmy_utils::error::LemmyResult;
|
||||
use lemmy_utils::{error::LemmyResult, LemmyErrorType, MAX_COMMENT_DEPTH_LIMIT};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::skip_serializing_none;
|
||||
use std::ops::Deref;
|
||||
use url::Url;
|
||||
|
||||
#[skip_serializing_none]
|
||||
@ -58,9 +57,19 @@ impl Note {
|
||||
&self,
|
||||
context: &Data<LemmyContext>,
|
||||
) -> LemmyResult<(ApubPost, Option<ApubComment>)> {
|
||||
// Fetch parent comment chain in a box, otherwise it can cause a stack overflow.
|
||||
let parent = Box::pin(self.in_reply_to.dereference(context).await?);
|
||||
match parent.deref() {
|
||||
// We use recursion here to fetch the entire comment chain up to the top-level parent. This is
|
||||
// necessary because we need to know the post and parent comment in order to insert a new
|
||||
// comment. However it can also lead to stack overflow when fetching many comments recursively.
|
||||
// To avoid this we check the request count against max comment depth, which based on testing
|
||||
// can be handled without risking stack overflow. This is not a perfect solution, because in
|
||||
// some cases we have to fetch user profiles too, and reach the limit after only 25 comments
|
||||
// or so.
|
||||
// A cleaner solution would be converting the recursion into a loop, but that is tricky.
|
||||
if context.request_count() > MAX_COMMENT_DEPTH_LIMIT as u32 {
|
||||
Err(LemmyErrorType::MaxCommentDepthReached)?;
|
||||
}
|
||||
let parent = self.in_reply_to.dereference(context).await?;
|
||||
match parent {
|
||||
PostOrComment::Post(p) => Ok((p.clone(), None)),
|
||||
PostOrComment::Comment(c) => {
|
||||
let post_id = c.post_id;
|
||||
|
@ -75,7 +75,7 @@ impl<S: ValidGrouping<(), IsAggregate = is_aggregate::No>> ValidGrouping<()>
|
||||
type IsAggregate = is_aggregate::No;
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[expect(non_camel_case_types)]
|
||||
#[derive(QueryId, Clone, Copy, Debug)]
|
||||
pub struct current_value;
|
||||
|
||||
|
@ -30,8 +30,7 @@ impl CommentAggregates {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
mod tests {
|
||||
|
||||
use crate::{
|
||||
|
@ -36,8 +36,7 @@ impl CommunityAggregates {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
mod tests {
|
||||
|
||||
use crate::{
|
||||
|
@ -20,8 +20,7 @@ impl PersonAggregates {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
mod tests {
|
||||
|
||||
use crate::{
|
||||
|
@ -49,8 +49,8 @@ impl PostAggregates {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
|
||||
mod tests {
|
||||
|
||||
use crate::{
|
||||
|
@ -15,8 +15,8 @@ impl SiteAggregates {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
|
||||
mod tests {
|
||||
|
||||
use crate::{
|
||||
|
@ -58,8 +58,7 @@ impl ReceivedActivity {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
@ -392,8 +392,8 @@ async fn convert_read_languages(
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
#[expect(clippy::indexing_slicing)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
@ -51,8 +51,6 @@ impl CaptchaAnswer {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
mod tests {
|
||||
|
||||
use crate::{
|
||||
|
@ -196,8 +196,7 @@ impl Saveable for CommentSaved {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
mod tests {
|
||||
|
||||
use crate::{
|
||||
|
@ -431,7 +431,6 @@ impl ApubActor for Community {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
mod tests {
|
||||
use crate::{
|
||||
source::{
|
||||
|
@ -48,8 +48,7 @@ impl FederationAllowList {
|
||||
}
|
||||
}
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
mod tests {
|
||||
|
||||
use crate::{
|
||||
|
@ -41,8 +41,8 @@ impl Language {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
#[expect(clippy::indexing_slicing)]
|
||||
mod tests {
|
||||
|
||||
use crate::{source::language::Language, utils::build_db_pool_for_tests};
|
||||
|
@ -369,7 +369,6 @@ pub struct UserBackupLists {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
mod tests {
|
||||
use crate::{
|
||||
source::{
|
||||
|
@ -465,8 +465,7 @@ impl Crud for AdminPurgeComment {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
mod tests {
|
||||
|
||||
use crate::{
|
||||
|
@ -1,32 +1,13 @@
|
||||
use crate::{
|
||||
newtypes::{LocalUserId, OAuthProviderId},
|
||||
newtypes::LocalUserId,
|
||||
schema::{oauth_account, oauth_account::dsl::local_user_id},
|
||||
source::oauth_account::{OAuthAccount, OAuthAccountInsertForm},
|
||||
utils::{get_conn, DbPool},
|
||||
};
|
||||
use diesel::{
|
||||
dsl::{exists, insert_into},
|
||||
result::Error,
|
||||
select,
|
||||
ExpressionMethods,
|
||||
QueryDsl,
|
||||
};
|
||||
use diesel::{insert_into, result::Error, ExpressionMethods, QueryDsl};
|
||||
use diesel_async::RunQueryDsl;
|
||||
|
||||
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> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
insert_into(oauth_account::table)
|
||||
@ -35,17 +16,6 @@ impl OAuthAccount {
|
||||
.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(
|
||||
pool: &mut DbPool<'_>,
|
||||
for_local_user_id: LocalUserId,
|
||||
|
@ -42,8 +42,6 @@ impl PasswordResetRequest {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
mod tests {
|
||||
|
||||
use crate::{
|
||||
|
@ -21,6 +21,7 @@ use diesel::{
|
||||
QueryDsl,
|
||||
};
|
||||
use diesel_async::RunQueryDsl;
|
||||
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
|
||||
|
||||
#[async_trait]
|
||||
impl Crud for Person {
|
||||
@ -121,16 +122,18 @@ impl Person {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn is_username_taken(pool: &mut DbPool<'_>, username: &str) -> Result<bool, Error> {
|
||||
pub async fn check_username_taken(pool: &mut DbPool<'_>, username: &str) -> LemmyResult<()> {
|
||||
use diesel::dsl::{exists, select};
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
select(exists(
|
||||
select(not(exists(
|
||||
person::table
|
||||
.filter(lower(person::name).eq(username.to_lowercase()))
|
||||
.filter(person::local.eq(true)),
|
||||
))
|
||||
.get_result(conn)
|
||||
.await
|
||||
)))
|
||||
.get_result::<bool>(conn)
|
||||
.await?
|
||||
.then_some(())
|
||||
.ok_or(LemmyErrorType::UsernameAlreadyExists.into())
|
||||
}
|
||||
}
|
||||
|
||||
@ -232,7 +235,6 @@ impl PersonFollower {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
mod tests {
|
||||
|
||||
use crate::{
|
||||
|
@ -39,7 +39,6 @@ use diesel::{
|
||||
TextExpressionMethods,
|
||||
};
|
||||
use diesel_async::RunQueryDsl;
|
||||
use std::collections::HashSet;
|
||||
|
||||
#[async_trait]
|
||||
impl Crud for Post {
|
||||
@ -258,9 +257,9 @@ impl Post {
|
||||
post::table
|
||||
.inner_join(person::table)
|
||||
.inner_join(community::table)
|
||||
// find all posts which have scheduled_publish_time that is in the past
|
||||
// find all posts which have scheduled_publish_time that is in the future
|
||||
.filter(post::scheduled_publish_time.is_not_null())
|
||||
.filter(coalesce(post::scheduled_publish_time, now()).lt(now()))
|
||||
.filter(coalesce(post::scheduled_publish_time, now()).gt(now()))
|
||||
// make sure the post and community are still around
|
||||
.filter(not(post::deleted.or(post::removed)))
|
||||
.filter(not(community::removed.or(community::deleted)))
|
||||
@ -322,17 +321,15 @@ impl Saveable for PostSaved {
|
||||
impl PostRead {
|
||||
pub async fn mark_as_read(
|
||||
pool: &mut DbPool<'_>,
|
||||
post_ids: HashSet<PostId>,
|
||||
post_id: PostId,
|
||||
person_id: PersonId,
|
||||
) -> Result<usize, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
|
||||
let forms = post_ids
|
||||
.into_iter()
|
||||
.map(|post_id| PostReadForm { post_id, person_id })
|
||||
.collect::<Vec<PostReadForm>>();
|
||||
let form = PostReadForm { post_id, person_id };
|
||||
|
||||
insert_into(post_read::table)
|
||||
.values(forms)
|
||||
.values(form)
|
||||
.on_conflict_do_nothing()
|
||||
.execute(conn)
|
||||
.await
|
||||
@ -340,35 +337,30 @@ impl PostRead {
|
||||
|
||||
pub async fn mark_as_unread(
|
||||
pool: &mut DbPool<'_>,
|
||||
post_id_: HashSet<PostId>,
|
||||
post_id_: PostId,
|
||||
person_id_: PersonId,
|
||||
) -> Result<usize, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
|
||||
diesel::delete(
|
||||
post_read::table
|
||||
.filter(post_read::post_id.eq_any(post_id_))
|
||||
.filter(post_read::person_id.eq(person_id_)),
|
||||
)
|
||||
.execute(conn)
|
||||
.await
|
||||
let read_post = post_read::table
|
||||
.filter(post_read::post_id.eq(post_id_))
|
||||
.filter(post_read::person_id.eq(person_id_));
|
||||
|
||||
diesel::delete(read_post).execute(conn).await
|
||||
}
|
||||
}
|
||||
|
||||
impl PostHide {
|
||||
pub async fn hide(
|
||||
pool: &mut DbPool<'_>,
|
||||
post_ids: HashSet<PostId>,
|
||||
post_id: PostId,
|
||||
person_id: PersonId,
|
||||
) -> Result<usize, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
|
||||
let forms = post_ids
|
||||
.into_iter()
|
||||
.map(|post_id| PostHideForm { post_id, person_id })
|
||||
.collect::<Vec<PostHideForm>>();
|
||||
let form = PostHideForm { post_id, person_id };
|
||||
insert_into(post_hide::table)
|
||||
.values(forms)
|
||||
.values(form)
|
||||
.on_conflict_do_nothing()
|
||||
.execute(conn)
|
||||
.await
|
||||
@ -376,23 +368,20 @@ impl PostHide {
|
||||
|
||||
pub async fn unhide(
|
||||
pool: &mut DbPool<'_>,
|
||||
post_id_: HashSet<PostId>,
|
||||
post_id_: PostId,
|
||||
person_id_: PersonId,
|
||||
) -> Result<usize, Error> {
|
||||
let conn = &mut get_conn(pool).await?;
|
||||
|
||||
diesel::delete(
|
||||
post_hide::table
|
||||
.filter(post_hide::post_id.eq_any(post_id_))
|
||||
.filter(post_hide::person_id.eq(person_id_)),
|
||||
)
|
||||
.execute(conn)
|
||||
.await
|
||||
let hidden_post = post_hide::table
|
||||
.filter(post_hide::post_id.eq(post_id_))
|
||||
.filter(post_hide::person_id.eq(person_id_));
|
||||
|
||||
diesel::delete(hidden_post).execute(conn).await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
mod tests {
|
||||
|
||||
@ -415,24 +404,23 @@ mod tests {
|
||||
traits::{Crud, Likeable, Saveable},
|
||||
utils::build_db_pool_for_tests,
|
||||
};
|
||||
use chrono::DateTime;
|
||||
use lemmy_utils::error::LemmyResult;
|
||||
use pretty_assertions::assert_eq;
|
||||
use serial_test::serial;
|
||||
use std::collections::HashSet;
|
||||
use url::Url;
|
||||
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
async fn test_crud() {
|
||||
async fn test_crud() -> LemmyResult<()> {
|
||||
let pool = &build_db_pool_for_tests().await;
|
||||
let pool = &mut pool.into();
|
||||
|
||||
let inserted_instance = Instance::read_or_create(pool, "my_domain.tld".to_string())
|
||||
.await
|
||||
.unwrap();
|
||||
let inserted_instance = Instance::read_or_create(pool, "my_domain.tld".to_string()).await?;
|
||||
|
||||
let new_person = PersonInsertForm::test_form(inserted_instance.id, "jim");
|
||||
|
||||
let inserted_person = Person::create(pool, &new_person).await.unwrap();
|
||||
let inserted_person = Person::create(pool, &new_person).await?;
|
||||
|
||||
let new_community = CommunityInsertForm::new(
|
||||
inserted_instance.id,
|
||||
@ -441,21 +429,27 @@ mod tests {
|
||||
"pubkey".to_string(),
|
||||
);
|
||||
|
||||
let inserted_community = Community::create(pool, &new_community).await.unwrap();
|
||||
let inserted_community = Community::create(pool, &new_community).await?;
|
||||
|
||||
let new_post = PostInsertForm::new(
|
||||
"A test post".into(),
|
||||
inserted_person.id,
|
||||
inserted_community.id,
|
||||
);
|
||||
let inserted_post = Post::create(pool, &new_post).await.unwrap();
|
||||
let inserted_post = Post::create(pool, &new_post).await?;
|
||||
|
||||
let new_post2 = PostInsertForm::new(
|
||||
"A test post 2".into(),
|
||||
inserted_person.id,
|
||||
inserted_community.id,
|
||||
);
|
||||
let inserted_post2 = Post::create(pool, &new_post2).await.unwrap();
|
||||
let inserted_post2 = Post::create(pool, &new_post2).await?;
|
||||
|
||||
let new_scheduled_post = PostInsertForm {
|
||||
scheduled_publish_time: Some(DateTime::from_timestamp_nanos(i64::MAX)),
|
||||
..PostInsertForm::new("beans".into(), inserted_person.id, inserted_community.id)
|
||||
};
|
||||
let inserted_scheduled_post = Post::create(pool, &new_scheduled_post).await?;
|
||||
|
||||
let expected_post = Post {
|
||||
id: inserted_post.id,
|
||||
@ -475,9 +469,7 @@ mod tests {
|
||||
embed_description: None,
|
||||
embed_video_url: None,
|
||||
thumbnail_url: None,
|
||||
ap_id: Url::parse(&format!("https://lemmy-alpha/post/{}", inserted_post.id))
|
||||
.unwrap()
|
||||
.into(),
|
||||
ap_id: Url::parse(&format!("https://lemmy-alpha/post/{}", inserted_post.id))?.into(),
|
||||
local: true,
|
||||
language_id: Default::default(),
|
||||
featured_community: false,
|
||||
@ -493,7 +485,7 @@ mod tests {
|
||||
score: 1,
|
||||
};
|
||||
|
||||
let inserted_post_like = PostLike::like(pool, &post_like_form).await.unwrap();
|
||||
let inserted_post_like = PostLike::like(pool, &post_like_form).await?;
|
||||
|
||||
let expected_post_like = PostLike {
|
||||
post_id: inserted_post.id,
|
||||
@ -508,7 +500,7 @@ mod tests {
|
||||
person_id: inserted_person.id,
|
||||
};
|
||||
|
||||
let inserted_post_saved = PostSaved::save(pool, &post_saved_form).await.unwrap();
|
||||
let inserted_post_saved = PostSaved::save(pool, &post_saved_form).await?;
|
||||
|
||||
let expected_post_saved = PostSaved {
|
||||
post_id: inserted_post.id,
|
||||
@ -516,54 +508,51 @@ mod tests {
|
||||
published: inserted_post_saved.published,
|
||||
};
|
||||
|
||||
// Post Read
|
||||
let marked_as_read = PostRead::mark_as_read(
|
||||
pool,
|
||||
HashSet::from([inserted_post.id, inserted_post2.id]),
|
||||
inserted_person.id,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(2, marked_as_read);
|
||||
// Mark 2 posts as read
|
||||
PostRead::mark_as_read(pool, inserted_post.id, inserted_person.id).await?;
|
||||
PostRead::mark_as_read(pool, inserted_post2.id, inserted_person.id).await?;
|
||||
|
||||
let read_post = Post::read(pool, inserted_post.id).await.unwrap();
|
||||
let read_post = Post::read(pool, inserted_post.id).await?;
|
||||
|
||||
let new_post_update = PostUpdateForm {
|
||||
name: Some("A test post".into()),
|
||||
..Default::default()
|
||||
};
|
||||
let updated_post = Post::update(pool, inserted_post.id, &new_post_update)
|
||||
.await
|
||||
.unwrap();
|
||||
let updated_post = Post::update(pool, inserted_post.id, &new_post_update).await?;
|
||||
|
||||
let like_removed = PostLike::remove(pool, inserted_person.id, inserted_post.id)
|
||||
.await
|
||||
.unwrap();
|
||||
// Scheduled post count
|
||||
let scheduled_post_count = Post::user_scheduled_post_count(inserted_person.id, pool).await?;
|
||||
assert_eq!(1, scheduled_post_count);
|
||||
|
||||
let like_removed = PostLike::remove(pool, inserted_person.id, inserted_post.id).await?;
|
||||
assert_eq!(1, like_removed);
|
||||
let saved_removed = PostSaved::unsave(pool, &post_saved_form).await.unwrap();
|
||||
let saved_removed = PostSaved::unsave(pool, &post_saved_form).await?;
|
||||
assert_eq!(1, saved_removed);
|
||||
let read_removed = PostRead::mark_as_unread(
|
||||
pool,
|
||||
HashSet::from([inserted_post.id, inserted_post2.id]),
|
||||
inserted_person.id,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(2, read_removed);
|
||||
|
||||
let num_deleted = Post::delete(pool, inserted_post.id).await.unwrap()
|
||||
+ Post::delete(pool, inserted_post2.id).await.unwrap();
|
||||
assert_eq!(2, num_deleted);
|
||||
Community::delete(pool, inserted_community.id)
|
||||
.await
|
||||
.unwrap();
|
||||
Person::delete(pool, inserted_person.id).await.unwrap();
|
||||
Instance::delete(pool, inserted_instance.id).await.unwrap();
|
||||
// mark some posts as unread
|
||||
let read_removed_1 =
|
||||
PostRead::mark_as_unread(pool, inserted_post.id, inserted_person.id).await?;
|
||||
assert_eq!(1, read_removed_1);
|
||||
let read_removed_2 =
|
||||
PostRead::mark_as_unread(pool, inserted_post2.id, inserted_person.id).await?;
|
||||
assert_eq!(1, read_removed_2);
|
||||
|
||||
let num_deleted = Post::delete(pool, inserted_post.id).await?
|
||||
+ Post::delete(pool, inserted_post2.id).await?
|
||||
+ Post::delete(pool, inserted_scheduled_post.id).await?;
|
||||
|
||||
assert_eq!(3, num_deleted);
|
||||
Community::delete(pool, inserted_community.id).await?;
|
||||
|
||||
Person::delete(pool, inserted_person.id).await?;
|
||||
Instance::delete(pool, inserted_instance.id).await?;
|
||||
|
||||
assert_eq!(expected_post, read_post);
|
||||
assert_eq!(expected_post, inserted_post);
|
||||
assert_eq!(expected_post, updated_post);
|
||||
assert_eq!(expected_post_like, inserted_post_like);
|
||||
assert_eq!(expected_post_saved, inserted_post_saved);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -80,8 +80,7 @@ impl Reportable for PostReport {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
@ -85,8 +85,7 @@ impl PrivateMessage {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
mod tests {
|
||||
|
||||
use crate::{
|
||||
|
@ -27,7 +27,6 @@ pub mod newtypes;
|
||||
pub mod sensitive;
|
||||
#[cfg(feature = "full")]
|
||||
#[rustfmt::skip]
|
||||
#[allow(clippy::wildcard_imports)]
|
||||
pub mod schema;
|
||||
#[cfg(feature = "full")]
|
||||
pub mod aliases {
|
||||
|
@ -191,13 +191,13 @@ impl Display for DbUrl {
|
||||
}
|
||||
|
||||
// the project doesn't compile with From
|
||||
#[allow(clippy::from_over_into)]
|
||||
#[expect(clippy::from_over_into)]
|
||||
impl Into<DbUrl> for Url {
|
||||
fn into(self) -> DbUrl {
|
||||
DbUrl(Box::new(self))
|
||||
}
|
||||
}
|
||||
#[allow(clippy::from_over_into)]
|
||||
#[expect(clippy::from_over_into)]
|
||||
impl Into<Url> for DbUrl {
|
||||
fn into(self) -> Url {
|
||||
*self.0
|
||||
|
@ -769,7 +769,7 @@ diesel::table! {
|
||||
featured_local -> Bool,
|
||||
url_content_type -> Nullable<Text>,
|
||||
alt_text -> Nullable<Text>,
|
||||
scheduled_publish_time -> Nullable<Timestamptz>
|
||||
scheduled_publish_time -> Nullable<Timestamptz>,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,11 +14,12 @@ use serde_with::skip_serializing_none;
|
||||
use ts_rs::TS;
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Default)]
|
||||
#[cfg_attr(feature = "full", derive(Queryable, Selectable, Identifiable, TS))]
|
||||
#[cfg_attr(feature = "full", diesel(table_name = local_user))]
|
||||
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
#[serde(default)]
|
||||
/// A local user.
|
||||
pub struct LocalUser {
|
||||
pub id: LocalUserId,
|
||||
|
@ -87,39 +87,30 @@ impl Serialize for PublicOAuthProvider {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(feature = "full", derive(Insertable, AsChangeset, TS))]
|
||||
#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
|
||||
#[cfg_attr(feature = "full", diesel(table_name = oauth_provider))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
pub struct OAuthProviderInsertForm {
|
||||
pub display_name: String,
|
||||
#[cfg_attr(feature = "full", ts(type = "string"))]
|
||||
pub issuer: DbUrl,
|
||||
#[cfg_attr(feature = "full", ts(type = "string"))]
|
||||
pub authorization_endpoint: DbUrl,
|
||||
#[cfg_attr(feature = "full", ts(type = "string"))]
|
||||
pub token_endpoint: DbUrl,
|
||||
#[cfg_attr(feature = "full", ts(type = "string"))]
|
||||
pub userinfo_endpoint: DbUrl,
|
||||
pub id_claim: String,
|
||||
pub client_id: String,
|
||||
pub client_secret: String,
|
||||
pub scopes: String,
|
||||
pub auto_verify_email: bool,
|
||||
pub account_linking_enabled: bool,
|
||||
pub enabled: bool,
|
||||
pub auto_verify_email: Option<bool>,
|
||||
pub account_linking_enabled: Option<bool>,
|
||||
pub enabled: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(feature = "full", derive(Insertable, AsChangeset, TS))]
|
||||
#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
|
||||
#[cfg_attr(feature = "full", diesel(table_name = oauth_provider))]
|
||||
#[cfg_attr(feature = "full", ts(export))]
|
||||
pub struct OAuthProviderUpdateForm {
|
||||
pub display_name: Option<String>,
|
||||
#[cfg_attr(feature = "full", ts(type = "string"))]
|
||||
pub authorization_endpoint: Option<DbUrl>,
|
||||
#[cfg_attr(feature = "full", ts(type = "string"))]
|
||||
pub token_endpoint: Option<DbUrl>,
|
||||
#[cfg_attr(feature = "full", ts(type = "string"))]
|
||||
pub userinfo_endpoint: Option<DbUrl>,
|
||||
pub id_claim: Option<String>,
|
||||
pub client_secret: Option<String>,
|
||||
|
@ -595,7 +595,6 @@ impl<RF, LF> Queries<RF, LF> {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
@ -259,8 +259,8 @@ impl CommentReportQuery {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
#[expect(clippy::indexing_slicing)]
|
||||
mod tests {
|
||||
|
||||
use crate::{
|
||||
|
@ -422,8 +422,8 @@ impl<'a> CommentQuery<'a> {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[expect(clippy::indexing_slicing)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
mod tests {
|
||||
|
||||
use crate::{
|
||||
|
@ -284,8 +284,8 @@ impl PostReportQuery {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
#[expect(clippy::indexing_slicing)]
|
||||
mod tests {
|
||||
|
||||
use crate::{
|
||||
|
@ -394,14 +394,12 @@ fn queries<'a>() -> Queries<
|
||||
query = query.filter(post::url.eq(search_term));
|
||||
} else {
|
||||
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.filter(post::name.ilike(searcher))
|
||||
query.filter(name_filter)
|
||||
} else {
|
||||
query.filter(
|
||||
post::name
|
||||
.ilike(searcher.clone())
|
||||
.or(post::body.ilike(searcher)),
|
||||
)
|
||||
query.filter(name_filter.or(body_filter))
|
||||
}
|
||||
.filter(not(post::removed.or(post::deleted)));
|
||||
}
|
||||
@ -741,7 +739,7 @@ impl<'a> PostQuery<'a> {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
mod tests {
|
||||
use crate::{
|
||||
post_view::{PaginationCursorData, PostQuery, PostView},
|
||||
@ -794,7 +792,7 @@ mod tests {
|
||||
use lemmy_utils::error::LemmyResult;
|
||||
use pretty_assertions::assert_eq;
|
||||
use serial_test::serial;
|
||||
use std::{collections::HashSet, time::Duration};
|
||||
use std::time::Duration;
|
||||
use url::Url;
|
||||
|
||||
const POST_WITH_ANOTHER_TITLE: &str = "Another title";
|
||||
@ -1629,7 +1627,7 @@ mod tests {
|
||||
// Mark a post as read
|
||||
PostRead::mark_as_read(
|
||||
pool,
|
||||
HashSet::from([data.inserted_bot_post.id]),
|
||||
data.inserted_bot_post.id,
|
||||
data.local_user_view.person.id,
|
||||
)
|
||||
.await?;
|
||||
@ -1671,7 +1669,7 @@ mod tests {
|
||||
// Mark a post as hidden
|
||||
PostHide::hide(
|
||||
pool,
|
||||
HashSet::from([data.inserted_bot_post.id]),
|
||||
data.inserted_bot_post.id,
|
||||
data.local_user_view.person.id,
|
||||
)
|
||||
.await?;
|
||||
|
@ -111,8 +111,8 @@ impl PrivateMessageReportQuery {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
#[expect(clippy::indexing_slicing)]
|
||||
mod tests {
|
||||
|
||||
use crate::private_message_report_view::PrivateMessageReportQuery;
|
||||
|
@ -173,8 +173,8 @@ impl PrivateMessageQuery {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
#[expect(clippy::indexing_slicing)]
|
||||
mod tests {
|
||||
|
||||
use crate::{private_message_view::PrivateMessageQuery, structs::PrivateMessageView};
|
||||
|
@ -135,8 +135,7 @@ impl RegistrationApplicationQuery {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
mod tests {
|
||||
|
||||
use crate::registration_application_view::{
|
||||
|
@ -83,8 +83,7 @@ impl VoteView {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
mod tests {
|
||||
|
||||
use crate::structs::VoteView;
|
||||
|
@ -303,7 +303,6 @@ impl CommentReplyQuery {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
mod tests {
|
||||
|
||||
use crate::{comment_reply_view::CommentReplyQuery, structs::CommentReplyView};
|
||||
|
@ -112,9 +112,14 @@ fn queries<'a>() -> Queries<
|
||||
|
||||
if let Some(search_term) = options.search_term {
|
||||
let searcher = fuzzy_search(&search_term);
|
||||
query = query
|
||||
.filter(community::name.ilike(searcher.clone()))
|
||||
.or_filter(community::title.ilike(searcher))
|
||||
let name_filter = community::name.ilike(searcher.clone());
|
||||
let title_filter = community::title.ilike(searcher.clone());
|
||||
let description_filter = community::description.ilike(searcher.clone());
|
||||
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
|
||||
@ -229,6 +234,7 @@ pub struct CommunityQuery<'a> {
|
||||
pub sort: Option<PostSortType>,
|
||||
pub local_user: Option<&'a LocalUser>,
|
||||
pub search_term: Option<String>,
|
||||
pub title_only: Option<bool>,
|
||||
pub is_mod_or_admin: bool,
|
||||
pub show_nsfw: bool,
|
||||
pub page: Option<i64>,
|
||||
@ -242,8 +248,7 @@ impl<'a> CommunityQuery<'a> {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
mod tests {
|
||||
|
||||
use crate::{community_view::CommunityQuery, structs::CommunityView};
|
||||
|
@ -303,7 +303,6 @@ impl PersonMentionQuery {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
mod tests {
|
||||
|
||||
use crate::{person_mention_view::PersonMentionQuery, structs::PersonMentionView};
|
||||
|
@ -164,7 +164,7 @@ impl PersonQuery {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::indexing_slicing)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
@ -222,8 +222,8 @@ impl<T: DataSource> CommunityInboxCollector<T> {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
#[expect(clippy::indexing_slicing)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use lemmy_db_schema::{
|
||||
|
@ -192,8 +192,8 @@ impl SendManager {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
#[expect(clippy::indexing_slicing)]
|
||||
mod test {
|
||||
|
||||
use super::*;
|
||||
|
@ -439,8 +439,8 @@ impl InstanceWorker {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
#[expect(clippy::indexing_slicing)]
|
||||
mod test {
|
||||
|
||||
use super::*;
|
||||
|
@ -29,6 +29,8 @@ pub const CACHE_DURATION_FEDERATION: Duration = Duration::from_secs(60);
|
||||
|
||||
pub const CACHE_DURATION_API: Duration = Duration::from_secs(1);
|
||||
|
||||
pub const MAX_COMMENT_DEPTH_LIMIT: usize = 50;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! location_info {
|
||||
() => {
|
||||
|
@ -221,8 +221,6 @@ fn parse_ip(addr: &str) -> Option<IpAddr> {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
mod tests {
|
||||
|
||||
#[test]
|
||||
|
@ -136,7 +136,6 @@ impl<K: Eq + Hash, C: MapLevel> MapLevel for Map<K, C> {
|
||||
.entry(addr_part)
|
||||
.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 children_pass = group.children.check(
|
||||
@ -161,7 +160,6 @@ impl<K: Eq + Hash, C: MapLevel> MapLevel for Map<K, C> {
|
||||
// Evaluated if `some_children_remaining` is false
|
||||
let total_has_refill_in_future = || {
|
||||
group.total.into_iter().any(|(action_type, bucket)| {
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
let config = configs[action_type];
|
||||
bucket.update(now, config).tokens != config.capacity
|
||||
})
|
||||
@ -214,7 +212,6 @@ impl<C: Default> RateLimitedGroup<C> {
|
||||
now: InstantSecs,
|
||||
config: BucketConfig,
|
||||
) -> bool {
|
||||
#[allow(clippy::indexing_slicing)] // `EnumMap` has no `get` function
|
||||
let bucket = &mut self.total[action_type];
|
||||
|
||||
let new_bucket = bucket.update(now, config);
|
||||
@ -311,8 +308,7 @@ fn split_ipv6(ip: Ipv6Addr) -> ([u8; 6], u8, u8) {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
mod tests {
|
||||
|
||||
use super::{ActionType, BucketConfig, InstantSecs, RateLimitState, RateLimitedGroup};
|
||||
@ -361,7 +357,6 @@ mod tests {
|
||||
assert!(post_passed);
|
||||
}
|
||||
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
let expected_buckets = |factor: u32, tokens_consumed: u32| {
|
||||
let adjusted_configs = bucket_configs.map(|_, config| BucketConfig {
|
||||
capacity: config.capacity.saturating_mul(factor),
|
||||
|
@ -107,8 +107,7 @@ pub fn markdown_check_for_blocked_urls(text: &str, blocklist: &RegexSet) -> Lemm
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
@ -134,8 +134,6 @@ pub fn add(markdown_parser: &mut MarkdownIt) {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
mod tests {
|
||||
|
||||
use crate::utils::markdown::spoiler_rule::add;
|
||||
|
@ -34,8 +34,7 @@ pub fn scrape_text_for_mentions(text: &str) -> Vec<MentionData> {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::indexing_slicing)]
|
||||
mod test {
|
||||
|
||||
use crate::utils::mention::scrape_text_for_mentions;
|
||||
|
@ -61,8 +61,7 @@ pub(crate) fn slurs_vec_to_str(slurs: &[&str]) -> String {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
mod test {
|
||||
|
||||
use crate::utils::slurs::{remove_slurs, slur_check, slurs_vec_to_str};
|
||||
|
@ -351,7 +351,6 @@ pub fn build_url_str_without_scheme(url_str: &str) -> LemmyResult<String> {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
mod tests {
|
||||
|
||||
use crate::{
|
||||
|
@ -14,7 +14,7 @@ CREATE TABLE oauth_provider (
|
||||
scopes text NOT NULL,
|
||||
auto_verify_email boolean DEFAULT TRUE NOT NULL,
|
||||
account_linking_enabled boolean DEFAULT FALSE NOT NULL,
|
||||
enabled boolean DEFAULT FALSE NOT NULL,
|
||||
enabled boolean DEFAULT TRUE NOT NULL,
|
||||
published timestamp with time zone DEFAULT now() NOT NULL,
|
||||
updated timestamp with time zone
|
||||
);
|
||||
|
@ -605,7 +605,6 @@ async fn build_update_instance_form(
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
mod tests {
|
||||
|
||||
use crate::scheduled_tasks::build_update_instance_form;
|
||||
|
@ -97,8 +97,7 @@ where
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::unwrap_used)]
|
||||
#[allow(clippy::indexing_slicing)]
|
||||
#[expect(clippy::unwrap_used)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
Loading…
Reference in New Issue
Block a user