From 007e9b7aabe859faeacc7b3128ddc57fe930a308 Mon Sep 17 00:00:00 2001 From: dullbananas Date: Tue, 2 Apr 2024 08:19:04 -0700 Subject: [PATCH 01/26] Optimize Community::set_featured_posts (#4579) * Don't lock excess rows in Community::set_featured_posts * Update community.rs * Update community.rs * Update community.rs * Update community.rs --- crates/db_schema/src/impls/community.rs | 35 ++++++++----------------- 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/crates/db_schema/src/impls/community.rs b/crates/db_schema/src/impls/community.rs index dbacbcb72..af3bf9bcf 100644 --- a/crates/db_schema/src/impls/community.rs +++ b/crates/db_schema/src/impls/community.rs @@ -29,6 +29,7 @@ use diesel::{ select, sql_types, update, + BoolExpressionMethods, ExpressionMethods, NullableExpressionMethods, QueryDsl, @@ -150,30 +151,16 @@ impl Community { for p in &posts { debug_assert!(p.community_id == community_id); } - conn - .build_transaction() - .run(|conn| { - Box::pin(async move { - update( - // first remove all existing featured posts - post::table, - ) - .filter(post::dsl::community_id.eq(community_id)) - .set(post::dsl::featured_community.eq(false)) - .execute(conn) - .await?; - - // then mark the given posts as featured - let post_ids: Vec<_> = posts.iter().map(|p| p.id).collect(); - update(post::table) - .filter(post::dsl::id.eq_any(post_ids)) - .set(post::dsl::featured_community.eq(true)) - .execute(conn) - .await?; - Ok(()) - }) as _ - }) - .await + // Mark the given posts as featured and all other posts as not featured. + let post_ids = posts.iter().map(|p| p.id); + update(post::table) + .filter(post::dsl::community_id.eq(community_id)) + // This filter is just for performance + .filter(post::dsl::featured_community.or(post::dsl::id.eq_any(post_ids.clone()))) + .set(post::dsl::featured_community.eq(post::dsl::id.eq_any(post_ids))) + .execute(conn) + .await?; + Ok(()) } } From ae9f82b45229d42ce223766ead297b2345b0dfc8 Mon Sep 17 00:00:00 2001 From: Nutomic Date: Tue, 2 Apr 2024 17:19:51 +0200 Subject: [PATCH 02/26] Read crate version from cargo.toml (fixes #4583) (#4584) --- crates/api/src/site/leave_admin.rs | 4 ++-- crates/api_common/src/request.rs | 8 ++------ crates/api_crud/src/site/read.rs | 4 ++-- crates/routes/src/nodeinfo.rs | 4 ++-- crates/utils/src/lib.rs | 3 ++- crates/utils/src/version.rs | 1 - docker/Dockerfile | 4 ---- src/lib.rs | 4 ++-- 8 files changed, 12 insertions(+), 20 deletions(-) delete mode 100644 crates/utils/src/version.rs diff --git a/crates/api/src/site/leave_admin.rs b/crates/api/src/site/leave_admin.rs index 0d149d07d..f2db0fc26 100644 --- a/crates/api/src/site/leave_admin.rs +++ b/crates/api/src/site/leave_admin.rs @@ -15,7 +15,7 @@ use lemmy_db_views::structs::{CustomEmojiView, LocalUserView, SiteView}; use lemmy_db_views_actor::structs::PersonView; use lemmy_utils::{ error::{LemmyError, LemmyErrorType}, - version, + VERSION, }; #[tracing::instrument(skip(context))] @@ -68,7 +68,7 @@ pub async fn leave_admin( Ok(Json(GetSiteResponse { site_view, admins, - version: version::VERSION.to_string(), + version: VERSION.to_string(), my_user: None, all_languages, discussion_languages, diff --git a/crates/api_common/src/request.rs b/crates/api_common/src/request.rs index 7c8768e41..d77ea2daa 100644 --- a/crates/api_common/src/request.rs +++ b/crates/api_common/src/request.rs @@ -19,8 +19,8 @@ use lemmy_utils::{ error::{LemmyError, LemmyErrorType}, settings::structs::{PictrsImageMode, Settings}, spawn_try_task, - version::VERSION, REQWEST_TIMEOUT, + VERSION, }; use mime::Mime; use reqwest::{header::CONTENT_TYPE, Client, ClientBuilder}; @@ -32,11 +32,7 @@ use urlencoding::encode; use webpage::HTML; pub fn client_builder(settings: &Settings) -> ClientBuilder { - let user_agent = format!( - "Lemmy/{}; +{}", - VERSION, - settings.get_protocol_and_hostname() - ); + let user_agent = format!("Lemmy/{VERSION}; +{}", settings.get_protocol_and_hostname()); Client::builder() .user_agent(user_agent.clone()) diff --git a/crates/api_crud/src/site/read.rs b/crates/api_crud/src/site/read.rs index e99a222fa..77113b08a 100644 --- a/crates/api_crud/src/site/read.rs +++ b/crates/api_crud/src/site/read.rs @@ -20,7 +20,7 @@ use lemmy_db_views_actor::structs::{ }; use lemmy_utils::{ error::{LemmyError, LemmyErrorExt, LemmyErrorType}, - version, + VERSION, }; use moka::future::Cache; use once_cell::sync::Lazy; @@ -52,7 +52,7 @@ pub async fn get_site( Ok(GetSiteResponse { site_view, admins, - version: version::VERSION.to_string(), + version: VERSION.to_string(), my_user: None, all_languages, discussion_languages, diff --git a/crates/routes/src/nodeinfo.rs b/crates/routes/src/nodeinfo.rs index 06d4c2dd6..62082b4c8 100644 --- a/crates/routes/src/nodeinfo.rs +++ b/crates/routes/src/nodeinfo.rs @@ -6,7 +6,7 @@ use lemmy_db_views::structs::SiteView; use lemmy_utils::{ cache_header::{cache_1hour, cache_3days}, error::LemmyError, - version, + VERSION, }; use serde::{Deserialize, Serialize}; use url::Url; @@ -56,7 +56,7 @@ async fn node_info(context: web::Data) -> Result crates/utils/src/version.rs; \ cargo build --features "${CARGO_BUILD_FEATURES}"; \ mv target/"${RUST_RELEASE_MODE}"/lemmy_server ./lemmy_server; \ fi @@ -36,7 +35,6 @@ RUN --mount=type=cache,target=/lemmy/target set -ex; \ # Release build RUN --mount=type=cache,target=/lemmy/target set -ex; \ if [ "${RUST_RELEASE_MODE}" = "release" ]; then \ - echo "pub const VERSION: &str = \"$(git describe --tag)\";" > crates/utils/src/version.rs; \ [ -z "$USE_RELEASE_CACHE" ] && cargo clean --release; \ cargo build --features "${CARGO_BUILD_FEATURES}" --release; \ mv target/"${RUST_RELEASE_MODE}"/lemmy_server ./lemmy_server; \ @@ -63,7 +61,6 @@ ENV RUST_RELEASE_MODE=${RUST_RELEASE_MODE} \ # Debug build RUN --mount=type=cache,target=./target,uid=10001,gid=10001 set -ex; \ if [ "${RUST_RELEASE_MODE}" = "debug" ]; then \ - echo "pub const VERSION: &str = \"$(git describe --tag)\";" > crates/utils/src/version.rs; \ cargo build --features "${CARGO_BUILD_FEATURES}"; \ mv "./target/$CARGO_BUILD_TARGET/$RUST_RELEASE_MODE/lemmy_server" /home/lemmy/lemmy_server; \ fi @@ -71,7 +68,6 @@ RUN --mount=type=cache,target=./target,uid=10001,gid=10001 set -ex; \ # Release build RUN --mount=type=cache,target=./target,uid=10001,gid=10001 set -ex; \ if [ "${RUST_RELEASE_MODE}" = "release" ]; then \ - echo "pub const VERSION: &str = \"$(git describe --tag)\";" > crates/utils/src/version.rs; \ [ -z "$USE_RELEASE_CACHE" ] && cargo clean --release; \ cargo build --features "${CARGO_BUILD_FEATURES}" --release; \ mv "./target/$CARGO_BUILD_TARGET/$RUST_RELEASE_MODE/lemmy_server" /home/lemmy/lemmy_server; \ diff --git a/src/lib.rs b/src/lib.rs index 1b2507f4e..777c5d9ce 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -49,7 +49,7 @@ use lemmy_utils::{ rate_limit::RateLimitCell, response::jsonify_plain_text_errors, settings::{structs::Settings, SETTINGS}, - version, + VERSION, }; use prometheus::default_registry; use prometheus_metrics::serve_prometheus; @@ -109,7 +109,7 @@ pub struct CmdArgs { /// Placing the main function in lib.rs allows other crates to import it and embed Lemmy pub async fn start_lemmy_server(args: CmdArgs) -> Result<(), LemmyError> { // Print version number to log - println!("Lemmy v{}", version::VERSION); + println!("Lemmy v{VERSION}"); // return error 503 while running db migrations and startup tasks let mut startup_server_handle = None; From 4d9c16a336d40190bce51a67acd5ace3ae79cff1 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Tue, 2 Apr 2024 13:25:28 -0400 Subject: [PATCH 03/26] Fix private message sort order. #4581 (#4587) --- crates/db_views/src/private_message_report_view.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/crates/db_views/src/private_message_report_view.rs b/crates/db_views/src/private_message_report_view.rs index 091071b16..dff9820d9 100644 --- a/crates/db_views/src/private_message_report_view.rs +++ b/crates/db_views/src/private_message_report_view.rs @@ -49,14 +49,18 @@ fn queries<'a>() -> Queries< let list = move |mut conn: DbConn<'a>, options: PrivateMessageReportQuery| async move { let mut query = all_joins(private_message_report::table.into_boxed()); + // If viewing all reports, order by newest, but if viewing unresolved only, show the oldest first (FIFO) if options.unresolved_only { - query = query.filter(private_message_report::resolved.eq(false)); + query = query + .filter(private_message_report::resolved.eq(false)) + .order_by(private_message_report::published.asc()); + } else { + query = query.order_by(private_message_report::published.desc()); } let (limit, offset) = limit_and_offset(options.page, options.limit)?; query - .order_by(private_message::published.asc()) .limit(limit) .offset(offset) .load::(&mut conn) From 94438a85161f5870d50151728492085a353d94f6 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Wed, 3 Apr 2024 04:38:57 -0400 Subject: [PATCH 04/26] Removing cardano, this was never used. (#4588) --- README.md | 1 - readmes/README.ja.md | 1 - 2 files changed, 2 deletions(-) diff --git a/README.md b/README.md index 96c19bc03..6c8398cd9 100644 --- a/README.md +++ b/README.md @@ -133,7 +133,6 @@ Lemmy is made possible by a generous grant from the [NLnet foundation](https://n - bitcoin: `1Hefs7miXS5ff5Ck5xvmjKjXf5242KzRtK` - ethereum: `0x400c96c96acbC6E7B3B43B1dc1BB446540a88A01` - monero: `41taVyY6e1xApqKyMVDRVxJ76sPkfZhALLTjRvVKpaAh2pBd4wv9RgYj1tSPrx8wc6iE1uWUfjtQdTmTy2FGMeChGVKPQuV` -- cardano: `addr1q858t89l2ym6xmrugjs0af9cslfwvnvsh2xxp6x4dcez7pf5tushkp4wl7zxfhm2djp6gq60dk4cmc7seaza5p3slx0sakjutm` ## Contributing diff --git a/readmes/README.ja.md b/readmes/README.ja.md index 0a64cd055..fe11b6859 100644 --- a/readmes/README.ja.md +++ b/readmes/README.ja.md @@ -150,7 +150,6 @@ Lemmy はフリーでオープンソースのソフトウェアです。つま - bitcoin: `1Hefs7miXS5ff5Ck5xvmjKjXf5242KzRtK` - ethereum: `0x400c96c96acbC6E7B3B43B1dc1BB446540a88A01` - monero: `41taVyY6e1xApqKyMVDRVxJ76sPkfZhALLTjRvVKpaAh2pBd4wv9RgYj1tSPrx8wc6iE1uWUfjtQdTmTy2FGMeChGVKPQuV` -- cardano: `addr1q858t89l2ym6xmrugjs0af9cslfwvnvsh2xxp6x4dcez7pf5tushkp4wl7zxfhm2djp6gq60dk4cmc7seaza5p3slx0sakjutm` ## コントリビュート From 5237233f9781075d6d30d86f512d16660a9ad0df Mon Sep 17 00:00:00 2001 From: Dessalines Date: Wed, 3 Apr 2024 16:50:35 -0400 Subject: [PATCH 05/26] Version 0.19.4-beta.1 --- Cargo.lock | 26 +++++++++++++------------- Cargo.toml | 24 ++++++++++++------------ crates/utils/translations | 2 +- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0ce7859e4..e0b275243 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2612,7 +2612,7 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "lemmy_api" -version = "0.19.3" +version = "0.19.4-beta.1" dependencies = [ "activitypub_federation", "actix-web", @@ -2641,7 +2641,7 @@ dependencies = [ [[package]] name = "lemmy_api_common" -version = "0.19.3" +version = "0.19.4-beta.1" dependencies = [ "activitypub_federation", "actix-web", @@ -2679,7 +2679,7 @@ dependencies = [ [[package]] name = "lemmy_api_crud" -version = "0.19.3" +version = "0.19.4-beta.1" dependencies = [ "accept-language", "activitypub_federation", @@ -2702,7 +2702,7 @@ dependencies = [ [[package]] name = "lemmy_apub" -version = "0.19.3" +version = "0.19.4-beta.1" dependencies = [ "activitypub_federation", "actix-web", @@ -2740,7 +2740,7 @@ dependencies = [ [[package]] name = "lemmy_db_perf" -version = "0.19.3" +version = "0.19.4-beta.1" dependencies = [ "anyhow", "clap", @@ -2755,7 +2755,7 @@ dependencies = [ [[package]] name = "lemmy_db_schema" -version = "0.19.3" +version = "0.19.4-beta.1" dependencies = [ "activitypub_federation", "anyhow", @@ -2794,7 +2794,7 @@ dependencies = [ [[package]] name = "lemmy_db_views" -version = "0.19.3" +version = "0.19.4-beta.1" dependencies = [ "actix-web", "chrono", @@ -2816,7 +2816,7 @@ dependencies = [ [[package]] name = "lemmy_db_views_actor" -version = "0.19.3" +version = "0.19.4-beta.1" dependencies = [ "chrono", "diesel", @@ -2836,7 +2836,7 @@ dependencies = [ [[package]] name = "lemmy_db_views_moderator" -version = "0.19.3" +version = "0.19.4-beta.1" dependencies = [ "diesel", "diesel-async", @@ -2848,7 +2848,7 @@ dependencies = [ [[package]] name = "lemmy_federate" -version = "0.19.3" +version = "0.19.4-beta.1" dependencies = [ "activitypub_federation", "anyhow", @@ -2871,7 +2871,7 @@ dependencies = [ [[package]] name = "lemmy_routes" -version = "0.19.3" +version = "0.19.4-beta.1" dependencies = [ "activitypub_federation", "actix-web", @@ -2896,7 +2896,7 @@ dependencies = [ [[package]] name = "lemmy_server" -version = "0.19.3" +version = "0.19.4-beta.1" dependencies = [ "activitypub_federation", "actix-cors", @@ -2939,7 +2939,7 @@ dependencies = [ [[package]] name = "lemmy_utils" -version = "0.19.3" +version = "0.19.4-beta.1" dependencies = [ "actix-web", "anyhow", diff --git a/Cargo.toml b/Cargo.toml index 366bdc353..a7ca399a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace.package] -version = "0.19.3" +version = "0.19.4-beta.1" edition = "2021" description = "A link aggregator for the fediverse" license = "AGPL-3.0" @@ -88,16 +88,16 @@ unused_self = "deny" unwrap_used = "deny" [workspace.dependencies] -lemmy_api = { version = "=0.19.3", path = "./crates/api" } -lemmy_api_crud = { version = "=0.19.3", path = "./crates/api_crud" } -lemmy_apub = { version = "=0.19.3", path = "./crates/apub" } -lemmy_utils = { version = "=0.19.3", path = "./crates/utils", default-features = false } -lemmy_db_schema = { version = "=0.19.3", path = "./crates/db_schema" } -lemmy_api_common = { version = "=0.19.3", path = "./crates/api_common" } -lemmy_routes = { version = "=0.19.3", path = "./crates/routes" } -lemmy_db_views = { version = "=0.19.3", path = "./crates/db_views" } -lemmy_db_views_actor = { version = "=0.19.3", path = "./crates/db_views_actor" } -lemmy_db_views_moderator = { version = "=0.19.3", path = "./crates/db_views_moderator" } +lemmy_api = { version = "=0.19.4-beta.1", path = "./crates/api" } +lemmy_api_crud = { version = "=0.19.4-beta.1", path = "./crates/api_crud" } +lemmy_apub = { version = "=0.19.4-beta.1", path = "./crates/apub" } +lemmy_utils = { version = "=0.19.4-beta.1", path = "./crates/utils", default-features = false } +lemmy_db_schema = { version = "=0.19.4-beta.1", path = "./crates/db_schema" } +lemmy_api_common = { version = "=0.19.4-beta.1", path = "./crates/api_common" } +lemmy_routes = { version = "=0.19.4-beta.1", path = "./crates/routes" } +lemmy_db_views = { version = "=0.19.4-beta.1", path = "./crates/db_views" } +lemmy_db_views_actor = { version = "=0.19.4-beta.1", path = "./crates/db_views_actor" } +lemmy_db_views_moderator = { version = "=0.19.4-beta.1", path = "./crates/db_views_moderator" } activitypub_federation = { version = "0.5.2", default-features = false, features = [ "actix-web", ] } @@ -175,7 +175,7 @@ lemmy_utils = { workspace = true } lemmy_db_schema = { workspace = true } lemmy_api_common = { workspace = true } lemmy_routes = { workspace = true } -lemmy_federate = { version = "0.19.3", path = "crates/federate" } +lemmy_federate = { version = "0.19.4-beta.1", path = "crates/federate" } activitypub_federation = { workspace = true } diesel = { workspace = true } diesel-async = { workspace = true } diff --git a/crates/utils/translations b/crates/utils/translations index c3e61706e..b3131d688 160000 --- a/crates/utils/translations +++ b/crates/utils/translations @@ -1 +1 @@ -Subproject commit c3e61706e2ff7977db83e964e3010f72cad5e408 +Subproject commit b3131d6881adb639dc0e298cc7c213c5245091f6 From aaaa362b98b477785b4c739e148d7efc311cdcba Mon Sep 17 00:00:00 2001 From: Dessalines Date: Wed, 3 Apr 2024 17:29:24 -0400 Subject: [PATCH 06/26] Remove latest tag for pgformatter. (#4589) --- .woodpecker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker.yml b/.woodpecker.yml index 99dc16489..1baf462e7 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -59,7 +59,7 @@ steps: - event: pull_request sql_fmt: - image: backplane/pgformatter:latest + image: backplane/pgformatter commands: - ./scripts/sql_format_check.sh when: From 087684658a5d2008dff3df54d9b6e0ebde1ce1bc Mon Sep 17 00:00:00 2001 From: Nutomic Date: Wed, 3 Apr 2024 23:38:31 +0200 Subject: [PATCH 07/26] Cache result of LocalSite::read to avoid unnecessary db calls (#4585) * Cache result of LocalSite::read to avoid unnecessary db calls * single const for cache duration * clippy * revert apub send changes * clippy * fmt --- Cargo.lock | 1 + crates/api_common/src/utils.rs | 9 +++------ crates/api_crud/src/site/read.rs | 4 ++-- crates/apub/src/lib.rs | 18 ++++++++++-------- crates/db_schema/Cargo.toml | 1 + crates/db_schema/src/impls/local_site.rs | 21 ++++++++++++++++++--- crates/federate/src/util.rs | 13 ++++--------- crates/utils/src/lib.rs | 5 +++++ 8 files changed, 44 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e0b275243..a446fe418 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2772,6 +2772,7 @@ dependencies = [ "futures-util", "i-love-jesus", "lemmy_utils", + "moka", "once_cell", "pretty_assertions", "regex", diff --git a/crates/api_common/src/utils.rs b/crates/api_common/src/utils.rs index 73333c3a0..ad416ffbb 100644 --- a/crates/api_common/src/utils.rs +++ b/crates/api_common/src/utils.rs @@ -42,21 +42,18 @@ use lemmy_utils::{ markdown::{markdown_check_for_blocked_urls, markdown_rewrite_image_links}, slurs::{build_slur_regex, remove_slurs}, }, + CACHE_DURATION_SHORT, }; use moka::future::Cache; use once_cell::sync::Lazy; use regex::{escape, Regex, RegexSet}; use rosetta_i18n::{Language, LanguageId}; -use std::{collections::HashSet, time::Duration}; +use std::collections::HashSet; use tracing::warn; use url::{ParseError, Url}; use urlencoding::encode; pub static AUTH_COOKIE_NAME: &str = "jwt"; -#[cfg(debug_assertions)] -static URL_BLOCKLIST_RECHECK_DELAY: Duration = Duration::from_millis(500); -#[cfg(not(debug_assertions))] -static URL_BLOCKLIST_RECHECK_DELAY: Duration = Duration::from_secs(60); #[tracing::instrument(skip_all)] pub async fn is_mod_or_admin( @@ -527,7 +524,7 @@ pub async fn get_url_blocklist(context: &LemmyContext) -> LemmyResult static URL_BLOCKLIST: Lazy> = Lazy::new(|| { Cache::builder() .max_capacity(1) - .time_to_live(URL_BLOCKLIST_RECHECK_DELAY) + .time_to_live(CACHE_DURATION_SHORT) .build() }); diff --git a/crates/api_crud/src/site/read.rs b/crates/api_crud/src/site/read.rs index 77113b08a..0d3685a94 100644 --- a/crates/api_crud/src/site/read.rs +++ b/crates/api_crud/src/site/read.rs @@ -20,11 +20,11 @@ use lemmy_db_views_actor::structs::{ }; use lemmy_utils::{ error::{LemmyError, LemmyErrorExt, LemmyErrorType}, + CACHE_DURATION_SHORT, VERSION, }; use moka::future::Cache; use once_cell::sync::Lazy; -use std::time::Duration; #[tracing::instrument(skip(context))] pub async fn get_site( @@ -34,7 +34,7 @@ pub async fn get_site( static CACHE: Lazy> = Lazy::new(|| { Cache::builder() .max_capacity(1) - .time_to_live(Duration::from_secs(1)) + .time_to_live(CACHE_DURATION_SHORT) .build() }); diff --git a/crates/apub/src/lib.rs b/crates/apub/src/lib.rs index e6530e4b8..c09a3007c 100644 --- a/crates/apub/src/lib.rs +++ b/crates/apub/src/lib.rs @@ -9,11 +9,14 @@ use lemmy_db_schema::{ source::{activity::ReceivedActivity, instance::Instance, local_site::LocalSite}, utils::{ActualDbPool, DbPool}, }; -use lemmy_utils::error::{LemmyError, LemmyErrorType, LemmyResult}; +use lemmy_utils::{ + error::{LemmyError, LemmyErrorType, LemmyResult}, + CACHE_DURATION_SHORT, +}; use moka::future::Cache; use once_cell::sync::Lazy; use serde_json::Value; -use std::{sync::Arc, time::Duration}; +use std::sync::Arc; use url::Url; pub mod activities; @@ -27,11 +30,6 @@ pub mod objects; pub mod protocol; pub const FEDERATION_HTTP_FETCH_LIMIT: u32 = 50; -/// All incoming and outgoing federation actions read the blocklist/allowlist and slur filters -/// multiple times. This causes a huge number of database reads if we hit the db directly. So we -/// cache these values for a short time, which will already make a huge difference and ensures that -/// changes take effect quickly. -const BLOCKLIST_CACHE_DURATION: Duration = Duration::from_secs(60); /// Only include a basic context to save space and bandwidth. The main context is hosted statically /// on join-lemmy.org. Include activitystreams explicitly for better compat, but this could @@ -122,10 +120,14 @@ pub(crate) struct LocalSiteData { pub(crate) async fn local_site_data_cached( pool: &mut DbPool<'_>, ) -> LemmyResult> { + // All incoming and outgoing federation actions read the blocklist/allowlist and slur filters + // multiple times. This causes a huge number of database reads if we hit the db directly. So we + // cache these values for a short time, which will already make a huge difference and ensures that + // changes take effect quickly. static CACHE: Lazy>> = Lazy::new(|| { Cache::builder() .max_capacity(1) - .time_to_live(BLOCKLIST_CACHE_DURATION) + .time_to_live(CACHE_DURATION_SHORT) .build() }); Ok( diff --git a/crates/db_schema/Cargo.toml b/crates/db_schema/Cargo.toml index d0d66d69f..a0654f063 100644 --- a/crates/db_schema/Cargo.toml +++ b/crates/db_schema/Cargo.toml @@ -80,6 +80,7 @@ rustls = { workspace = true, optional = true } uuid = { workspace = true, features = ["v4"] } i-love-jesus = { workspace = true, optional = true } anyhow = { workspace = true } +moka.workspace = true [dev-dependencies] serial_test = { workspace = true } diff --git a/crates/db_schema/src/impls/local_site.rs b/crates/db_schema/src/impls/local_site.rs index 2d527c0ee..5a6cf2a53 100644 --- a/crates/db_schema/src/impls/local_site.rs +++ b/crates/db_schema/src/impls/local_site.rs @@ -5,6 +5,9 @@ use crate::{ }; use diesel::{dsl::insert_into, result::Error}; use diesel_async::RunQueryDsl; +use lemmy_utils::{error::LemmyError, CACHE_DURATION_SHORT}; +use moka::future::Cache; +use once_cell::sync::Lazy; impl LocalSite { pub async fn create(pool: &mut DbPool<'_>, form: &LocalSiteInsertForm) -> Result { @@ -14,9 +17,21 @@ impl LocalSite { .get_result::(conn) .await } - pub async fn read(pool: &mut DbPool<'_>) -> Result { - let conn = &mut get_conn(pool).await?; - local_site.first::(conn).await + pub async fn read(pool: &mut DbPool<'_>) -> Result { + static CACHE: Lazy> = Lazy::new(|| { + Cache::builder() + .max_capacity(1) + .time_to_live(CACHE_DURATION_SHORT) + .build() + }); + Ok( + CACHE + .try_get_with((), async { + let conn = &mut get_conn(pool).await?; + local_site.first::(conn).await + }) + .await?, + ) } pub async fn update(pool: &mut DbPool<'_>, form: &LocalSiteUpdateForm) -> Result { let conn = &mut get_conn(pool).await?; diff --git a/crates/federate/src/util.rs b/crates/federate/src/util.rs index 848785836..2809b9bb4 100644 --- a/crates/federate/src/util.rs +++ b/crates/federate/src/util.rs @@ -1,6 +1,7 @@ use anyhow::{anyhow, Context, Result}; use diesel::prelude::*; use diesel_async::RunQueryDsl; +use lemmy_api_common::lemmy_utils::CACHE_DURATION_SHORT; use lemmy_apub::{ activity_lists::SharedInboxActivities, fetcher::{site_or_community_or_user::SiteOrCommunityOrUser, user_or_community::UserOrCommunity}, @@ -31,6 +32,7 @@ pub(crate) static LEMMY_TEST_FAST_FEDERATION: Lazy = Lazy::new(|| { .map(|s| !s.is_empty()) .unwrap_or(false) }); + /// Recheck for new federation work every n seconds. /// /// When the queue is processed faster than new activities are added and it reaches the current time with an empty batch, @@ -167,15 +169,8 @@ pub(crate) async fn get_activity_cached( /// return the most current activity id (with 1 second cache) pub(crate) async fn get_latest_activity_id(pool: &mut DbPool<'_>) -> Result { - static CACHE: Lazy> = Lazy::new(|| { - Cache::builder() - .time_to_live(if *LEMMY_TEST_FAST_FEDERATION { - *WORK_FINISHED_RECHECK_DELAY - } else { - Duration::from_secs(1) - }) - .build() - }); + static CACHE: Lazy> = + Lazy::new(|| Cache::builder().time_to_live(CACHE_DURATION_SHORT).build()); CACHE .try_get_with((), async { use diesel::dsl::max; diff --git a/crates/utils/src/lib.rs b/crates/utils/src/lib.rs index d8e112f89..46508eb50 100644 --- a/crates/utils/src/lib.rs +++ b/crates/utils/src/lib.rs @@ -23,6 +23,11 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION"); pub const REQWEST_TIMEOUT: Duration = Duration::from_secs(10); +#[cfg(debug_assertions)] +pub const CACHE_DURATION_SHORT: Duration = Duration::from_millis(500); +#[cfg(not(debug_assertions))] +pub const CACHE_DURATION_SHORT: Duration = Duration::from_secs(60); + #[macro_export] macro_rules! location_info { () => { From a1d632e582a46b8af5b2a8971ea5bccfe9b62b80 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Thu, 4 Apr 2024 04:21:31 -0400 Subject: [PATCH 08/26] Re-add notif on tag failure. (#4591) --- .woodpecker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.woodpecker.yml b/.woodpecker.yml index 1baf462e7..28c526a0c 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -263,7 +263,7 @@ steps: - apk add curl - "curl -d'Lemmy CI build failed: ${CI_PIPELINE_URL}' ntfy.sh/lemmy_drone_ci" when: - - event: pull_request + - event: [pull_request, tag] status: failure notify_on_tag_deploy: From 705e86eb4c0079d0775f0c1490968f1183095fcc Mon Sep 17 00:00:00 2001 From: Dessalines Date: Thu, 4 Apr 2024 10:14:59 -0400 Subject: [PATCH 09/26] Fixing docker release (#4592) * Re-add notif on tag failure. * Upping rust version. * Version 0.19.4-beta.1a * Try again. * Version 0.19.4-beta.1b * Removing unstable inspect. * Version 0.19.4-beta.1c * Remove use release cache. * Trying to fix cargo publish 1. * Version 0.19.4-beta.1d * Re-adding publish release * Version 0.19.4-beta.2 * Fixing workspace for lemmy_federate --- .woodpecker.yml | 5 ++--- Cargo.lock | 26 +++++++++++++------------- Cargo.toml | 25 +++++++++++++------------ docker/Dockerfile | 6 +++--- docker/docker-compose.yml | 2 -- src/scheduled_tasks.rs | 32 ++++++++++++++++---------------- 6 files changed, 47 insertions(+), 49 deletions(-) diff --git a/.woodpecker.yml b/.woodpecker.yml index 28c526a0c..4c9af5441 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -2,7 +2,7 @@ # See https://github.com/woodpecker-ci/woodpecker/issues/1677 variables: - - &rust_image "rust:1.76" + - &rust_image "rust:1.77" - &install_pnpm "corepack enable pnpm" - &slow_check_paths - event: pull_request @@ -42,7 +42,7 @@ steps: - git submodule init - git submodule update when: - - event: pull_request + - event: [pull_request, tag] prettier_check: image: tmknom/prettier:3.0.0 @@ -248,7 +248,6 @@ steps: publish_to_crates_io: image: *rust_image commands: - - 'echo "pub const VERSION: &str = \"$(git describe --tag)\";" > "crates/utils/src/version.rs"' - cargo install cargo-workspaces - cp -r migrations crates/db_schema/ - cargo login "$CARGO_API_TOKEN" diff --git a/Cargo.lock b/Cargo.lock index a446fe418..c0edf2dcf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2612,7 +2612,7 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "lemmy_api" -version = "0.19.4-beta.1" +version = "0.19.4-beta.2" dependencies = [ "activitypub_federation", "actix-web", @@ -2641,7 +2641,7 @@ dependencies = [ [[package]] name = "lemmy_api_common" -version = "0.19.4-beta.1" +version = "0.19.4-beta.2" dependencies = [ "activitypub_federation", "actix-web", @@ -2679,7 +2679,7 @@ dependencies = [ [[package]] name = "lemmy_api_crud" -version = "0.19.4-beta.1" +version = "0.19.4-beta.2" dependencies = [ "accept-language", "activitypub_federation", @@ -2702,7 +2702,7 @@ dependencies = [ [[package]] name = "lemmy_apub" -version = "0.19.4-beta.1" +version = "0.19.4-beta.2" dependencies = [ "activitypub_federation", "actix-web", @@ -2740,7 +2740,7 @@ dependencies = [ [[package]] name = "lemmy_db_perf" -version = "0.19.4-beta.1" +version = "0.19.4-beta.2" dependencies = [ "anyhow", "clap", @@ -2755,7 +2755,7 @@ dependencies = [ [[package]] name = "lemmy_db_schema" -version = "0.19.4-beta.1" +version = "0.19.4-beta.2" dependencies = [ "activitypub_federation", "anyhow", @@ -2795,7 +2795,7 @@ dependencies = [ [[package]] name = "lemmy_db_views" -version = "0.19.4-beta.1" +version = "0.19.4-beta.2" dependencies = [ "actix-web", "chrono", @@ -2817,7 +2817,7 @@ dependencies = [ [[package]] name = "lemmy_db_views_actor" -version = "0.19.4-beta.1" +version = "0.19.4-beta.2" dependencies = [ "chrono", "diesel", @@ -2837,7 +2837,7 @@ dependencies = [ [[package]] name = "lemmy_db_views_moderator" -version = "0.19.4-beta.1" +version = "0.19.4-beta.2" dependencies = [ "diesel", "diesel-async", @@ -2849,7 +2849,7 @@ dependencies = [ [[package]] name = "lemmy_federate" -version = "0.19.4-beta.1" +version = "0.19.4-beta.2" dependencies = [ "activitypub_federation", "anyhow", @@ -2872,7 +2872,7 @@ dependencies = [ [[package]] name = "lemmy_routes" -version = "0.19.4-beta.1" +version = "0.19.4-beta.2" dependencies = [ "activitypub_federation", "actix-web", @@ -2897,7 +2897,7 @@ dependencies = [ [[package]] name = "lemmy_server" -version = "0.19.4-beta.1" +version = "0.19.4-beta.2" dependencies = [ "activitypub_federation", "actix-cors", @@ -2940,7 +2940,7 @@ dependencies = [ [[package]] name = "lemmy_utils" -version = "0.19.4-beta.1" +version = "0.19.4-beta.2" dependencies = [ "actix-web", "anyhow", diff --git a/Cargo.toml b/Cargo.toml index a7ca399a9..554448d02 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace.package] -version = "0.19.4-beta.1" +version = "0.19.4-beta.2" edition = "2021" description = "A link aggregator for the fediverse" license = "AGPL-3.0" @@ -88,16 +88,17 @@ unused_self = "deny" unwrap_used = "deny" [workspace.dependencies] -lemmy_api = { version = "=0.19.4-beta.1", path = "./crates/api" } -lemmy_api_crud = { version = "=0.19.4-beta.1", path = "./crates/api_crud" } -lemmy_apub = { version = "=0.19.4-beta.1", path = "./crates/apub" } -lemmy_utils = { version = "=0.19.4-beta.1", path = "./crates/utils", default-features = false } -lemmy_db_schema = { version = "=0.19.4-beta.1", path = "./crates/db_schema" } -lemmy_api_common = { version = "=0.19.4-beta.1", path = "./crates/api_common" } -lemmy_routes = { version = "=0.19.4-beta.1", path = "./crates/routes" } -lemmy_db_views = { version = "=0.19.4-beta.1", path = "./crates/db_views" } -lemmy_db_views_actor = { version = "=0.19.4-beta.1", path = "./crates/db_views_actor" } -lemmy_db_views_moderator = { version = "=0.19.4-beta.1", path = "./crates/db_views_moderator" } +lemmy_api = { version = "=0.19.4-beta.2", path = "./crates/api" } +lemmy_api_crud = { version = "=0.19.4-beta.2", path = "./crates/api_crud" } +lemmy_apub = { version = "=0.19.4-beta.2", path = "./crates/apub" } +lemmy_utils = { version = "=0.19.4-beta.2", path = "./crates/utils", default-features = false } +lemmy_db_schema = { version = "=0.19.4-beta.2", path = "./crates/db_schema" } +lemmy_api_common = { version = "=0.19.4-beta.2", path = "./crates/api_common" } +lemmy_routes = { version = "=0.19.4-beta.2", path = "./crates/routes" } +lemmy_db_views = { version = "=0.19.4-beta.2", path = "./crates/db_views" } +lemmy_db_views_actor = { version = "=0.19.4-beta.2", path = "./crates/db_views_actor" } +lemmy_db_views_moderator = { version = "=0.19.4-beta.2", path = "./crates/db_views_moderator" } +lemmy_federate = { version = "=0.19.4-beta.2", path = "./crates/federate" } activitypub_federation = { version = "0.5.2", default-features = false, features = [ "actix-web", ] } @@ -175,7 +176,7 @@ lemmy_utils = { workspace = true } lemmy_db_schema = { workspace = true } lemmy_api_common = { workspace = true } lemmy_routes = { workspace = true } -lemmy_federate = { version = "0.19.4-beta.1", path = "crates/federate" } +lemmy_federate = { workspace = true } activitypub_federation = { workspace = true } diesel = { workspace = true } diesel-async = { workspace = true } diff --git a/docker/Dockerfile b/docker/Dockerfile index 9539402df..ff3dfc7ff 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,5 +1,5 @@ # syntax=docker/dockerfile:1.6 -ARG RUST_VERSION=1.76 +ARG RUST_VERSION=1.77 ARG CARGO_BUILD_FEATURES=default ARG RUST_RELEASE_MODE=debug @@ -35,7 +35,7 @@ RUN --mount=type=cache,target=/lemmy/target set -ex; \ # Release build RUN --mount=type=cache,target=/lemmy/target set -ex; \ if [ "${RUST_RELEASE_MODE}" = "release" ]; then \ - [ -z "$USE_RELEASE_CACHE" ] && cargo clean --release; \ + cargo clean --release; \ cargo build --features "${CARGO_BUILD_FEATURES}" --release; \ mv target/"${RUST_RELEASE_MODE}"/lemmy_server ./lemmy_server; \ fi @@ -68,7 +68,7 @@ RUN --mount=type=cache,target=./target,uid=10001,gid=10001 set -ex; \ # Release build RUN --mount=type=cache,target=./target,uid=10001,gid=10001 set -ex; \ if [ "${RUST_RELEASE_MODE}" = "release" ]; then \ - [ -z "$USE_RELEASE_CACHE" ] && cargo clean --release; \ + cargo clean --release; \ cargo build --features "${CARGO_BUILD_FEATURES}" --release; \ mv "./target/$CARGO_BUILD_TARGET/$RUST_RELEASE_MODE/lemmy_server" /home/lemmy/lemmy_server; \ fi diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 30b38ad85..1bf38863f 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -1,5 +1,3 @@ -version: "3.7" - x-logging: &default-logging driver: "json-file" options: diff --git a/src/scheduled_tasks.rs b/src/scheduled_tasks.rs index 491902fb3..e225b96ff 100644 --- a/src/scheduled_tasks.rs +++ b/src/scheduled_tasks.rs @@ -94,7 +94,7 @@ pub async fn setup(context: LemmyContext) -> Result<(), LemmyError> { delete_old_denied_users(&mut context.pool()).await; update_instance_software(&mut context.pool(), context.client()) .await - .inspect_err(|e| warn!("Failed to update instance software: {e}")) + .map_err(|e| warn!("Failed to update instance software: {e}")) .ok(); } }); @@ -276,10 +276,10 @@ async fn delete_expired_captcha_answers(pool: &mut DbPool<'_>) { ) .execute(&mut conn) .await - .inspect(|_| { + .map(|_| { info!("Done."); }) - .inspect_err(|e| error!("Failed to clear old captcha answers: {e}")) + .map_err(|e| error!("Failed to clear old captcha answers: {e}")) .ok(); } Err(e) => { @@ -300,7 +300,7 @@ async fn clear_old_activities(pool: &mut DbPool<'_>) { ) .execute(&mut conn) .await - .inspect_err(|e| error!("Failed to clear old sent activities: {e}")) + .map_err(|e| error!("Failed to clear old sent activities: {e}")) .ok(); diesel::delete( @@ -309,8 +309,8 @@ async fn clear_old_activities(pool: &mut DbPool<'_>) { ) .execute(&mut conn) .await - .inspect(|_| info!("Done.")) - .inspect_err(|e| error!("Failed to clear old received activities: {e}")) + .map(|_| info!("Done.")) + .map_err(|e| error!("Failed to clear old received activities: {e}")) .ok(); } Err(e) => { @@ -322,10 +322,10 @@ async fn clear_old_activities(pool: &mut DbPool<'_>) { async fn delete_old_denied_users(pool: &mut DbPool<'_>) { LocalUser::delete_old_denied_local_users(pool) .await - .inspect(|_| { + .map(|_| { info!("Done."); }) - .inspect(|e| error!("Failed to deleted old denied users: {e}")) + .map_err(|e| error!("Failed to deleted old denied users: {e}")) .ok(); } @@ -348,10 +348,10 @@ async fn overwrite_deleted_posts_and_comments(pool: &mut DbPool<'_>) { )) .execute(&mut conn) .await - .inspect(|_| { + .map(|_| { info!("Done."); }) - .inspect_err(|e| error!("Failed to overwrite deleted posts: {e}")) + .map_err(|e| error!("Failed to overwrite deleted posts: {e}")) .ok(); info!("Overwriting deleted comments..."); @@ -364,10 +364,10 @@ async fn overwrite_deleted_posts_and_comments(pool: &mut DbPool<'_>) { .set(comment::content.eq(DELETED_REPLACEMENT_TEXT)) .execute(&mut conn) .await - .inspect(|_| { + .map(|_| { info!("Done."); }) - .inspect_err(|e| error!("Failed to overwrite deleted comments: {e}")) + .map_err(|e| error!("Failed to overwrite deleted comments: {e}")) .ok(); } Err(e) => { @@ -399,14 +399,14 @@ async fn active_counts(pool: &mut DbPool<'_>) { sql_query(update_site_stmt) .execute(&mut conn) .await - .inspect_err(|e| error!("Failed to update site stats: {e}")) + .map_err(|e| error!("Failed to update site stats: {e}")) .ok(); let update_community_stmt = format!("update community_aggregates ca set users_active_{} = mv.count_ from community_aggregates_activity('{}') mv where ca.community_id = mv.community_id_", i.1, i.0); sql_query(update_community_stmt) .execute(&mut conn) .await - .inspect_err(|e| error!("Failed to update community stats: {e}")) + .map_err(|e| error!("Failed to update community stats: {e}")) .ok(); } @@ -433,7 +433,7 @@ async fn update_banned_when_expired(pool: &mut DbPool<'_>) { .set(person::banned.eq(false)) .execute(&mut conn) .await - .inspect_err(|e| error!("Failed to update person.banned when expires: {e}")) + .map_err(|e| error!("Failed to update person.banned when expires: {e}")) .ok(); diesel::delete( @@ -441,7 +441,7 @@ async fn update_banned_when_expired(pool: &mut DbPool<'_>) { ) .execute(&mut conn) .await - .inspect_err(|e| error!("Failed to remove community_ban expired rows: {e}")) + .map_err(|e| error!("Failed to remove community_ban expired rows: {e}")) .ok(); } Err(e) => { From a14ebefd24a7f086db1d5a46eb5ad9b0b9663a31 Mon Sep 17 00:00:00 2001 From: jim-taylor-business Date: Mon, 8 Apr 2024 11:05:54 +0100 Subject: [PATCH 10/26] When env variable is set, any config file will be ignored and the default settings will be used (#4594) * do not panic when no config file found use defaults * formatting * implement env variable * ermove commented code * remove redundant comment * remove redundant space * simplify check logic * format * returns and messages * correct mistake --- crates/utils/src/settings/mod.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/crates/utils/src/settings/mod.rs b/crates/utils/src/settings/mod.rs index f630d0217..d0f802e5b 100644 --- a/crates/utils/src/settings/mod.rs +++ b/crates/utils/src/settings/mod.rs @@ -13,8 +13,17 @@ use structs::{DatabaseConnection, PictrsConfig, PictrsImageMode, Settings}; static DEFAULT_CONFIG_FILE: &str = "config/config.hjson"; pub static SETTINGS: Lazy = Lazy::new(|| { - Settings::init().expect("Failed to load settings file, see documentation (https://join-lemmy.org/docs/en/administration/configuration.html)") + if env::var("LEMMY_INITIALIZE_WITH_DEFAULT_SETTINGS").is_ok() { + println!( + "LEMMY_INITIALIZE_WITH_DEFAULT_SETTINGS was set, any configuration file has been ignored." + ); + println!("Use with other environment variables to configure this instance further; e.g. LEMMY_DATABASE_URL."); + Settings::default() + } else { + Settings::init().expect("Failed to load settings file, see documentation (https://join-lemmy.org/docs/en/administration/configuration.html).") + } }); + static WEBFINGER_REGEX: Lazy = Lazy::new(|| { Regex::new(&format!( "^acct:([a-zA-Z0-9_]{{3,}})@{}$", @@ -30,9 +39,7 @@ impl Settings { /// `lemmy_db_schema/src/lib.rs::get_database_url_from_env()` /// Warning: Only call this once. pub(crate) fn init() -> Result { - // Read the config file let config = from_str::(&Self::read_config_file()?)?; - if config.hostname == "unset" { Err(anyhow!("Hostname variable is not set!").into()) } else { From 8e54a4a6ccc9491bb9defbfe82ef6353846098b8 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Mon, 8 Apr 2024 10:26:24 -0400 Subject: [PATCH 11/26] Fixing bug where comment replies wouldn't be sent to blocked instances. (#4595) * Fixing bug where comment replies wouldn't be sent to blocked instances. - Instance blocks should only affect communities, not comments. - Fixes #4590 * Revert "Fixing bug where comment replies wouldn't be sent to blocked instances." This reverts commit 1349aa351a195fdf0d179c27a8057257ca37e255. * Only block replies from the community's instance id. - Also refactor send_local_notifs slightly, since it has to fetch the community now. - Fixes #4590 --------- Co-authored-by: SleeplessOne1917 <28871516+SleeplessOne1917@users.noreply.github.com> --- crates/api_common/src/build_response.rs | 23 +++++++++++-------- crates/api_common/src/utils.rs | 4 ++-- crates/api_crud/src/comment/create.rs | 3 +-- crates/api_crud/src/comment/delete.rs | 18 +++------------ crates/api_crud/src/comment/remove.rs | 6 +---- crates/api_crud/src/comment/update.rs | 3 +-- .../activities/create_or_update/comment.rs | 4 +--- 7 files changed, 23 insertions(+), 38 deletions(-) diff --git a/crates/api_common/src/build_response.rs b/crates/api_common/src/build_response.rs index 19e0bb46b..990b96544 100644 --- a/crates/api_common/src/build_response.rs +++ b/crates/api_common/src/build_response.rs @@ -19,7 +19,6 @@ use lemmy_db_schema::{ comment_reply::{CommentReply, CommentReplyInsertForm}, person::Person, person_mention::{PersonMention, PersonMentionInsertForm}, - post::Post, }, traits::Crud, }; @@ -91,16 +90,19 @@ pub async fn build_post_response( #[tracing::instrument(skip_all)] pub async fn send_local_notifs( mentions: Vec, - comment: &Comment, + comment_id: CommentId, person: &Person, - post: &Post, do_send_email: bool, context: &LemmyContext, ) -> Result, LemmyError> { let mut recipient_ids = Vec::new(); let inbox_link = format!("{}/inbox", context.settings().get_protocol_and_hostname()); - let community_id = post.community_id; + // Read the comment view to get extra info + let comment_view = CommentView::read(&mut context.pool(), comment_id, None).await?; + let comment = comment_view.comment; + let post = comment_view.post; + let community = comment_view.community; // Send the local mentions for mention in mentions @@ -117,7 +119,7 @@ pub async fn send_local_notifs( let user_mention_form = PersonMentionInsertForm { recipient_id: mention_user_view.person.id, - comment_id: comment.id, + comment_id, read: None, }; @@ -152,8 +154,9 @@ pub async fn send_local_notifs( let check_blocks = check_person_instance_community_block( person.id, parent_creator_id, - person.instance_id, - community_id, + // Only block from the community's instance_id + community.instance_id, + community.id, &mut context.pool(), ) .await @@ -194,11 +197,13 @@ pub async fn send_local_notifs( } } } else { + // Use the post creator to check blocks let check_blocks = check_person_instance_community_block( person.id, post.creator_id, - person.instance_id, - community_id, + // Only block from the community's instance_id + community.instance_id, + community.id, &mut context.pool(), ) .await diff --git a/crates/api_common/src/utils.rs b/crates/api_common/src/utils.rs index ad416ffbb..dd0a8c0c6 100644 --- a/crates/api_common/src/utils.rs +++ b/crates/api_common/src/utils.rs @@ -295,12 +295,12 @@ async fn check_instance_block( pub async fn check_person_instance_community_block( my_id: PersonId, potential_blocker_id: PersonId, - instance_id: InstanceId, + community_instance_id: InstanceId, community_id: CommunityId, pool: &mut DbPool<'_>, ) -> Result<(), LemmyError> { check_person_block(my_id, potential_blocker_id, pool).await?; - check_instance_block(instance_id, potential_blocker_id, pool).await?; + check_instance_block(community_instance_id, potential_blocker_id, pool).await?; check_community_block(community_id, potential_blocker_id, pool).await?; Ok(()) } diff --git a/crates/api_crud/src/comment/create.rs b/crates/api_crud/src/comment/create.rs index acb386c60..f8092268f 100644 --- a/crates/api_crud/src/comment/create.rs +++ b/crates/api_crud/src/comment/create.rs @@ -138,9 +138,8 @@ pub async fn create_comment( let mentions = scrape_text_for_mentions(&content); let recipient_ids = send_local_notifs( mentions, - &updated_comment, + inserted_comment_id, &local_user_view.person, - &post, true, &context, ) diff --git a/crates/api_crud/src/comment/delete.rs b/crates/api_crud/src/comment/delete.rs index 2de2a7955..9db1ed034 100644 --- a/crates/api_crud/src/comment/delete.rs +++ b/crates/api_crud/src/comment/delete.rs @@ -8,10 +8,7 @@ use lemmy_api_common::{ utils::check_community_user_action, }; use lemmy_db_schema::{ - source::{ - comment::{Comment, CommentUpdateForm}, - post::Post, - }, + source::comment::{Comment, CommentUpdateForm}, traits::Crud, }; use lemmy_db_views::structs::{CommentView, LocalUserView}; @@ -56,17 +53,8 @@ pub async fn delete_comment( .await .with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?; - let post_id = updated_comment.post_id; - let post = Post::read(&mut context.pool(), post_id).await?; - let recipient_ids = send_local_notifs( - vec![], - &updated_comment, - &local_user_view.person, - &post, - false, - &context, - ) - .await?; + let recipient_ids = + send_local_notifs(vec![], comment_id, &local_user_view.person, false, &context).await?; let updated_comment_id = updated_comment.id; ActivityChannel::submit_activity( diff --git a/crates/api_crud/src/comment/remove.rs b/crates/api_crud/src/comment/remove.rs index 5bb6f55b1..d735c4462 100644 --- a/crates/api_crud/src/comment/remove.rs +++ b/crates/api_crud/src/comment/remove.rs @@ -12,7 +12,6 @@ use lemmy_db_schema::{ comment::{Comment, CommentUpdateForm}, comment_report::CommentReport, moderator::{ModRemoveComment, ModRemoveCommentForm}, - post::Post, }, traits::{Crud, Reportable}, }; @@ -61,13 +60,10 @@ pub async fn remove_comment( }; ModRemoveComment::create(&mut context.pool(), &form).await?; - let post_id = updated_comment.post_id; - let post = Post::read(&mut context.pool(), post_id).await?; let recipient_ids = send_local_notifs( vec![], - &updated_comment, + comment_id, &local_user_view.person.clone(), - &post, false, &context, ) diff --git a/crates/api_crud/src/comment/update.rs b/crates/api_crud/src/comment/update.rs index e814ebd6b..b35333ec5 100644 --- a/crates/api_crud/src/comment/update.rs +++ b/crates/api_crud/src/comment/update.rs @@ -79,9 +79,8 @@ pub async fn update_comment( let mentions = scrape_text_for_mentions(&updated_comment_content); let recipient_ids = send_local_notifs( mentions, - &updated_comment, + comment_id, &local_user_view.person, - &orig_comment.post, false, &context, ) diff --git a/crates/apub/src/activities/create_or_update/comment.rs b/crates/apub/src/activities/create_or_update/comment.rs index c8d9a017e..ea6af2fcf 100644 --- a/crates/apub/src/activities/create_or_update/comment.rs +++ b/crates/apub/src/activities/create_or_update/comment.rs @@ -159,8 +159,6 @@ impl ActivityHandler for CreateOrUpdateNote { CommentAggregates::update_hot_rank(&mut context.pool(), comment.id).await?; let do_send_email = self.kind == CreateOrUpdateType::Create; - let post_id = comment.post_id; - let post = Post::read(&mut context.pool(), post_id).await?; let actor = self.actor.dereference(context).await?; // Note: @@ -169,7 +167,7 @@ impl ActivityHandler for CreateOrUpdateNote { // anyway. // TODO: for compatibility with other projects, it would be much better to read this from cc or tags let mentions = scrape_text_for_mentions(&comment.content); - send_local_notifs(mentions, &comment.0, &actor, &post, do_send_email, context).await?; + send_local_notifs(mentions, comment.id, &actor, do_send_email, context).await?; Ok(()) } } From 1d0a6ac08fd1e5e488bbd5bbf0105c8fe146da73 Mon Sep 17 00:00:00 2001 From: Nutomic Date: Tue, 9 Apr 2024 16:10:20 +0200 Subject: [PATCH 12/26] Avoid breaking api change, reduce api cache duration (#4610) * Dont mark site.public_key as `serde(skip)` to avoid breaking change (fixes #4605) * Reduce cache duration for api --- crates/api_common/src/utils.rs | 4 ++-- crates/api_crud/src/site/read.rs | 4 ++-- crates/apub/src/lib.rs | 4 ++-- crates/db_schema/src/impls/local_site.rs | 4 ++-- crates/db_schema/src/source/site.rs | 2 +- crates/federate/src/util.rs | 9 ++++++--- crates/utils/src/lib.rs | 6 ++++-- 7 files changed, 19 insertions(+), 14 deletions(-) diff --git a/crates/api_common/src/utils.rs b/crates/api_common/src/utils.rs index dd0a8c0c6..58e3f382b 100644 --- a/crates/api_common/src/utils.rs +++ b/crates/api_common/src/utils.rs @@ -42,7 +42,7 @@ use lemmy_utils::{ markdown::{markdown_check_for_blocked_urls, markdown_rewrite_image_links}, slurs::{build_slur_regex, remove_slurs}, }, - CACHE_DURATION_SHORT, + CACHE_DURATION_FEDERATION, }; use moka::future::Cache; use once_cell::sync::Lazy; @@ -524,7 +524,7 @@ pub async fn get_url_blocklist(context: &LemmyContext) -> LemmyResult static URL_BLOCKLIST: Lazy> = Lazy::new(|| { Cache::builder() .max_capacity(1) - .time_to_live(CACHE_DURATION_SHORT) + .time_to_live(CACHE_DURATION_FEDERATION) .build() }); diff --git a/crates/api_crud/src/site/read.rs b/crates/api_crud/src/site/read.rs index 0d3685a94..c4b27de1e 100644 --- a/crates/api_crud/src/site/read.rs +++ b/crates/api_crud/src/site/read.rs @@ -20,7 +20,7 @@ use lemmy_db_views_actor::structs::{ }; use lemmy_utils::{ error::{LemmyError, LemmyErrorExt, LemmyErrorType}, - CACHE_DURATION_SHORT, + CACHE_DURATION_API, VERSION, }; use moka::future::Cache; @@ -34,7 +34,7 @@ pub async fn get_site( static CACHE: Lazy> = Lazy::new(|| { Cache::builder() .max_capacity(1) - .time_to_live(CACHE_DURATION_SHORT) + .time_to_live(CACHE_DURATION_API) .build() }); diff --git a/crates/apub/src/lib.rs b/crates/apub/src/lib.rs index c09a3007c..5d10dd93d 100644 --- a/crates/apub/src/lib.rs +++ b/crates/apub/src/lib.rs @@ -11,7 +11,7 @@ use lemmy_db_schema::{ }; use lemmy_utils::{ error::{LemmyError, LemmyErrorType, LemmyResult}, - CACHE_DURATION_SHORT, + CACHE_DURATION_FEDERATION, }; use moka::future::Cache; use once_cell::sync::Lazy; @@ -127,7 +127,7 @@ pub(crate) async fn local_site_data_cached( static CACHE: Lazy>> = Lazy::new(|| { Cache::builder() .max_capacity(1) - .time_to_live(CACHE_DURATION_SHORT) + .time_to_live(CACHE_DURATION_FEDERATION) .build() }); Ok( diff --git a/crates/db_schema/src/impls/local_site.rs b/crates/db_schema/src/impls/local_site.rs index 5a6cf2a53..90b25fed5 100644 --- a/crates/db_schema/src/impls/local_site.rs +++ b/crates/db_schema/src/impls/local_site.rs @@ -5,7 +5,7 @@ use crate::{ }; use diesel::{dsl::insert_into, result::Error}; use diesel_async::RunQueryDsl; -use lemmy_utils::{error::LemmyError, CACHE_DURATION_SHORT}; +use lemmy_utils::{error::LemmyError, CACHE_DURATION_API}; use moka::future::Cache; use once_cell::sync::Lazy; @@ -21,7 +21,7 @@ impl LocalSite { static CACHE: Lazy> = Lazy::new(|| { Cache::builder() .max_capacity(1) - .time_to_live(CACHE_DURATION_SHORT) + .time_to_live(CACHE_DURATION_API) .build() }); Ok( diff --git a/crates/db_schema/src/source/site.rs b/crates/db_schema/src/source/site.rs index 40ba14f96..83d23c779 100644 --- a/crates/db_schema/src/source/site.rs +++ b/crates/db_schema/src/source/site.rs @@ -36,7 +36,7 @@ pub struct Site { pub inbox_url: DbUrl, #[serde(skip)] pub private_key: Option, - #[serde(skip)] + // TODO: mark as `serde(skip)` in next major release as its not needed for api pub public_key: String, pub instance_id: InstanceId, /// If present, nsfw content is visible by default. Should be displayed by frontends/clients diff --git a/crates/federate/src/util.rs b/crates/federate/src/util.rs index 2809b9bb4..cedf3387f 100644 --- a/crates/federate/src/util.rs +++ b/crates/federate/src/util.rs @@ -1,7 +1,7 @@ use anyhow::{anyhow, Context, Result}; use diesel::prelude::*; use diesel_async::RunQueryDsl; -use lemmy_api_common::lemmy_utils::CACHE_DURATION_SHORT; +use lemmy_api_common::lemmy_utils::CACHE_DURATION_FEDERATION; use lemmy_apub::{ activity_lists::SharedInboxActivities, fetcher::{site_or_community_or_user::SiteOrCommunityOrUser, user_or_community::UserOrCommunity}, @@ -169,8 +169,11 @@ pub(crate) async fn get_activity_cached( /// return the most current activity id (with 1 second cache) pub(crate) async fn get_latest_activity_id(pool: &mut DbPool<'_>) -> Result { - static CACHE: Lazy> = - Lazy::new(|| Cache::builder().time_to_live(CACHE_DURATION_SHORT).build()); + static CACHE: Lazy> = Lazy::new(|| { + Cache::builder() + .time_to_live(CACHE_DURATION_FEDERATION) + .build() + }); CACHE .try_get_with((), async { use diesel::dsl::max; diff --git a/crates/utils/src/lib.rs b/crates/utils/src/lib.rs index 46508eb50..95c1d0144 100644 --- a/crates/utils/src/lib.rs +++ b/crates/utils/src/lib.rs @@ -24,9 +24,11 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION"); pub const REQWEST_TIMEOUT: Duration = Duration::from_secs(10); #[cfg(debug_assertions)] -pub const CACHE_DURATION_SHORT: Duration = Duration::from_millis(500); +pub const CACHE_DURATION_FEDERATION: Duration = Duration::from_millis(500); #[cfg(not(debug_assertions))] -pub const CACHE_DURATION_SHORT: Duration = Duration::from_secs(60); +pub const CACHE_DURATION_FEDERATION: Duration = Duration::from_secs(60); + +pub const CACHE_DURATION_API: Duration = Duration::from_secs(1); #[macro_export] macro_rules! location_info { From b4670988b55d1c0ce6bcb436fc3f6af82ec5c013 Mon Sep 17 00:00:00 2001 From: Nutomic Date: Wed, 10 Apr 2024 01:33:01 +0200 Subject: [PATCH 13/26] Change exponential backoff algorithm for federation send (#4597) * Limit federation send retry interval to one hour * clippy * avoid overflow * change base for exp backoff * ignore first error * fix day duration --- crates/api_common/src/lib.rs | 38 +++++++++++++++++++++++++++++++++--- scripts/test.sh | 4 ++-- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/crates/api_common/src/lib.rs b/crates/api_common/src/lib.rs index b55dff32f..4bb7ada5b 100644 --- a/crates/api_common/src/lib.rs +++ b/crates/api_common/src/lib.rs @@ -27,7 +27,7 @@ pub extern crate lemmy_utils; pub use lemmy_utils::LemmyErrorType; use serde::{Deserialize, Serialize}; -use std::time::Duration; +use std::{cmp::min, time::Duration}; #[derive(Debug, Serialize, Deserialize, Clone)] #[cfg_attr(feature = "full", derive(ts_rs::TS))] @@ -43,7 +43,39 @@ impl Default for SuccessResponse { } } -/// how long to sleep based on how many retries have already happened +// TODO: use from_days once stabilized +// https://github.com/rust-lang/rust/issues/120301 +const DAY: Duration = Duration::from_secs(24 * 60 * 60); + +/// Calculate how long to sleep until next federation send based on how many +/// retries have already happened. Uses exponential backoff with maximum of one day. The first +/// error is ignored. pub fn federate_retry_sleep_duration(retry_count: i32) -> Duration { - Duration::from_secs_f64(2.0_f64.powf(f64::from(retry_count))) + debug_assert!(retry_count != 0); + if retry_count == 1 { + return Duration::from_secs(0); + } + let retry_count = retry_count - 1; + let pow = 1.25_f64.powf(retry_count.into()); + let pow = Duration::try_from_secs_f64(pow).unwrap_or(DAY); + min(DAY, pow) +} + +#[cfg(test)] +pub(crate) mod tests { + use super::*; + + #[test] + fn test_federate_retry_sleep_duration() { + assert_eq!(Duration::from_secs(0), federate_retry_sleep_duration(1)); + assert_eq!( + Duration::new(1, 250000000), + federate_retry_sleep_duration(2) + ); + assert_eq!( + Duration::new(2, 441406250), + federate_retry_sleep_duration(5) + ); + assert_eq!(DAY, federate_retry_sleep_duration(100)); + } } diff --git a/scripts/test.sh b/scripts/test.sh index efe9b1513..3e0581fc7 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -6,7 +6,7 @@ CWD="$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)" cd $CWD/../ PACKAGE="$1" -echo "$PACKAGE" +TEST="$2" source scripts/start_dev_db.sh @@ -17,7 +17,7 @@ export RUST_BACKTRACE=1 if [ -n "$PACKAGE" ]; then - cargo test -p $PACKAGE --all-features --no-fail-fast + cargo test -p $PACKAGE --all-features --no-fail-fast $TEST else cargo test --workspace --no-fail-fast fi From 99d585b7bedf3556aca2ced805271e64327299a9 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Wed, 10 Apr 2024 04:47:05 -0400 Subject: [PATCH 14/26] Change defaults on user vote display mode to upvotes + downvotes (#4599) * Change defaults on user vote display mode to upvotes + downvotes * Forgot to regenerate the rows. * Drop and re-add columns instead. --- .../down.sql | 10 ++++++++++ .../up.sql | 14 ++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 migrations/2024-04-05-153647_alter_vote_display_mode_defaults/down.sql create mode 100644 migrations/2024-04-05-153647_alter_vote_display_mode_defaults/up.sql diff --git a/migrations/2024-04-05-153647_alter_vote_display_mode_defaults/down.sql b/migrations/2024-04-05-153647_alter_vote_display_mode_defaults/down.sql new file mode 100644 index 000000000..484cbef5b --- /dev/null +++ b/migrations/2024-04-05-153647_alter_vote_display_mode_defaults/down.sql @@ -0,0 +1,10 @@ +ALTER TABLE local_user_vote_display_mode + DROP COLUMN score, + ADD COLUMN score boolean DEFAULT TRUE NOT NULL, + DROP COLUMN upvotes, + ADD COLUMN upvotes boolean DEFAULT FALSE NOT NULL, + DROP COLUMN downvotes, + ADD COLUMN downvotes boolean DEFAULT FALSE NOT NULL, + DROP COLUMN upvote_percentage, + ADD COLUMN upvote_percentage boolean DEFAULT TRUE NOT NULL; + diff --git a/migrations/2024-04-05-153647_alter_vote_display_mode_defaults/up.sql b/migrations/2024-04-05-153647_alter_vote_display_mode_defaults/up.sql new file mode 100644 index 000000000..39a01eb07 --- /dev/null +++ b/migrations/2024-04-05-153647_alter_vote_display_mode_defaults/up.sql @@ -0,0 +1,14 @@ +-- Based on a poll, update the local_user_vote_display_mode defaults to: +-- Upvotes + Downvotes +-- Rather than +-- Score + upvote_percentage +ALTER TABLE local_user_vote_display_mode + DROP COLUMN score, + ADD COLUMN score boolean DEFAULT FALSE NOT NULL, + DROP COLUMN upvotes, + ADD COLUMN upvotes boolean DEFAULT TRUE NOT NULL, + DROP COLUMN downvotes, + ADD COLUMN downvotes boolean DEFAULT TRUE NOT NULL, + DROP COLUMN upvote_percentage, + ADD COLUMN upvote_percentage boolean DEFAULT FALSE NOT NULL; + From 0203b62a6de969153427c4ac4c4a3efbe2621010 Mon Sep 17 00:00:00 2001 From: Nutomic Date: Wed, 10 Apr 2024 16:03:51 +0200 Subject: [PATCH 15/26] Ignore old federated post edits (ref #4529) (#4586) * Ignore old federated post edits (ref #4529) * use filter on insert * coalesce(updated, published) * avoid comment conflict clause --------- Co-authored-by: SleeplessOne1917 <28871516+SleeplessOne1917@users.noreply.github.com> --- crates/apub/src/objects/comment.rs | 11 ++++- crates/apub/src/objects/community.rs | 3 +- crates/apub/src/objects/post.rs | 4 +- crates/apub/src/objects/private_message.rs | 4 +- crates/db_schema/src/impls/comment.rs | 36 +++++++++++--- crates/db_schema/src/impls/community.rs | 49 ++++++++++++++----- crates/db_schema/src/impls/post.rs | 30 ++++++++++-- crates/db_schema/src/impls/private_message.rs | 41 +++++++++++----- 8 files changed, 136 insertions(+), 42 deletions(-) diff --git a/crates/apub/src/objects/comment.rs b/crates/apub/src/objects/comment.rs index ba7cc914f..1acef5cbf 100644 --- a/crates/apub/src/objects/comment.rs +++ b/crates/apub/src/objects/comment.rs @@ -29,6 +29,7 @@ use lemmy_db_schema::{ post::Post, }, traits::Crud, + utils::naive_now, }; use lemmy_utils::{ error::{LemmyError, LemmyErrorType}, @@ -141,6 +142,7 @@ impl Object for ApubComment { check_apub_id_valid_with_strictness(note.id.inner(), community.local, context).await?; verify_is_remote_object(note.id.inner(), context.settings())?; verify_person_in_community(¬e.attributed_to, &community, context).await?; + let (post, _) = note.get_parents(context).await?; let creator = note.attributed_to.dereference(context).await?; let is_mod_or_admin = is_mod_or_admin(&mut context.pool(), &creator, community.id) @@ -184,7 +186,14 @@ impl Object for ApubComment { language_id, }; let parent_comment_path = parent_comment.map(|t| t.0.path); - let comment = Comment::create(&mut context.pool(), &form, parent_comment_path.as_ref()).await?; + let timestamp: DateTime = note.updated.or(note.published).unwrap_or_else(naive_now); + let comment = Comment::insert_apub( + &mut context.pool(), + Some(timestamp), + &form, + parent_comment_path.as_ref(), + ) + .await?; Ok(comment.into()) } } diff --git a/crates/apub/src/objects/community.rs b/crates/apub/src/objects/community.rs index 7630d80b2..83cdc3a49 100644 --- a/crates/apub/src/objects/community.rs +++ b/crates/apub/src/objects/community.rs @@ -175,7 +175,8 @@ impl Object for ApubCommunity { let languages = LanguageTag::to_language_id_multiple(group.language, &mut context.pool()).await?; - let community = Community::create(&mut context.pool(), &form).await?; + let timestamp = group.updated.or(group.published).unwrap_or_else(naive_now); + let community = Community::insert_apub(&mut context.pool(), timestamp, &form).await?; CommunityLanguage::update(&mut context.pool(), languages, community.id).await?; let community: ApubCommunity = community.into(); diff --git a/crates/apub/src/objects/post.rs b/crates/apub/src/objects/post.rs index 0ddc6d17b..a53acee28 100644 --- a/crates/apub/src/objects/post.rs +++ b/crates/apub/src/objects/post.rs @@ -41,6 +41,7 @@ use lemmy_db_schema::{ post::{Post, PostInsertForm, PostUpdateForm}, }, traits::Crud, + utils::naive_now, }; use lemmy_db_views_actor::structs::CommunityModeratorView; use lemmy_utils::{ @@ -270,7 +271,8 @@ impl Object for ApubPost { .build() }; - let post = Post::create(&mut context.pool(), &form).await?; + let timestamp = page.updated.or(page.published).unwrap_or_else(naive_now); + let post = Post::insert_apub(&mut context.pool(), timestamp, &form).await?; generate_post_link_metadata( post.clone(), diff --git a/crates/apub/src/objects/private_message.rs b/crates/apub/src/objects/private_message.rs index 647510802..c32aa6458 100644 --- a/crates/apub/src/objects/private_message.rs +++ b/crates/apub/src/objects/private_message.rs @@ -23,6 +23,7 @@ use lemmy_db_schema::{ private_message::{PrivateMessage, PrivateMessageInsertForm}, }, traits::Crud, + utils::naive_now, }; use lemmy_utils::{ error::{LemmyError, LemmyErrorType}, @@ -142,7 +143,8 @@ impl Object for ApubPrivateMessage { ap_id: Some(note.id.into()), local: Some(false), }; - let pm = PrivateMessage::create(&mut context.pool(), &form).await?; + let timestamp = note.updated.or(note.published).unwrap_or_else(naive_now); + let pm = PrivateMessage::insert_apub(&mut context.pool(), timestamp, &form).await?; Ok(pm.into()) } } diff --git a/crates/db_schema/src/impls/comment.rs b/crates/db_schema/src/impls/comment.rs index b27d44591..c0dad0ad3 100644 --- a/crates/db_schema/src/impls/comment.rs +++ b/crates/db_schema/src/impls/comment.rs @@ -1,4 +1,5 @@ use crate::{ + diesel::DecoratableTarget, newtypes::{CommentId, DbUrl, PersonId}, schema::comment, source::comment::{ @@ -11,8 +12,9 @@ use crate::{ CommentUpdateForm, }, traits::{Crud, Likeable, Saveable}, - utils::{get_conn, naive_now, DbPool, DELETED_REPLACEMENT_TEXT}, + utils::{functions::coalesce, get_conn, naive_now, DbPool, DELETED_REPLACEMENT_TEXT}, }; +use chrono::{DateTime, Utc}; use diesel::{ dsl::{insert_into, sql_query}, result::Error, @@ -59,6 +61,15 @@ impl Comment { pool: &mut DbPool<'_>, comment_form: &CommentInsertForm, parent_path: Option<&Ltree>, + ) -> Result { + Self::insert_apub(pool, None, comment_form, parent_path).await + } + + pub async fn insert_apub( + pool: &mut DbPool<'_>, + timestamp: Option>, + comment_form: &CommentInsertForm, + parent_path: Option<&Ltree>, ) -> Result { let conn = &mut get_conn(pool).await?; @@ -67,13 +78,21 @@ impl Comment { .run(|conn| { Box::pin(async move { // Insert, to get the id - let inserted_comment = insert_into(comment::table) - .values(comment_form) - .on_conflict(comment::ap_id) - .do_update() - .set(comment_form) - .get_result::(conn) - .await?; + let inserted_comment = if let Some(timestamp) = timestamp { + insert_into(comment::table) + .values(comment_form) + .on_conflict(comment::ap_id) + .filter_target(coalesce(comment::updated, comment::published).lt(timestamp)) + .do_update() + .set(comment_form) + .get_result::(conn) + .await? + } else { + insert_into(comment::table) + .values(comment_form) + .get_result::(conn) + .await? + }; let comment_id = inserted_comment.id; @@ -129,6 +148,7 @@ where ca.comment_id = c.id" }) .await } + pub async fn read_from_apub_id( pool: &mut DbPool<'_>, object_id: Url, diff --git a/crates/db_schema/src/impls/community.rs b/crates/db_schema/src/impls/community.rs index af3bf9bcf..4dc45c09b 100644 --- a/crates/db_schema/src/impls/community.rs +++ b/crates/db_schema/src/impls/community.rs @@ -1,4 +1,5 @@ use crate::{ + diesel::DecoratableTarget, newtypes::{CommunityId, DbUrl, PersonId}, schema::{community, community_follower, instance}, source::{ @@ -17,9 +18,14 @@ use crate::{ post::Post, }, traits::{ApubActor, Bannable, Crud, Followable, Joinable}, - utils::{functions::lower, get_conn, DbPool}, + utils::{ + functions::{coalesce, lower}, + get_conn, + DbPool, + }, SubscribedType, }; +use chrono::{DateTime, Utc}; use diesel::{ deserialize, dsl, @@ -44,25 +50,15 @@ impl Crud for Community { type IdType = CommunityId; async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result { - let is_new_community = match &form.actor_id { - Some(id) => Community::read_from_apub_id(pool, id).await?.is_none(), - None => true, - }; let conn = &mut get_conn(pool).await?; - // Can't do separate insert/update commands because InsertForm/UpdateForm aren't convertible let community_ = insert_into(community::table) .values(form) - .on_conflict(community::actor_id) - .do_update() - .set(form) .get_result::(conn) .await?; // Initialize languages for new community - if is_new_community { - CommunityLanguage::update(pool, vec![], community_.id).await?; - } + CommunityLanguage::update(pool, vec![], community_.id).await?; Ok(community_) } @@ -116,6 +112,35 @@ pub enum CollectionType { } impl Community { + pub async fn insert_apub( + pool: &mut DbPool<'_>, + timestamp: DateTime, + form: &CommunityInsertForm, + ) -> Result { + let is_new_community = match &form.actor_id { + Some(id) => Community::read_from_apub_id(pool, id).await?.is_none(), + None => true, + }; + let conn = &mut get_conn(pool).await?; + + // Can't do separate insert/update commands because InsertForm/UpdateForm aren't convertible + let community_ = insert_into(community::table) + .values(form) + .on_conflict(community::actor_id) + .filter_target(coalesce(community::updated, community::published).lt(timestamp)) + .do_update() + .set(form) + .get_result::(conn) + .await?; + + // Initialize languages for new community + if is_new_community { + CommunityLanguage::update(pool, vec![], community_.id).await?; + } + + Ok(community_) + } + /// Get the community which has a given moderators or featured url, also return the collection type pub async fn get_by_collection_url( pool: &mut DbPool<'_>, diff --git a/crates/db_schema/src/impls/post.rs b/crates/db_schema/src/impls/post.rs index 8db871ad5..596eb62bf 100644 --- a/crates/db_schema/src/impls/post.rs +++ b/crates/db_schema/src/impls/post.rs @@ -27,8 +27,15 @@ use crate::{ }, }; use ::url::Url; -use chrono::Utc; -use diesel::{dsl::insert_into, result::Error, ExpressionMethods, QueryDsl, TextExpressionMethods}; +use chrono::{DateTime, Utc}; +use diesel::{ + dsl::insert_into, + result::Error, + DecoratableTarget, + ExpressionMethods, + QueryDsl, + TextExpressionMethods, +}; use diesel_async::RunQueryDsl; use std::collections::HashSet; @@ -42,9 +49,6 @@ impl Crud for Post { let conn = &mut get_conn(pool).await?; insert_into(post::table) .values(form) - .on_conflict(post::ap_id) - .do_update() - .set(form) .get_result::(conn) .await } @@ -63,6 +67,22 @@ impl Crud for Post { } impl Post { + pub async fn insert_apub( + pool: &mut DbPool<'_>, + timestamp: DateTime, + form: &PostInsertForm, + ) -> Result { + let conn = &mut get_conn(pool).await?; + insert_into(post::table) + .values(form) + .on_conflict(post::ap_id) + .filter_target(coalesce(post::updated, post::published).lt(timestamp)) + .do_update() + .set(form) + .get_result::(conn) + .await + } + pub async fn list_for_community( pool: &mut DbPool<'_>, the_community_id: CommunityId, diff --git a/crates/db_schema/src/impls/private_message.rs b/crates/db_schema/src/impls/private_message.rs index ee0009189..8370d5d08 100644 --- a/crates/db_schema/src/impls/private_message.rs +++ b/crates/db_schema/src/impls/private_message.rs @@ -1,10 +1,12 @@ use crate::{ + diesel::DecoratableTarget, newtypes::{DbUrl, PersonId, PrivateMessageId}, - schema::private_message::dsl::{ap_id, private_message, read, recipient_id}, + schema::private_message, source::private_message::{PrivateMessage, PrivateMessageInsertForm, PrivateMessageUpdateForm}, traits::Crud, - utils::{get_conn, DbPool}, + utils::{functions::coalesce, get_conn, DbPool}, }; +use chrono::{DateTime, Utc}; use diesel::{dsl::insert_into, result::Error, ExpressionMethods, QueryDsl}; use diesel_async::RunQueryDsl; use lemmy_utils::error::LemmyError; @@ -18,11 +20,8 @@ impl Crud for PrivateMessage { async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result { let conn = &mut get_conn(pool).await?; - insert_into(private_message) + insert_into(private_message::table) .values(form) - .on_conflict(ap_id) - .do_update() - .set(form) .get_result::(conn) .await } @@ -33,7 +32,7 @@ impl Crud for PrivateMessage { form: &Self::UpdateForm, ) -> Result { let conn = &mut get_conn(pool).await?; - diesel::update(private_message.find(private_message_id)) + diesel::update(private_message::table.find(private_message_id)) .set(form) .get_result::(conn) .await @@ -41,17 +40,33 @@ impl Crud for PrivateMessage { } impl PrivateMessage { + pub async fn insert_apub( + pool: &mut DbPool<'_>, + timestamp: DateTime, + form: &PrivateMessageInsertForm, + ) -> Result { + let conn = &mut get_conn(pool).await?; + insert_into(private_message::table) + .values(form) + .on_conflict(private_message::ap_id) + .filter_target(coalesce(private_message::updated, private_message::published).lt(timestamp)) + .do_update() + .set(form) + .get_result::(conn) + .await + } + pub async fn mark_all_as_read( pool: &mut DbPool<'_>, for_recipient_id: PersonId, ) -> Result, Error> { let conn = &mut get_conn(pool).await?; diesel::update( - private_message - .filter(recipient_id.eq(for_recipient_id)) - .filter(read.eq(false)), + private_message::table + .filter(private_message::recipient_id.eq(for_recipient_id)) + .filter(private_message::read.eq(false)), ) - .set(read.eq(true)) + .set(private_message::read.eq(true)) .get_results::(conn) .await } @@ -63,8 +78,8 @@ impl PrivateMessage { let conn = &mut get_conn(pool).await?; let object_id: DbUrl = object_id.into(); Ok( - private_message - .filter(ap_id.eq(object_id)) + private_message::table + .filter(private_message::ap_id.eq(object_id)) .first::(conn) .await .ok() From 9059de856934b1673e6abf0444002cad94f0a9ba Mon Sep 17 00:00:00 2001 From: Nutomic Date: Wed, 10 Apr 2024 16:04:57 +0200 Subject: [PATCH 16/26] Allow fetching from local url, add fetch redirect test (fixes #4526) (#4607) * Allow fetching from local url, at fetch redirect test (fixes #4526) * prettier * update lib * update apub lib --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- api_tests/src/post.spec.ts | 20 ++++++++++++++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c0edf2dcf..e2561e7a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,9 +16,9 @@ checksum = "8f27d075294830fcab6f66e320dab524bc6d048f4a151698e153205559113772" [[package]] name = "activitypub_federation" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a028034c642d3ed16b535f98f48b3df30397833c183d68852d79de16650d5ed5" +checksum = "7f2a21d597eb09353bc83bea36095e1de0ef5297a6fe16edba3de676898a5ba9" dependencies = [ "activitystreams-kinds", "actix-web", diff --git a/Cargo.toml b/Cargo.toml index 554448d02..8175cd68f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -99,7 +99,7 @@ lemmy_db_views = { version = "=0.19.4-beta.2", path = "./crates/db_views" } lemmy_db_views_actor = { version = "=0.19.4-beta.2", path = "./crates/db_views_actor" } lemmy_db_views_moderator = { version = "=0.19.4-beta.2", path = "./crates/db_views_moderator" } lemmy_federate = { version = "=0.19.4-beta.2", path = "./crates/federate" } -activitypub_federation = { version = "0.5.2", default-features = false, features = [ +activitypub_federation = { version = "0.5.3", default-features = false, features = [ "actix-web", ] } diesel = "2.1.4" diff --git a/api_tests/src/post.spec.ts b/api_tests/src/post.spec.ts index c1640e93e..75f965431 100644 --- a/api_tests/src/post.spec.ts +++ b/api_tests/src/post.spec.ts @@ -745,3 +745,23 @@ test("Block post that contains banned URL", async () => { editSiteForm.blocked_urls = []; await epsilon.editSite(editSiteForm); }); + +test("Fetch post with redirect", async () => { + let alphaPost = await createPost(alpha, betaCommunity!.community.id); + expect(alphaPost.post_view.post).toBeDefined(); + + // beta fetches from alpha as usual + let betaPost = await resolvePost(beta, alphaPost.post_view.post); + expect(betaPost.post).toBeDefined(); + + // gamma fetches from beta, and gets redirected to alpha + let gammaPost = await resolvePost(gamma, betaPost.post!.post); + expect(gammaPost.post).toBeDefined(); + + // fetch remote object from local url, which redirects to the original url + let form: ResolveObject = { + q: `http://lemmy-gamma:8561/post/${gammaPost.post!.post.id}`, + }; + let gammaPost2 = await gamma.resolveObject(form); + expect(gammaPost2.post).toBeDefined(); +}); From d5622a65f813c000e12b45a475e1855685348a38 Mon Sep 17 00:00:00 2001 From: Kroese Date: Wed, 10 Apr 2024 16:09:54 +0200 Subject: [PATCH 17/26] Fix for PictrsImageMode::None (#4604) * Fix PictrsImageMode::None * Update crates/api_common/src/request.rs Co-authored-by: SleeplessOne1917 <28871516+SleeplessOne1917@users.noreply.github.com> * Fix formatting --------- Co-authored-by: SleeplessOne1917 <28871516+SleeplessOne1917@users.noreply.github.com> --- crates/api_common/src/request.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/crates/api_common/src/request.rs b/crates/api_common/src/request.rs index d77ea2daa..06410b70c 100644 --- a/crates/api_common/src/request.rs +++ b/crates/api_common/src/request.rs @@ -302,9 +302,13 @@ async fn generate_pictrs_thumbnail( ) -> Result { let pictrs_config = context.settings().pictrs_config()?; - if pictrs_config.image_mode() == PictrsImageMode::ProxyAllImages { - return Ok(proxy_image_link(image_url.clone(), context).await?.into()); - } + match pictrs_config.image_mode() { + PictrsImageMode::None => return Ok(image_url.clone()), + PictrsImageMode::ProxyAllImages => { + return Ok(proxy_image_link(image_url.clone(), context).await?.into()) + } + _ => {} + }; // fetch remote non-pictrs images for persistent thumbnail link // TODO: should limit size once supported by pictrs From 5dea21d5313b011fb92126f60606a61343d34da0 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Wed, 10 Apr 2024 10:14:11 -0400 Subject: [PATCH 18/26] Convert all Result<..., LemmyError> into LemmyResult<...> Fixes #4613 (#4614) * Convert all Result<..., LemmyError> into LemmyResult<...> Fixes #4613 * Fixing clippy. --- crates/api/src/comment/distinguish.rs | 4 +- crates/api/src/comment/like.rs | 4 +- crates/api/src/comment/list_comment_likes.rs | 4 +- crates/api/src/comment/save.rs | 4 +- crates/api/src/comment_report/create.rs | 4 +- crates/api/src/comment_report/list.rs | 4 +- crates/api/src/comment_report/resolve.rs | 4 +- crates/api/src/community/add_mod.rs | 4 +- crates/api/src/community/ban.rs | 4 +- crates/api/src/community/block.rs | 4 +- crates/api/src/community/follow.rs | 4 +- crates/api/src/community/hide.rs | 4 +- crates/api/src/community/transfer.rs | 4 +- crates/api/src/lib.rs | 12 +-- crates/api/src/local_user/add_admin.rs | 4 +- crates/api/src/local_user/ban_person.rs | 4 +- crates/api/src/local_user/block.rs | 4 +- crates/api/src/local_user/change_password.rs | 4 +- .../local_user/change_password_after_reset.rs | 4 +- .../src/local_user/generate_totp_secret.rs | 4 +- crates/api/src/local_user/get_captcha.rs | 4 +- crates/api/src/local_user/list_banned.rs | 4 +- crates/api/src/local_user/list_logins.rs | 4 +- crates/api/src/local_user/list_media.rs | 4 +- crates/api/src/local_user/login.rs | 6 +- .../local_user/notifications/list_mentions.rs | 4 +- .../local_user/notifications/list_replies.rs | 4 +- .../local_user/notifications/mark_all_read.rs | 4 +- .../notifications/mark_mention_read.rs | 4 +- .../notifications/mark_reply_read.rs | 4 +- .../local_user/notifications/unread_count.rs | 4 +- crates/api/src/local_user/report_count.rs | 4 +- crates/api/src/local_user/save_settings.rs | 4 +- crates/api/src/local_user/update_totp.rs | 4 +- crates/api/src/local_user/validate_auth.rs | 4 +- crates/api/src/post/feature.rs | 4 +- crates/api/src/post/get_link_metadata.rs | 4 +- crates/api/src/post/hide.rs | 4 +- crates/api/src/post/like.rs | 4 +- crates/api/src/post/list_post_likes.rs | 4 +- crates/api/src/post/lock.rs | 4 +- crates/api/src/post/mark_read.rs | 4 +- crates/api/src/post/save.rs | 4 +- crates/api/src/post_report/create.rs | 4 +- crates/api/src/post_report/list.rs | 4 +- crates/api/src/post_report/resolve.rs | 4 +- crates/api/src/private_message/mark_read.rs | 4 +- .../api/src/private_message_report/create.rs | 4 +- crates/api/src/private_message_report/list.rs | 4 +- .../api/src/private_message_report/resolve.rs | 4 +- crates/api/src/site/block.rs | 4 +- crates/api/src/site/federated_instances.rs | 4 +- crates/api/src/site/leave_admin.rs | 4 +- crates/api/src/site/list_all_media.rs | 4 +- crates/api/src/site/mod_log.rs | 4 +- crates/api/src/site/purge/comment.rs | 4 +- crates/api/src/site/purge/community.rs | 4 +- crates/api/src/site/purge/person.rs | 4 +- crates/api/src/site/purge/post.rs | 4 +- .../site/registration_applications/approve.rs | 4 +- .../site/registration_applications/list.rs | 4 +- .../registration_applications/unread_count.rs | 4 +- crates/api_common/src/build_response.rs | 10 +-- crates/api_common/src/request.rs | 22 ++---- crates/api_common/src/utils.rs | 76 +++++++++---------- crates/api_crud/src/comment/create.rs | 6 +- crates/api_crud/src/comment/delete.rs | 4 +- crates/api_crud/src/comment/read.rs | 4 +- crates/api_crud/src/comment/remove.rs | 4 +- crates/api_crud/src/comment/update.rs | 4 +- crates/api_crud/src/community/create.rs | 4 +- crates/api_crud/src/community/delete.rs | 4 +- crates/api_crud/src/community/list.rs | 4 +- crates/api_crud/src/community/remove.rs | 4 +- crates/api_crud/src/community/update.rs | 4 +- crates/api_crud/src/custom_emoji/create.rs | 4 +- crates/api_crud/src/custom_emoji/delete.rs | 4 +- crates/api_crud/src/custom_emoji/update.rs | 4 +- crates/api_crud/src/post/create.rs | 4 +- crates/api_crud/src/post/delete.rs | 4 +- crates/api_crud/src/post/read.rs | 4 +- crates/api_crud/src/post/remove.rs | 4 +- crates/api_crud/src/post/update.rs | 4 +- crates/api_crud/src/private_message/create.rs | 4 +- crates/api_crud/src/private_message/delete.rs | 4 +- crates/api_crud/src/private_message/read.rs | 4 +- crates/api_crud/src/private_message/update.rs | 4 +- crates/api_crud/src/site/create.rs | 4 +- crates/api_crud/src/site/read.rs | 4 +- crates/api_crud/src/site/update.rs | 4 +- crates/api_crud/src/user/create.rs | 4 +- .../apub/src/activities/block/block_user.rs | 10 +-- crates/apub/src/activities/block/mod.rs | 20 ++--- .../src/activities/block/undo_block_user.rs | 8 +- .../apub/src/activities/community/announce.rs | 8 +- .../activities/community/collection_add.rs | 14 ++-- .../activities/community/collection_remove.rs | 10 +-- .../src/activities/community/lock_page.rs | 4 +- crates/apub/src/activities/community/mod.rs | 4 +- .../apub/src/activities/community/report.rs | 8 +- .../apub/src/activities/community/update.rs | 8 +- .../activities/create_or_update/comment.rs | 11 ++- .../src/activities/create_or_update/post.rs | 10 +-- .../create_or_update/private_message.rs | 8 +- crates/apub/src/activities/deletion/delete.rs | 10 +-- crates/apub/src/activities/deletion/mod.rs | 16 ++-- .../src/activities/deletion/undo_delete.rs | 8 +- .../apub/src/activities/following/accept.rs | 8 +- .../apub/src/activities/following/follow.rs | 10 +-- crates/apub/src/activities/following/mod.rs | 4 +- .../src/activities/following/undo_follow.rs | 8 +- crates/apub/src/activities/mod.rs | 17 ++--- crates/apub/src/activities/voting/mod.rs | 12 +-- .../apub/src/activities/voting/undo_vote.rs | 8 +- crates/apub/src/activities/voting/vote.rs | 8 +- crates/apub/src/activity_lists.rs | 4 +- crates/apub/src/api/list_comments.rs | 4 +- crates/apub/src/api/list_posts.rs | 4 +- crates/apub/src/api/read_community.rs | 4 +- crates/apub/src/api/read_person.rs | 4 +- crates/apub/src/api/resolve_object.rs | 6 +- crates/apub/src/api/search.rs | 4 +- crates/apub/src/api/user_settings_backup.rs | 6 +- .../src/collections/community_moderators.rs | 12 +-- .../apub/src/collections/community_outbox.rs | 11 +-- crates/apub/src/fetcher/mod.rs | 4 +- crates/apub/src/fetcher/post_or_comment.rs | 17 ++--- crates/apub/src/fetcher/search.rs | 16 ++-- .../src/fetcher/site_or_community_or_user.rs | 12 +-- crates/apub/src/fetcher/user_or_community.rs | 15 ++-- crates/apub/src/http/comment.rs | 4 +- crates/apub/src/http/community.rs | 19 +++-- crates/apub/src/http/mod.rs | 4 +- crates/apub/src/http/person.rs | 8 +- crates/apub/src/http/post.rs | 4 +- crates/apub/src/http/site.rs | 10 +-- crates/apub/src/lib.rs | 9 +-- crates/apub/src/mentions.rs | 6 +- crates/apub/src/objects/comment.rs | 13 ++-- crates/apub/src/objects/community.rs | 25 +++--- crates/apub/src/objects/instance.rs | 18 ++--- crates/apub/src/objects/mod.rs | 4 +- crates/apub/src/objects/person.rs | 16 ++-- crates/apub/src/objects/post.rs | 13 ++-- crates/apub/src/objects/private_message.rs | 13 ++-- .../protocol/activities/block/block_user.rs | 4 +- .../activities/block/undo_block_user.rs | 4 +- .../activities/community/collection_add.rs | 4 +- .../activities/community/collection_remove.rs | 4 +- .../activities/community/lock_page.rs | 6 +- .../protocol/activities/community/report.rs | 4 +- .../protocol/activities/community/update.rs | 4 +- .../activities/create_or_update/note.rs | 4 +- .../activities/create_or_update/page.rs | 4 +- .../protocol/activities/deletion/delete.rs | 4 +- .../activities/deletion/undo_delete.rs | 4 +- .../protocol/activities/voting/undo_vote.rs | 4 +- .../src/protocol/activities/voting/vote.rs | 4 +- .../src/protocol/collections/empty_outbox.rs | 4 +- crates/apub/src/protocol/mod.rs | 16 ++-- crates/apub/src/protocol/objects/group.rs | 4 +- crates/apub/src/protocol/objects/mod.rs | 10 +-- crates/apub/src/protocol/objects/note.rs | 6 +- crates/apub/src/protocol/objects/page.rs | 15 ++-- crates/db_schema/src/impls/actor_language.rs | 4 +- crates/db_schema/src/impls/local_site.rs | 14 ++-- crates/db_schema/src/impls/private_message.rs | 4 +- crates/db_schema/src/utils.rs | 14 ++-- crates/routes/src/feeds.rs | 25 +++--- crates/routes/src/lib.rs | 7 +- crates/routes/src/nodeinfo.rs | 6 +- crates/routes/src/webfinger.rs | 4 +- crates/utils/src/email.rs | 4 +- crates/utils/src/error.rs | 10 +-- crates/utils/src/settings/mod.rs | 6 +- crates/utils/src/utils/slurs.rs | 9 +-- src/code_migrations.rs | 27 +++---- src/lib.rs | 11 ++- src/main.rs | 4 +- src/scheduled_tasks.rs | 4 +- src/telemetry.rs | 8 +- 181 files changed, 591 insertions(+), 672 deletions(-) diff --git a/crates/api/src/comment/distinguish.rs b/crates/api/src/comment/distinguish.rs index a346bf4ca..dc2be8ad8 100644 --- a/crates/api/src/comment/distinguish.rs +++ b/crates/api/src/comment/distinguish.rs @@ -9,14 +9,14 @@ use lemmy_db_schema::{ traits::Crud, }; use lemmy_db_views::structs::{CommentView, LocalUserView}; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn distinguish_comment( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let orig_comment = CommentView::read(&mut context.pool(), data.comment_id, None).await?; check_community_user_action( diff --git a/crates/api/src/comment/like.rs b/crates/api/src/comment/like.rs index e15d74422..bfa522739 100644 --- a/crates/api/src/comment/like.rs +++ b/crates/api/src/comment/like.rs @@ -17,7 +17,7 @@ use lemmy_db_schema::{ traits::Likeable, }; use lemmy_db_views::structs::{CommentView, LocalUserView}; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; use std::ops::Deref; #[tracing::instrument(skip(context))] @@ -25,7 +25,7 @@ pub async fn like_comment( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let local_site = LocalSite::read(&mut context.pool()).await?; let mut recipient_ids = Vec::::new(); diff --git a/crates/api/src/comment/list_comment_likes.rs b/crates/api/src/comment/list_comment_likes.rs index b442cce23..649ae249d 100644 --- a/crates/api/src/comment/list_comment_likes.rs +++ b/crates/api/src/comment/list_comment_likes.rs @@ -5,7 +5,7 @@ use lemmy_api_common::{ utils::is_mod_or_admin, }; use lemmy_db_views::structs::{CommentView, LocalUserView, VoteView}; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; /// Lists likes for a comment #[tracing::instrument(skip(context))] @@ -13,7 +13,7 @@ pub async fn list_comment_likes( data: Query, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let comment_view = CommentView::read( &mut context.pool(), data.comment_id, diff --git a/crates/api/src/comment/save.rs b/crates/api/src/comment/save.rs index 95c08e701..f197ecb4c 100644 --- a/crates/api/src/comment/save.rs +++ b/crates/api/src/comment/save.rs @@ -8,14 +8,14 @@ use lemmy_db_schema::{ traits::Saveable, }; use lemmy_db_views::structs::{CommentView, LocalUserView}; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn save_comment( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let comment_saved_form = CommentSavedForm { comment_id: data.comment_id, person_id: local_user_view.person.id, diff --git a/crates/api/src/comment_report/create.rs b/crates/api/src/comment_report/create.rs index f8075460f..de40571fe 100644 --- a/crates/api/src/comment_report/create.rs +++ b/crates/api/src/comment_report/create.rs @@ -19,7 +19,7 @@ use lemmy_db_schema::{ traits::Reportable, }; use lemmy_db_views::structs::{CommentReportView, CommentView, LocalUserView}; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; /// Creates a comment report and notifies the moderators of the community #[tracing::instrument(skip(context))] @@ -27,7 +27,7 @@ pub async fn create_comment_report( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let local_site = LocalSite::read(&mut context.pool()).await?; let reason = data.reason.trim().to_string(); diff --git a/crates/api/src/comment_report/list.rs b/crates/api/src/comment_report/list.rs index f1577a77f..d2f723819 100644 --- a/crates/api/src/comment_report/list.rs +++ b/crates/api/src/comment_report/list.rs @@ -5,7 +5,7 @@ use lemmy_api_common::{ utils::check_community_mod_of_any_or_admin_action, }; use lemmy_db_views::{comment_report_view::CommentReportQuery, structs::LocalUserView}; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; /// Lists comment reports for a community if an id is supplied /// or returns all comment reports for communities a user moderates @@ -14,7 +14,7 @@ pub async fn list_comment_reports( data: Query, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let community_id = data.community_id; let comment_id = data.comment_id; let unresolved_only = data.unresolved_only.unwrap_or_default(); diff --git a/crates/api/src/comment_report/resolve.rs b/crates/api/src/comment_report/resolve.rs index 70e7d89f6..a663fdf74 100644 --- a/crates/api/src/comment_report/resolve.rs +++ b/crates/api/src/comment_report/resolve.rs @@ -6,7 +6,7 @@ use lemmy_api_common::{ }; use lemmy_db_schema::{source::comment_report::CommentReport, traits::Reportable}; use lemmy_db_views::structs::{CommentReportView, LocalUserView}; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; /// Resolves or unresolves a comment report and notifies the moderators of the community #[tracing::instrument(skip(context))] @@ -14,7 +14,7 @@ pub async fn resolve_comment_report( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let report_id = data.report_id; let person_id = local_user_view.person.id; let report = CommentReportView::read(&mut context.pool(), report_id, person_id).await?; diff --git a/crates/api/src/community/add_mod.rs b/crates/api/src/community/add_mod.rs index 69692e58c..92799fb6b 100644 --- a/crates/api/src/community/add_mod.rs +++ b/crates/api/src/community/add_mod.rs @@ -15,14 +15,14 @@ use lemmy_db_schema::{ }; use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::structs::CommunityModeratorView; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn add_mod_to_community( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let community_id = data.community_id; // Verify that only mods or admins can add mod diff --git a/crates/api/src/community/ban.rs b/crates/api/src/community/ban.rs index 91cb8884f..0ad9952df 100644 --- a/crates/api/src/community/ban.rs +++ b/crates/api/src/community/ban.rs @@ -21,7 +21,7 @@ use lemmy_db_schema::{ use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::structs::PersonView; use lemmy_utils::{ - error::{LemmyError, LemmyErrorExt, LemmyErrorType}, + error::{LemmyErrorExt, LemmyErrorType, LemmyResult}, utils::validation::is_valid_body_field, }; @@ -30,7 +30,7 @@ pub async fn ban_from_community( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let banned_person_id = data.person_id; let remove_data = data.remove_data.unwrap_or(false); let expires = check_expire_time(data.expires)?; diff --git a/crates/api/src/community/block.rs b/crates/api/src/community/block.rs index fd4a5a01b..d5d8a0287 100644 --- a/crates/api/src/community/block.rs +++ b/crates/api/src/community/block.rs @@ -14,14 +14,14 @@ use lemmy_db_schema::{ }; use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::structs::CommunityView; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn block_community( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let community_id = data.community_id; let person_id = local_user_view.person.id; let community_block_form = CommunityBlockForm { diff --git a/crates/api/src/community/follow.rs b/crates/api/src/community/follow.rs index bb7b80f00..94109192b 100644 --- a/crates/api/src/community/follow.rs +++ b/crates/api/src/community/follow.rs @@ -15,14 +15,14 @@ use lemmy_db_schema::{ }; use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::structs::CommunityView; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn follow_community( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let community = Community::read(&mut context.pool(), data.community_id).await?; let mut community_follower_form = CommunityFollowerForm { community_id: community.id, diff --git a/crates/api/src/community/hide.rs b/crates/api/src/community/hide.rs index 27919a42b..997d88de3 100644 --- a/crates/api/src/community/hide.rs +++ b/crates/api/src/community/hide.rs @@ -15,14 +15,14 @@ use lemmy_db_schema::{ traits::Crud, }; use lemmy_db_views::structs::LocalUserView; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn hide_community( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { // Verify its a admin (only admin can hide or unhide it) is_admin(&local_user_view)?; diff --git a/crates/api/src/community/transfer.rs b/crates/api/src/community/transfer.rs index 340bb6b63..399eeadae 100644 --- a/crates/api/src/community/transfer.rs +++ b/crates/api/src/community/transfer.rs @@ -15,7 +15,7 @@ use lemmy_db_schema::{ use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView}; use lemmy_utils::{ - error::{LemmyError, LemmyErrorExt, LemmyErrorType}, + error::{LemmyErrorExt, LemmyErrorType, LemmyResult}, location_info, }; @@ -26,7 +26,7 @@ pub async fn transfer_community( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let community_id = data.community_id; let mut community_mods = CommunityModeratorView::for_community(&mut context.pool(), community_id).await?; diff --git a/crates/api/src/lib.rs b/crates/api/src/lib.rs index d65ae0a28..498dff3bd 100644 --- a/crates/api/src/lib.rs +++ b/crates/api/src/lib.rs @@ -26,7 +26,7 @@ use lemmy_db_schema::{ }; use lemmy_db_views::structs::LocalUserView; use lemmy_utils::{ - error::{LemmyError, LemmyErrorExt, LemmyErrorExt2, LemmyErrorType, LemmyResult}, + error::{LemmyErrorExt, LemmyErrorExt2, LemmyErrorType, LemmyResult}, utils::slurs::check_slurs, }; use std::io::Cursor; @@ -44,7 +44,7 @@ pub mod site; pub mod sitemap; /// Converts the captcha to a base64 encoded wav audio file -pub(crate) fn captcha_as_wav_base64(captcha: &Captcha) -> Result { +pub(crate) fn captcha_as_wav_base64(captcha: &Captcha) -> LemmyResult { let letters = captcha.as_wav(); // Decode each wav file, concatenate the samples @@ -78,7 +78,7 @@ pub(crate) fn captcha_as_wav_base64(captcha: &Captcha) -> Result Result<(), LemmyError> { +pub(crate) fn check_report_reason(reason: &str, local_site: &LocalSite) -> LemmyResult<()> { let slur_regex = &local_site_to_slur_regex(local_site); check_slurs(reason, slur_regex)?; @@ -91,7 +91,7 @@ pub(crate) fn check_report_reason(reason: &str, local_site: &LocalSite) -> Resul } } -pub fn read_auth_token(req: &HttpRequest) -> Result, LemmyError> { +pub fn read_auth_token(req: &HttpRequest) -> LemmyResult> { // Try reading jwt from auth header if let Ok(header) = Authorization::::parse(req) { Ok(Some(header.as_ref().token().to_string())) @@ -135,7 +135,7 @@ pub(crate) fn generate_totp_2fa_secret() -> String { Secret::generate_secret().to_string() } -fn build_totp_2fa(hostname: &str, username: &str, secret: &str) -> Result { +fn build_totp_2fa(hostname: &str, username: &str, secret: &str) -> LemmyResult { let sec = Secret::Raw(secret.as_bytes().to_vec()); let sec_bytes = sec .to_bytes() @@ -248,7 +248,7 @@ pub(crate) async fn ban_nonlocal_user_from_local_communities( pub async fn local_user_view_from_jwt( jwt: &str, context: &LemmyContext, -) -> Result { +) -> LemmyResult { let local_user_id = Claims::validate(jwt, context) .await .with_lemmy_type(LemmyErrorType::NotLoggedIn)?; diff --git a/crates/api/src/local_user/add_admin.rs b/crates/api/src/local_user/add_admin.rs index 502335876..6ebdbd08f 100644 --- a/crates/api/src/local_user/add_admin.rs +++ b/crates/api/src/local_user/add_admin.rs @@ -13,14 +13,14 @@ use lemmy_db_schema::{ }; use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::structs::PersonView; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn add_admin( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { // Make sure user is an admin is_admin(&local_user_view)?; diff --git a/crates/api/src/local_user/ban_person.rs b/crates/api/src/local_user/ban_person.rs index f039c9a0c..f0e6ffc26 100644 --- a/crates/api/src/local_user/ban_person.rs +++ b/crates/api/src/local_user/ban_person.rs @@ -18,7 +18,7 @@ use lemmy_db_schema::{ use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::structs::PersonView; use lemmy_utils::{ - error::{LemmyError, LemmyErrorExt, LemmyErrorType}, + error::{LemmyErrorExt, LemmyErrorType, LemmyResult}, utils::validation::is_valid_body_field, }; @@ -27,7 +27,7 @@ pub async fn ban_from_site( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { // Make sure user is an admin is_admin(&local_user_view)?; diff --git a/crates/api/src/local_user/block.rs b/crates/api/src/local_user/block.rs index cb345616b..46a1e44aa 100644 --- a/crates/api/src/local_user/block.rs +++ b/crates/api/src/local_user/block.rs @@ -9,14 +9,14 @@ use lemmy_db_schema::{ }; use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::structs::PersonView; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn block_person( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let target_id = data.person_id; let person_id = local_user_view.person.id; diff --git a/crates/api/src/local_user/change_password.rs b/crates/api/src/local_user/change_password.rs index ab5b32dd9..50ee10bb6 100644 --- a/crates/api/src/local_user/change_password.rs +++ b/crates/api/src/local_user/change_password.rs @@ -11,7 +11,7 @@ use lemmy_api_common::{ }; use lemmy_db_schema::source::{local_user::LocalUser, login_token::LoginToken}; use lemmy_db_views::structs::LocalUserView; -use lemmy_utils::error::{LemmyError, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn change_password( @@ -19,7 +19,7 @@ pub async fn change_password( req: HttpRequest, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { password_length_check(&data.new_password)?; // Make sure passwords match diff --git a/crates/api/src/local_user/change_password_after_reset.rs b/crates/api/src/local_user/change_password_after_reset.rs index 50a267d6a..9d759d7e9 100644 --- a/crates/api/src/local_user/change_password_after_reset.rs +++ b/crates/api/src/local_user/change_password_after_reset.rs @@ -10,13 +10,13 @@ use lemmy_db_schema::source::{ login_token::LoginToken, password_reset_request::PasswordResetRequest, }; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn change_password_after_reset( data: Json, context: Data, -) -> Result, LemmyError> { +) -> LemmyResult> { // Fetch the user_id from the token let token = data.token.clone(); let local_user_id = PasswordResetRequest::read_from_token(&mut context.pool(), &token) diff --git a/crates/api/src/local_user/generate_totp_secret.rs b/crates/api/src/local_user/generate_totp_secret.rs index 342a90a78..285fa2ad5 100644 --- a/crates/api/src/local_user/generate_totp_secret.rs +++ b/crates/api/src/local_user/generate_totp_secret.rs @@ -8,7 +8,7 @@ use lemmy_api_common::{ }; use lemmy_db_schema::source::local_user::{LocalUser, LocalUserUpdateForm}; use lemmy_db_views::structs::{LocalUserView, SiteView}; -use lemmy_utils::error::{LemmyError, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorType, LemmyResult}; /// Generate a new secret for two-factor-authentication. Afterwards you need to call [toggle_totp] /// to enable it. This can only be called if 2FA is currently disabled. @@ -16,7 +16,7 @@ use lemmy_utils::error::{LemmyError, LemmyErrorType}; pub async fn generate_totp_secret( local_user_view: LocalUserView, context: Data, -) -> Result, LemmyError> { +) -> LemmyResult> { let site_view = SiteView::read_local(&mut context.pool()).await?; if local_user_view.local_user.totp_2fa_enabled { diff --git a/crates/api/src/local_user/get_captcha.rs b/crates/api/src/local_user/get_captcha.rs index 3d93a793c..ac64fa07c 100644 --- a/crates/api/src/local_user/get_captcha.rs +++ b/crates/api/src/local_user/get_captcha.rs @@ -17,10 +17,10 @@ use lemmy_db_schema::source::{ captcha_answer::{CaptchaAnswer, CaptchaAnswerForm}, local_site::LocalSite, }; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; #[tracing::instrument(skip(context))] -pub async fn get_captcha(context: Data) -> Result { +pub async fn get_captcha(context: Data) -> LemmyResult { let local_site = LocalSite::read(&mut context.pool()).await?; let mut res = HttpResponseBuilder::new(StatusCode::OK); res.insert_header(CacheControl(vec![CacheDirective::NoStore])); diff --git a/crates/api/src/local_user/list_banned.rs b/crates/api/src/local_user/list_banned.rs index 5c76d89a8..ba2c0d403 100644 --- a/crates/api/src/local_user/list_banned.rs +++ b/crates/api/src/local_user/list_banned.rs @@ -2,12 +2,12 @@ use actix_web::web::{Data, Json}; use lemmy_api_common::{context::LemmyContext, person::BannedPersonsResponse, utils::is_admin}; use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::structs::PersonView; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; pub async fn list_banned_users( context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { // Make sure user is an admin is_admin(&local_user_view)?; diff --git a/crates/api/src/local_user/list_logins.rs b/crates/api/src/local_user/list_logins.rs index f1ae76be5..013236dcd 100644 --- a/crates/api/src/local_user/list_logins.rs +++ b/crates/api/src/local_user/list_logins.rs @@ -2,12 +2,12 @@ use actix_web::web::{Data, Json}; use lemmy_api_common::context::LemmyContext; use lemmy_db_schema::source::login_token::LoginToken; use lemmy_db_views::structs::LocalUserView; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; pub async fn list_logins( context: Data, local_user_view: LocalUserView, -) -> Result>, LemmyError> { +) -> LemmyResult>> { let logins = LoginToken::list(&mut context.pool(), local_user_view.local_user.id).await?; Ok(Json(logins)) diff --git a/crates/api/src/local_user/list_media.rs b/crates/api/src/local_user/list_media.rs index 25df8a4c2..bf69c4a34 100644 --- a/crates/api/src/local_user/list_media.rs +++ b/crates/api/src/local_user/list_media.rs @@ -5,14 +5,14 @@ use lemmy_api_common::{ }; use lemmy_db_schema::source::images::LocalImage; use lemmy_db_views::structs::LocalUserView; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; #[tracing::instrument(skip(context))] pub async fn list_media( data: Query, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let page = data.page; let limit = data.limit; let images = LocalImage::get_all_paged_by_local_user_id( diff --git a/crates/api/src/local_user/login.rs b/crates/api/src/local_user/login.rs index 4eae762be..8e3301af9 100644 --- a/crates/api/src/local_user/login.rs +++ b/crates/api/src/local_user/login.rs @@ -16,14 +16,14 @@ use lemmy_db_schema::{ RegistrationMode, }; use lemmy_db_views::structs::{LocalUserView, SiteView}; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn login( data: Json, req: HttpRequest, context: Data, -) -> Result, LemmyError> { +) -> LemmyResult> { let site_view = SiteView::read_local(&mut context.pool()).await?; // Fetch that username / email @@ -70,7 +70,7 @@ async fn check_registration_application( local_user_view: &LocalUserView, local_site: &LocalSite, pool: &mut DbPool<'_>, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { if (local_site.registration_mode == RegistrationMode::RequireApplication || local_site.registration_mode == RegistrationMode::Closed) && !local_user_view.local_user.accepted_application diff --git a/crates/api/src/local_user/notifications/list_mentions.rs b/crates/api/src/local_user/notifications/list_mentions.rs index 9f9ee3ae8..bf3cd8e0d 100644 --- a/crates/api/src/local_user/notifications/list_mentions.rs +++ b/crates/api/src/local_user/notifications/list_mentions.rs @@ -5,14 +5,14 @@ use lemmy_api_common::{ }; use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::person_mention_view::PersonMentionQuery; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; #[tracing::instrument(skip(context))] pub async fn list_mentions( data: Query, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let sort = data.sort; let page = data.page; let limit = data.limit; diff --git a/crates/api/src/local_user/notifications/list_replies.rs b/crates/api/src/local_user/notifications/list_replies.rs index 555989721..d88595d96 100644 --- a/crates/api/src/local_user/notifications/list_replies.rs +++ b/crates/api/src/local_user/notifications/list_replies.rs @@ -5,14 +5,14 @@ use lemmy_api_common::{ }; use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::comment_reply_view::CommentReplyQuery; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; #[tracing::instrument(skip(context))] pub async fn list_replies( data: Query, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let sort = data.sort; let page = data.page; let limit = data.limit; diff --git a/crates/api/src/local_user/notifications/mark_all_read.rs b/crates/api/src/local_user/notifications/mark_all_read.rs index d3667460b..558d276f7 100644 --- a/crates/api/src/local_user/notifications/mark_all_read.rs +++ b/crates/api/src/local_user/notifications/mark_all_read.rs @@ -6,13 +6,13 @@ use lemmy_db_schema::source::{ private_message::PrivateMessage, }; use lemmy_db_views::structs::LocalUserView; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn mark_all_notifications_read( context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let person_id = local_user_view.person.id; // Mark all comment_replies as read diff --git a/crates/api/src/local_user/notifications/mark_mention_read.rs b/crates/api/src/local_user/notifications/mark_mention_read.rs index 4cce598ac..9a839b2b4 100644 --- a/crates/api/src/local_user/notifications/mark_mention_read.rs +++ b/crates/api/src/local_user/notifications/mark_mention_read.rs @@ -9,14 +9,14 @@ use lemmy_db_schema::{ }; use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::structs::PersonMentionView; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn mark_person_mention_as_read( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let person_mention_id = data.person_mention_id; let read_person_mention = PersonMention::read(&mut context.pool(), person_mention_id).await?; diff --git a/crates/api/src/local_user/notifications/mark_reply_read.rs b/crates/api/src/local_user/notifications/mark_reply_read.rs index f7b259c94..5b263145f 100644 --- a/crates/api/src/local_user/notifications/mark_reply_read.rs +++ b/crates/api/src/local_user/notifications/mark_reply_read.rs @@ -9,14 +9,14 @@ use lemmy_db_schema::{ }; use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::structs::CommentReplyView; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn mark_reply_as_read( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let comment_reply_id = data.comment_reply_id; let read_comment_reply = CommentReply::read(&mut context.pool(), comment_reply_id).await?; diff --git a/crates/api/src/local_user/notifications/unread_count.rs b/crates/api/src/local_user/notifications/unread_count.rs index c0b1f0f2e..9d06f7c62 100644 --- a/crates/api/src/local_user/notifications/unread_count.rs +++ b/crates/api/src/local_user/notifications/unread_count.rs @@ -2,13 +2,13 @@ use actix_web::web::{Data, Json}; use lemmy_api_common::{context::LemmyContext, person::GetUnreadCountResponse}; use lemmy_db_views::structs::{LocalUserView, PrivateMessageView}; use lemmy_db_views_actor::structs::{CommentReplyView, PersonMentionView}; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; #[tracing::instrument(skip(context))] pub async fn unread_count( context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let person_id = local_user_view.person.id; let replies = CommentReplyView::get_unread_replies(&mut context.pool(), person_id).await?; diff --git a/crates/api/src/local_user/report_count.rs b/crates/api/src/local_user/report_count.rs index 3352f64eb..32448dcaa 100644 --- a/crates/api/src/local_user/report_count.rs +++ b/crates/api/src/local_user/report_count.rs @@ -10,14 +10,14 @@ use lemmy_db_views::structs::{ PostReportView, PrivateMessageReportView, }; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; #[tracing::instrument(skip(context))] pub async fn report_count( data: Query, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let person_id = local_user_view.person.id; let admin = local_user_view.local_user.admin; let community_id = data.community_id; diff --git a/crates/api/src/local_user/save_settings.rs b/crates/api/src/local_user/save_settings.rs index 972760a00..3fa835f58 100644 --- a/crates/api/src/local_user/save_settings.rs +++ b/crates/api/src/local_user/save_settings.rs @@ -25,7 +25,7 @@ use lemmy_db_schema::{ }; use lemmy_db_views::structs::{LocalUserView, SiteView}; use lemmy_utils::{ - error::{LemmyError, LemmyErrorType}, + error::{LemmyErrorType, LemmyResult}, utils::validation::{is_valid_bio_field, is_valid_display_name, is_valid_matrix_id}, }; @@ -34,7 +34,7 @@ pub async fn save_user_settings( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let site_view = SiteView::read_local(&mut context.pool()).await?; let slur_regex = local_site_to_slur_regex(&site_view.local_site); diff --git a/crates/api/src/local_user/update_totp.rs b/crates/api/src/local_user/update_totp.rs index c8ca9f64e..c28ac7228 100644 --- a/crates/api/src/local_user/update_totp.rs +++ b/crates/api/src/local_user/update_totp.rs @@ -6,7 +6,7 @@ use lemmy_api_common::{ }; use lemmy_db_schema::source::local_user::{LocalUser, LocalUserUpdateForm}; use lemmy_db_views::structs::LocalUserView; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; /// Enable or disable two-factor-authentication. The current setting is determined from /// [LocalUser.totp_2fa_enabled]. @@ -21,7 +21,7 @@ pub async fn update_totp( data: Json, local_user_view: LocalUserView, context: Data, -) -> Result, LemmyError> { +) -> LemmyResult> { check_totp_2fa_valid( &local_user_view, &Some(data.totp_token.clone()), diff --git a/crates/api/src/local_user/validate_auth.rs b/crates/api/src/local_user/validate_auth.rs index d95195dc9..36d31ff01 100644 --- a/crates/api/src/local_user/validate_auth.rs +++ b/crates/api/src/local_user/validate_auth.rs @@ -4,7 +4,7 @@ use actix_web::{ HttpRequest, }; use lemmy_api_common::{context::LemmyContext, SuccessResponse}; -use lemmy_utils::error::{LemmyError, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorType, LemmyResult}; /// Returns an error message if the auth token is invalid for any reason. Necessary because other /// endpoints silently treat any call with invalid auth as unauthenticated. @@ -12,7 +12,7 @@ use lemmy_utils::error::{LemmyError, LemmyErrorType}; pub async fn validate_auth( req: HttpRequest, context: Data, -) -> Result, LemmyError> { +) -> LemmyResult> { let jwt = read_auth_token(&req)?; if let Some(jwt) = jwt { local_user_view_from_jwt(&jwt, &context).await?; diff --git a/crates/api/src/post/feature.rs b/crates/api/src/post/feature.rs index 8c4b4978f..566ca3a0b 100644 --- a/crates/api/src/post/feature.rs +++ b/crates/api/src/post/feature.rs @@ -16,14 +16,14 @@ use lemmy_db_schema::{ PostFeatureType, }; use lemmy_db_views::structs::LocalUserView; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; #[tracing::instrument(skip(context))] pub async fn feature_post( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let post_id = data.post_id; let orig_post = Post::read(&mut context.pool(), post_id).await?; diff --git a/crates/api/src/post/get_link_metadata.rs b/crates/api/src/post/get_link_metadata.rs index a6a0c973b..8bc425125 100644 --- a/crates/api/src/post/get_link_metadata.rs +++ b/crates/api/src/post/get_link_metadata.rs @@ -4,13 +4,13 @@ use lemmy_api_common::{ post::{GetSiteMetadata, GetSiteMetadataResponse}, request::fetch_link_metadata, }; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; #[tracing::instrument(skip(context))] pub async fn get_link_metadata( data: Query, context: Data, -) -> Result, LemmyError> { +) -> LemmyResult> { let metadata = fetch_link_metadata(&data.url, false, &context).await?; Ok(Json(GetSiteMetadataResponse { metadata })) diff --git a/crates/api/src/post/hide.rs b/crates/api/src/post/hide.rs index 1adfa110d..f7c21ef31 100644 --- a/crates/api/src/post/hide.rs +++ b/crates/api/src/post/hide.rs @@ -2,7 +2,7 @@ use actix_web::web::{Data, Json}; use lemmy_api_common::{context::LemmyContext, post::HidePost, SuccessResponse}; use lemmy_db_schema::source::post::PostHide; use lemmy_db_views::structs::LocalUserView; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType, MAX_API_PARAM_ELEMENTS}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult, MAX_API_PARAM_ELEMENTS}; use std::collections::HashSet; #[tracing::instrument(skip(context))] @@ -10,7 +10,7 @@ pub async fn hide_post( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let post_ids = HashSet::from_iter(data.post_ids.clone()); if post_ids.len() > MAX_API_PARAM_ELEMENTS { diff --git a/crates/api/src/post/like.rs b/crates/api/src/post/like.rs index d99d2a5e2..1cbdba8e2 100644 --- a/crates/api/src/post/like.rs +++ b/crates/api/src/post/like.rs @@ -21,7 +21,7 @@ use lemmy_db_schema::{ traits::{Crud, Likeable}, }; use lemmy_db_views::structs::LocalUserView; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; use std::ops::Deref; #[tracing::instrument(skip(context))] @@ -29,7 +29,7 @@ pub async fn like_post( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let local_site = LocalSite::read(&mut context.pool()).await?; // Don't do a downvote if site has downvotes disabled diff --git a/crates/api/src/post/list_post_likes.rs b/crates/api/src/post/list_post_likes.rs index 84690a41b..a9b302f2e 100644 --- a/crates/api/src/post/list_post_likes.rs +++ b/crates/api/src/post/list_post_likes.rs @@ -6,7 +6,7 @@ use lemmy_api_common::{ }; use lemmy_db_schema::{source::post::Post, traits::Crud}; use lemmy_db_views::structs::{LocalUserView, VoteView}; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; /// Lists likes for a post #[tracing::instrument(skip(context))] @@ -14,7 +14,7 @@ pub async fn list_post_likes( data: Query, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let post = Post::read(&mut context.pool(), data.post_id).await?; is_mod_or_admin( &mut context.pool(), diff --git a/crates/api/src/post/lock.rs b/crates/api/src/post/lock.rs index b581f37a2..b48c415af 100644 --- a/crates/api/src/post/lock.rs +++ b/crates/api/src/post/lock.rs @@ -15,14 +15,14 @@ use lemmy_db_schema::{ traits::Crud, }; use lemmy_db_views::structs::LocalUserView; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; #[tracing::instrument(skip(context))] pub async fn lock_post( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let post_id = data.post_id; let orig_post = Post::read(&mut context.pool(), post_id).await?; diff --git a/crates/api/src/post/mark_read.rs b/crates/api/src/post/mark_read.rs index bfc455f4f..3e534675a 100644 --- a/crates/api/src/post/mark_read.rs +++ b/crates/api/src/post/mark_read.rs @@ -2,7 +2,7 @@ use actix_web::web::{Data, Json}; use lemmy_api_common::{context::LemmyContext, post::MarkPostAsRead, SuccessResponse}; use lemmy_db_schema::source::post::PostRead; use lemmy_db_views::structs::LocalUserView; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType, MAX_API_PARAM_ELEMENTS}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult, MAX_API_PARAM_ELEMENTS}; use std::collections::HashSet; #[tracing::instrument(skip(context))] @@ -10,7 +10,7 @@ pub async fn mark_post_as_read( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let post_ids = HashSet::from_iter(data.post_ids.clone()); if post_ids.len() > MAX_API_PARAM_ELEMENTS { diff --git a/crates/api/src/post/save.rs b/crates/api/src/post/save.rs index 164840770..05c7b3589 100644 --- a/crates/api/src/post/save.rs +++ b/crates/api/src/post/save.rs @@ -9,14 +9,14 @@ use lemmy_db_schema::{ traits::Saveable, }; use lemmy_db_views::structs::{LocalUserView, PostView}; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn save_post( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let post_saved_form = PostSavedForm { post_id: data.post_id, person_id: local_user_view.person.id, diff --git a/crates/api/src/post_report/create.rs b/crates/api/src/post_report/create.rs index 1327d7bb9..590c9af40 100644 --- a/crates/api/src/post_report/create.rs +++ b/crates/api/src/post_report/create.rs @@ -19,7 +19,7 @@ use lemmy_db_schema::{ traits::Reportable, }; use lemmy_db_views::structs::{LocalUserView, PostReportView, PostView}; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; /// Creates a post report and notifies the moderators of the community #[tracing::instrument(skip(context))] @@ -27,7 +27,7 @@ pub async fn create_post_report( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let local_site = LocalSite::read(&mut context.pool()).await?; let reason = data.reason.trim().to_string(); diff --git a/crates/api/src/post_report/list.rs b/crates/api/src/post_report/list.rs index 1f1aa9653..7d1d50b0b 100644 --- a/crates/api/src/post_report/list.rs +++ b/crates/api/src/post_report/list.rs @@ -5,7 +5,7 @@ use lemmy_api_common::{ utils::check_community_mod_of_any_or_admin_action, }; use lemmy_db_views::{post_report_view::PostReportQuery, structs::LocalUserView}; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; /// Lists post reports for a community if an id is supplied /// or returns all post reports for communities a user moderates @@ -14,7 +14,7 @@ pub async fn list_post_reports( data: Query, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let community_id = data.community_id; let post_id = data.post_id; let unresolved_only = data.unresolved_only.unwrap_or_default(); diff --git a/crates/api/src/post_report/resolve.rs b/crates/api/src/post_report/resolve.rs index ab6688012..a3cb85c6c 100644 --- a/crates/api/src/post_report/resolve.rs +++ b/crates/api/src/post_report/resolve.rs @@ -6,7 +6,7 @@ use lemmy_api_common::{ }; use lemmy_db_schema::{source::post_report::PostReport, traits::Reportable}; use lemmy_db_views::structs::{LocalUserView, PostReportView}; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; /// Resolves or unresolves a post report and notifies the moderators of the community #[tracing::instrument(skip(context))] @@ -14,7 +14,7 @@ pub async fn resolve_post_report( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let report_id = data.report_id; let person_id = local_user_view.person.id; let report = PostReportView::read(&mut context.pool(), report_id, person_id).await?; diff --git a/crates/api/src/private_message/mark_read.rs b/crates/api/src/private_message/mark_read.rs index 6b089c0ab..7c213464b 100644 --- a/crates/api/src/private_message/mark_read.rs +++ b/crates/api/src/private_message/mark_read.rs @@ -8,14 +8,14 @@ use lemmy_db_schema::{ traits::Crud, }; use lemmy_db_views::structs::{LocalUserView, PrivateMessageView}; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn mark_pm_as_read( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { // Checking permissions let private_message_id = data.private_message_id; let orig_private_message = PrivateMessage::read(&mut context.pool(), private_message_id).await?; diff --git a/crates/api/src/private_message_report/create.rs b/crates/api/src/private_message_report/create.rs index 7aca9661b..de8ca390f 100644 --- a/crates/api/src/private_message_report/create.rs +++ b/crates/api/src/private_message_report/create.rs @@ -14,14 +14,14 @@ use lemmy_db_schema::{ traits::{Crud, Reportable}, }; use lemmy_db_views::structs::{LocalUserView, PrivateMessageReportView}; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn create_pm_report( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let local_site = LocalSite::read(&mut context.pool()).await?; let reason = data.reason.trim().to_string(); diff --git a/crates/api/src/private_message_report/list.rs b/crates/api/src/private_message_report/list.rs index 2dc3e6efc..79ef53e1c 100644 --- a/crates/api/src/private_message_report/list.rs +++ b/crates/api/src/private_message_report/list.rs @@ -8,14 +8,14 @@ use lemmy_db_views::{ private_message_report_view::PrivateMessageReportQuery, structs::LocalUserView, }; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; #[tracing::instrument(skip(context))] pub async fn list_pm_reports( data: Query, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { is_admin(&local_user_view)?; let unresolved_only = data.unresolved_only.unwrap_or_default(); diff --git a/crates/api/src/private_message_report/resolve.rs b/crates/api/src/private_message_report/resolve.rs index 202fdcd29..7d821a60c 100644 --- a/crates/api/src/private_message_report/resolve.rs +++ b/crates/api/src/private_message_report/resolve.rs @@ -6,14 +6,14 @@ use lemmy_api_common::{ }; use lemmy_db_schema::{source::private_message_report::PrivateMessageReport, traits::Reportable}; use lemmy_db_views::structs::{LocalUserView, PrivateMessageReportView}; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn resolve_pm_report( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { is_admin(&local_user_view)?; let report_id = data.report_id; diff --git a/crates/api/src/site/block.rs b/crates/api/src/site/block.rs index 7d28e43d5..823dda612 100644 --- a/crates/api/src/site/block.rs +++ b/crates/api/src/site/block.rs @@ -9,14 +9,14 @@ use lemmy_db_schema::{ traits::Blockable, }; use lemmy_db_views::structs::LocalUserView; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn block_instance( data: Json, local_user_view: LocalUserView, context: Data, -) -> Result, LemmyError> { +) -> LemmyResult> { let instance_id = data.instance_id; let person_id = local_user_view.person.id; if local_user_view.person.instance_id == instance_id { diff --git a/crates/api/src/site/federated_instances.rs b/crates/api/src/site/federated_instances.rs index 8f224b2eb..5943cfd9a 100644 --- a/crates/api/src/site/federated_instances.rs +++ b/crates/api/src/site/federated_instances.rs @@ -5,12 +5,12 @@ use lemmy_api_common::{ utils::build_federated_instances, }; use lemmy_db_views::structs::SiteView; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; #[tracing::instrument(skip(context))] pub async fn get_federated_instances( context: Data, -) -> Result, LemmyError> { +) -> LemmyResult> { let site_view = SiteView::read_local(&mut context.pool()).await?; let federated_instances = build_federated_instances(&site_view.local_site, &mut context.pool()).await?; diff --git a/crates/api/src/site/leave_admin.rs b/crates/api/src/site/leave_admin.rs index f2db0fc26..52b8a32ef 100644 --- a/crates/api/src/site/leave_admin.rs +++ b/crates/api/src/site/leave_admin.rs @@ -14,7 +14,7 @@ use lemmy_db_schema::{ use lemmy_db_views::structs::{CustomEmojiView, LocalUserView, SiteView}; use lemmy_db_views_actor::structs::PersonView; use lemmy_utils::{ - error::{LemmyError, LemmyErrorType}, + error::{LemmyErrorType, LemmyResult}, VERSION, }; @@ -22,7 +22,7 @@ use lemmy_utils::{ pub async fn leave_admin( context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { is_admin(&local_user_view)?; // Make sure there isn't just one admin (so if one leaves, there will still be one left) diff --git a/crates/api/src/site/list_all_media.rs b/crates/api/src/site/list_all_media.rs index 495e72e48..49132cd64 100644 --- a/crates/api/src/site/list_all_media.rs +++ b/crates/api/src/site/list_all_media.rs @@ -6,14 +6,14 @@ use lemmy_api_common::{ }; use lemmy_db_schema::source::images::LocalImage; use lemmy_db_views::structs::LocalUserView; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; #[tracing::instrument(skip(context))] pub async fn list_all_media( data: Query, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { // Only let admins view all media is_admin(&local_user_view)?; diff --git a/crates/api/src/site/mod_log.rs b/crates/api/src/site/mod_log.rs index 1a4148d89..8f5538566 100644 --- a/crates/api/src/site/mod_log.rs +++ b/crates/api/src/site/mod_log.rs @@ -24,7 +24,7 @@ use lemmy_db_views_moderator::structs::{ ModTransferCommunityView, ModlogListParams, }; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; use ModlogActionType::*; #[tracing::instrument(skip(context))] @@ -32,7 +32,7 @@ pub async fn get_mod_log( data: Query, context: Data, local_user_view: Option, -) -> Result, LemmyError> { +) -> LemmyResult> { let local_site = LocalSite::read(&mut context.pool()).await?; check_private_instance(&local_user_view, &local_site)?; diff --git a/crates/api/src/site/purge/comment.rs b/crates/api/src/site/purge/comment.rs index a06085f24..cbb3637f0 100644 --- a/crates/api/src/site/purge/comment.rs +++ b/crates/api/src/site/purge/comment.rs @@ -15,14 +15,14 @@ use lemmy_db_schema::{ traits::Crud, }; use lemmy_db_views::structs::{CommentView, LocalUserView}; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; #[tracing::instrument(skip(context))] pub async fn purge_comment( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { // Only let admin purge an item is_admin(&local_user_view)?; diff --git a/crates/api/src/site/purge/community.rs b/crates/api/src/site/purge/community.rs index 61e58ba04..96c9c19cd 100644 --- a/crates/api/src/site/purge/community.rs +++ b/crates/api/src/site/purge/community.rs @@ -16,14 +16,14 @@ use lemmy_db_schema::{ traits::Crud, }; use lemmy_db_views::structs::LocalUserView; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; #[tracing::instrument(skip(context))] pub async fn purge_community( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { // Only let admin purge an item is_admin(&local_user_view)?; diff --git a/crates/api/src/site/purge/person.rs b/crates/api/src/site/purge/person.rs index 6023d7b41..a8233f76d 100644 --- a/crates/api/src/site/purge/person.rs +++ b/crates/api/src/site/purge/person.rs @@ -16,14 +16,14 @@ use lemmy_db_schema::{ traits::Crud, }; use lemmy_db_views::structs::LocalUserView; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; #[tracing::instrument(skip(context))] pub async fn purge_person( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { // Only let admin purge an item is_admin(&local_user_view)?; diff --git a/crates/api/src/site/purge/post.rs b/crates/api/src/site/purge/post.rs index 28e6668ff..ff34c471a 100644 --- a/crates/api/src/site/purge/post.rs +++ b/crates/api/src/site/purge/post.rs @@ -16,14 +16,14 @@ use lemmy_db_schema::{ traits::Crud, }; use lemmy_db_views::structs::LocalUserView; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; #[tracing::instrument(skip(context))] pub async fn purge_post( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { // Only let admin purge an item is_admin(&local_user_view)?; diff --git a/crates/api/src/site/registration_applications/approve.rs b/crates/api/src/site/registration_applications/approve.rs index 036a60e00..df3c3b428 100644 --- a/crates/api/src/site/registration_applications/approve.rs +++ b/crates/api/src/site/registration_applications/approve.rs @@ -13,13 +13,13 @@ use lemmy_db_schema::{ utils::diesel_option_overwrite, }; use lemmy_db_views::structs::{LocalUserView, RegistrationApplicationView}; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; pub async fn approve_registration_application( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let app_id = data.id; // Only let admins do this diff --git a/crates/api/src/site/registration_applications/list.rs b/crates/api/src/site/registration_applications/list.rs index 30ce9aaf2..df86b11d5 100644 --- a/crates/api/src/site/registration_applications/list.rs +++ b/crates/api/src/site/registration_applications/list.rs @@ -9,14 +9,14 @@ use lemmy_db_views::{ registration_application_view::RegistrationApplicationQuery, structs::LocalUserView, }; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; /// Lists registration applications, filterable by undenied only. pub async fn list_registration_applications( data: Query, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let local_site = LocalSite::read(&mut context.pool()).await?; // Make sure user is an admin diff --git a/crates/api/src/site/registration_applications/unread_count.rs b/crates/api/src/site/registration_applications/unread_count.rs index 255859198..a12ecb1d3 100644 --- a/crates/api/src/site/registration_applications/unread_count.rs +++ b/crates/api/src/site/registration_applications/unread_count.rs @@ -6,12 +6,12 @@ use lemmy_api_common::{ }; use lemmy_db_schema::source::local_site::LocalSite; use lemmy_db_views::structs::{LocalUserView, RegistrationApplicationView}; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; pub async fn get_unread_registration_application_count( context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let local_site = LocalSite::read(&mut context.pool()).await?; // Only let admins do this diff --git a/crates/api_common/src/build_response.rs b/crates/api_common/src/build_response.rs index 990b96544..cd55d399c 100644 --- a/crates/api_common/src/build_response.rs +++ b/crates/api_common/src/build_response.rs @@ -25,7 +25,7 @@ use lemmy_db_schema::{ use lemmy_db_views::structs::{CommentView, LocalUserView, PostView}; use lemmy_db_views_actor::structs::CommunityView; use lemmy_utils::{ - error::LemmyError, + error::LemmyResult, utils::{markdown::markdown_to_html, mention::MentionData}, }; @@ -34,7 +34,7 @@ pub async fn build_comment_response( comment_id: CommentId, local_user_view: Option, recipient_ids: Vec, -) -> Result { +) -> LemmyResult { let person_id = local_user_view.map(|l| l.person.id); let comment_view = CommentView::read(&mut context.pool(), comment_id, person_id).await?; Ok(CommentResponse { @@ -47,7 +47,7 @@ pub async fn build_community_response( context: &LemmyContext, local_user_view: LocalUserView, community_id: CommunityId, -) -> Result, LemmyError> { +) -> LemmyResult> { let is_mod_or_admin = is_mod_or_admin(&mut context.pool(), &local_user_view.person, community_id) .await .is_ok(); @@ -72,7 +72,7 @@ pub async fn build_post_response( community_id: CommunityId, person: &Person, post_id: PostId, -) -> Result, LemmyError> { +) -> LemmyResult> { let is_mod_or_admin = is_mod_or_admin(&mut context.pool(), person, community_id) .await .is_ok(); @@ -94,7 +94,7 @@ pub async fn send_local_notifs( person: &Person, do_send_email: bool, context: &LemmyContext, -) -> Result, LemmyError> { +) -> LemmyResult> { let mut recipient_ids = Vec::new(); let inbox_link = format!("{}/inbox", context.settings().get_protocol_and_hostname()); diff --git a/crates/api_common/src/request.rs b/crates/api_common/src/request.rs index 06410b70c..fdd29a254 100644 --- a/crates/api_common/src/request.rs +++ b/crates/api_common/src/request.rs @@ -16,7 +16,7 @@ use lemmy_db_schema::{ }, }; use lemmy_utils::{ - error::{LemmyError, LemmyErrorType}, + error::{LemmyError, LemmyErrorType, LemmyResult}, settings::structs::{PictrsImageMode, Settings}, spawn_try_task, REQWEST_TIMEOUT, @@ -46,7 +46,7 @@ pub async fn fetch_link_metadata( url: &Url, generate_thumbnail: bool, context: &LemmyContext, -) -> Result { +) -> LemmyResult { info!("Fetching site metadata for url: {}", url); let response = context.client().get(url.as_str()).send().await?; @@ -132,7 +132,7 @@ pub fn generate_post_link_metadata( } /// Extract site metadata from HTML Opengraph attributes. -fn extract_opengraph_data(html_bytes: &[u8], url: &Url) -> Result { +fn extract_opengraph_data(html_bytes: &[u8], url: &Url) -> LemmyResult { let html = String::from_utf8_lossy(html_bytes); // Make sure the first line is doctype html @@ -240,10 +240,7 @@ struct PictrsPurgeResponse { /// - It might fail due to image being not local /// - It might not be an image /// - Pictrs might not be set up -pub async fn purge_image_from_pictrs( - image_url: &Url, - context: &LemmyContext, -) -> Result<(), LemmyError> { +pub async fn purge_image_from_pictrs(image_url: &Url, context: &LemmyContext) -> LemmyResult<()> { is_image_content_type(context.client(), image_url).await?; let alias = image_url @@ -278,7 +275,7 @@ pub async fn delete_image_from_pictrs( alias: &str, delete_token: &str, context: &LemmyContext, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { let pictrs_config = context.settings().pictrs_config()?; let url = format!( "{}image/delete/{}/{}", @@ -296,10 +293,7 @@ pub async fn delete_image_from_pictrs( /// Retrieves the image with local pict-rs and generates a thumbnail. Returns the thumbnail url. #[tracing::instrument(skip_all)] -async fn generate_pictrs_thumbnail( - image_url: &Url, - context: &LemmyContext, -) -> Result { +async fn generate_pictrs_thumbnail(image_url: &Url, context: &LemmyContext) -> LemmyResult { let pictrs_config = context.settings().pictrs_config()?; match pictrs_config.image_mode() { @@ -349,7 +343,7 @@ async fn generate_pictrs_thumbnail( // TODO: get rid of this by reading content type from db #[tracing::instrument(skip_all)] -async fn is_image_content_type(client: &ClientWithMiddleware, url: &Url) -> Result<(), LemmyError> { +async fn is_image_content_type(client: &ClientWithMiddleware, url: &Url) -> LemmyResult<()> { let response = client.get(url.as_str()).send().await?; if response .headers() @@ -369,7 +363,7 @@ pub async fn replace_image( new_image: &Option, old_image: &Option, context: &Data, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { if new_image.is_some() { // Ignore errors because image may be stored externally. if let Some(avatar) = &old_image { diff --git a/crates/api_common/src/utils.rs b/crates/api_common/src/utils.rs index 58e3f382b..9810e2390 100644 --- a/crates/api_common/src/utils.rs +++ b/crates/api_common/src/utils.rs @@ -60,7 +60,7 @@ pub async fn is_mod_or_admin( pool: &mut DbPool<'_>, person: &Person, community_id: CommunityId, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { check_user_valid(person)?; let is_mod_or_admin = CommunityView::is_mod_or_admin(pool, person.id, community_id).await?; @@ -76,7 +76,7 @@ pub async fn is_mod_or_admin_opt( pool: &mut DbPool<'_>, local_user_view: Option<&LocalUserView>, community_id: Option, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { if let Some(local_user_view) = local_user_view { if let Some(community_id) = community_id { is_mod_or_admin(pool, &local_user_view.person, community_id).await @@ -108,7 +108,7 @@ pub async fn check_community_mod_of_any_or_admin_action( } } -pub fn is_admin(local_user_view: &LocalUserView) -> Result<(), LemmyError> { +pub fn is_admin(local_user_view: &LocalUserView) -> LemmyResult<()> { check_user_valid(&local_user_view.person)?; if !local_user_view.local_user.admin { Err(LemmyErrorType::NotAnAdmin)? @@ -122,7 +122,7 @@ pub fn is_admin(local_user_view: &LocalUserView) -> Result<(), LemmyError> { pub fn is_top_mod( local_user_view: &LocalUserView, community_mods: &[CommunityModeratorView], -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { check_user_valid(&local_user_view.person)?; if local_user_view.person.id != community_mods @@ -137,7 +137,7 @@ pub fn is_top_mod( } #[tracing::instrument(skip_all)] -pub async fn get_post(post_id: PostId, pool: &mut DbPool<'_>) -> Result { +pub async fn get_post(post_id: PostId, pool: &mut DbPool<'_>) -> LemmyResult { Post::read(pool, post_id) .await .with_lemmy_type(LemmyErrorType::CouldntFindPost) @@ -148,14 +148,14 @@ pub async fn mark_post_as_read( person_id: PersonId, post_id: PostId, pool: &mut DbPool<'_>, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { PostRead::mark_as_read(pool, HashSet::from([post_id]), person_id) .await .with_lemmy_type(LemmyErrorType::CouldntMarkPostAsRead)?; Ok(()) } -pub fn check_user_valid(person: &Person) -> Result<(), LemmyError> { +pub fn check_user_valid(person: &Person) -> LemmyResult<()> { // Check for a site ban if person.banned { Err(LemmyErrorType::SiteBan)? @@ -230,7 +230,7 @@ pub async fn check_community_mod_action( } /// Don't allow creating reports for removed / deleted posts -pub fn check_post_deleted_or_removed(post: &Post) -> Result<(), LemmyError> { +pub fn check_post_deleted_or_removed(post: &Post) -> LemmyResult<()> { if post.deleted || post.removed { Err(LemmyErrorType::Deleted)? } else { @@ -238,7 +238,7 @@ pub fn check_post_deleted_or_removed(post: &Post) -> Result<(), LemmyError> { } } -pub fn check_comment_deleted_or_removed(comment: &Comment) -> Result<(), LemmyError> { +pub fn check_comment_deleted_or_removed(comment: &Comment) -> LemmyResult<()> { if comment.deleted || comment.removed { Err(LemmyErrorType::Deleted)? } else { @@ -252,7 +252,7 @@ pub async fn check_person_block( my_id: PersonId, potential_blocker_id: PersonId, pool: &mut DbPool<'_>, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { let is_blocked = PersonBlock::read(pool, potential_blocker_id, my_id).await?; if is_blocked { Err(LemmyErrorType::PersonIsBlocked)? @@ -267,7 +267,7 @@ async fn check_community_block( community_id: CommunityId, person_id: PersonId, pool: &mut DbPool<'_>, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { let is_blocked = CommunityBlock::read(pool, person_id, community_id).await?; if is_blocked { Err(LemmyErrorType::CommunityIsBlocked)? @@ -282,7 +282,7 @@ async fn check_instance_block( instance_id: InstanceId, person_id: PersonId, pool: &mut DbPool<'_>, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { let is_blocked = InstanceBlock::read(pool, person_id, instance_id).await?; if is_blocked { Err(LemmyErrorType::InstanceIsBlocked)? @@ -298,7 +298,7 @@ pub async fn check_person_instance_community_block( community_instance_id: InstanceId, community_id: CommunityId, pool: &mut DbPool<'_>, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { check_person_block(my_id, potential_blocker_id, pool).await?; check_instance_block(community_instance_id, potential_blocker_id, pool).await?; check_community_block(community_id, potential_blocker_id, pool).await?; @@ -306,7 +306,7 @@ pub async fn check_person_instance_community_block( } #[tracing::instrument(skip_all)] -pub fn check_downvotes_enabled(score: i16, local_site: &LocalSite) -> Result<(), LemmyError> { +pub fn check_downvotes_enabled(score: i16, local_site: &LocalSite) -> LemmyResult<()> { if score == -1 && !local_site.enable_downvotes { Err(LemmyErrorType::DownvotesAreDisabled)? } else { @@ -316,7 +316,7 @@ pub fn check_downvotes_enabled(score: i16, local_site: &LocalSite) -> Result<(), /// Dont allow bots to do certain actions, like voting #[tracing::instrument(skip_all)] -pub fn check_bot_account(person: &Person) -> Result<(), LemmyError> { +pub fn check_bot_account(person: &Person) -> LemmyResult<()> { if person.bot_account { Err(LemmyErrorType::InvalidBotAction)? } else { @@ -328,7 +328,7 @@ pub fn check_bot_account(person: &Person) -> Result<(), LemmyError> { pub fn check_private_instance( local_user_view: &Option, local_site: &LocalSite, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { if local_user_view.is_none() && local_site.private_instance { Err(LemmyErrorType::InstanceIsPrivate)? } else { @@ -340,7 +340,7 @@ pub fn check_private_instance( pub async fn build_federated_instances( local_site: &LocalSite, pool: &mut DbPool<'_>, -) -> Result, LemmyError> { +) -> LemmyResult> { if local_site.federation_enabled { let mut linked = Vec::new(); let mut allowed = Vec::new(); @@ -375,7 +375,7 @@ pub async fn build_federated_instances( } /// Checks the password length -pub fn password_length_check(pass: &str) -> Result<(), LemmyError> { +pub fn password_length_check(pass: &str) -> LemmyResult<()> { if !(10..=60).contains(&pass.chars().count()) { Err(LemmyErrorType::InvalidPassword)? } else { @@ -384,7 +384,7 @@ pub fn password_length_check(pass: &str) -> Result<(), LemmyError> { } /// Checks for a honeypot. If this field is filled, fail the rest of the function -pub fn honeypot_check(honeypot: &Option) -> Result<(), LemmyError> { +pub fn honeypot_check(honeypot: &Option) -> LemmyResult<()> { if honeypot.is_some() && honeypot != &Some(String::new()) { Err(LemmyErrorType::HoneypotFailed)? } else { @@ -422,7 +422,7 @@ pub async fn send_password_reset_email( user: &LocalUserView, pool: &mut DbPool<'_>, settings: &Settings, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { // Generate a random token let token = uuid::Uuid::new_v4().to_string(); @@ -447,7 +447,7 @@ pub async fn send_verification_email( new_email: &str, pool: &mut DbPool<'_>, settings: &Settings, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { let form = EmailVerificationForm { local_user_id: user.local_user.id, email: new_email.to_string(), @@ -564,7 +564,7 @@ pub async fn get_url_blocklist(context: &LemmyContext) -> LemmyResult pub async fn send_application_approved_email( user: &LocalUserView, settings: &Settings, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { let email = &user.local_user.email.clone().expect("email"); let lang = get_interface_language(user); let subject = lang.registration_approved_subject(&user.person.actor_id); @@ -577,7 +577,7 @@ pub async fn send_new_applicant_email_to_admins( applicant_username: &str, pool: &mut DbPool<'_>, settings: &Settings, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { // Collect the admins with emails let admins = LocalUserView::list_admins_with_emails(pool).await?; @@ -602,7 +602,7 @@ pub async fn send_new_report_email_to_admins( reported_username: &str, pool: &mut DbPool<'_>, settings: &Settings, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { // Collect the admins with emails let admins = LocalUserView::list_admins_with_emails(pool).await?; @@ -618,9 +618,7 @@ pub async fn send_new_report_email_to_admins( Ok(()) } -pub fn check_private_instance_and_federation_enabled( - local_site: &LocalSite, -) -> Result<(), LemmyError> { +pub fn check_private_instance_and_federation_enabled(local_site: &LocalSite) -> LemmyResult<()> { if local_site.private_instance && local_site.federation_enabled { Err(LemmyErrorType::CantEnablePrivateInstanceAndFederationTogether)? } else { @@ -634,7 +632,7 @@ pub fn check_private_instance_and_federation_enabled( pub async fn read_site_for_actor( actor_id: DbUrl, context: &LemmyContext, -) -> Result, LemmyError> { +) -> LemmyResult> { let site_id = Site::instance_actor_id_from_url(actor_id.clone().into()); let site = Site::read_from_apub_id(&mut context.pool(), &site_id.into()).await?; Ok(site) @@ -643,7 +641,7 @@ pub async fn read_site_for_actor( pub async fn purge_image_posts_for_person( banned_person_id: PersonId, context: &LemmyContext, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { let pool = &mut context.pool(); let posts = Post::fetch_pictrs_posts_for_creator(pool, banned_person_id).await?; for post in posts { @@ -661,10 +659,7 @@ pub async fn purge_image_posts_for_person( } /// Delete a local_user's images -async fn delete_local_user_images( - person_id: PersonId, - context: &LemmyContext, -) -> Result<(), LemmyError> { +async fn delete_local_user_images(person_id: PersonId, context: &LemmyContext) -> LemmyResult<()> { if let Ok(local_user) = LocalUserView::read_person(&mut context.pool(), person_id).await { let pictrs_uploads = LocalImage::get_all_by_local_user_id(&mut context.pool(), local_user.local_user.id).await?; @@ -682,7 +677,7 @@ async fn delete_local_user_images( pub async fn purge_image_posts_for_community( banned_community_id: CommunityId, context: &LemmyContext, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { let pool = &mut context.pool(); let posts = Post::fetch_pictrs_posts_for_community(pool, banned_community_id).await?; for post in posts { @@ -702,7 +697,7 @@ pub async fn purge_image_posts_for_community( pub async fn remove_user_data( banned_person_id: PersonId, context: &LemmyContext, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { let pool = &mut context.pool(); // Purge user images let person = Person::read(pool, banned_person_id).await?; @@ -785,7 +780,7 @@ pub async fn remove_user_data_in_community( community_id: CommunityId, banned_person_id: PersonId, pool: &mut DbPool<'_>, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { // Posts Post::update_removed_for_creator(pool, banned_person_id, Some(community_id), true).await?; @@ -815,10 +810,7 @@ pub async fn remove_user_data_in_community( Ok(()) } -pub async fn purge_user_account( - person_id: PersonId, - context: &LemmyContext, -) -> Result<(), LemmyError> { +pub async fn purge_user_account(person_id: PersonId, context: &LemmyContext) -> LemmyResult<()> { let pool = &mut context.pool(); let person = Person::read(pool, person_id).await?; @@ -888,7 +880,7 @@ pub fn generate_inbox_url(actor_id: &DbUrl) -> Result { Ok(Url::parse(&format!("{actor_id}/inbox"))?.into()) } -pub fn generate_shared_inbox_url(settings: &Settings) -> Result { +pub fn generate_shared_inbox_url(settings: &Settings) -> LemmyResult { let url = format!("{}/inbox", settings.get_protocol_and_hostname()); Ok(Url::parse(&url)?.into()) } @@ -901,7 +893,7 @@ pub fn generate_featured_url(actor_id: &DbUrl) -> Result { Ok(Url::parse(&format!("{actor_id}/featured"))?.into()) } -pub fn generate_moderators_url(community_id: &DbUrl) -> Result { +pub fn generate_moderators_url(community_id: &DbUrl) -> LemmyResult { Ok(Url::parse(&format!("{community_id}/moderators"))?.into()) } diff --git a/crates/api_crud/src/comment/create.rs b/crates/api_crud/src/comment/create.rs index f8092268f..6b1c4ed30 100644 --- a/crates/api_crud/src/comment/create.rs +++ b/crates/api_crud/src/comment/create.rs @@ -30,7 +30,7 @@ use lemmy_db_schema::{ }; use lemmy_db_views::structs::LocalUserView; use lemmy_utils::{ - error::{LemmyError, LemmyErrorExt, LemmyErrorType}, + error::{LemmyErrorExt, LemmyErrorType, LemmyResult}, utils::{mention::scrape_text_for_mentions, validation::is_valid_body_field}, }; @@ -41,7 +41,7 @@ pub async fn create_comment( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let local_site = LocalSite::read(&mut context.pool()).await?; let slur_regex = local_site_to_slur_regex(&local_site); @@ -207,7 +207,7 @@ pub async fn create_comment( )) } -pub fn check_comment_depth(comment: &Comment) -> Result<(), LemmyError> { +pub fn check_comment_depth(comment: &Comment) -> LemmyResult<()> { let path = &comment.path.0; let length = path.split('.').count(); if length > MAX_COMMENT_DEPTH_LIMIT { diff --git a/crates/api_crud/src/comment/delete.rs b/crates/api_crud/src/comment/delete.rs index 9db1ed034..00a8ea0c1 100644 --- a/crates/api_crud/src/comment/delete.rs +++ b/crates/api_crud/src/comment/delete.rs @@ -12,14 +12,14 @@ use lemmy_db_schema::{ traits::Crud, }; use lemmy_db_views::structs::{CommentView, LocalUserView}; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn delete_comment( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let comment_id = data.comment_id; let orig_comment = CommentView::read(&mut context.pool(), comment_id, None).await?; diff --git a/crates/api_crud/src/comment/read.rs b/crates/api_crud/src/comment/read.rs index 733d08682..39852081f 100644 --- a/crates/api_crud/src/comment/read.rs +++ b/crates/api_crud/src/comment/read.rs @@ -7,14 +7,14 @@ use lemmy_api_common::{ }; use lemmy_db_schema::source::local_site::LocalSite; use lemmy_db_views::structs::LocalUserView; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; #[tracing::instrument(skip(context))] pub async fn get_comment( data: Query, context: Data, local_user_view: Option, -) -> Result, LemmyError> { +) -> LemmyResult> { let local_site = LocalSite::read(&mut context.pool()).await?; check_private_instance(&local_user_view, &local_site)?; diff --git a/crates/api_crud/src/comment/remove.rs b/crates/api_crud/src/comment/remove.rs index d735c4462..1355a7076 100644 --- a/crates/api_crud/src/comment/remove.rs +++ b/crates/api_crud/src/comment/remove.rs @@ -16,14 +16,14 @@ use lemmy_db_schema::{ traits::{Crud, Reportable}, }; use lemmy_db_views::structs::{CommentView, LocalUserView}; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn remove_comment( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let comment_id = data.comment_id; let orig_comment = CommentView::read(&mut context.pool(), comment_id, None).await?; diff --git a/crates/api_crud/src/comment/update.rs b/crates/api_crud/src/comment/update.rs index b35333ec5..ff6f78804 100644 --- a/crates/api_crud/src/comment/update.rs +++ b/crates/api_crud/src/comment/update.rs @@ -23,7 +23,7 @@ use lemmy_db_schema::{ }; use lemmy_db_views::structs::{CommentView, LocalUserView}; use lemmy_utils::{ - error::{LemmyError, LemmyErrorExt, LemmyErrorType}, + error::{LemmyErrorExt, LemmyErrorType, LemmyResult}, utils::{mention::scrape_text_for_mentions, validation::is_valid_body_field}, }; @@ -32,7 +32,7 @@ pub async fn update_comment( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let local_site = LocalSite::read(&mut context.pool()).await?; let comment_id = data.comment_id; diff --git a/crates/api_crud/src/community/create.rs b/crates/api_crud/src/community/create.rs index 679655078..32d37d8ef 100644 --- a/crates/api_crud/src/community/create.rs +++ b/crates/api_crud/src/community/create.rs @@ -33,7 +33,7 @@ use lemmy_db_schema::{ }; use lemmy_db_views::structs::{LocalUserView, SiteView}; use lemmy_utils::{ - error::{LemmyError, LemmyErrorExt, LemmyErrorType}, + error::{LemmyErrorExt, LemmyErrorType, LemmyResult}, utils::{ slurs::check_slurs, validation::{is_valid_actor_name, is_valid_body_field}, @@ -45,7 +45,7 @@ pub async fn create_community( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let site_view = SiteView::read_local(&mut context.pool()).await?; let local_site = site_view.local_site; diff --git a/crates/api_crud/src/community/delete.rs b/crates/api_crud/src/community/delete.rs index 60b79fd79..a2ceaff50 100644 --- a/crates/api_crud/src/community/delete.rs +++ b/crates/api_crud/src/community/delete.rs @@ -13,14 +13,14 @@ use lemmy_db_schema::{ }; use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::structs::CommunityModeratorView; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn delete_community( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { // Fetch the community mods let community_id = data.community_id; let community_mods = diff --git a/crates/api_crud/src/community/list.rs b/crates/api_crud/src/community/list.rs index 7990352fc..9c13ae89f 100644 --- a/crates/api_crud/src/community/list.rs +++ b/crates/api_crud/src/community/list.rs @@ -6,14 +6,14 @@ use lemmy_api_common::{ }; use lemmy_db_views::structs::{LocalUserView, SiteView}; use lemmy_db_views_actor::community_view::CommunityQuery; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; #[tracing::instrument(skip(context))] pub async fn list_communities( data: Query, context: Data, local_user_view: Option, -) -> Result, LemmyError> { +) -> LemmyResult> { let local_site = SiteView::read_local(&mut context.pool()).await?; let is_admin = local_user_view .as_ref() diff --git a/crates/api_crud/src/community/remove.rs b/crates/api_crud/src/community/remove.rs index d7be60927..f4271565d 100644 --- a/crates/api_crud/src/community/remove.rs +++ b/crates/api_crud/src/community/remove.rs @@ -15,14 +15,14 @@ use lemmy_db_schema::{ traits::Crud, }; use lemmy_db_views::structs::LocalUserView; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn remove_community( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { check_community_mod_action( &local_user_view.person, data.community_id, diff --git a/crates/api_crud/src/community/update.rs b/crates/api_crud/src/community/update.rs index 51c57e1c8..bc0945ba1 100644 --- a/crates/api_crud/src/community/update.rs +++ b/crates/api_crud/src/community/update.rs @@ -25,7 +25,7 @@ use lemmy_db_schema::{ }; use lemmy_db_views::structs::LocalUserView; use lemmy_utils::{ - error::{LemmyError, LemmyErrorExt, LemmyErrorType}, + error::{LemmyErrorExt, LemmyErrorType, LemmyResult}, utils::{slurs::check_slurs_opt, validation::is_valid_body_field}, }; @@ -34,7 +34,7 @@ pub async fn update_community( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let local_site = LocalSite::read(&mut context.pool()).await?; let slur_regex = local_site_to_slur_regex(&local_site); diff --git a/crates/api_crud/src/custom_emoji/create.rs b/crates/api_crud/src/custom_emoji/create.rs index cd30ef1e9..3c5ce3296 100644 --- a/crates/api_crud/src/custom_emoji/create.rs +++ b/crates/api_crud/src/custom_emoji/create.rs @@ -11,14 +11,14 @@ use lemmy_db_schema::source::{ local_site::LocalSite, }; use lemmy_db_views::structs::{CustomEmojiView, LocalUserView}; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; #[tracing::instrument(skip(context))] pub async fn create_custom_emoji( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let local_site = LocalSite::read(&mut context.pool()).await?; // Make sure user is an admin is_admin(&local_user_view)?; diff --git a/crates/api_crud/src/custom_emoji/delete.rs b/crates/api_crud/src/custom_emoji/delete.rs index 93c5f8d80..45ac8d0ba 100644 --- a/crates/api_crud/src/custom_emoji/delete.rs +++ b/crates/api_crud/src/custom_emoji/delete.rs @@ -8,14 +8,14 @@ use lemmy_api_common::{ }; use lemmy_db_schema::source::custom_emoji::CustomEmoji; use lemmy_db_views::structs::LocalUserView; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; #[tracing::instrument(skip(context))] pub async fn delete_custom_emoji( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { // Make sure user is an admin is_admin(&local_user_view)?; diff --git a/crates/api_crud/src/custom_emoji/update.rs b/crates/api_crud/src/custom_emoji/update.rs index 5a2631a62..63246f85d 100644 --- a/crates/api_crud/src/custom_emoji/update.rs +++ b/crates/api_crud/src/custom_emoji/update.rs @@ -11,14 +11,14 @@ use lemmy_db_schema::source::{ local_site::LocalSite, }; use lemmy_db_views::structs::{CustomEmojiView, LocalUserView}; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; #[tracing::instrument(skip(context))] pub async fn update_custom_emoji( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let local_site = LocalSite::read(&mut context.pool()).await?; // Make sure user is an admin is_admin(&local_user_view)?; diff --git a/crates/api_crud/src/post/create.rs b/crates/api_crud/src/post/create.rs index 6a61c032b..cea0d5a31 100644 --- a/crates/api_crud/src/post/create.rs +++ b/crates/api_crud/src/post/create.rs @@ -32,7 +32,7 @@ use lemmy_db_schema::{ use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::structs::CommunityModeratorView; use lemmy_utils::{ - error::{LemmyError, LemmyErrorExt, LemmyErrorType}, + error::{LemmyErrorExt, LemmyErrorType, LemmyResult}, spawn_try_task, utils::{ slurs::check_slurs, @@ -55,7 +55,7 @@ pub async fn create_post( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let local_site = LocalSite::read(&mut context.pool()).await?; honeypot_check(&data.honeypot)?; diff --git a/crates/api_crud/src/post/delete.rs b/crates/api_crud/src/post/delete.rs index a8fce28fc..e07ff7723 100644 --- a/crates/api_crud/src/post/delete.rs +++ b/crates/api_crud/src/post/delete.rs @@ -12,14 +12,14 @@ use lemmy_db_schema::{ traits::Crud, }; use lemmy_db_views::structs::LocalUserView; -use lemmy_utils::error::{LemmyError, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn delete_post( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let post_id = data.post_id; let orig_post = Post::read(&mut context.pool(), post_id).await?; diff --git a/crates/api_crud/src/post/read.rs b/crates/api_crud/src/post/read.rs index e701008b7..cb4ba7e9f 100644 --- a/crates/api_crud/src/post/read.rs +++ b/crates/api_crud/src/post/read.rs @@ -14,14 +14,14 @@ use lemmy_db_views::{ structs::{LocalUserView, PostView, SiteView}, }; use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView}; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn get_post( data: Query, context: Data, local_user_view: Option, -) -> Result, LemmyError> { +) -> LemmyResult> { let local_site = SiteView::read_local(&mut context.pool()).await?; check_private_instance(&local_user_view, &local_site.local_site)?; diff --git a/crates/api_crud/src/post/remove.rs b/crates/api_crud/src/post/remove.rs index cbcf069b6..37f3f6148 100644 --- a/crates/api_crud/src/post/remove.rs +++ b/crates/api_crud/src/post/remove.rs @@ -16,14 +16,14 @@ use lemmy_db_schema::{ traits::{Crud, Reportable}, }; use lemmy_db_views::structs::LocalUserView; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; #[tracing::instrument(skip(context))] pub async fn remove_post( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let post_id = data.post_id; let orig_post = Post::read(&mut context.pool(), post_id).await?; diff --git a/crates/api_crud/src/post/update.rs b/crates/api_crud/src/post/update.rs index c08f35307..48a1b6523 100644 --- a/crates/api_crud/src/post/update.rs +++ b/crates/api_crud/src/post/update.rs @@ -25,7 +25,7 @@ use lemmy_db_schema::{ }; use lemmy_db_views::structs::LocalUserView; use lemmy_utils::{ - error::{LemmyError, LemmyErrorExt, LemmyErrorType}, + error::{LemmyErrorExt, LemmyErrorType, LemmyResult}, utils::{ slurs::check_slurs_opt, validation::{ @@ -45,7 +45,7 @@ pub async fn update_post( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let local_site = LocalSite::read(&mut context.pool()).await?; // TODO No good way to handle a clear. diff --git a/crates/api_crud/src/private_message/create.rs b/crates/api_crud/src/private_message/create.rs index 32d8b99e6..1fe4f9b48 100644 --- a/crates/api_crud/src/private_message/create.rs +++ b/crates/api_crud/src/private_message/create.rs @@ -24,7 +24,7 @@ use lemmy_db_schema::{ }; use lemmy_db_views::structs::{LocalUserView, PrivateMessageView}; use lemmy_utils::{ - error::{LemmyError, LemmyErrorExt, LemmyErrorType}, + error::{LemmyErrorExt, LemmyErrorType, LemmyResult}, utils::{markdown::markdown_to_html, validation::is_valid_body_field}, }; @@ -33,7 +33,7 @@ pub async fn create_private_message( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let local_site = LocalSite::read(&mut context.pool()).await?; let slur_regex = local_site_to_slur_regex(&local_site); diff --git a/crates/api_crud/src/private_message/delete.rs b/crates/api_crud/src/private_message/delete.rs index ef0864d70..936ff57b8 100644 --- a/crates/api_crud/src/private_message/delete.rs +++ b/crates/api_crud/src/private_message/delete.rs @@ -10,14 +10,14 @@ use lemmy_db_schema::{ traits::Crud, }; use lemmy_db_views::structs::{LocalUserView, PrivateMessageView}; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn delete_private_message( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { // Checking permissions let private_message_id = data.private_message_id; let orig_private_message = PrivateMessage::read(&mut context.pool(), private_message_id).await?; diff --git a/crates/api_crud/src/private_message/read.rs b/crates/api_crud/src/private_message/read.rs index 9f289c911..7558b97fc 100644 --- a/crates/api_crud/src/private_message/read.rs +++ b/crates/api_crud/src/private_message/read.rs @@ -4,14 +4,14 @@ use lemmy_api_common::{ private_message::{GetPrivateMessages, PrivateMessagesResponse}, }; use lemmy_db_views::{private_message_view::PrivateMessageQuery, structs::LocalUserView}; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; #[tracing::instrument(skip(context))] pub async fn get_private_message( data: Query, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let person_id = local_user_view.person.id; let page = data.page; diff --git a/crates/api_crud/src/private_message/update.rs b/crates/api_crud/src/private_message/update.rs index 29063fd10..765a33053 100644 --- a/crates/api_crud/src/private_message/update.rs +++ b/crates/api_crud/src/private_message/update.rs @@ -16,7 +16,7 @@ use lemmy_db_schema::{ }; use lemmy_db_views::structs::{LocalUserView, PrivateMessageView}; use lemmy_utils::{ - error::{LemmyError, LemmyErrorExt, LemmyErrorType}, + error::{LemmyErrorExt, LemmyErrorType, LemmyResult}, utils::validation::is_valid_body_field, }; @@ -25,7 +25,7 @@ pub async fn update_private_message( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let local_site = LocalSite::read(&mut context.pool()).await?; // Checking permissions diff --git a/crates/api_crud/src/site/create.rs b/crates/api_crud/src/site/create.rs index 8542117e7..1c2fed3ed 100644 --- a/crates/api_crud/src/site/create.rs +++ b/crates/api_crud/src/site/create.rs @@ -27,7 +27,7 @@ use lemmy_db_schema::{ }; use lemmy_db_views::structs::{LocalUserView, SiteView}; use lemmy_utils::{ - error::{LemmyError, LemmyErrorType, LemmyResult}, + error::{LemmyErrorType, LemmyResult}, utils::{ slurs::{check_slurs, check_slurs_opt}, validation::{ @@ -46,7 +46,7 @@ pub async fn create_site( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let local_site = LocalSite::read(&mut context.pool()).await?; // Make sure user is an admin; other types of users should not create site data... diff --git a/crates/api_crud/src/site/read.rs b/crates/api_crud/src/site/read.rs index c4b27de1e..c8ad866a3 100644 --- a/crates/api_crud/src/site/read.rs +++ b/crates/api_crud/src/site/read.rs @@ -19,7 +19,7 @@ use lemmy_db_views_actor::structs::{ PersonView, }; use lemmy_utils::{ - error::{LemmyError, LemmyErrorExt, LemmyErrorType}, + error::{LemmyError, LemmyErrorExt, LemmyErrorType, LemmyResult}, CACHE_DURATION_API, VERSION, }; @@ -30,7 +30,7 @@ use once_cell::sync::Lazy; pub async fn get_site( local_user_view: Option, context: Data, -) -> Result, LemmyError> { +) -> LemmyResult> { static CACHE: Lazy> = Lazy::new(|| { Cache::builder() .max_capacity(1) diff --git a/crates/api_crud/src/site/update.rs b/crates/api_crud/src/site/update.rs index 530dbb47f..adf44fad4 100644 --- a/crates/api_crud/src/site/update.rs +++ b/crates/api_crud/src/site/update.rs @@ -32,7 +32,7 @@ use lemmy_db_schema::{ }; use lemmy_db_views::structs::{LocalUserView, SiteView}; use lemmy_utils::{ - error::{LemmyError, LemmyErrorExt, LemmyErrorType, LemmyResult}, + error::{LemmyErrorExt, LemmyErrorType, LemmyResult}, utils::{ slurs::check_slurs_opt, validation::{ @@ -51,7 +51,7 @@ pub async fn update_site( data: Json, context: Data, local_user_view: LocalUserView, -) -> Result, LemmyError> { +) -> LemmyResult> { let site_view = SiteView::read_local(&mut context.pool()).await?; let local_site = site_view.local_site; let site = site_view.site; diff --git a/crates/api_crud/src/user/create.rs b/crates/api_crud/src/user/create.rs index d24a287db..1f81d4324 100644 --- a/crates/api_crud/src/user/create.rs +++ b/crates/api_crud/src/user/create.rs @@ -31,7 +31,7 @@ use lemmy_db_schema::{ }; use lemmy_db_views::structs::{LocalUserView, SiteView}; use lemmy_utils::{ - error::{LemmyError, LemmyErrorExt, LemmyErrorType}, + error::{LemmyErrorExt, LemmyErrorType, LemmyResult}, utils::{ slurs::{check_slurs, check_slurs_opt}, validation::is_valid_actor_name, @@ -44,7 +44,7 @@ pub async fn register( data: Json, req: HttpRequest, context: Data, -) -> Result, LemmyError> { +) -> LemmyResult> { let site_view = SiteView::read_local(&mut context.pool()).await?; let local_site = site_view.local_site; let require_registration_application = diff --git a/crates/apub/src/activities/block/block_user.rs b/crates/apub/src/activities/block/block_user.rs index a2a1f25bf..f68301be1 100644 --- a/crates/apub/src/activities/block/block_user.rs +++ b/crates/apub/src/activities/block/block_user.rs @@ -39,7 +39,7 @@ use lemmy_db_schema::{ }, traits::{Bannable, Crud, Followable}, }; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::{LemmyError, LemmyResult}; use url::Url; impl BlockUser { @@ -51,7 +51,7 @@ impl BlockUser { reason: Option, expires: Option>, context: &Data, - ) -> Result { + ) -> LemmyResult { let audience = if let SiteOrCommunity::Community(c) = target { Some(c.id().into()) } else { @@ -85,7 +85,7 @@ impl BlockUser { reason: Option, expires: Option>, context: &Data, - ) -> Result<(), LemmyError> { + ) -> LemmyResult<()> { let block = BlockUser::new( target, user, @@ -125,7 +125,7 @@ impl ActivityHandler for BlockUser { } #[tracing::instrument(skip_all)] - async fn verify(&self, context: &Data) -> Result<(), LemmyError> { + async fn verify(&self, context: &Data) -> LemmyResult<()> { verify_is_public(&self.to, &self.cc)?; match self.target.dereference(context).await? { SiteOrCommunity::Site(site) => { @@ -148,7 +148,7 @@ impl ActivityHandler for BlockUser { } #[tracing::instrument(skip_all)] - async fn receive(self, context: &Data) -> Result<(), LemmyError> { + async fn receive(self, context: &Data) -> LemmyResult<()> { insert_received_activity(&self.id, context).await?; let expires = self.expires.or(self.end_time).map(Into::into); let mod_person = self.actor.dereference(context).await?; diff --git a/crates/apub/src/activities/block/mod.rs b/crates/apub/src/activities/block/mod.rs index 92fea4ec5..51d8bf5e0 100644 --- a/crates/apub/src/activities/block/mod.rs +++ b/crates/apub/src/activities/block/mod.rs @@ -58,10 +58,7 @@ impl Object for SiteOrCommunity { } #[tracing::instrument(skip_all)] - async fn read_from_id( - object_id: Url, - data: &Data, - ) -> Result, LemmyError> + async fn read_from_id(object_id: Url, data: &Data) -> LemmyResult> where Self: Sized, { @@ -74,11 +71,11 @@ impl Object for SiteOrCommunity { }) } - async fn delete(self, _data: &Data) -> Result<(), LemmyError> { + async fn delete(self, _data: &Data) -> LemmyResult<()> { unimplemented!() } - async fn into_json(self, _data: &Data) -> Result { + async fn into_json(self, _data: &Data) -> LemmyResult { unimplemented!() } @@ -87,7 +84,7 @@ impl Object for SiteOrCommunity { apub: &Self::Kind, expected_domain: &Url, data: &Data, - ) -> Result<(), LemmyError> { + ) -> LemmyResult<()> { match apub { InstanceOrGroup::Instance(i) => ApubSite::verify(i, expected_domain, data).await, InstanceOrGroup::Group(g) => ApubCommunity::verify(g, expected_domain, data).await, @@ -95,7 +92,7 @@ impl Object for SiteOrCommunity { } #[tracing::instrument(skip_all)] - async fn from_json(apub: Self::Kind, data: &Data) -> Result + async fn from_json(apub: Self::Kind, data: &Data) -> LemmyResult where Self: Sized, { @@ -117,10 +114,7 @@ impl SiteOrCommunity { } } -async fn generate_cc( - target: &SiteOrCommunity, - pool: &mut DbPool<'_>, -) -> Result, LemmyError> { +async fn generate_cc(target: &SiteOrCommunity, pool: &mut DbPool<'_>) -> LemmyResult> { Ok(match target { SiteOrCommunity::Site(_) => Site::read_remote_sites(pool) .await? @@ -139,7 +133,7 @@ pub(crate) async fn send_ban_from_site( ban: bool, expires: Option, context: Data, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { let site = SiteOrCommunity::Site(SiteView::read_local(&mut context.pool()).await?.site.into()); let expires = check_expire_time(expires)?; diff --git a/crates/apub/src/activities/block/undo_block_user.rs b/crates/apub/src/activities/block/undo_block_user.rs index 756d0a149..b92320b2d 100644 --- a/crates/apub/src/activities/block/undo_block_user.rs +++ b/crates/apub/src/activities/block/undo_block_user.rs @@ -27,7 +27,7 @@ use lemmy_db_schema::{ }, traits::{Bannable, Crud}, }; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::{LemmyError, LemmyResult}; use url::Url; impl UndoBlockUser { @@ -38,7 +38,7 @@ impl UndoBlockUser { mod_: &ApubPerson, reason: Option, context: &Data, - ) -> Result<(), LemmyError> { + ) -> LemmyResult<()> { let block = BlockUser::new(target, user, mod_, None, reason, None, context).await?; let audience = if let SiteOrCommunity::Community(c) = target { Some(c.id().into()) @@ -88,7 +88,7 @@ impl ActivityHandler for UndoBlockUser { } #[tracing::instrument(skip_all)] - async fn verify(&self, context: &Data) -> Result<(), LemmyError> { + async fn verify(&self, context: &Data) -> LemmyResult<()> { verify_is_public(&self.to, &self.cc)?; verify_domains_match(self.actor.inner(), self.object.actor.inner())?; self.object.verify(context).await?; @@ -96,7 +96,7 @@ impl ActivityHandler for UndoBlockUser { } #[tracing::instrument(skip_all)] - async fn receive(self, context: &Data) -> Result<(), LemmyError> { + async fn receive(self, context: &Data) -> LemmyResult<()> { insert_received_activity(&self.id, context).await?; let expires = self.object.expires.or(self.object.end_time).map(Into::into); let mod_person = self.actor.dereference(context).await?; diff --git a/crates/apub/src/activities/community/announce.rs b/crates/apub/src/activities/community/announce.rs index 474afc3b9..9a3928882 100644 --- a/crates/apub/src/activities/community/announce.rs +++ b/crates/apub/src/activities/community/announce.rs @@ -82,7 +82,7 @@ impl AnnounceActivity { object: RawAnnouncableActivities, community: &ApubCommunity, context: &Data, - ) -> Result { + ) -> LemmyResult { let inner_kind = object .other .get("type") @@ -105,7 +105,7 @@ impl AnnounceActivity { object: RawAnnouncableActivities, community: &ApubCommunity, context: &Data, - ) -> Result<(), LemmyError> { + ) -> LemmyResult<()> { let announce = AnnounceActivity::new(object.clone(), community, context)?; let inboxes = ActivitySendTargets::to_local_community_followers(community.id); send_lemmy_activity(context, announce, community, inboxes.clone(), false).await?; @@ -148,13 +148,13 @@ impl ActivityHandler for AnnounceActivity { } #[tracing::instrument(skip_all)] - async fn verify(&self, _context: &Data) -> Result<(), LemmyError> { + async fn verify(&self, _context: &Data) -> LemmyResult<()> { verify_is_public(&self.to, &self.cc)?; Ok(()) } #[tracing::instrument(skip_all)] - async fn receive(self, context: &Data) -> Result<(), LemmyError> { + async fn receive(self, context: &Data) -> LemmyResult<()> { insert_received_activity(&self.id, context).await?; let object: AnnouncableActivities = self.object.object(context).await?.try_into()?; diff --git a/crates/apub/src/activities/community/collection_add.rs b/crates/apub/src/activities/community/collection_add.rs index fdd62bdb1..34c46cf6b 100644 --- a/crates/apub/src/activities/community/collection_add.rs +++ b/crates/apub/src/activities/community/collection_add.rs @@ -36,7 +36,7 @@ use lemmy_db_schema::{ }, traits::{Crud, Joinable}, }; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::{LemmyError, LemmyResult}; use url::Url; impl CollectionAdd { @@ -46,7 +46,7 @@ impl CollectionAdd { added_mod: &ApubPerson, actor: &ApubPerson, context: &Data, - ) -> Result<(), LemmyError> { + ) -> LemmyResult<()> { let id = generate_activity_id( AddType::Add, &context.settings().get_protocol_and_hostname(), @@ -72,7 +72,7 @@ impl CollectionAdd { featured_post: &ApubPost, actor: &ApubPerson, context: &Data, - ) -> Result<(), LemmyError> { + ) -> LemmyResult<()> { let id = generate_activity_id( AddType::Add, &context.settings().get_protocol_and_hostname(), @@ -114,7 +114,7 @@ impl ActivityHandler for CollectionAdd { } #[tracing::instrument(skip_all)] - async fn verify(&self, context: &Data) -> Result<(), LemmyError> { + async fn verify(&self, context: &Data) -> LemmyResult<()> { verify_is_public(&self.to, &self.cc)?; let community = self.community(context).await?; verify_person_in_community(&self.actor, &community, context).await?; @@ -123,7 +123,7 @@ impl ActivityHandler for CollectionAdd { } #[tracing::instrument(skip_all)] - async fn receive(self, context: &Data) -> Result<(), LemmyError> { + async fn receive(self, context: &Data) -> LemmyResult<()> { insert_received_activity(&self.id, context).await?; let (community, collection_type) = Community::get_by_collection_url(&mut context.pool(), &self.target.into()).await?; @@ -179,7 +179,7 @@ pub(crate) async fn send_add_mod_to_community( updated_mod_id: PersonId, added: bool, context: Data, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { let actor: ApubPerson = actor.into(); let community: ApubCommunity = Community::read(&mut context.pool(), community_id) .await? @@ -199,7 +199,7 @@ pub(crate) async fn send_feature_post( actor: Person, featured: bool, context: Data, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { let actor: ApubPerson = actor.into(); let post: ApubPost = post.into(); let community = Community::read(&mut context.pool(), post.community_id) diff --git a/crates/apub/src/activities/community/collection_remove.rs b/crates/apub/src/activities/community/collection_remove.rs index 06238a890..90df1fd14 100644 --- a/crates/apub/src/activities/community/collection_remove.rs +++ b/crates/apub/src/activities/community/collection_remove.rs @@ -31,7 +31,7 @@ use lemmy_db_schema::{ }, traits::{Crud, Joinable}, }; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::{LemmyError, LemmyResult}; use url::Url; impl CollectionRemove { @@ -41,7 +41,7 @@ impl CollectionRemove { removed_mod: &ApubPerson, actor: &ApubPerson, context: &Data, - ) -> Result<(), LemmyError> { + ) -> LemmyResult<()> { let id = generate_activity_id( RemoveType::Remove, &context.settings().get_protocol_and_hostname(), @@ -67,7 +67,7 @@ impl CollectionRemove { featured_post: &ApubPost, actor: &ApubPerson, context: &Data, - ) -> Result<(), LemmyError> { + ) -> LemmyResult<()> { let id = generate_activity_id( RemoveType::Remove, &context.settings().get_protocol_and_hostname(), @@ -109,7 +109,7 @@ impl ActivityHandler for CollectionRemove { } #[tracing::instrument(skip_all)] - async fn verify(&self, context: &Data) -> Result<(), LemmyError> { + async fn verify(&self, context: &Data) -> LemmyResult<()> { verify_is_public(&self.to, &self.cc)?; let community = self.community(context).await?; verify_person_in_community(&self.actor, &community, context).await?; @@ -118,7 +118,7 @@ impl ActivityHandler for CollectionRemove { } #[tracing::instrument(skip_all)] - async fn receive(self, context: &Data) -> Result<(), LemmyError> { + async fn receive(self, context: &Data) -> LemmyResult<()> { insert_received_activity(&self.id, context).await?; let (community, collection_type) = Community::get_by_collection_url(&mut context.pool(), &self.target.into()).await?; diff --git a/crates/apub/src/activities/community/lock_page.rs b/crates/apub/src/activities/community/lock_page.rs index db9dfa36c..ba3e16417 100644 --- a/crates/apub/src/activities/community/lock_page.rs +++ b/crates/apub/src/activities/community/lock_page.rs @@ -31,7 +31,7 @@ use lemmy_db_schema::{ }, traits::Crud, }; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::{LemmyError, LemmyResult}; use url::Url; #[async_trait::async_trait] @@ -106,7 +106,7 @@ pub(crate) async fn send_lock_post( actor: Person, locked: bool, context: Data, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { let community: ApubCommunity = Community::read(&mut context.pool(), post.community_id) .await? .into(); diff --git a/crates/apub/src/activities/community/mod.rs b/crates/apub/src/activities/community/mod.rs index 612fd8a7a..a47dec2bd 100644 --- a/crates/apub/src/activities/community/mod.rs +++ b/crates/apub/src/activities/community/mod.rs @@ -10,7 +10,7 @@ use lemmy_db_schema::{ source::{activity::ActivitySendTargets, person::PersonFollower}, CommunityVisibility, }; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; pub mod announce; pub mod collection_add; @@ -39,7 +39,7 @@ pub(crate) async fn send_activity_in_community( extra_inboxes: ActivitySendTargets, is_mod_action: bool, context: &Data, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { // If community is local only, don't send anything out if community.visibility != CommunityVisibility::Public { return Ok(()); diff --git a/crates/apub/src/activities/community/report.rs b/crates/apub/src/activities/community/report.rs index 6b1fce066..4966add34 100644 --- a/crates/apub/src/activities/community/report.rs +++ b/crates/apub/src/activities/community/report.rs @@ -29,7 +29,7 @@ use lemmy_db_schema::{ }, traits::{Crud, Reportable}, }; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::{LemmyError, LemmyResult}; use url::Url; impl Report { @@ -40,7 +40,7 @@ impl Report { community: Community, reason: String, context: Data, - ) -> Result<(), LemmyError> { + ) -> LemmyResult<()> { let actor: ApubPerson = actor.into(); let community: ApubCommunity = community.into(); let kind = FlagType::Flag; @@ -94,14 +94,14 @@ impl ActivityHandler for Report { } #[tracing::instrument(skip_all)] - async fn verify(&self, context: &Data) -> Result<(), LemmyError> { + async fn verify(&self, context: &Data) -> LemmyResult<()> { let community = self.community(context).await?; verify_person_in_community(&self.actor, &community, context).await?; Ok(()) } #[tracing::instrument(skip_all)] - async fn receive(self, context: &Data) -> Result<(), LemmyError> { + async fn receive(self, context: &Data) -> LemmyResult<()> { insert_received_activity(&self.id, context).await?; let actor = self.actor.dereference(context).await?; let reason = self.reason()?; diff --git a/crates/apub/src/activities/community/update.rs b/crates/apub/src/activities/community/update.rs index ca293d002..3457e6c24 100644 --- a/crates/apub/src/activities/community/update.rs +++ b/crates/apub/src/activities/community/update.rs @@ -26,14 +26,14 @@ use lemmy_db_schema::{ traits::Crud, utils::naive_now, }; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::{LemmyError, LemmyResult}; use url::Url; pub(crate) async fn send_update_community( community: Community, actor: Person, context: Data, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { let community: ApubCommunity = community.into(); let actor: ApubPerson = actor.into(); let id = generate_activity_id( @@ -76,7 +76,7 @@ impl ActivityHandler for UpdateCommunity { } #[tracing::instrument(skip_all)] - async fn verify(&self, context: &Data) -> Result<(), LemmyError> { + async fn verify(&self, context: &Data) -> LemmyResult<()> { verify_is_public(&self.to, &self.cc)?; let community = self.community(context).await?; verify_person_in_community(&self.actor, &community, context).await?; @@ -86,7 +86,7 @@ impl ActivityHandler for UpdateCommunity { } #[tracing::instrument(skip_all)] - async fn receive(self, context: &Data) -> Result<(), LemmyError> { + async fn receive(self, context: &Data) -> LemmyResult<()> { insert_received_activity(&self.id, context).await?; let community = self.community(context).await?; diff --git a/crates/apub/src/activities/create_or_update/comment.rs b/crates/apub/src/activities/create_or_update/comment.rs index ea6af2fcf..8fbbe42b3 100644 --- a/crates/apub/src/activities/create_or_update/comment.rs +++ b/crates/apub/src/activities/create_or_update/comment.rs @@ -39,7 +39,10 @@ use lemmy_db_schema::{ }, traits::{Crud, Likeable}, }; -use lemmy_utils::{error::LemmyError, utils::mention::scrape_text_for_mentions}; +use lemmy_utils::{ + error::{LemmyError, LemmyResult}, + utils::mention::scrape_text_for_mentions, +}; use url::Url; impl CreateOrUpdateNote { @@ -49,7 +52,7 @@ impl CreateOrUpdateNote { person_id: PersonId, kind: CreateOrUpdateType, context: Data, - ) -> Result<(), LemmyError> { + ) -> LemmyResult<()> { // TODO: might be helpful to add a comment method to retrieve community directly let post_id = comment.post_id; let post = Post::read(&mut context.pool(), post_id).await?; @@ -114,7 +117,7 @@ impl ActivityHandler for CreateOrUpdateNote { } #[tracing::instrument(skip_all)] - async fn verify(&self, context: &Data) -> Result<(), LemmyError> { + async fn verify(&self, context: &Data) -> LemmyResult<()> { verify_is_public(&self.to, &self.cc)?; let post = self.object.get_parents(context).await?.0; let community = self.community(context).await?; @@ -129,7 +132,7 @@ impl ActivityHandler for CreateOrUpdateNote { } #[tracing::instrument(skip_all)] - async fn receive(self, context: &Data) -> Result<(), LemmyError> { + async fn receive(self, context: &Data) -> LemmyResult<()> { insert_received_activity(&self.id, context).await?; // Need to do this check here instead of Note::from_json because we need the person who // send the activity, not the comment author. diff --git a/crates/apub/src/activities/create_or_update/post.rs b/crates/apub/src/activities/create_or_update/post.rs index 8b2fdbdb4..eb59e054a 100644 --- a/crates/apub/src/activities/create_or_update/post.rs +++ b/crates/apub/src/activities/create_or_update/post.rs @@ -33,7 +33,7 @@ use lemmy_db_schema::{ }, traits::{Crud, Likeable}, }; -use lemmy_utils::error::{LemmyError, LemmyErrorType}; +use lemmy_utils::error::{LemmyError, LemmyErrorType, LemmyResult}; use url::Url; impl CreateOrUpdatePage { @@ -43,7 +43,7 @@ impl CreateOrUpdatePage { community: &ApubCommunity, kind: CreateOrUpdateType, context: &Data, - ) -> Result { + ) -> LemmyResult { let id = generate_activity_id( kind.clone(), &context.settings().get_protocol_and_hostname(), @@ -65,7 +65,7 @@ impl CreateOrUpdatePage { person_id: PersonId, kind: CreateOrUpdateType, context: Data, - ) -> Result<(), LemmyError> { + ) -> LemmyResult<()> { let post = ApubPost(post); let community_id = post.community_id; let person: ApubPerson = Person::read(&mut context.pool(), person_id).await?.into(); @@ -104,7 +104,7 @@ impl ActivityHandler for CreateOrUpdatePage { } #[tracing::instrument(skip_all)] - async fn verify(&self, context: &Data) -> Result<(), LemmyError> { + async fn verify(&self, context: &Data) -> LemmyResult<()> { verify_is_public(&self.to, &self.cc)?; let community = self.community(context).await?; verify_person_in_community(&self.actor, &community, context).await?; @@ -138,7 +138,7 @@ impl ActivityHandler for CreateOrUpdatePage { } #[tracing::instrument(skip_all)] - async fn receive(self, context: &Data) -> Result<(), LemmyError> { + async fn receive(self, context: &Data) -> LemmyResult<()> { insert_received_activity(&self.id, context).await?; let post = ApubPost::from_json(self.object, context).await?; diff --git a/crates/apub/src/activities/create_or_update/private_message.rs b/crates/apub/src/activities/create_or_update/private_message.rs index f3ea3ca26..950f4ae99 100644 --- a/crates/apub/src/activities/create_or_update/private_message.rs +++ b/crates/apub/src/activities/create_or_update/private_message.rs @@ -15,14 +15,14 @@ use activitypub_federation::{ use lemmy_api_common::context::LemmyContext; use lemmy_db_schema::source::activity::ActivitySendTargets; use lemmy_db_views::structs::PrivateMessageView; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::{LemmyError, LemmyResult}; use url::Url; pub(crate) async fn send_create_or_update_pm( pm_view: PrivateMessageView, kind: CreateOrUpdateType, context: Data, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { let actor: ApubPerson = pm_view.creator.into(); let recipient: ApubPerson = pm_view.recipient.into(); @@ -57,7 +57,7 @@ impl ActivityHandler for CreateOrUpdateChatMessage { } #[tracing::instrument(skip_all)] - async fn verify(&self, context: &Data) -> Result<(), LemmyError> { + async fn verify(&self, context: &Data) -> LemmyResult<()> { verify_person(&self.actor, context).await?; verify_domains_match(self.actor.inner(), self.object.id.inner())?; verify_domains_match(self.to[0].inner(), self.object.to[0].inner())?; @@ -66,7 +66,7 @@ impl ActivityHandler for CreateOrUpdateChatMessage { } #[tracing::instrument(skip_all)] - async fn receive(self, context: &Data) -> Result<(), LemmyError> { + async fn receive(self, context: &Data) -> LemmyResult<()> { insert_received_activity(&self.id, context).await?; ApubPrivateMessage::from_json(self.object, context).await?; Ok(()) diff --git a/crates/apub/src/activities/deletion/delete.rs b/crates/apub/src/activities/deletion/delete.rs index 18f8cf6fb..cecc051b4 100644 --- a/crates/apub/src/activities/deletion/delete.rs +++ b/crates/apub/src/activities/deletion/delete.rs @@ -27,7 +27,7 @@ use lemmy_db_schema::{ }, traits::{Crud, Reportable}, }; -use lemmy_utils::error::{LemmyError, LemmyErrorType}; +use lemmy_utils::error::{LemmyError, LemmyErrorType, LemmyResult}; use url::Url; #[async_trait::async_trait] @@ -44,13 +44,13 @@ impl ActivityHandler for Delete { } #[tracing::instrument(skip_all)] - async fn verify(&self, context: &Data) -> Result<(), LemmyError> { + async fn verify(&self, context: &Data) -> LemmyResult<()> { verify_delete_activity(self, self.summary.is_some(), context).await?; Ok(()) } #[tracing::instrument(skip_all)] - async fn receive(self, context: &Data) -> Result<(), LemmyError> { + async fn receive(self, context: &Data) -> LemmyResult<()> { insert_received_activity(&self.id, context).await?; if let Some(reason) = self.summary { // We set reason to empty string if it doesn't exist, to distinguish between delete and @@ -88,7 +88,7 @@ impl Delete { community: Option<&Community>, summary: Option, context: &Data, - ) -> Result { + ) -> LemmyResult { let id = generate_activity_id( DeleteType::Delete, &context.settings().get_protocol_and_hostname(), @@ -114,7 +114,7 @@ pub(in crate::activities) async fn receive_remove_action( object: &Url, reason: Option, context: &Data, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { match DeletableObjects::read_from_db(object, context).await? { DeletableObjects::Community(community) => { if community.local { diff --git a/crates/apub/src/activities/deletion/mod.rs b/crates/apub/src/activities/deletion/mod.rs index 03f01a3b9..b12532087 100644 --- a/crates/apub/src/activities/deletion/mod.rs +++ b/crates/apub/src/activities/deletion/mod.rs @@ -39,7 +39,7 @@ use lemmy_db_schema::{ }, traits::Crud, }; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; use std::ops::Deref; use url::Url; @@ -56,7 +56,7 @@ pub(crate) async fn send_apub_delete_in_community( reason: Option, deleted: bool, context: &Data, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { let actor = ApubPerson::from(actor); let is_mod_action = reason.is_some(); let activity = if deleted { @@ -83,7 +83,7 @@ pub(crate) async fn send_apub_delete_private_message( pm: PrivateMessage, deleted: bool, context: Data, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { let recipient_id = pm.recipient_id; let recipient: ApubPerson = Person::read(&mut context.pool(), recipient_id) .await? @@ -105,7 +105,7 @@ pub async fn send_apub_delete_user( person: Person, remove_data: bool, context: Data, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { let person: ApubPerson = person.into(); let deletable = DeletableObjects::Person(person.clone()); @@ -131,7 +131,7 @@ impl DeletableObjects { pub(crate) async fn read_from_db( ap_id: &Url, context: &Data, - ) -> Result { + ) -> LemmyResult { if let Some(c) = ApubCommunity::read_from_id(ap_id.clone(), context).await? { return Ok(DeletableObjects::Community(c)); } @@ -166,7 +166,7 @@ pub(in crate::activities) async fn verify_delete_activity( activity: &Delete, is_mod_action: bool, context: &Data, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { let object = DeletableObjects::read_from_db(activity.object.id(), context).await?; match object { DeletableObjects::Community(community) => { @@ -221,7 +221,7 @@ async fn verify_delete_post_or_comment( community: &ApubCommunity, is_mod_action: bool, context: &Data, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { verify_person_in_community(actor, community, context).await?; if is_mod_action { verify_mod_action(actor, community, context).await?; @@ -240,7 +240,7 @@ async fn receive_delete_action( deleted: bool, do_purge_user_account: Option, context: &Data, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { match DeletableObjects::read_from_db(object, context).await? { DeletableObjects::Community(community) => { if community.local { diff --git a/crates/apub/src/activities/deletion/undo_delete.rs b/crates/apub/src/activities/deletion/undo_delete.rs index 558d72b57..4f0fad670 100644 --- a/crates/apub/src/activities/deletion/undo_delete.rs +++ b/crates/apub/src/activities/deletion/undo_delete.rs @@ -25,7 +25,7 @@ use lemmy_db_schema::{ }, traits::Crud, }; -use lemmy_utils::error::{LemmyError, LemmyErrorType}; +use lemmy_utils::error::{LemmyError, LemmyErrorType, LemmyResult}; use url::Url; #[async_trait::async_trait] @@ -48,7 +48,7 @@ impl ActivityHandler for UndoDelete { } #[tracing::instrument(skip_all)] - async fn receive(self, context: &Data) -> Result<(), LemmyError> { + async fn receive(self, context: &Data) -> LemmyResult<()> { insert_received_activity(&self.id, context).await?; if self.object.summary.is_some() { UndoDelete::receive_undo_remove_action( @@ -72,7 +72,7 @@ impl UndoDelete { community: Option<&Community>, summary: Option, context: &Data, - ) -> Result { + ) -> LemmyResult { let object = Delete::new(actor, object, to.clone(), community, summary, context)?; let id = generate_activity_id( @@ -96,7 +96,7 @@ impl UndoDelete { actor: &ApubPerson, object: &Url, context: &Data, - ) -> Result<(), LemmyError> { + ) -> LemmyResult<()> { match DeletableObjects::read_from_db(object, context).await? { DeletableObjects::Community(community) => { if community.local { diff --git a/crates/apub/src/activities/following/accept.rs b/crates/apub/src/activities/following/accept.rs index efecef7f1..fa711b904 100644 --- a/crates/apub/src/activities/following/accept.rs +++ b/crates/apub/src/activities/following/accept.rs @@ -14,12 +14,12 @@ use lemmy_db_schema::{ source::{activity::ActivitySendTargets, community::CommunityFollower}, traits::Followable, }; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::{LemmyError, LemmyResult}; use url::Url; impl AcceptFollow { #[tracing::instrument(skip_all)] - pub async fn send(follow: Follow, context: &Data) -> Result<(), LemmyError> { + pub async fn send(follow: Follow, context: &Data) -> LemmyResult<()> { let user_or_community = follow.object.dereference_local(context).await?; let person = follow.actor.clone().dereference(context).await?; let accept = AcceptFollow { @@ -52,7 +52,7 @@ impl ActivityHandler for AcceptFollow { } #[tracing::instrument(skip_all)] - async fn verify(&self, context: &Data) -> Result<(), LemmyError> { + async fn verify(&self, context: &Data) -> LemmyResult<()> { verify_urls_match(self.actor.inner(), self.object.object.inner())?; self.object.verify(context).await?; if let Some(to) = &self.to { @@ -62,7 +62,7 @@ impl ActivityHandler for AcceptFollow { } #[tracing::instrument(skip_all)] - async fn receive(self, context: &Data) -> Result<(), LemmyError> { + async fn receive(self, context: &Data) -> LemmyResult<()> { insert_received_activity(&self.id, context).await?; let community = self.actor.dereference(context).await?; let person = self.object.actor.dereference(context).await?; diff --git a/crates/apub/src/activities/following/follow.rs b/crates/apub/src/activities/following/follow.rs index 6b954ebf2..97227835a 100644 --- a/crates/apub/src/activities/following/follow.rs +++ b/crates/apub/src/activities/following/follow.rs @@ -26,7 +26,7 @@ use lemmy_db_schema::{ traits::Followable, CommunityVisibility, }; -use lemmy_utils::error::{LemmyError, LemmyErrorType}; +use lemmy_utils::error::{LemmyError, LemmyErrorType, LemmyResult}; use url::Url; impl Follow { @@ -34,7 +34,7 @@ impl Follow { actor: &ApubPerson, community: &ApubCommunity, context: &Data, - ) -> Result { + ) -> LemmyResult { Ok(Follow { actor: actor.id().into(), object: community.id().into(), @@ -52,7 +52,7 @@ impl Follow { actor: &ApubPerson, community: &ApubCommunity, context: &Data, - ) -> Result<(), LemmyError> { + ) -> LemmyResult<()> { let follow = Follow::new(actor, community, context)?; let inbox = if community.local { ActivitySendTargets::empty() @@ -77,7 +77,7 @@ impl ActivityHandler for Follow { } #[tracing::instrument(skip_all)] - async fn verify(&self, context: &Data) -> Result<(), LemmyError> { + async fn verify(&self, context: &Data) -> LemmyResult<()> { verify_person(&self.actor, context).await?; let object = self.object.dereference(context).await?; if let UserOrCommunity::Community(c) = object { @@ -90,7 +90,7 @@ impl ActivityHandler for Follow { } #[tracing::instrument(skip_all)] - async fn receive(self, context: &Data) -> Result<(), LemmyError> { + async fn receive(self, context: &Data) -> LemmyResult<()> { insert_received_activity(&self.id, context).await?; let actor = self.actor.dereference(context).await?; let object = self.object.dereference(context).await?; diff --git a/crates/apub/src/activities/following/mod.rs b/crates/apub/src/activities/following/mod.rs index c4f0bd0b7..7c7163f12 100644 --- a/crates/apub/src/activities/following/mod.rs +++ b/crates/apub/src/activities/following/mod.rs @@ -5,7 +5,7 @@ use crate::{ use activitypub_federation::config::Data; use lemmy_api_common::context::LemmyContext; use lemmy_db_schema::source::{community::Community, person::Person}; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; pub mod accept; pub mod follow; @@ -16,7 +16,7 @@ pub async fn send_follow_community( person: Person, follow: bool, context: &Data, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { let community: ApubCommunity = community.into(); let actor: ApubPerson = person.into(); if follow { diff --git a/crates/apub/src/activities/following/undo_follow.rs b/crates/apub/src/activities/following/undo_follow.rs index 90dd452f2..ba6253946 100644 --- a/crates/apub/src/activities/following/undo_follow.rs +++ b/crates/apub/src/activities/following/undo_follow.rs @@ -20,7 +20,7 @@ use lemmy_db_schema::{ }, traits::Followable, }; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::{LemmyError, LemmyResult}; use url::Url; impl UndoFollow { @@ -29,7 +29,7 @@ impl UndoFollow { actor: &ApubPerson, community: &ApubCommunity, context: &Data, - ) -> Result<(), LemmyError> { + ) -> LemmyResult<()> { let object = Follow::new(actor, community, context)?; let undo = UndoFollow { actor: actor.id().into(), @@ -64,7 +64,7 @@ impl ActivityHandler for UndoFollow { } #[tracing::instrument(skip_all)] - async fn verify(&self, context: &Data) -> Result<(), LemmyError> { + async fn verify(&self, context: &Data) -> LemmyResult<()> { verify_urls_match(self.actor.inner(), self.object.actor.inner())?; verify_person(&self.actor, context).await?; self.object.verify(context).await?; @@ -75,7 +75,7 @@ impl ActivityHandler for UndoFollow { } #[tracing::instrument(skip_all)] - async fn receive(self, context: &Data) -> Result<(), LemmyError> { + async fn receive(self, context: &Data) -> LemmyResult<()> { insert_received_activity(&self.id, context).await?; let person = self.actor.dereference(context).await?; let object = self.object.object.dereference(context).await?; diff --git a/crates/apub/src/activities/mod.rs b/crates/apub/src/activities/mod.rs index 1472d6866..6547b957d 100644 --- a/crates/apub/src/activities/mod.rs +++ b/crates/apub/src/activities/mod.rs @@ -61,7 +61,7 @@ pub mod voting; async fn verify_person( person_id: &ObjectId, context: &Data, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { let person = person_id.dereference(context).await?; if person.banned { Err(anyhow!("Person {} is banned", person_id)) @@ -78,7 +78,7 @@ pub(crate) async fn verify_person_in_community( person_id: &ObjectId, community: &ApubCommunity, context: &Data, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { let person = person_id.dereference(context).await?; if person.banned { Err(LemmyErrorType::PersonIsBannedFromSite( @@ -105,7 +105,7 @@ pub(crate) async fn verify_mod_action( mod_id: &ObjectId, community: &Community, context: &Data, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { let mod_ = mod_id.dereference(context).await?; let is_mod_or_admin = @@ -124,7 +124,7 @@ pub(crate) async fn verify_mod_action( Err(LemmyErrorType::NotAModerator)? } -pub(crate) fn verify_is_public(to: &[Url], cc: &[Url]) -> Result<(), LemmyError> { +pub(crate) fn verify_is_public(to: &[Url], cc: &[Url]) -> LemmyResult<()> { if ![to, cc].iter().any(|set| set.contains(&public())) { Err(LemmyErrorType::ObjectIsNotPublic)? } else { @@ -132,10 +132,7 @@ pub(crate) fn verify_is_public(to: &[Url], cc: &[Url]) -> Result<(), LemmyError> } } -pub(crate) fn verify_community_matches( - a: &ObjectId, - b: T, -) -> Result<(), LemmyError> +pub(crate) fn verify_community_matches(a: &ObjectId, b: T) -> LemmyResult<()> where T: Into>, { @@ -147,7 +144,7 @@ where } } -pub(crate) fn check_community_deleted_or_removed(community: &Community) -> Result<(), LemmyError> { +pub(crate) fn check_community_deleted_or_removed(community: &Community) -> LemmyResult<()> { if community.deleted || community.removed { Err(LemmyErrorType::CannotCreatePostOrCommentInDeletedOrRemovedCommunity)? } else { @@ -196,7 +193,7 @@ async fn send_lemmy_activity( actor: &ActorT, send_targets: ActivitySendTargets, sensitive: bool, -) -> Result<(), LemmyError> +) -> LemmyResult<()> where Activity: ActivityHandler + Serialize + Send + Sync + Clone, ActorT: Actor + GetActorType, diff --git a/crates/apub/src/activities/voting/mod.rs b/crates/apub/src/activities/voting/mod.rs index 0f9876f1a..2022252c1 100644 --- a/crates/apub/src/activities/voting/mod.rs +++ b/crates/apub/src/activities/voting/mod.rs @@ -21,7 +21,7 @@ use lemmy_db_schema::{ }, traits::Likeable, }; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; pub mod undo_vote; pub mod vote; @@ -32,7 +32,7 @@ pub(crate) async fn send_like_activity( community: Community, score: i16, context: Data, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { let object_id: ObjectId = object_id.into(); let actor: ApubPerson = actor.into(); let community: ApubCommunity = community.into(); @@ -58,7 +58,7 @@ async fn vote_comment( actor: ApubPerson, comment: &ApubComment, context: &Data, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { let comment_id = comment.id; let like_form = CommentLikeForm { comment_id, @@ -78,7 +78,7 @@ async fn vote_post( actor: ApubPerson, post: &ApubPost, context: &Data, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { let post_id = post.id; let like_form = PostLikeForm { post_id: post.id, @@ -96,7 +96,7 @@ async fn undo_vote_comment( actor: ApubPerson, comment: &ApubComment, context: &Data, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { let comment_id = comment.id; let person_id = actor.id; CommentLike::remove(&mut context.pool(), person_id, comment_id).await?; @@ -108,7 +108,7 @@ async fn undo_vote_post( actor: ApubPerson, post: &ApubPost, context: &Data, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { let post_id = post.id; let person_id = actor.id; PostLike::remove(&mut context.pool(), person_id, post_id).await?; diff --git a/crates/apub/src/activities/voting/undo_vote.rs b/crates/apub/src/activities/voting/undo_vote.rs index f83055620..61875d442 100644 --- a/crates/apub/src/activities/voting/undo_vote.rs +++ b/crates/apub/src/activities/voting/undo_vote.rs @@ -19,7 +19,7 @@ use activitypub_federation::{ traits::{ActivityHandler, Actor}, }; use lemmy_api_common::context::LemmyContext; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::{LemmyError, LemmyResult}; use url::Url; impl UndoVote { @@ -28,7 +28,7 @@ impl UndoVote { actor: &ApubPerson, community: &ApubCommunity, context: &Data, - ) -> Result { + ) -> LemmyResult { Ok(UndoVote { actor: actor.id().into(), object: vote, @@ -56,7 +56,7 @@ impl ActivityHandler for UndoVote { } #[tracing::instrument(skip_all)] - async fn verify(&self, context: &Data) -> Result<(), LemmyError> { + async fn verify(&self, context: &Data) -> LemmyResult<()> { let community = self.community(context).await?; verify_person_in_community(&self.actor, &community, context).await?; verify_urls_match(self.actor.inner(), self.object.actor.inner())?; @@ -65,7 +65,7 @@ impl ActivityHandler for UndoVote { } #[tracing::instrument(skip_all)] - async fn receive(self, context: &Data) -> Result<(), LemmyError> { + async fn receive(self, context: &Data) -> LemmyResult<()> { insert_received_activity(&self.id, context).await?; let actor = self.actor.dereference(context).await?; let object = self.object.object.dereference(context).await?; diff --git a/crates/apub/src/activities/voting/vote.rs b/crates/apub/src/activities/voting/vote.rs index 5625ea6ba..324c8b300 100644 --- a/crates/apub/src/activities/voting/vote.rs +++ b/crates/apub/src/activities/voting/vote.rs @@ -19,7 +19,7 @@ use activitypub_federation::{ }; use lemmy_api_common::{context::LemmyContext, utils::check_bot_account}; use lemmy_db_schema::source::local_site::LocalSite; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::{LemmyError, LemmyResult}; use url::Url; impl Vote { @@ -29,7 +29,7 @@ impl Vote { community: &ApubCommunity, kind: VoteType, context: &Data, - ) -> Result { + ) -> LemmyResult { Ok(Vote { actor: actor.id().into(), object: object_id, @@ -54,14 +54,14 @@ impl ActivityHandler for Vote { } #[tracing::instrument(skip_all)] - async fn verify(&self, context: &Data) -> Result<(), LemmyError> { + async fn verify(&self, context: &Data) -> LemmyResult<()> { let community = self.community(context).await?; verify_person_in_community(&self.actor, &community, context).await?; Ok(()) } #[tracing::instrument(skip_all)] - async fn receive(self, context: &Data) -> Result<(), LemmyError> { + async fn receive(self, context: &Data) -> LemmyResult<()> { insert_received_activity(&self.id, context).await?; let actor = self.actor.dereference(context).await?; let object = self.object.dereference(context).await?; diff --git a/crates/apub/src/activity_lists.rs b/crates/apub/src/activity_lists.rs index 7b33499c8..3aeb7e45e 100644 --- a/crates/apub/src/activity_lists.rs +++ b/crates/apub/src/activity_lists.rs @@ -26,7 +26,7 @@ use crate::{ }; use activitypub_federation::{config::Data, traits::ActivityHandler}; use lemmy_api_common::context::LemmyContext; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; use serde::{Deserialize, Serialize}; use url::Url; @@ -101,7 +101,7 @@ pub enum AnnouncableActivities { #[async_trait::async_trait] impl InCommunity for AnnouncableActivities { #[tracing::instrument(skip(self, context))] - async fn community(&self, context: &Data) -> Result { + async fn community(&self, context: &Data) -> LemmyResult { use AnnouncableActivities::*; match self { CreateOrUpdateComment(a) => a.community(context).await, diff --git a/crates/apub/src/api/list_comments.rs b/crates/apub/src/api/list_comments.rs index c83756f54..a231b9080 100644 --- a/crates/apub/src/api/list_comments.rs +++ b/crates/apub/src/api/list_comments.rs @@ -15,14 +15,14 @@ use lemmy_db_schema::{ traits::Crud, }; use lemmy_db_views::{comment_view::CommentQuery, structs::LocalUserView}; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn list_comments( data: Query, context: Data, local_user_view: Option, -) -> Result, LemmyError> { +) -> LemmyResult> { let local_site = LocalSite::read(&mut context.pool()).await?; check_private_instance(&local_user_view, &local_site)?; diff --git a/crates/apub/src/api/list_posts.rs b/crates/apub/src/api/list_posts.rs index 384f1b60e..87e4bc679 100644 --- a/crates/apub/src/api/list_posts.rs +++ b/crates/apub/src/api/list_posts.rs @@ -15,14 +15,14 @@ use lemmy_db_views::{ post_view::PostQuery, structs::{LocalUserView, PaginationCursor, SiteView}, }; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn list_posts( data: Query, context: Data, local_user_view: Option, -) -> Result, LemmyError> { +) -> LemmyResult> { let local_site = SiteView::read_local(&mut context.pool()).await?; check_private_instance(&local_user_view, &local_site.local_site)?; diff --git a/crates/apub/src/api/read_community.rs b/crates/apub/src/api/read_community.rs index a41deb32c..0d32a0b49 100644 --- a/crates/apub/src/api/read_community.rs +++ b/crates/apub/src/api/read_community.rs @@ -13,14 +13,14 @@ use lemmy_db_schema::source::{ }; use lemmy_db_views::structs::LocalUserView; use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView}; -use lemmy_utils::error::{LemmyError, LemmyErrorExt, LemmyErrorExt2, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt, LemmyErrorExt2, LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn get_community( data: Query, context: Data, local_user_view: Option, -) -> Result, LemmyError> { +) -> LemmyResult> { let local_site = LocalSite::read(&mut context.pool()).await?; if data.name.is_none() && data.id.is_none() { diff --git a/crates/apub/src/api/read_person.rs b/crates/apub/src/api/read_person.rs index c779657c8..d4015f62d 100644 --- a/crates/apub/src/api/read_person.rs +++ b/crates/apub/src/api/read_person.rs @@ -13,14 +13,14 @@ use lemmy_db_views::{ structs::{LocalUserView, SiteView}, }; use lemmy_db_views_actor::structs::{CommunityModeratorView, PersonView}; -use lemmy_utils::error::{LemmyError, LemmyErrorExt2, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt2, LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn read_person( data: Query, context: Data, local_user_view: Option, -) -> Result, LemmyError> { +) -> LemmyResult> { // Check to make sure a person name or an id is given if data.username.is_none() && data.person_id.is_none() { Err(LemmyErrorType::NoIdGiven)? diff --git a/crates/apub/src/api/resolve_object.rs b/crates/apub/src/api/resolve_object.rs index 6d672a8cd..6ab98a052 100644 --- a/crates/apub/src/api/resolve_object.rs +++ b/crates/apub/src/api/resolve_object.rs @@ -13,14 +13,14 @@ use lemmy_api_common::{ use lemmy_db_schema::{newtypes::PersonId, source::local_site::LocalSite, utils::DbPool}; use lemmy_db_views::structs::{CommentView, LocalUserView, PostView}; use lemmy_db_views_actor::structs::{CommunityView, PersonView}; -use lemmy_utils::error::{LemmyError, LemmyErrorExt2, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorExt2, LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn resolve_object( data: Query, context: Data, local_user_view: Option, -) -> Result, LemmyError> { +) -> LemmyResult> { let local_site = LocalSite::read(&mut context.pool()).await?; check_private_instance(&local_user_view, &local_site)?; let person_id = local_user_view.map(|v| v.person.id); @@ -46,7 +46,7 @@ async fn convert_response( object: SearchableObjects, user_id: Option, pool: &mut DbPool<'_>, -) -> Result, LemmyError> { +) -> LemmyResult> { use SearchableObjects::*; let removed_or_deleted; let mut res = ResolveObjectResponse::default(); diff --git a/crates/apub/src/api/search.rs b/crates/apub/src/api/search.rs index 32128a3c1..0cac8351a 100644 --- a/crates/apub/src/api/search.rs +++ b/crates/apub/src/api/search.rs @@ -13,14 +13,14 @@ use lemmy_db_views::{ structs::{LocalUserView, SiteView}, }; use lemmy_db_views_actor::{community_view::CommunityQuery, person_view::PersonQuery}; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; #[tracing::instrument(skip(context))] pub async fn search( data: Query, context: Data, local_user_view: Option, -) -> Result, LemmyError> { +) -> LemmyResult> { let local_site = SiteView::read_local(&mut context.pool()).await?; check_private_instance(&local_user_view, &local_site.local_site)?; diff --git a/crates/apub/src/api/user_settings_backup.rs b/crates/apub/src/api/user_settings_backup.rs index 4c1edcbff..8053d66a0 100644 --- a/crates/apub/src/api/user_settings_backup.rs +++ b/crates/apub/src/api/user_settings_backup.rs @@ -26,7 +26,7 @@ use lemmy_db_schema::{ }; use lemmy_db_views::structs::LocalUserView; use lemmy_utils::{ - error::{LemmyError, LemmyErrorType, LemmyResult, MAX_API_PARAM_ELEMENTS}, + error::{LemmyErrorType, LemmyResult, MAX_API_PARAM_ELEMENTS}, spawn_try_task, }; use serde::{Deserialize, Serialize}; @@ -70,7 +70,7 @@ pub struct UserSettingsBackup { pub async fn export_settings( local_user_view: LocalUserView, context: Data, -) -> Result, LemmyError> { +) -> LemmyResult> { let lists = LocalUser::export_backup(&mut context.pool(), local_user_view.person.id).await?; let vec_into = |vec: Vec<_>| vec.into_iter().map(Into::into).collect(); @@ -97,7 +97,7 @@ pub async fn import_settings( data: Json, local_user_view: LocalUserView, context: Data, -) -> Result, LemmyError> { +) -> LemmyResult> { let person_form = PersonUpdateForm { display_name: Some(data.display_name.clone()), bio: Some(data.bio.clone()), diff --git a/crates/apub/src/collections/community_moderators.rs b/crates/apub/src/collections/community_moderators.rs index 0532d0aef..02b912f44 100644 --- a/crates/apub/src/collections/community_moderators.rs +++ b/crates/apub/src/collections/community_moderators.rs @@ -15,7 +15,7 @@ use lemmy_db_schema::{ traits::Joinable, }; use lemmy_db_views_actor::structs::CommunityModeratorView; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::{LemmyError, LemmyResult}; use url::Url; #[derive(Clone, Debug)] @@ -29,10 +29,7 @@ impl Collection for ApubCommunityModerators { type Error = LemmyError; #[tracing::instrument(skip_all)] - async fn read_local( - owner: &Self::Owner, - data: &Data, - ) -> Result { + async fn read_local(owner: &Self::Owner, data: &Data) -> LemmyResult { let moderators = CommunityModeratorView::for_community(&mut data.pool(), owner.id).await?; let ordered_items = moderators .into_iter() @@ -50,7 +47,7 @@ impl Collection for ApubCommunityModerators { group_moderators: &GroupModerators, expected_domain: &Url, _data: &Data, - ) -> Result<(), LemmyError> { + ) -> LemmyResult<()> { verify_domains_match(&group_moderators.id, expected_domain)?; Ok(()) } @@ -60,7 +57,7 @@ impl Collection for ApubCommunityModerators { apub: Self::Kind, owner: &Self::Owner, data: &Data, - ) -> Result { + ) -> LemmyResult { let community_id = owner.id; let current_moderators = CommunityModeratorView::for_community(&mut data.pool(), community_id).await?; @@ -118,7 +115,6 @@ mod tests { }, traits::Crud, }; - use lemmy_utils::error::LemmyResult; use pretty_assertions::assert_eq; use serial_test::serial; diff --git a/crates/apub/src/collections/community_outbox.rs b/crates/apub/src/collections/community_outbox.rs index 0799db789..f56708d09 100644 --- a/crates/apub/src/collections/community_outbox.rs +++ b/crates/apub/src/collections/community_outbox.rs @@ -23,7 +23,7 @@ use lemmy_db_schema::{ traits::Crud, utils::FETCH_LIMIT_MAX, }; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::{LemmyError, LemmyResult}; use url::Url; #[derive(Clone, Debug)] @@ -37,10 +37,7 @@ impl Collection for ApubCommunityOutbox { type Error = LemmyError; #[tracing::instrument(skip_all)] - async fn read_local( - owner: &Self::Owner, - data: &Data, - ) -> Result { + async fn read_local(owner: &Self::Owner, data: &Data) -> LemmyResult { let post_list: Vec = Post::list_for_community(&mut data.pool(), owner.id) .await? .into_iter() @@ -71,7 +68,7 @@ impl Collection for ApubCommunityOutbox { group_outbox: &GroupOutbox, expected_domain: &Url, _data: &Data, - ) -> Result<(), LemmyError> { + ) -> LemmyResult<()> { verify_domains_match(expected_domain, &group_outbox.id)?; Ok(()) } @@ -81,7 +78,7 @@ impl Collection for ApubCommunityOutbox { apub: Self::Kind, _owner: &Self::Owner, data: &Data, - ) -> Result { + ) -> LemmyResult { let mut outbox_activities = apub.ordered_items; if outbox_activities.len() as i64 > FETCH_LIMIT_MAX { outbox_activities = outbox_activities diff --git a/crates/apub/src/fetcher/mod.rs b/crates/apub/src/fetcher/mod.rs index 4e30b4b16..928656924 100644 --- a/crates/apub/src/fetcher/mod.rs +++ b/crates/apub/src/fetcher/mod.rs @@ -8,7 +8,7 @@ use itertools::Itertools; use lemmy_api_common::context::LemmyContext; use lemmy_db_schema::traits::ApubActor; use lemmy_db_views::structs::LocalUserView; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::{LemmyError, LemmyResult}; pub mod post_or_comment; pub mod search; @@ -25,7 +25,7 @@ pub async fn resolve_actor_identifier( context: &Data, local_user_view: &Option, include_deleted: bool, -) -> Result +) -> LemmyResult where ActorType: Object + Object diff --git a/crates/apub/src/fetcher/post_or_comment.rs b/crates/apub/src/fetcher/post_or_comment.rs index 31c53864a..9df0a04fb 100644 --- a/crates/apub/src/fetcher/post_or_comment.rs +++ b/crates/apub/src/fetcher/post_or_comment.rs @@ -12,7 +12,7 @@ use lemmy_db_schema::{ source::{community::Community, post::Post}, traits::Crud, }; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::{LemmyError, LemmyResult}; use serde::Deserialize; use url::Url; @@ -40,10 +40,7 @@ impl Object for PostOrComment { } #[tracing::instrument(skip_all)] - async fn read_from_id( - object_id: Url, - data: &Data, - ) -> Result, LemmyError> { + async fn read_from_id(object_id: Url, data: &Data) -> LemmyResult> { let post = ApubPost::read_from_id(object_id.clone(), data).await?; Ok(match post { Some(o) => Some(PostOrComment::Post(o)), @@ -54,14 +51,14 @@ impl Object for PostOrComment { } #[tracing::instrument(skip_all)] - async fn delete(self, data: &Data) -> Result<(), LemmyError> { + async fn delete(self, data: &Data) -> LemmyResult<()> { match self { PostOrComment::Post(p) => p.delete(data).await, PostOrComment::Comment(c) => c.delete(data).await, } } - async fn into_json(self, _data: &Data) -> Result { + async fn into_json(self, _data: &Data) -> LemmyResult { unimplemented!() } @@ -70,7 +67,7 @@ impl Object for PostOrComment { apub: &Self::Kind, expected_domain: &Url, data: &Data, - ) -> Result<(), LemmyError> { + ) -> LemmyResult<()> { match apub { PageOrNote::Page(a) => ApubPost::verify(a, expected_domain, data).await, PageOrNote::Note(a) => ApubComment::verify(a, expected_domain, data).await, @@ -78,7 +75,7 @@ impl Object for PostOrComment { } #[tracing::instrument(skip_all)] - async fn from_json(apub: PageOrNote, context: &Data) -> Result { + async fn from_json(apub: PageOrNote, context: &Data) -> LemmyResult { Ok(match apub { PageOrNote::Page(p) => PostOrComment::Post(ApubPost::from_json(*p, context).await?), PageOrNote::Note(n) => PostOrComment::Comment(ApubComment::from_json(n, context).await?), @@ -88,7 +85,7 @@ impl Object for PostOrComment { #[async_trait::async_trait] impl InCommunity for PostOrComment { - async fn community(&self, context: &Data) -> Result { + async fn community(&self, context: &Data) -> LemmyResult { let cid = match self { PostOrComment::Post(p) => p.community_id, PostOrComment::Comment(c) => { diff --git a/crates/apub/src/fetcher/search.rs b/crates/apub/src/fetcher/search.rs index 74d755da0..8c533ba88 100644 --- a/crates/apub/src/fetcher/search.rs +++ b/crates/apub/src/fetcher/search.rs @@ -10,7 +10,7 @@ use activitypub_federation::{ }; use chrono::{DateTime, Utc}; use lemmy_api_common::context::LemmyContext; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::{LemmyError, LemmyResult}; use serde::Deserialize; use url::Url; @@ -21,7 +21,7 @@ use url::Url; pub(crate) async fn search_query_to_object_id( mut query: String, context: &Data, -) -> Result { +) -> LemmyResult { Ok(match Url::parse(&query) { Ok(url) => { // its already an url, just go with it @@ -46,7 +46,7 @@ pub(crate) async fn search_query_to_object_id( pub(crate) async fn search_query_to_object_id_local( query: &str, context: &Data, -) -> Result { +) -> LemmyResult { let url = Url::parse(query)?; ObjectId::from(url).dereference_local(context).await } @@ -90,7 +90,7 @@ impl Object for SearchableObjects { async fn read_from_id( object_id: Url, context: &Data, - ) -> Result, LemmyError> { + ) -> LemmyResult> { let uc = UserOrCommunity::read_from_id(object_id.clone(), context).await?; if let Some(uc) = uc { return Ok(Some(SearchableObjects::PersonOrCommunity(Box::new(uc)))); @@ -107,7 +107,7 @@ impl Object for SearchableObjects { } #[tracing::instrument(skip_all)] - async fn delete(self, data: &Data) -> Result<(), LemmyError> { + async fn delete(self, data: &Data) -> LemmyResult<()> { match self { SearchableObjects::Post(p) => p.delete(data).await, SearchableObjects::Comment(c) => c.delete(data).await, @@ -118,7 +118,7 @@ impl Object for SearchableObjects { } } - async fn into_json(self, _data: &Data) -> Result { + async fn into_json(self, _data: &Data) -> LemmyResult { unimplemented!() } @@ -127,7 +127,7 @@ impl Object for SearchableObjects { apub: &Self::Kind, expected_domain: &Url, data: &Data, - ) -> Result<(), LemmyError> { + ) -> LemmyResult<()> { match apub { SearchableKinds::Page(a) => ApubPost::verify(a, expected_domain, data).await, SearchableKinds::Note(a) => ApubComment::verify(a, expected_domain, data).await, @@ -139,7 +139,7 @@ impl Object for SearchableObjects { } #[tracing::instrument(skip_all)] - async fn from_json(apub: Self::Kind, context: &Data) -> Result { + async fn from_json(apub: Self::Kind, context: &Data) -> LemmyResult { use SearchableKinds as SAT; use SearchableObjects as SO; Ok(match apub { diff --git a/crates/apub/src/fetcher/site_or_community_or_user.rs b/crates/apub/src/fetcher/site_or_community_or_user.rs index 76ee566c9..30b5fd568 100644 --- a/crates/apub/src/fetcher/site_or_community_or_user.rs +++ b/crates/apub/src/fetcher/site_or_community_or_user.rs @@ -9,7 +9,7 @@ use activitypub_federation::{ }; use chrono::{DateTime, Utc}; use lemmy_api_common::context::LemmyContext; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::{LemmyError, LemmyResult}; use reqwest::Url; use serde::{Deserialize, Serialize}; @@ -44,19 +44,19 @@ impl Object for SiteOrCommunityOrUser { async fn read_from_id( _object_id: Url, _data: &Data, - ) -> Result, LemmyError> { + ) -> LemmyResult> { unimplemented!(); } #[tracing::instrument(skip_all)] - async fn delete(self, data: &Data) -> Result<(), LemmyError> { + async fn delete(self, data: &Data) -> LemmyResult<()> { match self { SiteOrCommunityOrUser::Site(p) => p.delete(data).await, SiteOrCommunityOrUser::UserOrCommunity(p) => p.delete(data).await, } } - async fn into_json(self, _data: &Data) -> Result { + async fn into_json(self, _data: &Data) -> LemmyResult { unimplemented!() } @@ -65,7 +65,7 @@ impl Object for SiteOrCommunityOrUser { apub: &Self::Kind, expected_domain: &Url, data: &Data, - ) -> Result<(), LemmyError> { + ) -> LemmyResult<()> { match apub { SiteOrPersonOrGroup::Instance(a) => ApubSite::verify(a, expected_domain, data).await, SiteOrPersonOrGroup::PersonOrGroup(a) => { @@ -75,7 +75,7 @@ impl Object for SiteOrCommunityOrUser { } #[tracing::instrument(skip_all)] - async fn from_json(_apub: Self::Kind, _data: &Data) -> Result { + async fn from_json(_apub: Self::Kind, _data: &Data) -> LemmyResult { unimplemented!(); } } diff --git a/crates/apub/src/fetcher/user_or_community.rs b/crates/apub/src/fetcher/user_or_community.rs index 93e955c7b..d29cbb6b0 100644 --- a/crates/apub/src/fetcher/user_or_community.rs +++ b/crates/apub/src/fetcher/user_or_community.rs @@ -10,7 +10,7 @@ use activitypub_federation::{ use chrono::{DateTime, Utc}; use lemmy_api_common::context::LemmyContext; use lemmy_db_schema::source::activity::ActorType; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::{LemmyError, LemmyResult}; use serde::{Deserialize, Serialize}; use url::Url; @@ -47,10 +47,7 @@ impl Object for UserOrCommunity { } #[tracing::instrument(skip_all)] - async fn read_from_id( - object_id: Url, - data: &Data, - ) -> Result, LemmyError> { + async fn read_from_id(object_id: Url, data: &Data) -> LemmyResult> { let person = ApubPerson::read_from_id(object_id.clone(), data).await?; Ok(match person { Some(o) => Some(UserOrCommunity::User(o)), @@ -61,14 +58,14 @@ impl Object for UserOrCommunity { } #[tracing::instrument(skip_all)] - async fn delete(self, data: &Data) -> Result<(), LemmyError> { + async fn delete(self, data: &Data) -> LemmyResult<()> { match self { UserOrCommunity::User(p) => p.delete(data).await, UserOrCommunity::Community(p) => p.delete(data).await, } } - async fn into_json(self, _data: &Data) -> Result { + async fn into_json(self, _data: &Data) -> LemmyResult { unimplemented!() } @@ -77,7 +74,7 @@ impl Object for UserOrCommunity { apub: &Self::Kind, expected_domain: &Url, data: &Data, - ) -> Result<(), LemmyError> { + ) -> LemmyResult<()> { match apub { PersonOrGroup::Person(a) => ApubPerson::verify(a, expected_domain, data).await, PersonOrGroup::Group(a) => ApubCommunity::verify(a, expected_domain, data).await, @@ -85,7 +82,7 @@ impl Object for UserOrCommunity { } #[tracing::instrument(skip_all)] - async fn from_json(apub: Self::Kind, data: &Data) -> Result { + async fn from_json(apub: Self::Kind, data: &Data) -> LemmyResult { Ok(match apub { PersonOrGroup::Person(p) => UserOrCommunity::User(ApubPerson::from_json(p, data).await?), PersonOrGroup::Group(p) => { diff --git a/crates/apub/src/http/comment.rs b/crates/apub/src/http/comment.rs index 200dda8ed..d6b3c818d 100644 --- a/crates/apub/src/http/comment.rs +++ b/crates/apub/src/http/comment.rs @@ -15,7 +15,7 @@ use lemmy_db_schema::{ source::{comment::Comment, community::Community, post::Post}, traits::Crud, }; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; use serde::Deserialize; #[derive(Deserialize)] @@ -28,7 +28,7 @@ pub(crate) struct CommentQuery { pub(crate) async fn get_apub_comment( info: Path, context: Data, -) -> Result { +) -> LemmyResult { let id = CommentId(info.comment_id.parse::()?); // Can't use CommentView here because it excludes deleted/removed/local-only items let comment: ApubComment = Comment::read(&mut context.pool(), id).await?.into(); diff --git a/crates/apub/src/http/community.rs b/crates/apub/src/http/community.rs index cf0d1625d..2085ed1ac 100644 --- a/crates/apub/src/http/community.rs +++ b/crates/apub/src/http/community.rs @@ -18,7 +18,7 @@ use activitypub_federation::{ use actix_web::{web, web::Bytes, HttpRequest, HttpResponse}; use lemmy_api_common::context::LemmyContext; use lemmy_db_schema::{source::community::Community, traits::ApubActor}; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; use serde::Deserialize; #[derive(Deserialize, Clone)] @@ -31,7 +31,7 @@ pub(crate) struct CommunityQuery { pub(crate) async fn get_apub_community_http( info: web::Path, context: Data, -) -> Result { +) -> LemmyResult { let community: ApubCommunity = Community::read_from_name(&mut context.pool(), &info.community_name, true) .await? @@ -52,7 +52,7 @@ pub async fn community_inbox( request: HttpRequest, body: Bytes, data: Data, -) -> Result { +) -> LemmyResult { receive_activity::, ApubPerson, LemmyContext>( request, body, &data, ) @@ -63,7 +63,7 @@ pub async fn community_inbox( pub(crate) async fn get_apub_community_followers( info: web::Path, context: Data, -) -> Result { +) -> LemmyResult { let community = Community::read_from_name(&mut context.pool(), &info.community_name, false).await?; check_community_public(&community)?; @@ -76,7 +76,7 @@ pub(crate) async fn get_apub_community_followers( pub(crate) async fn get_apub_community_outbox( info: web::Path, context: Data, -) -> Result { +) -> LemmyResult { let community: ApubCommunity = Community::read_from_name(&mut context.pool(), &info.community_name, false) .await? @@ -90,7 +90,7 @@ pub(crate) async fn get_apub_community_outbox( pub(crate) async fn get_apub_community_moderators( info: web::Path, context: Data, -) -> Result { +) -> LemmyResult { let community: ApubCommunity = Community::read_from_name(&mut context.pool(), &info.community_name, false) .await? @@ -104,7 +104,7 @@ pub(crate) async fn get_apub_community_moderators( pub(crate) async fn get_apub_community_featured( info: web::Path, context: Data, -) -> Result { +) -> LemmyResult { let community: ApubCommunity = Community::read_from_name(&mut context.pool(), &info.community_name, false) .await? @@ -127,7 +127,6 @@ pub(crate) mod tests { traits::Crud, CommunityVisibility, }; - use lemmy_utils::error::LemmyResult; use serde::de::DeserializeOwned; use serial_test::serial; @@ -135,7 +134,7 @@ pub(crate) mod tests { deleted: bool, visibility: CommunityVisibility, context: &Data, - ) -> Result<(Instance, Community), LemmyError> { + ) -> LemmyResult<(Instance, Community)> { let instance = Instance::read_or_create(&mut context.pool(), "my_domain.tld".to_string()).await?; let community_form = CommunityInsertForm::builder() @@ -150,7 +149,7 @@ pub(crate) mod tests { Ok((instance, community)) } - async fn decode_response(res: HttpResponse) -> Result { + async fn decode_response(res: HttpResponse) -> LemmyResult { let body = to_bytes(res.into_body()).await.unwrap(); let body = std::str::from_utf8(&body)?; Ok(serde_json::from_str(body)?) diff --git a/crates/apub/src/http/mod.rs b/crates/apub/src/http/mod.rs index b400e3dab..86c51338a 100644 --- a/crates/apub/src/http/mod.rs +++ b/crates/apub/src/http/mod.rs @@ -18,7 +18,7 @@ use lemmy_db_schema::{ source::{activity::SentActivity, community::Community}, CommunityVisibility, }; -use lemmy_utils::error::{LemmyError, LemmyErrorType, LemmyResult}; +use lemmy_utils::error::{LemmyErrorType, LemmyResult}; use serde::{Deserialize, Serialize}; use std::ops::Deref; use url::Url; @@ -88,7 +88,7 @@ pub struct ActivityQuery { pub(crate) async fn get_activity( info: web::Path, context: web::Data, -) -> Result { +) -> LemmyResult { let settings = context.settings(); let activity_id = Url::parse(&format!( "{}/activities/{}/{}", diff --git a/crates/apub/src/http/person.rs b/crates/apub/src/http/person.rs index 254313634..b34f166b0 100644 --- a/crates/apub/src/http/person.rs +++ b/crates/apub/src/http/person.rs @@ -14,7 +14,7 @@ use activitypub_federation::{ use actix_web::{web, web::Bytes, HttpRequest, HttpResponse}; use lemmy_api_common::{context::LemmyContext, utils::generate_outbox_url}; use lemmy_db_schema::{source::person::Person, traits::ApubActor}; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; use serde::Deserialize; #[derive(Deserialize)] @@ -27,7 +27,7 @@ pub struct PersonQuery { pub(crate) async fn get_apub_person_http( info: web::Path, context: Data, -) -> Result { +) -> LemmyResult { let user_name = info.into_inner().user_name; // TODO: this needs to be able to read deleted persons, so that it can send tombstones let person: ApubPerson = Person::read_from_name(&mut context.pool(), &user_name, true) @@ -48,7 +48,7 @@ pub async fn person_inbox( request: HttpRequest, body: Bytes, data: Data, -) -> Result { +) -> LemmyResult { receive_activity::, UserOrCommunity, LemmyContext>( request, body, &data, ) @@ -59,7 +59,7 @@ pub async fn person_inbox( pub(crate) async fn get_apub_person_outbox( info: web::Path, context: Data, -) -> Result { +) -> LemmyResult { let person = Person::read_from_name(&mut context.pool(), &info.user_name, false).await?; let outbox_id = generate_outbox_url(&person.actor_id)?.into(); let outbox = EmptyOutbox::new(outbox_id)?; diff --git a/crates/apub/src/http/post.rs b/crates/apub/src/http/post.rs index 6ca07f684..ce6612826 100644 --- a/crates/apub/src/http/post.rs +++ b/crates/apub/src/http/post.rs @@ -15,7 +15,7 @@ use lemmy_db_schema::{ source::{community::Community, post::Post}, traits::Crud, }; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; use serde::Deserialize; #[derive(Deserialize)] @@ -28,7 +28,7 @@ pub(crate) struct PostQuery { pub(crate) async fn get_apub_post( info: web::Path, context: Data, -) -> Result { +) -> LemmyResult { let id = PostId(info.post_id.parse::()?); // Can't use PostView here because it excludes deleted/removed/local-only items let post: ApubPost = Post::read(&mut context.pool(), id).await?.into(); diff --git a/crates/apub/src/http/site.rs b/crates/apub/src/http/site.rs index 410b29b18..622c0f676 100644 --- a/crates/apub/src/http/site.rs +++ b/crates/apub/src/http/site.rs @@ -7,12 +7,10 @@ use activitypub_federation::{config::Data, traits::Object}; use actix_web::HttpResponse; use lemmy_api_common::context::LemmyContext; use lemmy_db_views::structs::SiteView; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; use url::Url; -pub(crate) async fn get_apub_site_http( - context: Data, -) -> Result { +pub(crate) async fn get_apub_site_http(context: Data) -> LemmyResult { let site: ApubSite = SiteView::read_local(&mut context.pool()).await?.site.into(); let apub = site.into_json(&context).await?; @@ -20,9 +18,7 @@ pub(crate) async fn get_apub_site_http( } #[tracing::instrument(skip_all)] -pub(crate) async fn get_apub_site_outbox( - context: Data, -) -> Result { +pub(crate) async fn get_apub_site_outbox(context: Data) -> LemmyResult { let outbox_id = format!( "{}/site_outbox", context.settings().get_protocol_and_hostname() diff --git a/crates/apub/src/lib.rs b/crates/apub/src/lib.rs index 5d10dd93d..29c9a12eb 100644 --- a/crates/apub/src/lib.rs +++ b/crates/apub/src/lib.rs @@ -77,7 +77,7 @@ impl UrlVerifier for VerifyUrlData { /// - URL being in the allowlist (if it is active) /// - URL not being in the blocklist (if it is active) #[tracing::instrument(skip(local_site_data))] -fn check_apub_id_valid(apub_id: &Url, local_site_data: &LocalSiteData) -> Result<(), LemmyError> { +fn check_apub_id_valid(apub_id: &Url, local_site_data: &LocalSiteData) -> LemmyResult<()> { let domain = apub_id.domain().expect("apud id has domain").to_string(); if !local_site_data @@ -157,7 +157,7 @@ pub(crate) async fn check_apub_id_valid_with_strictness( apub_id: &Url, is_strict: bool, context: &LemmyContext, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { let domain = apub_id.domain().expect("apud id has domain").to_string(); let local_instance = context .settings() @@ -198,10 +198,7 @@ pub(crate) async fn check_apub_id_valid_with_strictness( /// This ensures that the same activity doesnt get received and processed more than once, which /// would be a waste of resources. #[tracing::instrument(skip(data))] -async fn insert_received_activity( - ap_id: &Url, - data: &Data, -) -> Result<(), LemmyError> { +async fn insert_received_activity(ap_id: &Url, data: &Data) -> LemmyResult<()> { ReceivedActivity::create(&mut data.pool(), &ap_id.clone().into()).await?; Ok(()) } diff --git a/crates/apub/src/mentions.rs b/crates/apub/src/mentions.rs index b088dfd03..92b07db8e 100644 --- a/crates/apub/src/mentions.rs +++ b/crates/apub/src/mentions.rs @@ -11,7 +11,7 @@ use lemmy_db_schema::{ traits::Crud, utils::DbPool, }; -use lemmy_utils::{error::LemmyError, utils::mention::scrape_text_for_mentions}; +use lemmy_utils::{error::LemmyResult, utils::mention::scrape_text_for_mentions}; use serde::{Deserialize, Serialize}; use serde_json::Value; use url::Url; @@ -44,7 +44,7 @@ pub async fn collect_non_local_mentions( comment: &ApubComment, community_id: ObjectId, context: &Data, -) -> Result { +) -> LemmyResult { let parent_creator = get_comment_parent_creator(&mut context.pool(), comment).await?; let mut addressed_ccs: Vec = vec![community_id.into(), parent_creator.id()]; @@ -94,7 +94,7 @@ pub async fn collect_non_local_mentions( async fn get_comment_parent_creator( pool: &mut DbPool<'_>, comment: &Comment, -) -> Result { +) -> LemmyResult { let parent_creator_id = if let Some(parent_comment_id) = comment.parent_comment_id() { let parent_comment = Comment::read(pool, parent_comment_id).await?; parent_comment.creator_id diff --git a/crates/apub/src/objects/comment.rs b/crates/apub/src/objects/comment.rs index 1acef5cbf..e3128e439 100644 --- a/crates/apub/src/objects/comment.rs +++ b/crates/apub/src/objects/comment.rs @@ -32,7 +32,7 @@ use lemmy_db_schema::{ utils::naive_now, }; use lemmy_utils::{ - error::{LemmyError, LemmyErrorType}, + error::{LemmyError, LemmyErrorType, LemmyResult}, utils::markdown::markdown_to_html, }; use std::ops::Deref; @@ -68,7 +68,7 @@ impl Object for ApubComment { async fn read_from_id( object_id: Url, context: &Data, - ) -> Result, LemmyError> { + ) -> LemmyResult> { Ok( Comment::read_from_apub_id(&mut context.pool(), object_id) .await? @@ -77,7 +77,7 @@ impl Object for ApubComment { } #[tracing::instrument(skip_all)] - async fn delete(self, context: &Data) -> Result<(), LemmyError> { + async fn delete(self, context: &Data) -> LemmyResult<()> { if !self.deleted { let form = CommentUpdateForm { deleted: Some(true), @@ -89,7 +89,7 @@ impl Object for ApubComment { } #[tracing::instrument(skip_all)] - async fn into_json(self, context: &Data) -> Result { + async fn into_json(self, context: &Data) -> LemmyResult { let creator_id = self.creator_id; let creator = Person::read(&mut context.pool(), creator_id).await?; @@ -133,7 +133,7 @@ impl Object for ApubComment { note: &Note, expected_domain: &Url, context: &Data, - ) -> Result<(), LemmyError> { + ) -> LemmyResult<()> { verify_domains_match(note.id.inner(), expected_domain)?; verify_domains_match(note.attributed_to.inner(), note.id.inner())?; verify_is_public(¬e.to, ¬e.cc)?; @@ -159,7 +159,7 @@ impl Object for ApubComment { /// /// If the parent community, post and comment(s) are not known locally, these are also fetched. #[tracing::instrument(skip_all)] - async fn from_json(note: Note, context: &Data) -> Result { + async fn from_json(note: Note, context: &Data) -> LemmyResult { let creator = note.attributed_to.dereference(context).await?; let (post, parent_comment) = note.get_parents(context).await?; @@ -213,7 +213,6 @@ pub(crate) mod tests { use assert_json_diff::assert_json_include; use html2md::parse_html; use lemmy_db_schema::source::site::Site; - use lemmy_utils::error::LemmyResult; use pretty_assertions::assert_eq; use serial_test::serial; diff --git a/crates/apub/src/objects/community.rs b/crates/apub/src/objects/community.rs index 83cdc3a49..6638cc68d 100644 --- a/crates/apub/src/objects/community.rs +++ b/crates/apub/src/objects/community.rs @@ -38,7 +38,11 @@ use lemmy_db_schema::{ utils::naive_now, }; use lemmy_db_views_actor::structs::CommunityFollowerView; -use lemmy_utils::{error::LemmyError, spawn_try_task, utils::markdown::markdown_to_html}; +use lemmy_utils::{ + error::{LemmyError, LemmyResult}, + spawn_try_task, + utils::markdown::markdown_to_html, +}; use std::ops::Deref; use url::Url; @@ -72,7 +76,7 @@ impl Object for ApubCommunity { async fn read_from_id( object_id: Url, context: &Data, - ) -> Result, LemmyError> { + ) -> LemmyResult> { Ok( Community::read_from_apub_id(&mut context.pool(), &object_id.into()) .await? @@ -81,7 +85,7 @@ impl Object for ApubCommunity { } #[tracing::instrument(skip_all)] - async fn delete(self, context: &Data) -> Result<(), LemmyError> { + async fn delete(self, context: &Data) -> LemmyResult<()> { let form = CommunityUpdateForm { deleted: Some(true), ..Default::default() @@ -91,7 +95,7 @@ impl Object for ApubCommunity { } #[tracing::instrument(skip_all)] - async fn into_json(self, data: &Data) -> Result { + async fn into_json(self, data: &Data) -> LemmyResult { let community_id = self.id; let langs = CommunityLanguage::read(&mut data.pool(), community_id).await?; let language = LanguageTag::new_multiple(langs, &mut data.pool()).await?; @@ -128,16 +132,13 @@ impl Object for ApubCommunity { group: &Group, expected_domain: &Url, context: &Data, - ) -> Result<(), LemmyError> { + ) -> LemmyResult<()> { group.verify(expected_domain, context).await } /// Converts a `Group` to `Community`, inserts it into the database and updates moderators. #[tracing::instrument(skip_all)] - async fn from_json( - group: Group, - context: &Data, - ) -> Result { + async fn from_json(group: Group, context: &Data) -> LemmyResult { let instance_id = fetch_instance_actor_for_object(&group.id, context).await?; let local_site = LocalSite::read(&mut context.pool()).await.ok(); @@ -235,10 +236,7 @@ impl GetActorType for ApubCommunity { impl ApubCommunity { /// For a given community, returns the inboxes of all followers. #[tracing::instrument(skip_all)] - pub(crate) async fn get_follower_inboxes( - &self, - context: &LemmyContext, - ) -> Result, LemmyError> { + pub(crate) async fn get_follower_inboxes(&self, context: &LemmyContext) -> LemmyResult> { let id = self.id; let local_site_data = local_site_data_cached(&mut context.pool()).await?; @@ -265,7 +263,6 @@ pub(crate) mod tests { }; use activitypub_federation::fetch::collection_id::CollectionId; use lemmy_db_schema::source::site::Site; - use lemmy_utils::error::LemmyResult; use pretty_assertions::assert_eq; use serial_test::serial; diff --git a/crates/apub/src/objects/instance.rs b/crates/apub/src/objects/instance.rs index 6894643d6..021d2b1cd 100644 --- a/crates/apub/src/objects/instance.rs +++ b/crates/apub/src/objects/instance.rs @@ -39,7 +39,7 @@ use lemmy_db_schema::{ utils::naive_now, }; use lemmy_utils::{ - error::LemmyError, + error::{LemmyError, LemmyResult}, utils::{ markdown::markdown_to_html, slurs::{check_slurs, check_slurs_opt}, @@ -76,10 +76,7 @@ impl Object for ApubSite { } #[tracing::instrument(skip_all)] - async fn read_from_id( - object_id: Url, - data: &Data, - ) -> Result, LemmyError> { + async fn read_from_id(object_id: Url, data: &Data) -> LemmyResult> { Ok( Site::read_from_apub_id(&mut data.pool(), &object_id.into()) .await? @@ -87,12 +84,12 @@ impl Object for ApubSite { ) } - async fn delete(self, _data: &Data) -> Result<(), LemmyError> { + async fn delete(self, _data: &Data) -> LemmyResult<()> { unimplemented!() } #[tracing::instrument(skip_all)] - async fn into_json(self, data: &Data) -> Result { + async fn into_json(self, data: &Data) -> LemmyResult { let site_id = self.id; let langs = SiteLanguage::read(&mut data.pool(), site_id).await?; let language = LanguageTag::new_multiple(langs, &mut data.pool()).await?; @@ -124,7 +121,7 @@ impl Object for ApubSite { apub: &Self::Kind, expected_domain: &Url, data: &Data, - ) -> Result<(), LemmyError> { + ) -> LemmyResult<()> { check_apub_id_valid_with_strictness(apub.id.inner(), true, data).await?; verify_domains_match(expected_domain, apub.id.inner())?; @@ -137,7 +134,7 @@ impl Object for ApubSite { } #[tracing::instrument(skip_all)] - async fn from_json(apub: Self::Kind, context: &Data) -> Result { + async fn from_json(apub: Self::Kind, context: &Data) -> LemmyResult { let domain = apub.id.inner().domain().expect("group id has domain"); let instance = DbInstance::read_or_create(&mut context.pool(), domain.to_string()).await?; @@ -200,7 +197,7 @@ impl GetActorType for ApubSite { pub(in crate::objects) async fn fetch_instance_actor_for_object + Clone>( object_id: &T, context: &Data, -) -> Result { +) -> LemmyResult { let object_id: Url = object_id.clone().into(); let instance_id = Site::instance_actor_id_from_url(object_id); let site = ObjectId::::from(instance_id.clone()) @@ -225,7 +222,6 @@ pub(in crate::objects) async fn fetch_instance_actor_for_object + C pub(crate) mod tests { use super::*; use crate::protocol::tests::file_to_json_object; - use lemmy_utils::error::LemmyResult; use pretty_assertions::assert_eq; use serial_test::serial; diff --git a/crates/apub/src/objects/mod.rs b/crates/apub/src/objects/mod.rs index cabd07e6d..693521ee1 100644 --- a/crates/apub/src/objects/mod.rs +++ b/crates/apub/src/objects/mod.rs @@ -2,7 +2,7 @@ use crate::protocol::Source; use activitypub_federation::protocol::values::MediaTypeMarkdownOrHtml; use anyhow::anyhow; use html2md::parse_html; -use lemmy_utils::{error::LemmyError, settings::structs::Settings}; +use lemmy_utils::{error::LemmyResult, settings::structs::Settings}; use url::Url; pub mod comment; @@ -43,7 +43,7 @@ pub(crate) fn read_from_string_or_source_opt( /// wrapped in Announce. If we simply receive this like any other federated object, overwrite the /// existing, local Post. In particular, it will set the field local = false, so that the object /// can't be fetched from the Activitypub HTTP endpoint anymore (which only serves local objects). -pub(crate) fn verify_is_remote_object(id: &Url, settings: &Settings) -> Result<(), LemmyError> { +pub(crate) fn verify_is_remote_object(id: &Url, settings: &Settings) -> LemmyResult<()> { let local_domain = settings.get_hostname_without_port()?; if id.domain() == Some(&local_domain) { Err(anyhow!("cant accept local object from remote instance").into()) diff --git a/crates/apub/src/objects/person.rs b/crates/apub/src/objects/person.rs index d4456344f..c99e09f72 100644 --- a/crates/apub/src/objects/person.rs +++ b/crates/apub/src/objects/person.rs @@ -38,7 +38,7 @@ use lemmy_db_schema::{ utils::naive_now, }; use lemmy_utils::{ - error::LemmyError, + error::{LemmyError, LemmyResult}, utils::{ markdown::markdown_to_html, slurs::{check_slurs, check_slurs_opt}, @@ -77,7 +77,7 @@ impl Object for ApubPerson { async fn read_from_id( object_id: Url, context: &Data, - ) -> Result, LemmyError> { + ) -> LemmyResult> { Ok( DbPerson::read_from_apub_id(&mut context.pool(), &object_id.into()) .await? @@ -86,7 +86,7 @@ impl Object for ApubPerson { } #[tracing::instrument(skip_all)] - async fn delete(self, context: &Data) -> Result<(), LemmyError> { + async fn delete(self, context: &Data) -> LemmyResult<()> { let form = PersonUpdateForm { deleted: Some(true), ..Default::default() @@ -96,7 +96,7 @@ impl Object for ApubPerson { } #[tracing::instrument(skip_all)] - async fn into_json(self, _context: &Data) -> Result { + async fn into_json(self, _context: &Data) -> LemmyResult { let kind = if self.bot_account { UserTypes::Service } else { @@ -130,7 +130,7 @@ impl Object for ApubPerson { person: &Person, expected_domain: &Url, context: &Data, - ) -> Result<(), LemmyError> { + ) -> LemmyResult<()> { let local_site_data = local_site_data_cached(&mut context.pool()).await?; let slur_regex = &local_site_opt_to_slur_regex(&local_site_data.local_site); check_slurs(&person.preferred_username, slur_regex)?; @@ -145,10 +145,7 @@ impl Object for ApubPerson { } #[tracing::instrument(skip_all)] - async fn from_json( - person: Person, - context: &Data, - ) -> Result { + async fn from_json(person: Person, context: &Data) -> LemmyResult { let instance_id = fetch_instance_actor_for_object(&person.id, context).await?; let local_site = LocalSite::read(&mut context.pool()).await.ok(); @@ -228,7 +225,6 @@ pub(crate) mod tests { }; use activitypub_federation::fetch::object_id::ObjectId; use lemmy_db_schema::source::site::Site; - use lemmy_utils::error::LemmyResult; use pretty_assertions::assert_eq; use serial_test::serial; diff --git a/crates/apub/src/objects/post.rs b/crates/apub/src/objects/post.rs index a53acee28..ba1e3f6a1 100644 --- a/crates/apub/src/objects/post.rs +++ b/crates/apub/src/objects/post.rs @@ -45,7 +45,7 @@ use lemmy_db_schema::{ }; use lemmy_db_views_actor::structs::CommunityModeratorView; use lemmy_utils::{ - error::LemmyError, + error::{LemmyError, LemmyResult}, utils::{markdown::markdown_to_html, slurs::check_slurs_opt, validation::check_url_scheme}, }; use std::ops::Deref; @@ -84,7 +84,7 @@ impl Object for ApubPost { async fn read_from_id( object_id: Url, context: &Data, - ) -> Result, LemmyError> { + ) -> LemmyResult> { Ok( Post::read_from_apub_id(&mut context.pool(), object_id) .await? @@ -93,7 +93,7 @@ impl Object for ApubPost { } #[tracing::instrument(skip_all)] - async fn delete(self, context: &Data) -> Result<(), LemmyError> { + async fn delete(self, context: &Data) -> LemmyResult<()> { if !self.deleted { let form = PostUpdateForm { deleted: Some(true), @@ -106,7 +106,7 @@ impl Object for ApubPost { // Turn a Lemmy post into an ActivityPub page that can be sent out over the network. #[tracing::instrument(skip_all)] - async fn into_json(self, context: &Data) -> Result { + async fn into_json(self, context: &Data) -> LemmyResult { let creator_id = self.creator_id; let creator = Person::read(&mut context.pool(), creator_id).await?; let community_id = self.community_id; @@ -160,7 +160,7 @@ impl Object for ApubPost { page: &Page, expected_domain: &Url, context: &Data, - ) -> Result<(), LemmyError> { + ) -> LemmyResult<()> { // We can't verify the domain in case of mod action, because the mod may be on a different // instance from the post author. if !page.is_mod_action(context).await? { @@ -182,7 +182,7 @@ impl Object for ApubPost { } #[tracing::instrument(skip_all)] - async fn from_json(page: Page, context: &Data) -> Result { + async fn from_json(page: Page, context: &Data) -> LemmyResult { let creator = page.creator()?.dereference(context).await?; let community = page.community(context).await?; if community.posting_restricted_to_mods { @@ -307,7 +307,6 @@ mod tests { protocol::tests::file_to_json_object, }; use lemmy_db_schema::source::site::Site; - use lemmy_utils::error::LemmyResult; use pretty_assertions::assert_eq; use serial_test::serial; diff --git a/crates/apub/src/objects/private_message.rs b/crates/apub/src/objects/private_message.rs index c32aa6458..a78324633 100644 --- a/crates/apub/src/objects/private_message.rs +++ b/crates/apub/src/objects/private_message.rs @@ -26,7 +26,7 @@ use lemmy_db_schema::{ utils::naive_now, }; use lemmy_utils::{ - error::{LemmyError, LemmyErrorType}, + error::{LemmyError, LemmyErrorType, LemmyResult}, utils::markdown::markdown_to_html, }; use std::ops::Deref; @@ -62,7 +62,7 @@ impl Object for ApubPrivateMessage { async fn read_from_id( object_id: Url, context: &Data, - ) -> Result, LemmyError> { + ) -> LemmyResult> { Ok( PrivateMessage::read_from_apub_id(&mut context.pool(), object_id) .await? @@ -70,13 +70,13 @@ impl Object for ApubPrivateMessage { ) } - async fn delete(self, _context: &Data) -> Result<(), LemmyError> { + async fn delete(self, _context: &Data) -> LemmyResult<()> { // do nothing, because pm can't be fetched over http unimplemented!() } #[tracing::instrument(skip_all)] - async fn into_json(self, context: &Data) -> Result { + async fn into_json(self, context: &Data) -> LemmyResult { let creator_id = self.creator_id; let creator = Person::read(&mut context.pool(), creator_id).await?; @@ -102,7 +102,7 @@ impl Object for ApubPrivateMessage { note: &ChatMessage, expected_domain: &Url, context: &Data, - ) -> Result<(), LemmyError> { + ) -> LemmyResult<()> { verify_domains_match(note.id.inner(), expected_domain)?; verify_domains_match(note.attributed_to.inner(), note.id.inner())?; @@ -121,7 +121,7 @@ impl Object for ApubPrivateMessage { async fn from_json( note: ChatMessage, context: &Data, - ) -> Result { + ) -> LemmyResult { let creator = note.attributed_to.dereference(context).await?; let recipient = note.to[0].dereference(context).await?; check_person_block(creator.id, recipient.id, &mut context.pool()).await?; @@ -161,7 +161,6 @@ mod tests { }; use assert_json_diff::assert_json_include; use lemmy_db_schema::source::site::Site; - use lemmy_utils::error::LemmyResult; use pretty_assertions::assert_eq; use serial_test::serial; diff --git a/crates/apub/src/protocol/activities/block/block_user.rs b/crates/apub/src/protocol/activities/block/block_user.rs index c5cb4306c..c1a4c64c7 100644 --- a/crates/apub/src/protocol/activities/block/block_user.rs +++ b/crates/apub/src/protocol/activities/block/block_user.rs @@ -12,7 +12,7 @@ use activitypub_federation::{ use anyhow::anyhow; use chrono::{DateTime, Utc}; use lemmy_api_common::context::LemmyContext; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; use serde::{Deserialize, Serialize}; use serde_with::skip_serializing_none; use url::Url; @@ -45,7 +45,7 @@ pub struct BlockUser { #[async_trait::async_trait] impl InCommunity for BlockUser { - async fn community(&self, context: &Data) -> Result { + async fn community(&self, context: &Data) -> LemmyResult { let target = self.target.dereference(context).await?; let community = match target { SiteOrCommunity::Community(c) => c, diff --git a/crates/apub/src/protocol/activities/block/undo_block_user.rs b/crates/apub/src/protocol/activities/block/undo_block_user.rs index 758d3fd4b..491ec7ed1 100644 --- a/crates/apub/src/protocol/activities/block/undo_block_user.rs +++ b/crates/apub/src/protocol/activities/block/undo_block_user.rs @@ -10,7 +10,7 @@ use activitypub_federation::{ protocol::helpers::deserialize_one_or_many, }; use lemmy_api_common::context::LemmyContext; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; use serde::{Deserialize, Serialize}; use serde_with::skip_serializing_none; use url::Url; @@ -33,7 +33,7 @@ pub struct UndoBlockUser { #[async_trait::async_trait] impl InCommunity for UndoBlockUser { - async fn community(&self, context: &Data) -> Result { + async fn community(&self, context: &Data) -> LemmyResult { let community = self.object.community(context).await?; if let Some(audience) = &self.audience { verify_community_matches(audience, community.actor_id.clone())?; diff --git a/crates/apub/src/protocol/activities/community/collection_add.rs b/crates/apub/src/protocol/activities/community/collection_add.rs index edf67740a..777ad8b62 100644 --- a/crates/apub/src/protocol/activities/community/collection_add.rs +++ b/crates/apub/src/protocol/activities/community/collection_add.rs @@ -11,7 +11,7 @@ use activitypub_federation::{ }; use lemmy_api_common::context::LemmyContext; use lemmy_db_schema::source::community::Community; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; use serde::{Deserialize, Serialize}; use url::Url; @@ -33,7 +33,7 @@ pub struct CollectionAdd { #[async_trait::async_trait] impl InCommunity for CollectionAdd { - async fn community(&self, context: &Data) -> Result { + async fn community(&self, context: &Data) -> LemmyResult { let (community, _) = Community::get_by_collection_url(&mut context.pool(), &self.clone().target.into()).await?; if let Some(audience) = &self.audience { diff --git a/crates/apub/src/protocol/activities/community/collection_remove.rs b/crates/apub/src/protocol/activities/community/collection_remove.rs index 960951732..afc0c24a0 100644 --- a/crates/apub/src/protocol/activities/community/collection_remove.rs +++ b/crates/apub/src/protocol/activities/community/collection_remove.rs @@ -11,7 +11,7 @@ use activitypub_federation::{ }; use lemmy_api_common::context::LemmyContext; use lemmy_db_schema::source::community::Community; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; use serde::{Deserialize, Serialize}; use url::Url; @@ -33,7 +33,7 @@ pub struct CollectionRemove { #[async_trait::async_trait] impl InCommunity for CollectionRemove { - async fn community(&self, context: &Data) -> Result { + async fn community(&self, context: &Data) -> LemmyResult { let (community, _) = Community::get_by_collection_url(&mut context.pool(), &self.clone().target.into()).await?; if let Some(audience) = &self.audience { diff --git a/crates/apub/src/protocol/activities/community/lock_page.rs b/crates/apub/src/protocol/activities/community/lock_page.rs index 33b108531..0a4a2ff75 100644 --- a/crates/apub/src/protocol/activities/community/lock_page.rs +++ b/crates/apub/src/protocol/activities/community/lock_page.rs @@ -11,7 +11,7 @@ use activitypub_federation::{ }; use lemmy_api_common::context::LemmyContext; use lemmy_db_schema::{source::community::Community, traits::Crud}; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; use serde::{Deserialize, Serialize}; use strum_macros::Display; use url::Url; @@ -53,7 +53,7 @@ pub struct UndoLockPage { #[async_trait::async_trait] impl InCommunity for LockPage { - async fn community(&self, context: &Data) -> Result { + async fn community(&self, context: &Data) -> LemmyResult { let post = self.object.dereference(context).await?; let community = Community::read(&mut context.pool(), post.community_id).await?; if let Some(audience) = &self.audience { @@ -65,7 +65,7 @@ impl InCommunity for LockPage { #[async_trait::async_trait] impl InCommunity for UndoLockPage { - async fn community(&self, context: &Data) -> Result { + async fn community(&self, context: &Data) -> LemmyResult { let community = self.object.community(context).await?; if let Some(audience) = &self.audience { verify_community_matches(audience, community.actor_id.clone())?; diff --git a/crates/apub/src/protocol/activities/community/report.rs b/crates/apub/src/protocol/activities/community/report.rs index adcddfdfc..7698cde50 100644 --- a/crates/apub/src/protocol/activities/community/report.rs +++ b/crates/apub/src/protocol/activities/community/report.rs @@ -11,7 +11,7 @@ use activitypub_federation::{ protocol::helpers::deserialize_one, }; use lemmy_api_common::context::LemmyContext; -use lemmy_utils::error::{LemmyError, LemmyErrorType, LemmyResult}; +use lemmy_utils::error::{LemmyErrorType, LemmyResult}; use serde::{Deserialize, Serialize}; use url::Url; @@ -71,7 +71,7 @@ impl ReportObject { #[async_trait::async_trait] impl InCommunity for Report { - async fn community(&self, context: &Data) -> Result { + async fn community(&self, context: &Data) -> LemmyResult { let community = self.to[0].dereference(context).await?; if let Some(audience) = &self.audience { verify_community_matches(audience, community.actor_id.clone())?; diff --git a/crates/apub/src/protocol/activities/community/update.rs b/crates/apub/src/protocol/activities/community/update.rs index 49ec1f5d6..268f05073 100644 --- a/crates/apub/src/protocol/activities/community/update.rs +++ b/crates/apub/src/protocol/activities/community/update.rs @@ -10,7 +10,7 @@ use activitypub_federation::{ protocol::helpers::deserialize_one_or_many, }; use lemmy_api_common::context::LemmyContext; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; use serde::{Deserialize, Serialize}; use url::Url; @@ -34,7 +34,7 @@ pub struct UpdateCommunity { #[async_trait::async_trait] impl InCommunity for UpdateCommunity { - async fn community(&self, context: &Data) -> Result { + async fn community(&self, context: &Data) -> LemmyResult { let community: ApubCommunity = self.object.id.clone().dereference(context).await?; if let Some(audience) = &self.audience { verify_community_matches(audience, community.actor_id.clone())?; diff --git a/crates/apub/src/protocol/activities/create_or_update/note.rs b/crates/apub/src/protocol/activities/create_or_update/note.rs index 6fabc0aaa..ff0728174 100644 --- a/crates/apub/src/protocol/activities/create_or_update/note.rs +++ b/crates/apub/src/protocol/activities/create_or_update/note.rs @@ -11,7 +11,7 @@ use activitypub_federation::{ }; use lemmy_api_common::context::LemmyContext; use lemmy_db_schema::{source::community::Community, traits::Crud}; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; use serde::{Deserialize, Serialize}; use url::Url; @@ -34,7 +34,7 @@ pub struct CreateOrUpdateNote { #[async_trait::async_trait] impl InCommunity for CreateOrUpdateNote { - async fn community(&self, context: &Data) -> Result { + async fn community(&self, context: &Data) -> LemmyResult { let post = self.object.get_parents(context).await?.0; let community = Community::read(&mut context.pool(), post.community_id).await?; if let Some(audience) = &self.audience { diff --git a/crates/apub/src/protocol/activities/create_or_update/page.rs b/crates/apub/src/protocol/activities/create_or_update/page.rs index ec64c31a0..21052a9ef 100644 --- a/crates/apub/src/protocol/activities/create_or_update/page.rs +++ b/crates/apub/src/protocol/activities/create_or_update/page.rs @@ -9,7 +9,7 @@ use activitypub_federation::{ protocol::helpers::deserialize_one_or_many, }; use lemmy_api_common::context::LemmyContext; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; use serde::{Deserialize, Serialize}; use url::Url; @@ -30,7 +30,7 @@ pub struct CreateOrUpdatePage { #[async_trait::async_trait] impl InCommunity for CreateOrUpdatePage { - async fn community(&self, context: &Data) -> Result { + async fn community(&self, context: &Data) -> LemmyResult { let community = self.object.community(context).await?; if let Some(audience) = &self.audience { verify_community_matches(audience, community.actor_id.clone())?; diff --git a/crates/apub/src/protocol/activities/deletion/delete.rs b/crates/apub/src/protocol/activities/deletion/delete.rs index aefcf3f5f..3a29da069 100644 --- a/crates/apub/src/protocol/activities/deletion/delete.rs +++ b/crates/apub/src/protocol/activities/deletion/delete.rs @@ -15,7 +15,7 @@ use lemmy_db_schema::{ source::{community::Community, post::Post}, traits::Crud, }; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; use serde::{Deserialize, Serialize}; use serde_with::skip_serializing_none; use url::Url; @@ -47,7 +47,7 @@ pub struct Delete { #[async_trait::async_trait] impl InCommunity for Delete { - async fn community(&self, context: &Data) -> Result { + async fn community(&self, context: &Data) -> LemmyResult { let community_id = match DeletableObjects::read_from_db(self.object.id(), context).await? { DeletableObjects::Community(c) => c.id, DeletableObjects::Comment(c) => { diff --git a/crates/apub/src/protocol/activities/deletion/undo_delete.rs b/crates/apub/src/protocol/activities/deletion/undo_delete.rs index 35d9951b1..508b90113 100644 --- a/crates/apub/src/protocol/activities/deletion/undo_delete.rs +++ b/crates/apub/src/protocol/activities/deletion/undo_delete.rs @@ -10,7 +10,7 @@ use activitypub_federation::{ protocol::helpers::deserialize_one_or_many, }; use lemmy_api_common::context::LemmyContext; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; use serde::{Deserialize, Serialize}; use serde_with::skip_serializing_none; use url::Url; @@ -35,7 +35,7 @@ pub struct UndoDelete { #[async_trait::async_trait] impl InCommunity for UndoDelete { - async fn community(&self, context: &Data) -> Result { + async fn community(&self, context: &Data) -> LemmyResult { let community = self.object.community(context).await?; if let Some(audience) = &self.audience { verify_community_matches(audience, community.actor_id.clone())?; diff --git a/crates/apub/src/protocol/activities/voting/undo_vote.rs b/crates/apub/src/protocol/activities/voting/undo_vote.rs index 746ae68df..e9ccbd593 100644 --- a/crates/apub/src/protocol/activities/voting/undo_vote.rs +++ b/crates/apub/src/protocol/activities/voting/undo_vote.rs @@ -5,7 +5,7 @@ use crate::{ }; use activitypub_federation::{config::Data, fetch::object_id::ObjectId, kinds::activity::UndoType}; use lemmy_api_common::context::LemmyContext; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; use serde::{Deserialize, Serialize}; use url::Url; @@ -22,7 +22,7 @@ pub struct UndoVote { #[async_trait::async_trait] impl InCommunity for UndoVote { - async fn community(&self, context: &Data) -> Result { + async fn community(&self, context: &Data) -> LemmyResult { let community = self.object.community(context).await?; if let Some(audience) = &self.audience { verify_community_matches(audience, community.actor_id.clone())?; diff --git a/crates/apub/src/protocol/activities/voting/vote.rs b/crates/apub/src/protocol/activities/voting/vote.rs index 013c15bfd..b632333c7 100644 --- a/crates/apub/src/protocol/activities/voting/vote.rs +++ b/crates/apub/src/protocol/activities/voting/vote.rs @@ -6,7 +6,7 @@ use crate::{ }; use activitypub_federation::{config::Data, fetch::object_id::ObjectId}; use lemmy_api_common::context::LemmyContext; -use lemmy_utils::error::{LemmyError, LemmyErrorType}; +use lemmy_utils::error::{LemmyError, LemmyErrorType, LemmyResult}; use serde::{Deserialize, Serialize}; use strum_macros::Display; use url::Url; @@ -51,7 +51,7 @@ impl From<&VoteType> for i16 { #[async_trait::async_trait] impl InCommunity for Vote { - async fn community(&self, context: &Data) -> Result { + async fn community(&self, context: &Data) -> LemmyResult { let community = self .object .dereference(context) diff --git a/crates/apub/src/protocol/collections/empty_outbox.rs b/crates/apub/src/protocol/collections/empty_outbox.rs index 3801c04e9..1e7a4c6a8 100644 --- a/crates/apub/src/protocol/collections/empty_outbox.rs +++ b/crates/apub/src/protocol/collections/empty_outbox.rs @@ -1,5 +1,5 @@ use activitypub_federation::kinds::collection::OrderedCollectionType; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; use serde::{Deserialize, Serialize}; use url::Url; @@ -14,7 +14,7 @@ pub(crate) struct EmptyOutbox { } impl EmptyOutbox { - pub(crate) fn new(outbox_id: Url) -> Result { + pub(crate) fn new(outbox_id: Url) -> LemmyResult { Ok(EmptyOutbox { r#type: OrderedCollectionType::OrderedCollection, id: outbox_id, diff --git a/crates/apub/src/protocol/mod.rs b/crates/apub/src/protocol/mod.rs index d538ee531..a4774ac1d 100644 --- a/crates/apub/src/protocol/mod.rs +++ b/crates/apub/src/protocol/mod.rs @@ -7,7 +7,7 @@ use activitypub_federation::{ }; use lemmy_api_common::context::LemmyContext; use lemmy_db_schema::newtypes::DbUrl; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use std::collections::HashMap; use url::Url; @@ -71,7 +71,7 @@ impl IdOrNestedObject { IdOrNestedObject::NestedObject(n) => n.object_id(), } } - pub(crate) async fn object(self, context: &Data) -> Result { + pub(crate) async fn object(self, context: &Data) -> LemmyResult { match self { // TODO: move IdOrNestedObject struct to library and make fetch_object_http private IdOrNestedObject::Id(i) => Ok(fetch_object_http(&i, context).await?.object), @@ -83,25 +83,25 @@ impl IdOrNestedObject { #[async_trait::async_trait] pub trait InCommunity { // TODO: after we use audience field and remove backwards compat, it should be possible to change - // this to simply `fn community(&self) -> Result, LemmyError>` - async fn community(&self, context: &Data) -> Result; + // this to simply `fn community(&self) -> LemmyResult>` + async fn community(&self, context: &Data) -> LemmyResult; } #[cfg(test)] pub(crate) mod tests { use activitypub_federation::protocol::context::WithContext; use assert_json_diff::assert_json_include; - use lemmy_utils::error::LemmyError; + use lemmy_utils::error::LemmyResult; use serde::{de::DeserializeOwned, Serialize}; use std::{collections::HashMap, fs::File, io::BufReader}; - pub(crate) fn file_to_json_object(path: &str) -> Result { + pub(crate) fn file_to_json_object(path: &str) -> LemmyResult { let file = File::open(path)?; let reader = BufReader::new(file); Ok(serde_json::from_reader(reader)?) } - pub(crate) fn test_json(path: &str) -> Result, LemmyError> { + pub(crate) fn test_json(path: &str) -> LemmyResult> { file_to_json_object::>(path) } @@ -109,7 +109,7 @@ pub(crate) mod tests { /// Ensures that there are no breaking changes in sent data. pub(crate) fn test_parse_lemmy_item( path: &str, - ) -> Result { + ) -> LemmyResult { // parse file as T let parsed = file_to_json_object::(path)?; diff --git a/crates/apub/src/protocol/objects/group.rs b/crates/apub/src/protocol/objects/group.rs index 2a625a5a7..30cfafb17 100644 --- a/crates/apub/src/protocol/objects/group.rs +++ b/crates/apub/src/protocol/objects/group.rs @@ -26,7 +26,7 @@ use activitypub_federation::{ use chrono::{DateTime, Utc}; use lemmy_api_common::{context::LemmyContext, utils::local_site_opt_to_slur_regex}; use lemmy_utils::{ - error::LemmyError, + error::LemmyResult, utils::slurs::{check_slurs, check_slurs_opt}, }; use serde::{Deserialize, Serialize}; @@ -76,7 +76,7 @@ impl Group { &self, expected_domain: &Url, context: &LemmyContext, - ) -> Result<(), LemmyError> { + ) -> LemmyResult<()> { check_apub_id_valid_with_strictness(self.id.inner(), true, context).await?; verify_domains_match(expected_domain, self.id.inner())?; diff --git a/crates/apub/src/protocol/objects/mod.rs b/crates/apub/src/protocol/objects/mod.rs index 03229f739..efda3d7ed 100644 --- a/crates/apub/src/protocol/objects/mod.rs +++ b/crates/apub/src/protocol/objects/mod.rs @@ -4,7 +4,7 @@ use lemmy_db_schema::{ source::language::Language, utils::DbPool, }; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; use serde::{Deserialize, Serialize}; use url::Url; @@ -34,7 +34,7 @@ impl LanguageTag { pub(crate) async fn new_single( lang: LanguageId, pool: &mut DbPool<'_>, - ) -> Result, LemmyError> { + ) -> LemmyResult> { let lang = Language::read_from_id(pool, lang).await?; // undetermined @@ -51,7 +51,7 @@ impl LanguageTag { pub(crate) async fn new_multiple( lang_ids: Vec, pool: &mut DbPool<'_>, - ) -> Result, LemmyError> { + ) -> LemmyResult> { let mut langs = Vec::::new(); for l in lang_ids { @@ -71,7 +71,7 @@ impl LanguageTag { pub(crate) async fn to_language_id_single( lang: Option, pool: &mut DbPool<'_>, - ) -> Result, LemmyError> { + ) -> LemmyResult> { let identifier = lang.map(|l| l.identifier); let language = Language::read_id_from_code(pool, identifier.as_deref()).await?; @@ -81,7 +81,7 @@ impl LanguageTag { pub(crate) async fn to_language_id_multiple( langs: Vec, pool: &mut DbPool<'_>, - ) -> Result, LemmyError> { + ) -> LemmyResult> { let mut language_ids = Vec::new(); for l in langs { diff --git a/crates/apub/src/protocol/objects/note.rs b/crates/apub/src/protocol/objects/note.rs index 259a8fcfa..a092cec9f 100644 --- a/crates/apub/src/protocol/objects/note.rs +++ b/crates/apub/src/protocol/objects/note.rs @@ -20,7 +20,7 @@ use lemmy_db_schema::{ source::{community::Community, post::Post}, traits::Crud, }; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; use serde::{Deserialize, Serialize}; use serde_with::skip_serializing_none; use std::ops::Deref; @@ -57,7 +57,7 @@ impl Note { pub(crate) async fn get_parents( &self, context: &Data, - ) -> Result<(ApubPost, Option), LemmyError> { + ) -> LemmyResult<(ApubPost, Option)> { // 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() { @@ -73,7 +73,7 @@ impl Note { #[async_trait::async_trait] impl InCommunity for Note { - async fn community(&self, context: &Data) -> Result { + async fn community(&self, context: &Data) -> LemmyResult { let (post, _) = self.get_parents(context).await?; let community = Community::read(&mut context.pool(), post.community_id).await?; if let Some(audience) = &self.audience { diff --git a/crates/apub/src/protocol/objects/page.rs b/crates/apub/src/protocol/objects/page.rs index 170778297..acfd8f5fd 100644 --- a/crates/apub/src/protocol/objects/page.rs +++ b/crates/apub/src/protocol/objects/page.rs @@ -20,7 +20,7 @@ use activitypub_federation::{ use chrono::{DateTime, Utc}; use itertools::Itertools; use lemmy_api_common::context::LemmyContext; -use lemmy_utils::error::{LemmyError, LemmyErrorType}; +use lemmy_utils::error::{LemmyError, LemmyErrorType, LemmyResult}; use serde::{de::Error, Deserialize, Deserializer, Serialize}; use serde_with::skip_serializing_none; use url::Url; @@ -160,10 +160,7 @@ impl Page { /// it is a mod action and needs to be verified as such. /// /// Locked needs to be false on a newly created post (verified in [[CreatePost]]. - pub(crate) async fn is_mod_action( - &self, - context: &Data, - ) -> Result { + pub(crate) async fn is_mod_action(&self, context: &Data) -> LemmyResult { let old_post = self.id.clone().dereference_local(context).await; Ok(Page::is_locked_changed(&old_post, &self.comments_enabled)) } @@ -181,7 +178,7 @@ impl Page { false } - pub(crate) fn creator(&self) -> Result, LemmyError> { + pub(crate) fn creator(&self) -> LemmyResult> { match &self.attributed_to { AttributedTo::Lemmy(l) => Ok(l.clone()), AttributedTo::Peertube(p) => p @@ -224,10 +221,10 @@ impl ActivityHandler for Page { fn actor(&self) -> &Url { unimplemented!() } - async fn verify(&self, data: &Data) -> Result<(), LemmyError> { + async fn verify(&self, data: &Data) -> LemmyResult<()> { ApubPost::verify(self, self.id.inner(), data).await } - async fn receive(self, data: &Data) -> Result<(), LemmyError> { + async fn receive(self, data: &Data) -> LemmyResult<()> { ApubPost::from_json(self, data).await?; Ok(()) } @@ -235,7 +232,7 @@ impl ActivityHandler for Page { #[async_trait::async_trait] impl InCommunity for Page { - async fn community(&self, context: &Data) -> Result { + async fn community(&self, context: &Data) -> LemmyResult { let community = match &self.attributed_to { AttributedTo::Lemmy(_) => { let mut iter = self.to.iter().merge(self.cc.iter()); diff --git a/crates/db_schema/src/impls/actor_language.rs b/crates/db_schema/src/impls/actor_language.rs index 0191dd872..fe21cf003 100644 --- a/crates/db_schema/src/impls/actor_language.rs +++ b/crates/db_schema/src/impls/actor_language.rs @@ -26,7 +26,7 @@ use diesel::{ QueryDsl, }; use diesel_async::{AsyncPgConnection, RunQueryDsl}; -use lemmy_utils::error::{LemmyError, LemmyErrorType}; +use lemmy_utils::error::{LemmyErrorType, LemmyResult}; use tokio::sync::OnceCell; pub const UNDETERMINED_ID: LanguageId = LanguageId(0); @@ -194,7 +194,7 @@ impl CommunityLanguage { pool: &mut DbPool<'_>, for_language_id: Option, for_community_id: CommunityId, - ) -> Result<(), LemmyError> { + ) -> LemmyResult<()> { use crate::schema::community_language::dsl::community_language; let conn = &mut get_conn(pool).await?; diff --git a/crates/db_schema/src/impls/local_site.rs b/crates/db_schema/src/impls/local_site.rs index 90b25fed5..39ed624ef 100644 --- a/crates/db_schema/src/impls/local_site.rs +++ b/crates/db_schema/src/impls/local_site.rs @@ -1,23 +1,23 @@ use crate::{ - schema::local_site::dsl::local_site, + schema::local_site, source::local_site::{LocalSite, LocalSiteInsertForm, LocalSiteUpdateForm}, utils::{get_conn, DbPool}, }; use diesel::{dsl::insert_into, result::Error}; use diesel_async::RunQueryDsl; -use lemmy_utils::{error::LemmyError, CACHE_DURATION_API}; +use lemmy_utils::{error::LemmyResult, CACHE_DURATION_API}; use moka::future::Cache; use once_cell::sync::Lazy; impl LocalSite { pub async fn create(pool: &mut DbPool<'_>, form: &LocalSiteInsertForm) -> Result { let conn = &mut get_conn(pool).await?; - insert_into(local_site) + insert_into(local_site::table) .values(form) .get_result::(conn) .await } - pub async fn read(pool: &mut DbPool<'_>) -> Result { + pub async fn read(pool: &mut DbPool<'_>) -> LemmyResult { static CACHE: Lazy> = Lazy::new(|| { Cache::builder() .max_capacity(1) @@ -28,20 +28,20 @@ impl LocalSite { CACHE .try_get_with((), async { let conn = &mut get_conn(pool).await?; - local_site.first::(conn).await + local_site::table.first::(conn).await }) .await?, ) } pub async fn update(pool: &mut DbPool<'_>, form: &LocalSiteUpdateForm) -> Result { let conn = &mut get_conn(pool).await?; - diesel::update(local_site) + diesel::update(local_site::table) .set(form) .get_result::(conn) .await } pub async fn delete(pool: &mut DbPool<'_>) -> Result { let conn = &mut get_conn(pool).await?; - diesel::delete(local_site).execute(conn).await + diesel::delete(local_site::table).execute(conn).await } } diff --git a/crates/db_schema/src/impls/private_message.rs b/crates/db_schema/src/impls/private_message.rs index 8370d5d08..e3ad03972 100644 --- a/crates/db_schema/src/impls/private_message.rs +++ b/crates/db_schema/src/impls/private_message.rs @@ -9,7 +9,7 @@ use crate::{ use chrono::{DateTime, Utc}; use diesel::{dsl::insert_into, result::Error, ExpressionMethods, QueryDsl}; use diesel_async::RunQueryDsl; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; use url::Url; #[async_trait] @@ -74,7 +74,7 @@ impl PrivateMessage { pub async fn read_from_apub_id( pool: &mut DbPool<'_>, object_id: Url, - ) -> Result, LemmyError> { + ) -> LemmyResult> { let conn = &mut get_conn(pool).await?; let object_id: DbUrl = object_id.into(); Ok( diff --git a/crates/db_schema/src/utils.rs b/crates/db_schema/src/utils.rs index 465ecb4cd..f0b294c04 100644 --- a/crates/db_schema/src/utils.rs +++ b/crates/db_schema/src/utils.rs @@ -31,7 +31,7 @@ use diesel_migrations::EmbeddedMigrations; use futures_util::{future::BoxFuture, Future, FutureExt}; use i_love_jesus::CursorKey; use lemmy_utils::{ - error::{LemmyError, LemmyErrorExt, LemmyErrorType}, + error::{LemmyErrorExt, LemmyErrorType, LemmyResult}, settings::SETTINGS, }; use once_cell::sync::Lazy; @@ -292,9 +292,7 @@ pub fn diesel_option_overwrite(opt: Option) -> Option> { } } -pub fn diesel_option_overwrite_to_url( - opt: &Option, -) -> Result>, LemmyError> { +pub fn diesel_option_overwrite_to_url(opt: &Option) -> LemmyResult>> { match opt.as_ref().map(String::as_str) { // An empty string is an erase Some("") => Ok(Some(None)), @@ -305,9 +303,7 @@ pub fn diesel_option_overwrite_to_url( } } -pub fn diesel_option_overwrite_to_url_create( - opt: &Option, -) -> Result, LemmyError> { +pub fn diesel_option_overwrite_to_url_create(opt: &Option) -> LemmyResult> { match opt.as_ref().map(String::as_str) { // An empty string is nothing Some("") => Ok(None), @@ -365,7 +361,7 @@ impl ServerCertVerifier for NoCertVerifier { pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!(); -fn run_migrations(db_url: &str) -> Result<(), LemmyError> { +fn run_migrations(db_url: &str) -> LemmyResult<()> { // Needs to be a sync connection let mut conn = PgConnection::establish(db_url).with_context(|| "Error connecting to database")?; @@ -378,7 +374,7 @@ fn run_migrations(db_url: &str) -> Result<(), LemmyError> { Ok(()) } -pub async fn build_db_pool() -> Result { +pub async fn build_db_pool() -> LemmyResult { let db_url = SETTINGS.get_database_url(); // We only support TLS with sslmode=require currently let tls_enabled = db_url.contains("sslmode=require"); diff --git a/crates/routes/src/feeds.rs b/crates/routes/src/feeds.rs index b8ca2d5a6..2c29f192e 100644 --- a/crates/routes/src/feeds.rs +++ b/crates/routes/src/feeds.rs @@ -22,7 +22,7 @@ use lemmy_db_views_actor::{ }; use lemmy_utils::{ cache_header::cache_1hour, - error::{LemmyError, LemmyErrorType}, + error::{LemmyError, LemmyErrorType, LemmyResult}, utils::markdown::{markdown_to_html, sanitize_html}, }; use once_cell::sync::Lazy; @@ -151,7 +151,7 @@ async fn get_feed_data( sort_type: SortType, limit: i64, page: i64, -) -> Result { +) -> LemmyResult { let site_view = SiteView::read_local(&mut context.pool()).await?; check_private_instance(&None, &site_view.local_site)?; @@ -256,7 +256,7 @@ async fn get_feed_user( limit: &i64, page: &i64, user_name: &str, -) -> Result { +) -> LemmyResult { let site_view = SiteView::read_local(&mut context.pool()).await?; let person = Person::read_from_name(&mut context.pool(), user_name, false).await?; @@ -292,7 +292,7 @@ async fn get_feed_community( limit: &i64, page: &i64, community_name: &str, -) -> Result { +) -> LemmyResult { let site_view = SiteView::read_local(&mut context.pool()).await?; let community = Community::read_from_name(&mut context.pool(), community_name, false).await?; if community.visibility != CommunityVisibility::Public { @@ -335,7 +335,7 @@ async fn get_feed_front( limit: &i64, page: &i64, jwt: &str, -) -> Result { +) -> LemmyResult { let site_view = SiteView::read_local(&mut context.pool()).await?; let local_user = local_user_view_from_jwt(jwt, context).await?; @@ -370,7 +370,7 @@ async fn get_feed_front( } #[tracing::instrument(skip_all)] -async fn get_feed_inbox(context: &LemmyContext, jwt: &str) -> Result { +async fn get_feed_inbox(context: &LemmyContext, jwt: &str) -> LemmyResult { let site_view = SiteView::read_local(&mut context.pool()).await?; let local_user = local_user_view_from_jwt(jwt, context).await?; let person_id = local_user.local_user.person_id; @@ -425,7 +425,7 @@ fn create_reply_and_mention_items( replies: Vec, mentions: Vec, protocol_and_hostname: &str, -) -> Result, LemmyError> { +) -> LemmyResult> { let mut reply_items: Vec = replies .iter() .map(|r| { @@ -438,7 +438,7 @@ fn create_reply_and_mention_items( protocol_and_hostname, ) }) - .collect::, LemmyError>>()?; + .collect::>>()?; let mut mention_items: Vec = mentions .iter() @@ -452,7 +452,7 @@ fn create_reply_and_mention_items( protocol_and_hostname, ) }) - .collect::, LemmyError>>()?; + .collect::>>()?; reply_items.append(&mut mention_items); Ok(reply_items) @@ -465,7 +465,7 @@ fn build_item( url: &str, content: &str, protocol_and_hostname: &str, -) -> Result { +) -> LemmyResult { // TODO add images let author_url = format!("{protocol_and_hostname}/u/{creator_name}"); let guid = Some(Guid { @@ -489,10 +489,7 @@ fn build_item( } #[tracing::instrument(skip_all)] -fn create_post_items( - posts: Vec, - protocol_and_hostname: &str, -) -> Result, LemmyError> { +fn create_post_items(posts: Vec, protocol_and_hostname: &str) -> LemmyResult> { let mut items: Vec = Vec::new(); for p in posts { diff --git a/crates/routes/src/lib.rs b/crates/routes/src/lib.rs index ec28fda45..a88225622 100644 --- a/crates/routes/src/lib.rs +++ b/crates/routes/src/lib.rs @@ -1,6 +1,6 @@ use lemmy_api_common::{claims::Claims, context::LemmyContext, utils::check_user_valid}; use lemmy_db_views::structs::LocalUserView; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; pub mod feeds; pub mod images; @@ -8,10 +8,7 @@ pub mod nodeinfo; pub mod webfinger; #[tracing::instrument(skip_all)] -async fn local_user_view_from_jwt( - jwt: &str, - context: &LemmyContext, -) -> Result { +async fn local_user_view_from_jwt(jwt: &str, context: &LemmyContext) -> LemmyResult { let local_user_id = Claims::validate(jwt, context).await?; let local_user_view = LocalUserView::read(&mut context.pool(), local_user_id).await?; check_user_valid(&local_user_view.person)?; diff --git a/crates/routes/src/nodeinfo.rs b/crates/routes/src/nodeinfo.rs index 62082b4c8..b5db4e965 100644 --- a/crates/routes/src/nodeinfo.rs +++ b/crates/routes/src/nodeinfo.rs @@ -5,7 +5,7 @@ use lemmy_db_schema::RegistrationMode; use lemmy_db_views::structs::SiteView; use lemmy_utils::{ cache_header::{cache_1hour, cache_3days}, - error::LemmyError, + error::{LemmyError, LemmyResult}, VERSION, }; use serde::{Deserialize, Serialize}; @@ -24,9 +24,7 @@ pub fn config(cfg: &mut web::ServiceConfig) { ); } -async fn node_info_well_known( - context: web::Data, -) -> Result { +async fn node_info_well_known(context: web::Data) -> LemmyResult { let node_info = NodeInfoWellKnown { links: vec![NodeInfoWellKnownLinks { rel: Url::parse("http://nodeinfo.diaspora.software/ns/schema/2.0")?, diff --git a/crates/routes/src/webfinger.rs b/crates/routes/src/webfinger.rs index 95092b244..36dd97079 100644 --- a/crates/routes/src/webfinger.rs +++ b/crates/routes/src/webfinger.rs @@ -9,7 +9,7 @@ use lemmy_db_schema::{ traits::ApubActor, CommunityVisibility, }; -use lemmy_utils::{cache_header::cache_3days, error::LemmyError}; +use lemmy_utils::{cache_header::cache_3days, error::LemmyResult}; use serde::Deserialize; use std::collections::HashMap; use url::Url; @@ -35,7 +35,7 @@ pub fn config(cfg: &mut web::ServiceConfig) { async fn get_webfinger_response( info: Query, context: Data, -) -> Result { +) -> LemmyResult { let name = extract_webfinger_name(&info.resource, &context)?; let links = if name == context.settings().hostname { diff --git a/crates/utils/src/email.rs b/crates/utils/src/email.rs index 1a786b0ef..7bac7ad67 100644 --- a/crates/utils/src/email.rs +++ b/crates/utils/src/email.rs @@ -1,5 +1,5 @@ use crate::{ - error::{LemmyError, LemmyErrorExt, LemmyErrorType}, + error::{LemmyErrorExt, LemmyErrorType, LemmyResult}, settings::structs::Settings, }; use html2text; @@ -25,7 +25,7 @@ pub async fn send_email( to_username: &str, html: &str, settings: &Settings, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { let email_config = settings.email.clone().ok_or(LemmyErrorType::NoEmailSetup)?; let domain = settings.hostname.clone(); diff --git a/crates/utils/src/error.rs b/crates/utils/src/error.rs index d25845894..cc6897edd 100644 --- a/crates/utils/src/error.rs +++ b/crates/utils/src/error.rs @@ -244,11 +244,11 @@ cfg_if! { } pub trait LemmyErrorExt> { - fn with_lemmy_type(self, error_type: LemmyErrorType) -> Result; + fn with_lemmy_type(self, error_type: LemmyErrorType) -> LemmyResult; } impl> LemmyErrorExt for Result { - fn with_lemmy_type(self, error_type: LemmyErrorType) -> Result { + fn with_lemmy_type(self, error_type: LemmyErrorType) -> LemmyResult { self.map_err(|error| LemmyError { error_type, inner: error.into(), @@ -257,12 +257,12 @@ cfg_if! { } } pub trait LemmyErrorExt2 { - fn with_lemmy_type(self, error_type: LemmyErrorType) -> Result; + fn with_lemmy_type(self, error_type: LemmyErrorType) -> LemmyResult; fn into_anyhow(self) -> Result; } - impl LemmyErrorExt2 for Result { - fn with_lemmy_type(self, error_type: LemmyErrorType) -> Result { + impl LemmyErrorExt2 for LemmyResult { + fn with_lemmy_type(self, error_type: LemmyErrorType) -> LemmyResult { self.map_err(|mut e| { e.error_type = error_type; e diff --git a/crates/utils/src/settings/mod.rs b/crates/utils/src/settings/mod.rs index d0f802e5b..6efa3fdd3 100644 --- a/crates/utils/src/settings/mod.rs +++ b/crates/utils/src/settings/mod.rs @@ -1,4 +1,4 @@ -use crate::{error::LemmyError, location_info}; +use crate::{error::LemmyResult, location_info}; use anyhow::{anyhow, Context}; use deser_hjson::from_str; use once_cell::sync::Lazy; @@ -38,7 +38,7 @@ impl Settings { /// Note: The env var `LEMMY_DATABASE_URL` is parsed in /// `lemmy_db_schema/src/lib.rs::get_database_url_from_env()` /// Warning: Only call this once. - pub(crate) fn init() -> Result { + pub(crate) fn init() -> LemmyResult { let config = from_str::(&Self::read_config_file()?)?; if config.hostname == "unset" { Err(anyhow!("Hostname variable is not set!").into()) @@ -108,7 +108,7 @@ impl Settings { WEBFINGER_REGEX.clone() } - pub fn pictrs_config(&self) -> Result { + pub fn pictrs_config(&self) -> LemmyResult { self .pictrs .clone() diff --git a/crates/utils/src/utils/slurs.rs b/crates/utils/src/utils/slurs.rs index e379ae439..c7c8a88e3 100644 --- a/crates/utils/src/utils/slurs.rs +++ b/crates/utils/src/utils/slurs.rs @@ -1,4 +1,4 @@ -use crate::error::{LemmyError, LemmyErrorExt, LemmyErrorType}; +use crate::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; use regex::{Regex, RegexBuilder}; pub fn remove_slurs(test: &str, slur_regex: &Option) -> String { @@ -39,7 +39,7 @@ pub fn build_slur_regex(regex_str: Option<&str>) -> Option { }) } -pub fn check_slurs(text: &str, slur_regex: &Option) -> Result<(), LemmyError> { +pub fn check_slurs(text: &str, slur_regex: &Option) -> LemmyResult<()> { if let Err(slurs) = slur_check(text, slur_regex) { Err(anyhow::anyhow!("{}", slurs_vec_to_str(&slurs))).with_lemmy_type(LemmyErrorType::Slurs) } else { @@ -47,10 +47,7 @@ pub fn check_slurs(text: &str, slur_regex: &Option) -> Result<(), LemmyEr } } -pub fn check_slurs_opt( - text: &Option, - slur_regex: &Option, -) -> Result<(), LemmyError> { +pub fn check_slurs_opt(text: &Option, slur_regex: &Option) -> LemmyResult<()> { match text { Some(t) => check_slurs(t, slur_regex), None => Ok(()), diff --git a/src/code_migrations.rs b/src/code_migrations.rs index cee02075c..a2325971b 100644 --- a/src/code_migrations.rs +++ b/src/code_migrations.rs @@ -34,14 +34,14 @@ use lemmy_db_schema::{ traits::Crud, utils::{get_conn, naive_now, DbPool}, }; -use lemmy_utils::{error::LemmyError, settings::structs::Settings}; +use lemmy_utils::{error::LemmyResult, settings::structs::Settings}; use tracing::info; use url::Url; pub async fn run_advanced_migrations( pool: &mut DbPool<'_>, settings: &Settings, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { let protocol_and_hostname = &settings.get_protocol_and_hostname(); user_updates_2020_04_02(pool, protocol_and_hostname).await?; community_updates_2020_04_02(pool, protocol_and_hostname).await?; @@ -60,7 +60,7 @@ pub async fn run_advanced_migrations( async fn user_updates_2020_04_02( pool: &mut DbPool<'_>, protocol_and_hostname: &str, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { use lemmy_db_schema::schema::person::dsl::{actor_id, local, person}; let conn = &mut get_conn(pool).await?; @@ -99,7 +99,7 @@ async fn user_updates_2020_04_02( async fn community_updates_2020_04_02( pool: &mut DbPool<'_>, protocol_and_hostname: &str, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { use lemmy_db_schema::schema::community::dsl::{actor_id, community, local}; let conn = &mut get_conn(pool).await?; @@ -139,7 +139,7 @@ async fn community_updates_2020_04_02( async fn post_updates_2020_04_03( pool: &mut DbPool<'_>, protocol_and_hostname: &str, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { use lemmy_db_schema::schema::post::dsl::{ap_id, local, post}; let conn = &mut get_conn(pool).await?; @@ -177,7 +177,7 @@ async fn post_updates_2020_04_03( async fn comment_updates_2020_04_03( pool: &mut DbPool<'_>, protocol_and_hostname: &str, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { use lemmy_db_schema::schema::comment::dsl::{ap_id, comment, local}; let conn = &mut get_conn(pool).await?; @@ -215,7 +215,7 @@ async fn comment_updates_2020_04_03( async fn private_message_updates_2020_05_05( pool: &mut DbPool<'_>, protocol_and_hostname: &str, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { use lemmy_db_schema::schema::private_message::dsl::{ap_id, local, private_message}; let conn = &mut get_conn(pool).await?; @@ -253,7 +253,7 @@ async fn private_message_updates_2020_05_05( async fn post_thumbnail_url_updates_2020_07_27( pool: &mut DbPool<'_>, protocol_and_hostname: &str, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { use lemmy_db_schema::schema::post::dsl::{post, thumbnail_url}; let conn = &mut get_conn(pool).await?; @@ -282,10 +282,7 @@ async fn post_thumbnail_url_updates_2020_07_27( /// We are setting inbox and follower URLs for local and remote actors alike, because for now /// all federated instances are also Lemmy and use the same URL scheme. -async fn apub_columns_2021_02_02( - pool: &mut DbPool<'_>, - settings: &Settings, -) -> Result<(), LemmyError> { +async fn apub_columns_2021_02_02(pool: &mut DbPool<'_>, settings: &Settings) -> LemmyResult<()> { let conn = &mut get_conn(pool).await?; info!("Running apub_columns_2021_02_02"); { @@ -346,7 +343,7 @@ async fn instance_actor_2022_01_28( pool: &mut DbPool<'_>, protocol_and_hostname: &str, settings: &Settings, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { info!("Running instance_actor_2021_09_29"); if let Ok(site_view) = SiteView::read_local(pool).await { let site = site_view.site; @@ -374,7 +371,7 @@ async fn instance_actor_2022_01_28( /// key field is empty, generate a new keypair. It would be possible to regenerate only the pubkey, /// but thats more complicated and has no benefit, as federation is already broken for these actors. /// https://github.com/LemmyNet/lemmy/issues/2347 -async fn regenerate_public_keys_2022_07_05(pool: &mut DbPool<'_>) -> Result<(), LemmyError> { +async fn regenerate_public_keys_2022_07_05(pool: &mut DbPool<'_>) -> LemmyResult<()> { let conn = &mut get_conn(pool).await?; info!("Running regenerate_public_keys_2022_07_05"); @@ -433,7 +430,7 @@ async fn regenerate_public_keys_2022_07_05(pool: &mut DbPool<'_>) -> Result<(), async fn initialize_local_site_2022_10_10( pool: &mut DbPool<'_>, settings: &Settings, -) -> Result<(), LemmyError> { +) -> LemmyResult<()> { info!("Running initialize_local_site_2022_10_10"); // Check to see if local_site exists diff --git a/src/lib.rs b/src/lib.rs index 777c5d9ce..00960826a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,7 +21,6 @@ use actix_web::{ App, HttpResponse, HttpServer, - Result, }; use actix_web_prom::PrometheusMetricsBuilder; use clap::Parser; @@ -45,7 +44,7 @@ use lemmy_db_schema::{source::secret::Secret, utils::build_db_pool}; use lemmy_federate::{start_stop_federation_workers_cancellable, Opts}; use lemmy_routes::{feeds, images, nodeinfo, webfinger}; use lemmy_utils::{ - error::LemmyError, + error::LemmyResult, rate_limit::RateLimitCell, response::jsonify_plain_text_errors, settings::{structs::Settings, SETTINGS}, @@ -107,7 +106,7 @@ pub struct CmdArgs { } /// Placing the main function in lib.rs allows other crates to import it and embed Lemmy -pub async fn start_lemmy_server(args: CmdArgs) -> Result<(), LemmyError> { +pub async fn start_lemmy_server(args: CmdArgs) -> LemmyResult<()> { // Print version number to log println!("Lemmy v{VERSION}"); @@ -244,7 +243,7 @@ pub async fn start_lemmy_server(args: CmdArgs) -> Result<(), LemmyError> { } /// Creates temporary HTTP server which returns status 503 for all requests. -fn create_startup_server() -> Result { +fn create_startup_server() -> LemmyResult { let startup_server = HttpServer::new(move || { App::new().wrap(ErrorHandlers::new().default_handler(move |req| { let (req, _) = req.into_parts(); @@ -267,7 +266,7 @@ fn create_http_server( federation_config: FederationConfig, settings: Settings, federation_enabled: bool, -) -> Result { +) -> LemmyResult { // this must come before the HttpServer creation // creates a middleware that populates http metrics for each path, method, and status code let prom_api_metrics = PrometheusMetricsBuilder::new("lemmy_api") @@ -349,7 +348,7 @@ fn cors_config(settings: &Settings) -> Cors { } } -pub fn init_logging(opentelemetry_url: &Option) -> Result<(), LemmyError> { +pub fn init_logging(opentelemetry_url: &Option) -> LemmyResult<()> { LogTracer::init()?; let log_description = env::var("RUST_LOG").unwrap_or_else(|_| "info".into()); diff --git a/src/main.rs b/src/main.rs index 1544bcecf..dd17d6eb8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,9 @@ use clap::Parser; use lemmy_server::{init_logging, start_lemmy_server, CmdArgs}; -use lemmy_utils::{error::LemmyError, settings::SETTINGS}; +use lemmy_utils::{error::LemmyResult, settings::SETTINGS}; #[tokio::main] -pub async fn main() -> Result<(), LemmyError> { +pub async fn main() -> LemmyResult<()> { init_logging(&SETTINGS.opentelemetry_url)?; let args = CmdArgs::parse(); diff --git a/src/scheduled_tasks.rs b/src/scheduled_tasks.rs index e225b96ff..8c4cf9311 100644 --- a/src/scheduled_tasks.rs +++ b/src/scheduled_tasks.rs @@ -29,13 +29,13 @@ use lemmy_db_schema::{ utils::{get_conn, naive_now, now, DbPool, DELETED_REPLACEMENT_TEXT}, }; use lemmy_routes::nodeinfo::NodeInfo; -use lemmy_utils::error::{LemmyError, LemmyResult}; +use lemmy_utils::error::LemmyResult; use reqwest_middleware::ClientWithMiddleware; use std::time::Duration; use tracing::{error, info, warn}; /// Schedules various cleanup tasks for lemmy in a background thread -pub async fn setup(context: LemmyContext) -> Result<(), LemmyError> { +pub async fn setup(context: LemmyContext) -> LemmyResult<()> { // Setup the connections let mut scheduler = AsyncScheduler::new(); startup_jobs(&mut context.pool()).await; diff --git a/src/telemetry.rs b/src/telemetry.rs index 2f758e062..a7a1ac809 100644 --- a/src/telemetry.rs +++ b/src/telemetry.rs @@ -1,5 +1,5 @@ use console_subscriber::ConsoleLayer; -use lemmy_utils::error::LemmyError; +use lemmy_utils::error::LemmyResult; use opentelemetry::{ sdk::{propagation::TraceContextPropagator, Resource}, KeyValue, @@ -8,11 +8,7 @@ use opentelemetry_otlp::WithExportConfig; use tracing::{subscriber::set_global_default, Subscriber}; use tracing_subscriber::{filter::Targets, layer::SubscriberExt, registry::LookupSpan, Layer}; -pub fn init_tracing( - opentelemetry_url: &str, - subscriber: S, - targets: Targets, -) -> Result<(), LemmyError> +pub fn init_tracing(opentelemetry_url: &str, subscriber: S, targets: Targets) -> LemmyResult<()> where S: Subscriber + for<'a> LookupSpan<'a> + Send + Sync + 'static, { From 555f7892696c3105186ea8bd02ec8a0fc1001bce Mon Sep 17 00:00:00 2001 From: Dessalines Date: Wed, 10 Apr 2024 10:59:46 -0400 Subject: [PATCH 19/26] Fixing custom_thumbnail updates. (#4593) * Fixing custom_thumbnail updates. * Fixing issue with image posts. * Fixing upgrade deps script. * Adding API tests for custom thumbnails. * Remove pointless todo. * Address PR comments. --------- Co-authored-by: SleeplessOne1917 <28871516+SleeplessOne1917@users.noreply.github.com> --- api_tests/package.json | 10 +- api_tests/pnpm-lock.yaml | 198 +++++++++++++------------- api_tests/src/comment.spec.ts | 4 +- api_tests/src/community.spec.ts | 2 + api_tests/src/follow.spec.ts | 4 +- api_tests/src/image.spec.ts | 79 +++++++++- api_tests/src/post.spec.ts | 4 +- api_tests/src/private_message.spec.ts | 4 +- api_tests/src/shared.ts | 12 ++ api_tests/src/user.spec.ts | 2 + crates/api_common/src/request.rs | 33 +++-- scripts/upgrade_deps.sh | 6 +- 12 files changed, 227 insertions(+), 131 deletions(-) diff --git a/api_tests/package.json b/api_tests/package.json index 75ef362f8..60adac43c 100644 --- a/api_tests/package.json +++ b/api_tests/package.json @@ -20,16 +20,16 @@ }, "devDependencies": { "@types/jest": "^29.5.12", - "@types/node": "^20.11.27", - "@typescript-eslint/eslint-plugin": "^7.2.0", - "@typescript-eslint/parser": "^7.2.0", + "@types/node": "^20.12.4", + "@typescript-eslint/eslint-plugin": "^7.5.0", + "@typescript-eslint/parser": "^7.5.0", "download-file-sync": "^1.0.4", "eslint": "^8.57.0", "eslint-plugin-prettier": "^5.1.3", "jest": "^29.5.0", - "lemmy-js-client": "0.19.4-alpha.13", + "lemmy-js-client": "0.19.4-alpha.16", "prettier": "^3.2.5", "ts-jest": "^29.1.0", - "typescript": "^5.4.2" + "typescript": "^5.4.4" } } diff --git a/api_tests/pnpm-lock.yaml b/api_tests/pnpm-lock.yaml index 7b8c05328..81508d740 100644 --- a/api_tests/pnpm-lock.yaml +++ b/api_tests/pnpm-lock.yaml @@ -9,14 +9,14 @@ devDependencies: specifier: ^29.5.12 version: 29.5.12 '@types/node': - specifier: ^20.11.27 - version: 20.11.27 + specifier: ^20.12.4 + version: 20.12.4 '@typescript-eslint/eslint-plugin': - specifier: ^7.2.0 - version: 7.2.0(@typescript-eslint/parser@7.2.0)(eslint@8.57.0)(typescript@5.4.2) + specifier: ^7.5.0 + version: 7.5.0(@typescript-eslint/parser@7.5.0)(eslint@8.57.0)(typescript@5.4.4) '@typescript-eslint/parser': - specifier: ^7.2.0 - version: 7.2.0(eslint@8.57.0)(typescript@5.4.2) + specifier: ^7.5.0 + version: 7.5.0(eslint@8.57.0)(typescript@5.4.4) download-file-sync: specifier: ^1.0.4 version: 1.0.4 @@ -28,19 +28,19 @@ devDependencies: version: 5.1.3(eslint@8.57.0)(prettier@3.2.5) jest: specifier: ^29.5.0 - version: 29.7.0(@types/node@20.11.27) + version: 29.7.0(@types/node@20.12.4) lemmy-js-client: - specifier: 0.19.4-alpha.13 - version: 0.19.4-alpha.13 + specifier: 0.19.4-alpha.16 + version: 0.19.4-alpha.16 prettier: specifier: ^3.2.5 version: 3.2.5 ts-jest: specifier: ^29.1.0 - version: 29.1.2(@babel/core@7.23.9)(jest@29.7.0)(typescript@5.4.2) + version: 29.1.2(@babel/core@7.23.9)(jest@29.7.0)(typescript@5.4.4) typescript: - specifier: ^5.4.2 - version: 5.4.2 + specifier: ^5.4.4 + version: 5.4.4 packages: @@ -464,7 +464,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 20.11.27 + '@types/node': 20.12.4 chalk: 4.1.2 jest-message-util: 29.7.0 jest-util: 29.7.0 @@ -485,14 +485,14 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.11.27 + '@types/node': 20.12.4 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.9.0 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.11.27) + jest-config: 29.7.0(@types/node@20.12.4) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -520,7 +520,7 @@ packages: dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.11.27 + '@types/node': 20.12.4 jest-mock: 29.7.0 dev: true @@ -547,7 +547,7 @@ packages: dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 20.11.27 + '@types/node': 20.12.4 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -580,7 +580,7 @@ packages: '@jest/transform': 29.7.0 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.22 - '@types/node': 20.11.27 + '@types/node': 20.12.4 chalk: 4.1.2 collect-v8-coverage: 1.0.2 exit: 0.1.2 @@ -668,7 +668,7 @@ packages: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 20.11.27 + '@types/node': 20.12.4 '@types/yargs': 17.0.32 chalk: 4.1.2 dev: true @@ -777,7 +777,7 @@ packages: /@types/graceful-fs@4.1.9: resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} dependencies: - '@types/node': 20.11.27 + '@types/node': 20.12.4 dev: true /@types/istanbul-lib-coverage@2.0.6: @@ -807,8 +807,8 @@ packages: resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} dev: true - /@types/node@20.11.27: - resolution: {integrity: sha512-qyUZfMnCg1KEz57r7pzFtSGt49f6RPkPBis3Vo4PbS7roQEDn22hiHzl/Lo1q4i4hDEgBJmBF/NTNg2XR0HbFg==} + /@types/node@20.12.4: + resolution: {integrity: sha512-E+Fa9z3wSQpzgYQdYmme5X3OTuejnnTx88A6p6vkkJosR3KBz+HpE3kqNm98VE6cfLFcISx7zW7MsJkH6KwbTw==} dependencies: undici-types: 5.26.5 dev: true @@ -831,9 +831,9 @@ packages: '@types/yargs-parser': 21.0.3 dev: true - /@typescript-eslint/eslint-plugin@7.2.0(@typescript-eslint/parser@7.2.0)(eslint@8.57.0)(typescript@5.4.2): - resolution: {integrity: sha512-mdekAHOqS9UjlmyF/LSs6AIEvfceV749GFxoBAjwAv0nkevfKHWQFDMcBZWUiIC5ft6ePWivXoS36aKQ0Cy3sw==} - engines: {node: ^16.0.0 || >=18.0.0} + /@typescript-eslint/eslint-plugin@7.5.0(@typescript-eslint/parser@7.5.0)(eslint@8.57.0)(typescript@5.4.4): + resolution: {integrity: sha512-HpqNTH8Du34nLxbKgVMGljZMG0rJd2O9ecvr2QLYp+7512ty1j42KnsFwspPXg1Vh8an9YImf6CokUBltisZFQ==} + engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: '@typescript-eslint/parser': ^7.0.0 eslint: ^8.56.0 @@ -843,26 +843,26 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 7.2.0(eslint@8.57.0)(typescript@5.4.2) - '@typescript-eslint/scope-manager': 7.2.0 - '@typescript-eslint/type-utils': 7.2.0(eslint@8.57.0)(typescript@5.4.2) - '@typescript-eslint/utils': 7.2.0(eslint@8.57.0)(typescript@5.4.2) - '@typescript-eslint/visitor-keys': 7.2.0 + '@typescript-eslint/parser': 7.5.0(eslint@8.57.0)(typescript@5.4.4) + '@typescript-eslint/scope-manager': 7.5.0 + '@typescript-eslint/type-utils': 7.5.0(eslint@8.57.0)(typescript@5.4.4) + '@typescript-eslint/utils': 7.5.0(eslint@8.57.0)(typescript@5.4.4) + '@typescript-eslint/visitor-keys': 7.5.0 debug: 4.3.4 eslint: 8.57.0 graphemer: 1.4.0 ignore: 5.3.1 natural-compare: 1.4.0 semver: 7.6.0 - ts-api-utils: 1.3.0(typescript@5.4.2) - typescript: 5.4.2 + ts-api-utils: 1.3.0(typescript@5.4.4) + typescript: 5.4.4 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.2): - resolution: {integrity: sha512-5FKsVcHTk6TafQKQbuIVkXq58Fnbkd2wDL4LB7AURN7RUOu1utVP+G8+6u3ZhEroW3DF6hyo3ZEXxgKgp4KeCg==} - engines: {node: ^16.0.0 || >=18.0.0} + /@typescript-eslint/parser@7.5.0(eslint@8.57.0)(typescript@5.4.4): + resolution: {integrity: sha512-cj+XGhNujfD2/wzR1tabNsidnYRaFfEkcULdcIyVBYcXjBvBKOes+mpMBP7hMpOyk+gBcfXsrg4NBGAStQyxjQ==} + engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 typescript: '*' @@ -870,28 +870,28 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 7.2.0 - '@typescript-eslint/types': 7.2.0 - '@typescript-eslint/typescript-estree': 7.2.0(typescript@5.4.2) - '@typescript-eslint/visitor-keys': 7.2.0 + '@typescript-eslint/scope-manager': 7.5.0 + '@typescript-eslint/types': 7.5.0 + '@typescript-eslint/typescript-estree': 7.5.0(typescript@5.4.4) + '@typescript-eslint/visitor-keys': 7.5.0 debug: 4.3.4 eslint: 8.57.0 - typescript: 5.4.2 + typescript: 5.4.4 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/scope-manager@7.2.0: - resolution: {integrity: sha512-Qh976RbQM/fYtjx9hs4XkayYujB/aPwglw2choHmf3zBjB4qOywWSdt9+KLRdHubGcoSwBnXUH2sR3hkyaERRg==} - engines: {node: ^16.0.0 || >=18.0.0} + /@typescript-eslint/scope-manager@7.5.0: + resolution: {integrity: sha512-Z1r7uJY0MDeUlql9XJ6kRVgk/sP11sr3HKXn268HZyqL7i4cEfrdFuSSY/0tUqT37l5zT0tJOsuDP16kio85iA==} + engines: {node: ^18.18.0 || >=20.0.0} dependencies: - '@typescript-eslint/types': 7.2.0 - '@typescript-eslint/visitor-keys': 7.2.0 + '@typescript-eslint/types': 7.5.0 + '@typescript-eslint/visitor-keys': 7.5.0 dev: true - /@typescript-eslint/type-utils@7.2.0(eslint@8.57.0)(typescript@5.4.2): - resolution: {integrity: sha512-xHi51adBHo9O9330J8GQYQwrKBqbIPJGZZVQTHHmy200hvkLZFWJIFtAG/7IYTWUyun6DE6w5InDReePJYJlJA==} - engines: {node: ^16.0.0 || >=18.0.0} + /@typescript-eslint/type-utils@7.5.0(eslint@8.57.0)(typescript@5.4.4): + resolution: {integrity: sha512-A021Rj33+G8mx2Dqh0nMO9GyjjIBK3MqgVgZ2qlKf6CJy51wY/lkkFqq3TqqnH34XyAHUkq27IjlUkWlQRpLHw==} + engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 typescript: '*' @@ -899,55 +899,55 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 7.2.0(typescript@5.4.2) - '@typescript-eslint/utils': 7.2.0(eslint@8.57.0)(typescript@5.4.2) + '@typescript-eslint/typescript-estree': 7.5.0(typescript@5.4.4) + '@typescript-eslint/utils': 7.5.0(eslint@8.57.0)(typescript@5.4.4) debug: 4.3.4 eslint: 8.57.0 - ts-api-utils: 1.3.0(typescript@5.4.2) - typescript: 5.4.2 + ts-api-utils: 1.3.0(typescript@5.4.4) + typescript: 5.4.4 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/types@7.2.0: - resolution: {integrity: sha512-XFtUHPI/abFhm4cbCDc5Ykc8npOKBSJePY3a3s+lwumt7XWJuzP5cZcfZ610MIPHjQjNsOLlYK8ASPaNG8UiyA==} - engines: {node: ^16.0.0 || >=18.0.0} + /@typescript-eslint/types@7.5.0: + resolution: {integrity: sha512-tv5B4IHeAdhR7uS4+bf8Ov3k793VEVHd45viRRkehIUZxm0WF82VPiLgHzA/Xl4TGPg1ZD49vfxBKFPecD5/mg==} + engines: {node: ^18.18.0 || >=20.0.0} dev: true - /@typescript-eslint/typescript-estree@7.2.0(typescript@5.4.2): - resolution: {integrity: sha512-cyxS5WQQCoBwSakpMrvMXuMDEbhOo9bNHHrNcEWis6XHx6KF518tkF1wBvKIn/tpq5ZpUYK7Bdklu8qY0MsFIA==} - engines: {node: ^16.0.0 || >=18.0.0} + /@typescript-eslint/typescript-estree@7.5.0(typescript@5.4.4): + resolution: {integrity: sha512-YklQQfe0Rv2PZEueLTUffiQGKQneiIEKKnfIqPIOxgM9lKSZFCjT5Ad4VqRKj/U4+kQE3fa8YQpskViL7WjdPQ==} + engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@typescript-eslint/types': 7.2.0 - '@typescript-eslint/visitor-keys': 7.2.0 + '@typescript-eslint/types': 7.5.0 + '@typescript-eslint/visitor-keys': 7.5.0 debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 semver: 7.6.0 - ts-api-utils: 1.3.0(typescript@5.4.2) - typescript: 5.4.2 + ts-api-utils: 1.3.0(typescript@5.4.4) + typescript: 5.4.4 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/utils@7.2.0(eslint@8.57.0)(typescript@5.4.2): - resolution: {integrity: sha512-YfHpnMAGb1Eekpm3XRK8hcMwGLGsnT6L+7b2XyRv6ouDuJU1tZir1GS2i0+VXRatMwSI1/UfcyPe53ADkU+IuA==} - engines: {node: ^16.0.0 || >=18.0.0} + /@typescript-eslint/utils@7.5.0(eslint@8.57.0)(typescript@5.4.4): + resolution: {integrity: sha512-3vZl9u0R+/FLQcpy2EHyRGNqAS/ofJ3Ji8aebilfJe+fobK8+LbIFmrHciLVDxjDoONmufDcnVSF38KwMEOjzw==} + engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@types/json-schema': 7.0.15 '@types/semver': 7.5.8 - '@typescript-eslint/scope-manager': 7.2.0 - '@typescript-eslint/types': 7.2.0 - '@typescript-eslint/typescript-estree': 7.2.0(typescript@5.4.2) + '@typescript-eslint/scope-manager': 7.5.0 + '@typescript-eslint/types': 7.5.0 + '@typescript-eslint/typescript-estree': 7.5.0(typescript@5.4.4) eslint: 8.57.0 semver: 7.6.0 transitivePeerDependencies: @@ -955,11 +955,11 @@ packages: - typescript dev: true - /@typescript-eslint/visitor-keys@7.2.0: - resolution: {integrity: sha512-c6EIQRHhcpl6+tO8EMR+kjkkV+ugUNXOmeASA1rlzkd8EPIriavpWoiEz1HR/VLhbVIdhqnV6E7JZm00cBDx2A==} - engines: {node: ^16.0.0 || >=18.0.0} + /@typescript-eslint/visitor-keys@7.5.0: + resolution: {integrity: sha512-mcuHM/QircmA6O7fy6nn2w/3ditQkj+SgtOc8DW3uQ10Yfj42amm2i+6F2K4YAOPNNTmE6iM1ynM6lrSwdendA==} + engines: {node: ^18.18.0 || >=20.0.0} dependencies: - '@typescript-eslint/types': 7.2.0 + '@typescript-eslint/types': 7.5.0 eslint-visitor-keys: 3.4.3 dev: true @@ -1265,7 +1265,7 @@ packages: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} dev: true - /create-jest@29.7.0(@types/node@20.11.27): + /create-jest@29.7.0(@types/node@20.12.4): resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -1274,7 +1274,7 @@ packages: chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@20.11.27) + jest-config: 29.7.0(@types/node@20.12.4) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -1906,7 +1906,7 @@ packages: '@jest/expect': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.11.27 + '@types/node': 20.12.4 chalk: 4.1.2 co: 4.6.0 dedent: 1.5.1 @@ -1927,7 +1927,7 @@ packages: - supports-color dev: true - /jest-cli@29.7.0(@types/node@20.11.27): + /jest-cli@29.7.0(@types/node@20.12.4): resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -1941,10 +1941,10 @@ packages: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.11.27) + create-jest: 29.7.0(@types/node@20.12.4) exit: 0.1.2 import-local: 3.1.0 - jest-config: 29.7.0(@types/node@20.11.27) + jest-config: 29.7.0(@types/node@20.12.4) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -1955,7 +1955,7 @@ packages: - ts-node dev: true - /jest-config@29.7.0(@types/node@20.11.27): + /jest-config@29.7.0(@types/node@20.12.4): resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: @@ -1970,7 +1970,7 @@ packages: '@babel/core': 7.23.9 '@jest/test-sequencer': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.11.27 + '@types/node': 20.12.4 babel-jest: 29.7.0(@babel/core@7.23.9) chalk: 4.1.2 ci-info: 3.9.0 @@ -2030,7 +2030,7 @@ packages: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.11.27 + '@types/node': 20.12.4 jest-mock: 29.7.0 jest-util: 29.7.0 dev: true @@ -2046,7 +2046,7 @@ packages: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.9 - '@types/node': 20.11.27 + '@types/node': 20.12.4 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -2097,7 +2097,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 20.11.27 + '@types/node': 20.12.4 jest-util: 29.7.0 dev: true @@ -2152,7 +2152,7 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.11.27 + '@types/node': 20.12.4 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -2183,7 +2183,7 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.11.27 + '@types/node': 20.12.4 chalk: 4.1.2 cjs-module-lexer: 1.2.3 collect-v8-coverage: 1.0.2 @@ -2235,7 +2235,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 20.11.27 + '@types/node': 20.12.4 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -2260,7 +2260,7 @@ packages: dependencies: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.11.27 + '@types/node': 20.12.4 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -2272,13 +2272,13 @@ packages: resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@types/node': 20.11.27 + '@types/node': 20.12.4 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 dev: true - /jest@29.7.0(@types/node@20.11.27): + /jest@29.7.0(@types/node@20.12.4): resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -2291,7 +2291,7 @@ packages: '@jest/core': 29.7.0 '@jest/types': 29.6.3 import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@20.11.27) + jest-cli: 29.7.0(@types/node@20.12.4) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -2357,8 +2357,8 @@ packages: engines: {node: '>=6'} dev: true - /lemmy-js-client@0.19.4-alpha.13: - resolution: {integrity: sha512-ru1dCqPSfOJdsGq7am5J7P7f+/hpyHGhNbCEV/JAZP2U1lGHul32gLpBkilDnStDNdeq52scjKx+3WskRJFGFA==} + /lemmy-js-client@0.19.4-alpha.16: + resolution: {integrity: sha512-9BKCpZeH5+dDkSuYLVPvJnRGOSa3/jBUqYlQH3r1p8TyCCBrxstIC2I+h9dZZtOg4RmK7ShcuZdk9LSMe1ZMyw==} dev: true /leven@3.1.0: @@ -2890,16 +2890,16 @@ packages: is-number: 7.0.0 dev: true - /ts-api-utils@1.3.0(typescript@5.4.2): + /ts-api-utils@1.3.0(typescript@5.4.4): resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} engines: {node: '>=16'} peerDependencies: typescript: '>=4.2.0' dependencies: - typescript: 5.4.2 + typescript: 5.4.4 dev: true - /ts-jest@29.1.2(@babel/core@7.23.9)(jest@29.7.0)(typescript@5.4.2): + /ts-jest@29.1.2(@babel/core@7.23.9)(jest@29.7.0)(typescript@5.4.4): resolution: {integrity: sha512-br6GJoH/WUX4pu7FbZXuWGKGNDuU7b8Uj77g/Sp7puZV6EXzuByl6JrECvm0MzVzSTkSHWTihsXt+5XYER5b+g==} engines: {node: ^16.10.0 || ^18.0.0 || >=20.0.0} hasBin: true @@ -2923,13 +2923,13 @@ packages: '@babel/core': 7.23.9 bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@20.11.27) + jest: 29.7.0(@types/node@20.12.4) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 semver: 7.5.4 - typescript: 5.4.2 + typescript: 5.4.4 yargs-parser: 21.1.1 dev: true @@ -2959,8 +2959,8 @@ packages: engines: {node: '>=10'} dev: true - /typescript@5.4.2: - resolution: {integrity: sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==} + /typescript@5.4.4: + resolution: {integrity: sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw==} engines: {node: '>=14.17'} hasBin: true dev: true diff --git a/api_tests/src/comment.spec.ts b/api_tests/src/comment.spec.ts index de714f687..fc547481c 100644 --- a/api_tests/src/comment.spec.ts +++ b/api_tests/src/comment.spec.ts @@ -53,9 +53,7 @@ beforeAll(async () => { } }); -afterAll(() => { - unfollows(); -}); +afterAll(unfollows); function assertCommentFederation( commentOne?: CommentView, diff --git a/api_tests/src/community.spec.ts b/api_tests/src/community.spec.ts index 02fac3d9a..aa96f563c 100644 --- a/api_tests/src/community.spec.ts +++ b/api_tests/src/community.spec.ts @@ -31,10 +31,12 @@ import { searchPostLocal, longDelay, editCommunity, + unfollows, } from "./shared"; import { EditCommunity, EditSite } from "lemmy-js-client"; beforeAll(setupLogins); +afterAll(unfollows); function assertCommunityFederation( communityOne?: CommunityView, diff --git a/api_tests/src/follow.spec.ts b/api_tests/src/follow.spec.ts index 276213eac..161c7f045 100644 --- a/api_tests/src/follow.spec.ts +++ b/api_tests/src/follow.spec.ts @@ -15,9 +15,7 @@ import { beforeAll(setupLogins); -afterAll(() => { - unfollows(); -}); +afterAll(unfollows); test("Follow local community", async () => { let user = await registerUser(beta, betaUrl); diff --git a/api_tests/src/image.spec.ts b/api_tests/src/image.spec.ts index 3a82b572d..055c498e0 100644 --- a/api_tests/src/image.spec.ts +++ b/api_tests/src/image.spec.ts @@ -15,7 +15,6 @@ import { createCommunity, createPost, deleteAllImages, - delta, epsilon, followCommunity, gamma, @@ -28,14 +27,15 @@ import { setupLogins, waitForPost, unfollows, + editPostThumbnail, + getPost, + waitUntil, } from "./shared"; const downloadFileSync = require("download-file-sync"); beforeAll(setupLogins); -afterAll(() => { - unfollows(); -}); +afterAll(unfollows); test("Upload image and delete it", async () => { // Before running this test, you need to delete all previous images in the DB @@ -252,3 +252,74 @@ test("No image proxying if setting is disabled", async () => { // Make sure the alt text got federated expect(post.post_view.post.alt_text).toBe(betaPost.post.alt_text); }); + +test("Make regular post, and give it a custom thumbnail", async () => { + const uploadForm1: UploadImage = { + image: Buffer.from("testRegular1"), + }; + const upload1 = await alphaImage.uploadImage(uploadForm1); + + const community = await createCommunity(alphaImage); + + // Use wikipedia since it has an opengraph image + const wikipediaUrl = "https://wikipedia.org/"; + + let post = await createPost( + alphaImage, + community.community_view.community.id, + wikipediaUrl, + ); + + // Wait for the metadata to get fetched, since this is backgrounded now + post = await waitUntil( + () => getPost(alphaImage, post.post_view.post.id), + p => p.post_view.post.thumbnail_url != undefined, + ); + expect(post.post_view.post.url).toBe(wikipediaUrl); + expect(post.post_view.post.thumbnail_url).toBeDefined(); + + // Edit the thumbnail + await editPostThumbnail(alphaImage, post.post_view.post, upload1.url!); + + post = await waitUntil( + () => getPost(alphaImage, post.post_view.post.id), + p => p.post_view.post.thumbnail_url == upload1.url, + ); + + // Make sure the thumbnail got edited. + expect(post.post_view.post.thumbnail_url).toBe(upload1.url); +}); + +test("Create an image post, and make sure a custom thumbnail doesnt overwrite it", async () => { + const uploadForm1: UploadImage = { + image: Buffer.from("test1"), + }; + const upload1 = await alphaImage.uploadImage(uploadForm1); + + const uploadForm2: UploadImage = { + image: Buffer.from("test2"), + }; + const upload2 = await alphaImage.uploadImage(uploadForm2); + + const community = await createCommunity(alphaImage); + + let post = await createPost( + alphaImage, + community.community_view.community.id, + upload1.url, + ); + expect(post.post_view.post.url).toBe(upload1.url); + + // Edit the post + await editPostThumbnail(alphaImage, post.post_view.post, upload2.url!); + + // Wait for the metadata to get fetched + post = await waitUntil( + () => getPost(alphaImage, post.post_view.post.id), + p => p.post_view.post.thumbnail_url == upload1.url, + ); + + // Make sure the new custom thumbnail is ignored, and doesn't overwrite the image post + expect(post.post_view.post.url).toBe(upload1.url); + expect(post.post_view.post.thumbnail_url).toBe(upload1.url); +}); diff --git a/api_tests/src/post.spec.ts b/api_tests/src/post.spec.ts index 75f965431..b2ab50222 100644 --- a/api_tests/src/post.spec.ts +++ b/api_tests/src/post.spec.ts @@ -51,9 +51,7 @@ beforeAll(async () => { await unfollows(); }); -afterAll(() => { - unfollows(); -}); +afterAll(unfollows); async function assertPostFederation(postOne: PostView, postTwo: PostView) { // Link metadata is generated in background task and may not be ready yet at this time, diff --git a/api_tests/src/private_message.spec.ts b/api_tests/src/private_message.spec.ts index 063ee05ee..8fd683ff0 100644 --- a/api_tests/src/private_message.spec.ts +++ b/api_tests/src/private_message.spec.ts @@ -21,9 +21,7 @@ beforeAll(async () => { recipient_id = 3; }); -afterAll(() => { - unfollows(); -}); +afterAll(unfollows); test("Create a private message", async () => { let pmRes = await createPrivateMessage(alpha, recipient_id); diff --git a/api_tests/src/shared.ts b/api_tests/src/shared.ts index 723b63887..e363fffa4 100644 --- a/api_tests/src/shared.ts +++ b/api_tests/src/shared.ts @@ -226,6 +226,18 @@ export async function editPost( return api.editPost(form); } +export async function editPostThumbnail( + api: LemmyHttp, + post: Post, + customThumbnail: string, +): Promise { + let form: EditPost = { + post_id: post.id, + custom_thumbnail: customThumbnail, + }; + return api.editPost(form); +} + export async function deletePost( api: LemmyHttp, deleted: boolean, diff --git a/api_tests/src/user.spec.ts b/api_tests/src/user.spec.ts index 5af054918..f44f3cc0a 100644 --- a/api_tests/src/user.spec.ts +++ b/api_tests/src/user.spec.ts @@ -20,11 +20,13 @@ import { getComments, fetchFunction, alphaImage, + unfollows, } from "./shared"; import { LemmyHttp, SaveUserSettings, UploadImage } from "lemmy-js-client"; import { GetPosts } from "lemmy-js-client/dist/types/GetPosts"; beforeAll(setupLogins); +afterAll(unfollows); let apShortname: string; diff --git a/crates/api_common/src/request.rs b/crates/api_common/src/request.rs index fdd29a254..912fbc67e 100644 --- a/crates/api_common/src/request.rs +++ b/crates/api_common/src/request.rs @@ -97,29 +97,46 @@ pub fn generate_post_link_metadata( context: Data, ) { spawn_try_task(async move { + // Decide if the thumbnail should be generated let allow_sensitive = local_site_opt_to_sensitive(&local_site); let page_is_sensitive = post.nsfw; let allow_generate_thumbnail = allow_sensitive || !page_is_sensitive; - let mut thumbnail_url = custom_thumbnail.or_else(|| post.thumbnail_url.map(Into::into)); - let do_generate_thumbnail = thumbnail_url.is_none() && allow_generate_thumbnail; + let do_generate_thumbnail = + allow_generate_thumbnail && custom_thumbnail.is_none() && post.thumbnail_url.is_none(); // Generate local thumbnail only if no thumbnail was federated and 'sensitive' attributes allow it. let metadata = fetch_link_metadata_opt( - post.url.map(Into::into).as_ref(), + post.url.as_ref().map(DbUrl::inner), do_generate_thumbnail, &context, ) .await; - if let Some(thumbnail_url_) = metadata.thumbnail { - thumbnail_url = Some(thumbnail_url_.into()); - } - let thumbnail_url = proxy_image_link_opt_apub(thumbnail_url, &context).await?; + + // If its an image post, it needs to overwrite the thumbnail, and take precedence + let image_url = if metadata + .content_type + .as_ref() + .is_some_and(|content_type| content_type.starts_with("image")) + { + post.url.map(Into::into) + } else { + None + }; + + // Build the thumbnail url based on either the post image url, custom thumbnail, metadata fetch, or existing thumbnail. + let thumbnail_url = image_url + .or(custom_thumbnail) + .or(metadata.thumbnail.map(Into::into)) + .or(post.thumbnail_url.map(Into::into)); + + // Proxy the image fetch if necessary + let proxied_thumbnail_url = proxy_image_link_opt_apub(thumbnail_url, &context).await?; let form = PostUpdateForm { embed_title: Some(metadata.opengraph_data.title), embed_description: Some(metadata.opengraph_data.description), embed_video_url: Some(metadata.opengraph_data.embed_video_url), - thumbnail_url: Some(thumbnail_url), + thumbnail_url: Some(proxied_thumbnail_url), url_content_type: Some(metadata.content_type), ..Default::default() }; diff --git a/scripts/upgrade_deps.sh b/scripts/upgrade_deps.sh index 0c4ae6f0f..b20e9f35c 100755 --- a/scripts/upgrade_deps.sh +++ b/scripts/upgrade_deps.sh @@ -6,9 +6,9 @@ pushd ../ cargo udeps --all-targets # Upgrade deps -cargo upgrade --workspace +cargo upgrade -# Run check -cargo check +# Run clippy +cargo clippy popd From 64760ec960ff4bc1731fba8bfbd64589b1879cd2 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Wed, 10 Apr 2024 11:03:11 -0400 Subject: [PATCH 20/26] Version 0.19.4-beta.3 --- Cargo.lock | 26 +++++++++++++------------- Cargo.toml | 24 ++++++++++++------------ crates/utils/translations | 2 +- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e2561e7a3..6cf47cdd8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2612,7 +2612,7 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "lemmy_api" -version = "0.19.4-beta.2" +version = "0.19.4-beta.3" dependencies = [ "activitypub_federation", "actix-web", @@ -2641,7 +2641,7 @@ dependencies = [ [[package]] name = "lemmy_api_common" -version = "0.19.4-beta.2" +version = "0.19.4-beta.3" dependencies = [ "activitypub_federation", "actix-web", @@ -2679,7 +2679,7 @@ dependencies = [ [[package]] name = "lemmy_api_crud" -version = "0.19.4-beta.2" +version = "0.19.4-beta.3" dependencies = [ "accept-language", "activitypub_federation", @@ -2702,7 +2702,7 @@ dependencies = [ [[package]] name = "lemmy_apub" -version = "0.19.4-beta.2" +version = "0.19.4-beta.3" dependencies = [ "activitypub_federation", "actix-web", @@ -2740,7 +2740,7 @@ dependencies = [ [[package]] name = "lemmy_db_perf" -version = "0.19.4-beta.2" +version = "0.19.4-beta.3" dependencies = [ "anyhow", "clap", @@ -2755,7 +2755,7 @@ dependencies = [ [[package]] name = "lemmy_db_schema" -version = "0.19.4-beta.2" +version = "0.19.4-beta.3" dependencies = [ "activitypub_federation", "anyhow", @@ -2795,7 +2795,7 @@ dependencies = [ [[package]] name = "lemmy_db_views" -version = "0.19.4-beta.2" +version = "0.19.4-beta.3" dependencies = [ "actix-web", "chrono", @@ -2817,7 +2817,7 @@ dependencies = [ [[package]] name = "lemmy_db_views_actor" -version = "0.19.4-beta.2" +version = "0.19.4-beta.3" dependencies = [ "chrono", "diesel", @@ -2837,7 +2837,7 @@ dependencies = [ [[package]] name = "lemmy_db_views_moderator" -version = "0.19.4-beta.2" +version = "0.19.4-beta.3" dependencies = [ "diesel", "diesel-async", @@ -2849,7 +2849,7 @@ dependencies = [ [[package]] name = "lemmy_federate" -version = "0.19.4-beta.2" +version = "0.19.4-beta.3" dependencies = [ "activitypub_federation", "anyhow", @@ -2872,7 +2872,7 @@ dependencies = [ [[package]] name = "lemmy_routes" -version = "0.19.4-beta.2" +version = "0.19.4-beta.3" dependencies = [ "activitypub_federation", "actix-web", @@ -2897,7 +2897,7 @@ dependencies = [ [[package]] name = "lemmy_server" -version = "0.19.4-beta.2" +version = "0.19.4-beta.3" dependencies = [ "activitypub_federation", "actix-cors", @@ -2940,7 +2940,7 @@ dependencies = [ [[package]] name = "lemmy_utils" -version = "0.19.4-beta.2" +version = "0.19.4-beta.3" dependencies = [ "actix-web", "anyhow", diff --git a/Cargo.toml b/Cargo.toml index 8175cd68f..3ecba6d04 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace.package] -version = "0.19.4-beta.2" +version = "0.19.4-beta.3" edition = "2021" description = "A link aggregator for the fediverse" license = "AGPL-3.0" @@ -88,17 +88,17 @@ unused_self = "deny" unwrap_used = "deny" [workspace.dependencies] -lemmy_api = { version = "=0.19.4-beta.2", path = "./crates/api" } -lemmy_api_crud = { version = "=0.19.4-beta.2", path = "./crates/api_crud" } -lemmy_apub = { version = "=0.19.4-beta.2", path = "./crates/apub" } -lemmy_utils = { version = "=0.19.4-beta.2", path = "./crates/utils", default-features = false } -lemmy_db_schema = { version = "=0.19.4-beta.2", path = "./crates/db_schema" } -lemmy_api_common = { version = "=0.19.4-beta.2", path = "./crates/api_common" } -lemmy_routes = { version = "=0.19.4-beta.2", path = "./crates/routes" } -lemmy_db_views = { version = "=0.19.4-beta.2", path = "./crates/db_views" } -lemmy_db_views_actor = { version = "=0.19.4-beta.2", path = "./crates/db_views_actor" } -lemmy_db_views_moderator = { version = "=0.19.4-beta.2", path = "./crates/db_views_moderator" } -lemmy_federate = { version = "=0.19.4-beta.2", path = "./crates/federate" } +lemmy_api = { version = "=0.19.4-beta.3", path = "./crates/api" } +lemmy_api_crud = { version = "=0.19.4-beta.3", path = "./crates/api_crud" } +lemmy_apub = { version = "=0.19.4-beta.3", path = "./crates/apub" } +lemmy_utils = { version = "=0.19.4-beta.3", path = "./crates/utils", default-features = false } +lemmy_db_schema = { version = "=0.19.4-beta.3", path = "./crates/db_schema" } +lemmy_api_common = { version = "=0.19.4-beta.3", path = "./crates/api_common" } +lemmy_routes = { version = "=0.19.4-beta.3", path = "./crates/routes" } +lemmy_db_views = { version = "=0.19.4-beta.3", path = "./crates/db_views" } +lemmy_db_views_actor = { version = "=0.19.4-beta.3", path = "./crates/db_views_actor" } +lemmy_db_views_moderator = { version = "=0.19.4-beta.3", path = "./crates/db_views_moderator" } +lemmy_federate = { version = "=0.19.4-beta.3", path = "./crates/federate" } activitypub_federation = { version = "0.5.3", default-features = false, features = [ "actix-web", ] } diff --git a/crates/utils/translations b/crates/utils/translations index b3131d688..3d268fbca 160000 --- a/crates/utils/translations +++ b/crates/utils/translations @@ -1 +1 @@ -Subproject commit b3131d6881adb639dc0e298cc7c213c5245091f6 +Subproject commit 3d268fbca717648b1153094ba7eac931791a4fef From 0f6b13a4ec3cfb0496668d3e654cb0c3253c7014 Mon Sep 17 00:00:00 2001 From: dullbananas Date: Thu, 11 Apr 2024 01:32:07 -0700 Subject: [PATCH 21/26] Test coverage (#4596) * update .gitignore * add test-with-coverage.sh * coverage gutters extension comment * move lcov.info to target folder --------- Co-authored-by: SleeplessOne1917 <28871516+SleeplessOne1917@users.noreply.github.com> --- scripts/test-with-coverage.sh | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100755 scripts/test-with-coverage.sh diff --git a/scripts/test-with-coverage.sh b/scripts/test-with-coverage.sh new file mode 100755 index 000000000..e4dfcddf8 --- /dev/null +++ b/scripts/test-with-coverage.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -e + +CWD="$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)" + +cd $CWD/../ + +PACKAGE="$1" +echo "$PACKAGE" + +source scripts/start_dev_db.sh + +# tests are executed in working directory crates/api (or similar), +# so to load the config we need to traverse to the repo root +export LEMMY_CONFIG_LOCATION=../../config/config.hjson +export RUST_BACKTRACE=1 + +cargo install cargo-llvm-cov + +# Create lcov.info file, which is used by things like the Coverage Gutters extension for VS Code +cargo llvm-cov --workspace --all-features --no-fail-fast --lcov --output-path target/lcov.info + +# Add this to do printlns: -- --nocapture + +pg_ctl stop --silent +rm -rf $PGDATA From 3a0c1dca901205efa8b01b4ee1e8c0a5ec172f77 Mon Sep 17 00:00:00 2001 From: Nutomic Date: Thu, 11 Apr 2024 16:05:49 +0200 Subject: [PATCH 22/26] Avoid overwriting local objects via federation (#4611) * Dont allow federation to overwrite local objects * is_local check in apub lib * use imports * fix check, update lib * use verify_is_remote_object() * submodule --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- crates/apub/src/objects/comment.rs | 2 +- crates/apub/src/objects/instance.rs | 2 ++ crates/apub/src/objects/mod.rs | 25 ++++++++++++++++------ crates/apub/src/objects/person.rs | 2 ++ crates/apub/src/objects/post.rs | 2 +- crates/apub/src/objects/private_message.rs | 2 ++ crates/apub/src/protocol/objects/group.rs | 6 ++++-- 9 files changed, 34 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6cf47cdd8..97504600b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,9 +16,9 @@ checksum = "8f27d075294830fcab6f66e320dab524bc6d048f4a151698e153205559113772" [[package]] name = "activitypub_federation" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2a21d597eb09353bc83bea36095e1de0ef5297a6fe16edba3de676898a5ba9" +checksum = "6e16130d5914e6483f99bde5a9bb97ca62e1f359e0b9791c8ebd5c7abd50fe8e" dependencies = [ "activitystreams-kinds", "actix-web", diff --git a/Cargo.toml b/Cargo.toml index 3ecba6d04..4d9485ca5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -99,7 +99,7 @@ lemmy_db_views = { version = "=0.19.4-beta.3", path = "./crates/db_views" } lemmy_db_views_actor = { version = "=0.19.4-beta.3", path = "./crates/db_views_actor" } lemmy_db_views_moderator = { version = "=0.19.4-beta.3", path = "./crates/db_views_moderator" } lemmy_federate = { version = "=0.19.4-beta.3", path = "./crates/federate" } -activitypub_federation = { version = "0.5.3", default-features = false, features = [ +activitypub_federation = { version = "0.5.4", default-features = false, features = [ "actix-web", ] } diesel = "2.1.4" diff --git a/crates/apub/src/objects/comment.rs b/crates/apub/src/objects/comment.rs index e3128e439..ce0430cc0 100644 --- a/crates/apub/src/objects/comment.rs +++ b/crates/apub/src/objects/comment.rs @@ -140,7 +140,7 @@ impl Object for ApubComment { let community = note.community(context).await?; check_apub_id_valid_with_strictness(note.id.inner(), community.local, context).await?; - verify_is_remote_object(note.id.inner(), context.settings())?; + verify_is_remote_object(¬e.id, context)?; verify_person_in_community(¬e.attributed_to, &community, context).await?; let (post, _) = note.get_parents(context).await?; diff --git a/crates/apub/src/objects/instance.rs b/crates/apub/src/objects/instance.rs index 021d2b1cd..145dc63c2 100644 --- a/crates/apub/src/objects/instance.rs +++ b/crates/apub/src/objects/instance.rs @@ -1,3 +1,4 @@ +use super::verify_is_remote_object; use crate::{ activities::GetActorType, check_apub_id_valid_with_strictness, @@ -124,6 +125,7 @@ impl Object for ApubSite { ) -> LemmyResult<()> { check_apub_id_valid_with_strictness(apub.id.inner(), true, data).await?; verify_domains_match(expected_domain, apub.id.inner())?; + verify_is_remote_object(&apub.id, data)?; let local_site_data = local_site_data_cached(&mut data.pool()).await?; let slur_regex = &local_site_opt_to_slur_regex(&local_site_data.local_site); diff --git a/crates/apub/src/objects/mod.rs b/crates/apub/src/objects/mod.rs index 693521ee1..e199ebfad 100644 --- a/crates/apub/src/objects/mod.rs +++ b/crates/apub/src/objects/mod.rs @@ -1,9 +1,16 @@ use crate::protocol::Source; -use activitypub_federation::protocol::values::MediaTypeMarkdownOrHtml; +use activitypub_federation::{ + config::Data, + fetch::object_id::ObjectId, + protocol::values::MediaTypeMarkdownOrHtml, + traits::Object, +}; use anyhow::anyhow; use html2md::parse_html; -use lemmy_utils::{error::LemmyResult, settings::structs::Settings}; -use url::Url; +use lemmy_api_common::context::LemmyContext; +use lemmy_utils::error::LemmyResult; +use serde::Deserialize; +use std::fmt::Debug; pub mod comment; pub mod community; @@ -43,9 +50,15 @@ pub(crate) fn read_from_string_or_source_opt( /// wrapped in Announce. If we simply receive this like any other federated object, overwrite the /// existing, local Post. In particular, it will set the field local = false, so that the object /// can't be fetched from the Activitypub HTTP endpoint anymore (which only serves local objects). -pub(crate) fn verify_is_remote_object(id: &Url, settings: &Settings) -> LemmyResult<()> { - let local_domain = settings.get_hostname_without_port()?; - if id.domain() == Some(&local_domain) { +pub(crate) fn verify_is_remote_object( + id: &ObjectId, + context: &Data, +) -> LemmyResult<()> +where + T: Object + Debug + Send + 'static, + for<'de2> ::Kind: Deserialize<'de2>, +{ + if id.is_local(context) { Err(anyhow!("cant accept local object from remote instance").into()) } else { Ok(()) diff --git a/crates/apub/src/objects/person.rs b/crates/apub/src/objects/person.rs index c99e09f72..1aac170d7 100644 --- a/crates/apub/src/objects/person.rs +++ b/crates/apub/src/objects/person.rs @@ -1,3 +1,4 @@ +use super::verify_is_remote_object; use crate::{ activities::GetActorType, check_apub_id_valid_with_strictness, @@ -137,6 +138,7 @@ impl Object for ApubPerson { check_slurs_opt(&person.name, slur_regex)?; verify_domains_match(person.id.inner(), expected_domain)?; + verify_is_remote_object(&person.id, context)?; check_apub_id_valid_with_strictness(person.id.inner(), false, context).await?; let bio = read_from_string_or_source_opt(&person.summary, &None, &person.source); diff --git a/crates/apub/src/objects/post.rs b/crates/apub/src/objects/post.rs index ba1e3f6a1..55af850e5 100644 --- a/crates/apub/src/objects/post.rs +++ b/crates/apub/src/objects/post.rs @@ -165,7 +165,7 @@ impl Object for ApubPost { // instance from the post author. if !page.is_mod_action(context).await? { verify_domains_match(page.id.inner(), expected_domain)?; - verify_is_remote_object(page.id.inner(), context.settings())?; + verify_is_remote_object(&page.id, context)?; }; let community = page.community(context).await?; diff --git a/crates/apub/src/objects/private_message.rs b/crates/apub/src/objects/private_message.rs index a78324633..4600c997a 100644 --- a/crates/apub/src/objects/private_message.rs +++ b/crates/apub/src/objects/private_message.rs @@ -1,3 +1,4 @@ +use super::verify_is_remote_object; use crate::{ check_apub_id_valid_with_strictness, objects::read_from_string_or_source, @@ -105,6 +106,7 @@ impl Object for ApubPrivateMessage { ) -> LemmyResult<()> { verify_domains_match(note.id.inner(), expected_domain)?; verify_domains_match(note.attributed_to.inner(), note.id.inner())?; + verify_is_remote_object(¬e.id, context)?; check_apub_id_valid_with_strictness(note.id.inner(), false, context).await?; let person = note.attributed_to.dereference(context).await?; diff --git a/crates/apub/src/protocol/objects/group.rs b/crates/apub/src/protocol/objects/group.rs index 30cfafb17..2ed884484 100644 --- a/crates/apub/src/protocol/objects/group.rs +++ b/crates/apub/src/protocol/objects/group.rs @@ -7,7 +7,7 @@ use crate::{ community_outbox::ApubCommunityOutbox, }, local_site_data_cached, - objects::{community::ApubCommunity, read_from_string_or_source_opt}, + objects::{community::ApubCommunity, read_from_string_or_source_opt, verify_is_remote_object}, protocol::{ objects::{Endpoints, LanguageTag}, ImageObject, @@ -15,6 +15,7 @@ use crate::{ }, }; use activitypub_federation::{ + config::Data, fetch::{collection_id::CollectionId, object_id::ObjectId}, kinds::actor::GroupType, protocol::{ @@ -75,10 +76,11 @@ impl Group { pub(crate) async fn verify( &self, expected_domain: &Url, - context: &LemmyContext, + context: &Data, ) -> LemmyResult<()> { check_apub_id_valid_with_strictness(self.id.inner(), true, context).await?; verify_domains_match(expected_domain, self.id.inner())?; + verify_is_remote_object(&self.id, context)?; let local_site_data = local_site_data_cached(&mut context.pool()).await?; let slur_regex = &local_site_opt_to_slur_regex(&local_site_data.local_site); From d075acce43f2bd1c88f34729284c52f757d60cd1 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Tue, 16 Apr 2024 08:48:15 -0400 Subject: [PATCH 23/26] Make all single-fetch database calls return an Option. (#4617) - Diesel ordinarily throws an error when no results are returned for a single fetch, which is a bit confusing. This PR ensures that the missing value cases are all caught, and wrapped with new LemmyErrors, rather than diesel errors. - Fixes #4601 --- crates/api/src/comment/distinguish.rs | 7 +- crates/api/src/comment/like.rs | 9 ++- crates/api/src/comment/list_comment_likes.rs | 6 +- crates/api/src/comment/save.rs | 4 +- crates/api/src/comment_report/create.rs | 9 ++- crates/api/src/comment_report/resolve.rs | 9 ++- crates/api/src/community/add_mod.rs | 4 +- crates/api/src/community/ban.rs | 4 +- crates/api/src/community/block.rs | 4 +- crates/api/src/community/follow.rs | 9 ++- crates/api/src/community/transfer.rs | 4 +- crates/api/src/lib.rs | 4 +- crates/api/src/local_user/add_admin.rs | 4 +- crates/api/src/local_user/ban_person.rs | 6 +- crates/api/src/local_user/block.rs | 12 +++- .../local_user/change_password_after_reset.rs | 5 +- .../src/local_user/generate_totp_secret.rs | 4 +- crates/api/src/local_user/login.rs | 14 ++-- .../notifications/mark_mention_read.rs | 8 ++- .../notifications/mark_reply_read.rs | 8 ++- crates/api/src/local_user/reset_password.rs | 10 +-- crates/api/src/local_user/save_settings.rs | 4 +- crates/api/src/local_user/verify_email.rs | 15 +++-- crates/api/src/post/feature.rs | 6 +- crates/api/src/post/like.rs | 10 ++- crates/api/src/post/list_post_likes.rs | 6 +- crates/api/src/post/lock.rs | 6 +- crates/api/src/post/save.rs | 4 +- crates/api/src/post_report/create.rs | 8 ++- crates/api/src/post_report/resolve.rs | 8 ++- crates/api/src/private_message/mark_read.rs | 8 ++- .../api/src/private_message_report/create.rs | 9 ++- .../api/src/private_message_report/resolve.rs | 5 +- crates/api/src/site/federated_instances.rs | 6 +- crates/api/src/site/leave_admin.rs | 4 +- crates/api/src/site/purge/comment.rs | 6 +- crates/api/src/site/purge/community.rs | 6 +- crates/api/src/site/purge/person.rs | 6 +- crates/api/src/site/purge/post.rs | 6 +- .../site/registration_applications/approve.rs | 12 ++-- crates/api_common/src/build_response.rs | 25 +++++--- crates/api_common/src/claims.rs | 2 +- crates/api_common/src/utils.rs | 18 ++++-- crates/api_crud/src/comment/create.rs | 7 +- crates/api_crud/src/comment/delete.rs | 4 +- crates/api_crud/src/comment/remove.rs | 4 +- crates/api_crud/src/comment/update.rs | 4 +- crates/api_crud/src/community/create.rs | 4 +- crates/api_crud/src/community/list.rs | 6 +- crates/api_crud/src/community/update.rs | 4 +- crates/api_crud/src/post/create.rs | 4 +- crates/api_crud/src/post/delete.rs | 4 +- crates/api_crud/src/post/read.rs | 22 ++++--- crates/api_crud/src/post/remove.rs | 6 +- crates/api_crud/src/post/update.rs | 4 +- crates/api_crud/src/private_message/create.rs | 8 ++- crates/api_crud/src/private_message/delete.rs | 8 ++- crates/api_crud/src/private_message/update.rs | 8 ++- crates/api_crud/src/site/create.rs | 4 +- crates/api_crud/src/site/read.rs | 4 +- crates/api_crud/src/site/update.rs | 8 ++- crates/api_crud/src/user/create.rs | 4 +- crates/apub/src/activities/block/mod.rs | 14 +++- .../activities/community/collection_add.rs | 12 +++- .../activities/community/collection_remove.rs | 9 ++- .../src/activities/community/lock_page.rs | 6 +- .../apub/src/activities/community/report.rs | 9 ++- .../activities/create_or_update/comment.rs | 11 +++- .../src/activities/create_or_update/post.rs | 6 +- crates/apub/src/activities/deletion/mod.rs | 3 +- crates/apub/src/activities/mod.rs | 8 ++- crates/apub/src/api/list_comments.rs | 7 +- crates/apub/src/api/list_posts.rs | 4 +- crates/apub/src/api/read_community.rs | 4 +- crates/apub/src/api/read_person.rs | 8 ++- crates/apub/src/api/resolve_object.rs | 24 +++++-- crates/apub/src/api/search.rs | 6 +- crates/apub/src/api/user_settings_backup.rs | 11 +++- .../apub/src/collections/community_outbox.rs | 6 +- crates/apub/src/fetcher/mod.rs | 10 ++- crates/apub/src/fetcher/post_or_comment.rs | 13 +++- crates/apub/src/http/comment.rs | 15 +++-- crates/apub/src/http/community.rs | 11 +++- crates/apub/src/http/mod.rs | 4 +- crates/apub/src/http/person.rs | 7 +- crates/apub/src/http/post.rs | 11 +++- crates/apub/src/http/site.rs | 8 ++- crates/apub/src/mentions.rs | 17 +++-- crates/apub/src/objects/comment.rs | 16 +++-- crates/apub/src/objects/post.rs | 10 ++- crates/apub/src/objects/private_message.rs | 8 ++- .../activities/community/collection_add.rs | 6 +- .../activities/community/collection_remove.rs | 6 +- .../activities/community/lock_page.rs | 6 +- .../activities/create_or_update/note.rs | 6 +- .../protocol/activities/deletion/delete.rs | 10 ++- crates/apub/src/protocol/objects/note.rs | 10 ++- .../src/aggregates/comment_aggregates.rs | 15 +++-- .../src/aggregates/community_aggregates.rs | 23 +++++-- .../src/aggregates/person_aggregates.rs | 18 ++++-- .../src/aggregates/person_post_aggregates.rs | 6 +- .../src/aggregates/post_aggregates.rs | 51 +++++++++++---- .../src/aggregates/site_aggregates.rs | 21 +++--- crates/db_schema/src/impls/activity.rs | 17 +++-- crates/db_schema/src/impls/comment.rs | 20 +++--- crates/db_schema/src/impls/comment_reply.rs | 16 +++-- crates/db_schema/src/impls/community.rs | 60 +++++++++-------- .../db_schema/src/impls/email_verification.rs | 8 ++- crates/db_schema/src/impls/instance.rs | 13 ++-- crates/db_schema/src/impls/language.rs | 14 ++-- crates/db_schema/src/impls/local_site.rs | 2 +- .../src/impls/local_site_rate_limit.rs | 5 +- .../src/impls/local_user_vote_display_mode.rs | 6 +- crates/db_schema/src/impls/moderator.rs | 17 ++++- .../src/impls/password_reset_request.rs | 10 +-- crates/db_schema/src/impls/person.rs | 37 ++++++----- crates/db_schema/src/impls/person_mention.rs | 7 +- crates/db_schema/src/impls/post.rs | 16 ++--- crates/db_schema/src/impls/private_message.rs | 19 +++--- .../src/impls/registration_application.rs | 6 +- crates/db_schema/src/impls/secret.rs | 7 +- crates/db_schema/src/impls/site.rs | 29 +++++---- crates/db_schema/src/traits.rs | 9 +-- crates/db_schema/src/utils.rs | 11 +++- crates/db_views/src/comment_report_view.rs | 7 +- crates/db_views/src/comment_view.rs | 41 +++++++----- crates/db_views/src/local_user_view.rs | 21 ++++-- crates/db_views/src/post_report_view.rs | 6 +- crates/db_views/src/post_view.rs | 64 +++++++++++-------- .../src/private_message_report_view.rs | 4 +- crates/db_views/src/private_message_view.rs | 4 +- .../src/registration_application_view.rs | 7 +- crates/db_views/src/site_view.rs | 7 +- .../db_views_actor/src/comment_reply_view.rs | 4 +- crates/db_views_actor/src/community_view.rs | 24 ++++--- .../db_views_actor/src/person_mention_view.rs | 4 +- crates/db_views_actor/src/person_view.rs | 22 ++++--- crates/federate/src/util.rs | 1 - crates/routes/src/feeds.rs | 28 ++++++-- crates/routes/src/lib.rs | 6 +- crates/routes/src/nodeinfo.rs | 3 +- crates/routes/src/webfinger.rs | 2 + crates/utils/src/error.rs | 11 ++++ src/code_migrations.rs | 2 +- src/lib.rs | 4 +- src/session_middleware.rs | 2 +- 146 files changed, 1009 insertions(+), 491 deletions(-) diff --git a/crates/api/src/comment/distinguish.rs b/crates/api/src/comment/distinguish.rs index dc2be8ad8..dfd850e89 100644 --- a/crates/api/src/comment/distinguish.rs +++ b/crates/api/src/comment/distinguish.rs @@ -17,7 +17,9 @@ pub async fn distinguish_comment( context: Data, local_user_view: LocalUserView, ) -> LemmyResult> { - let orig_comment = CommentView::read(&mut context.pool(), data.comment_id, None).await?; + let orig_comment = CommentView::read(&mut context.pool(), data.comment_id, None) + .await? + .ok_or(LemmyErrorType::CouldntFindComment)?; check_community_user_action( &local_user_view.person, @@ -54,7 +56,8 @@ pub async fn distinguish_comment( data.comment_id, Some(local_user_view.person.id), ) - .await?; + .await? + .ok_or(LemmyErrorType::CouldntFindComment)?; Ok(Json(CommentResponse { comment_view, diff --git a/crates/api/src/comment/like.rs b/crates/api/src/comment/like.rs index bfa522739..d0aa4a6c2 100644 --- a/crates/api/src/comment/like.rs +++ b/crates/api/src/comment/like.rs @@ -35,7 +35,9 @@ pub async fn like_comment( check_bot_account(&local_user_view.person)?; let comment_id = data.comment_id; - let orig_comment = CommentView::read(&mut context.pool(), comment_id, None).await?; + let orig_comment = CommentView::read(&mut context.pool(), comment_id, None) + .await? + .ok_or(LemmyErrorType::CouldntFindComment)?; check_community_user_action( &local_user_view.person, @@ -46,9 +48,10 @@ pub async fn like_comment( // Add parent poster or commenter to recipients let comment_reply = CommentReply::read_by_comment(&mut context.pool(), comment_id).await; - if let Ok(reply) = comment_reply { + if let Ok(Some(reply)) = comment_reply { let recipient_id = reply.recipient_id; - if let Ok(local_recipient) = LocalUserView::read_person(&mut context.pool(), recipient_id).await + if let Ok(Some(local_recipient)) = + LocalUserView::read_person(&mut context.pool(), recipient_id).await { recipient_ids.push(local_recipient.local_user.id); } diff --git a/crates/api/src/comment/list_comment_likes.rs b/crates/api/src/comment/list_comment_likes.rs index 649ae249d..8c2c9dd32 100644 --- a/crates/api/src/comment/list_comment_likes.rs +++ b/crates/api/src/comment/list_comment_likes.rs @@ -5,7 +5,7 @@ use lemmy_api_common::{ utils::is_mod_or_admin, }; use lemmy_db_views::structs::{CommentView, LocalUserView, VoteView}; -use lemmy_utils::error::LemmyResult; +use lemmy_utils::{error::LemmyResult, LemmyErrorType}; /// Lists likes for a comment #[tracing::instrument(skip(context))] @@ -19,7 +19,9 @@ pub async fn list_comment_likes( data.comment_id, Some(local_user_view.person.id), ) - .await?; + .await? + .ok_or(LemmyErrorType::CouldntFindComment)?; + is_mod_or_admin( &mut context.pool(), &local_user_view.person, diff --git a/crates/api/src/comment/save.rs b/crates/api/src/comment/save.rs index f197ecb4c..f9d649e48 100644 --- a/crates/api/src/comment/save.rs +++ b/crates/api/src/comment/save.rs @@ -33,7 +33,9 @@ pub async fn save_comment( let comment_id = data.comment_id; let person_id = local_user_view.person.id; - let comment_view = CommentView::read(&mut context.pool(), comment_id, Some(person_id)).await?; + let comment_view = CommentView::read(&mut context.pool(), comment_id, Some(person_id)) + .await? + .ok_or(LemmyErrorType::CouldntFindComment)?; Ok(Json(CommentResponse { comment_view, diff --git a/crates/api/src/comment_report/create.rs b/crates/api/src/comment_report/create.rs index de40571fe..c008d1df2 100644 --- a/crates/api/src/comment_report/create.rs +++ b/crates/api/src/comment_report/create.rs @@ -35,7 +35,9 @@ pub async fn create_comment_report( let person_id = local_user_view.person.id; let comment_id = data.comment_id; - let comment_view = CommentView::read(&mut context.pool(), comment_id, None).await?; + let comment_view = CommentView::read(&mut context.pool(), comment_id, None) + .await? + .ok_or(LemmyErrorType::CouldntFindComment)?; check_community_user_action( &local_user_view.person, @@ -58,8 +60,9 @@ pub async fn create_comment_report( .await .with_lemmy_type(LemmyErrorType::CouldntCreateReport)?; - let comment_report_view = - CommentReportView::read(&mut context.pool(), report.id, person_id).await?; + let comment_report_view = CommentReportView::read(&mut context.pool(), report.id, person_id) + .await? + .ok_or(LemmyErrorType::CouldntFindCommentReport)?; // Email the admins if local_site.reports_email_admins { diff --git a/crates/api/src/comment_report/resolve.rs b/crates/api/src/comment_report/resolve.rs index a663fdf74..40aad9569 100644 --- a/crates/api/src/comment_report/resolve.rs +++ b/crates/api/src/comment_report/resolve.rs @@ -17,7 +17,9 @@ pub async fn resolve_comment_report( ) -> LemmyResult> { let report_id = data.report_id; let person_id = local_user_view.person.id; - let report = CommentReportView::read(&mut context.pool(), report_id, person_id).await?; + let report = CommentReportView::read(&mut context.pool(), report_id, person_id) + .await? + .ok_or(LemmyErrorType::CouldntFindCommentReport)?; let person_id = local_user_view.person.id; check_community_mod_action( @@ -39,8 +41,9 @@ pub async fn resolve_comment_report( } let report_id = data.report_id; - let comment_report_view = - CommentReportView::read(&mut context.pool(), report_id, person_id).await?; + let comment_report_view = CommentReportView::read(&mut context.pool(), report_id, person_id) + .await? + .ok_or(LemmyErrorType::CouldntFindCommentReport)?; Ok(Json(CommentReportResponse { comment_report_view, diff --git a/crates/api/src/community/add_mod.rs b/crates/api/src/community/add_mod.rs index 92799fb6b..df6b3fbe4 100644 --- a/crates/api/src/community/add_mod.rs +++ b/crates/api/src/community/add_mod.rs @@ -33,7 +33,9 @@ pub async fn add_mod_to_community( &mut context.pool(), ) .await?; - let community = Community::read(&mut context.pool(), community_id).await?; + let community = Community::read(&mut context.pool(), community_id) + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?; if local_user_view.local_user.admin && !community.local { Err(LemmyErrorType::NotAModerator)? } diff --git a/crates/api/src/community/ban.rs b/crates/api/src/community/ban.rs index 0ad9952df..93cf00415 100644 --- a/crates/api/src/community/ban.rs +++ b/crates/api/src/community/ban.rs @@ -89,7 +89,9 @@ pub async fn ban_from_community( ModBanFromCommunity::create(&mut context.pool(), &form).await?; - let person_view = PersonView::read(&mut context.pool(), data.person_id).await?; + let person_view = PersonView::read(&mut context.pool(), data.person_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPerson)?; ActivityChannel::submit_activity( SendActivityData::BanFromCommunity { diff --git a/crates/api/src/community/block.rs b/crates/api/src/community/block.rs index d5d8a0287..449addf32 100644 --- a/crates/api/src/community/block.rs +++ b/crates/api/src/community/block.rs @@ -51,7 +51,9 @@ pub async fn block_community( } let community_view = - CommunityView::read(&mut context.pool(), community_id, Some(person_id), false).await?; + CommunityView::read(&mut context.pool(), community_id, Some(person_id), false) + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?; ActivityChannel::submit_activity( SendActivityData::FollowCommunity( diff --git a/crates/api/src/community/follow.rs b/crates/api/src/community/follow.rs index 94109192b..853cfde14 100644 --- a/crates/api/src/community/follow.rs +++ b/crates/api/src/community/follow.rs @@ -23,7 +23,9 @@ pub async fn follow_community( context: Data, local_user_view: LocalUserView, ) -> LemmyResult> { - let community = Community::read(&mut context.pool(), data.community_id).await?; + let community = Community::read(&mut context.pool(), data.community_id) + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?; let mut community_follower_form = CommunityFollowerForm { community_id: community.id, person_id: local_user_view.person.id, @@ -62,7 +64,10 @@ pub async fn follow_community( let community_id = data.community_id; let person_id = local_user_view.person.id; let community_view = - CommunityView::read(&mut context.pool(), community_id, Some(person_id), false).await?; + CommunityView::read(&mut context.pool(), community_id, Some(person_id), false) + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?; + let discussion_languages = CommunityLanguage::read(&mut context.pool(), community_id).await?; Ok(Json(CommunityResponse { diff --git a/crates/api/src/community/transfer.rs b/crates/api/src/community/transfer.rs index 399eeadae..5f3a6032e 100644 --- a/crates/api/src/community/transfer.rs +++ b/crates/api/src/community/transfer.rs @@ -79,8 +79,8 @@ pub async fn transfer_community( let person_id = local_user_view.person.id; let community_view = CommunityView::read(&mut context.pool(), community_id, Some(person_id), false) - .await - .with_lemmy_type(LemmyErrorType::CouldntFindCommunity)?; + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?; let community_id = data.community_id; let moderators = CommunityModeratorView::for_community(&mut context.pool(), community_id) diff --git a/crates/api/src/lib.rs b/crates/api/src/lib.rs index 498dff3bd..4eee772c9 100644 --- a/crates/api/src/lib.rs +++ b/crates/api/src/lib.rs @@ -252,7 +252,9 @@ pub async fn local_user_view_from_jwt( let local_user_id = Claims::validate(jwt, context) .await .with_lemmy_type(LemmyErrorType::NotLoggedIn)?; - let local_user_view = LocalUserView::read(&mut context.pool(), local_user_id).await?; + let local_user_view = LocalUserView::read(&mut context.pool(), local_user_id) + .await? + .ok_or(LemmyErrorType::CouldntFindLocalUser)?; check_user_valid(&local_user_view.person)?; Ok(local_user_view) diff --git a/crates/api/src/local_user/add_admin.rs b/crates/api/src/local_user/add_admin.rs index 6ebdbd08f..cd827454e 100644 --- a/crates/api/src/local_user/add_admin.rs +++ b/crates/api/src/local_user/add_admin.rs @@ -26,8 +26,8 @@ pub async fn add_admin( // Make sure that the person_id added is local let added_local_user = LocalUserView::read_person(&mut context.pool(), data.person_id) - .await - .with_lemmy_type(LemmyErrorType::ObjectNotLocal)?; + .await? + .ok_or(LemmyErrorType::ObjectNotLocal)?; let added_admin = LocalUser::update( &mut context.pool(), diff --git a/crates/api/src/local_user/ban_person.rs b/crates/api/src/local_user/ban_person.rs index f0e6ffc26..c31940fba 100644 --- a/crates/api/src/local_user/ban_person.rs +++ b/crates/api/src/local_user/ban_person.rs @@ -49,7 +49,7 @@ pub async fn ban_from_site( // if its a local user, invalidate logins let local_user = LocalUserView::read_person(&mut context.pool(), person.id).await; - if let Ok(local_user) = local_user { + if let Ok(Some(local_user)) = local_user { LoginToken::invalidate_all(&mut context.pool(), local_user.local_user.id).await?; } @@ -70,7 +70,9 @@ pub async fn ban_from_site( ModBan::create(&mut context.pool(), &form).await?; - let person_view = PersonView::read(&mut context.pool(), person.id).await?; + let person_view = PersonView::read(&mut context.pool(), person.id) + .await? + .ok_or(LemmyErrorType::CouldntFindPerson)?; ban_nonlocal_user_from_local_communities( &local_user_view, diff --git a/crates/api/src/local_user/block.rs b/crates/api/src/local_user/block.rs index 46a1e44aa..698703a9b 100644 --- a/crates/api/src/local_user/block.rs +++ b/crates/api/src/local_user/block.rs @@ -30,8 +30,12 @@ pub async fn block_person( target_id, }; - let target_user = LocalUserView::read_person(&mut context.pool(), target_id).await; - if target_user.map(|t| t.local_user.admin) == Ok(true) { + let target_user = LocalUserView::read_person(&mut context.pool(), target_id) + .await + .ok() + .flatten(); + + if target_user.is_some_and(|t| t.local_user.admin) { Err(LemmyErrorType::CantBlockAdmin)? } @@ -45,7 +49,9 @@ pub async fn block_person( .with_lemmy_type(LemmyErrorType::PersonBlockAlreadyExists)?; } - let person_view = PersonView::read(&mut context.pool(), target_id).await?; + let person_view = PersonView::read(&mut context.pool(), target_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPerson)?; Ok(Json(BlockPersonResponse { person_view, blocked: data.block, diff --git a/crates/api/src/local_user/change_password_after_reset.rs b/crates/api/src/local_user/change_password_after_reset.rs index 9d759d7e9..9d693a750 100644 --- a/crates/api/src/local_user/change_password_after_reset.rs +++ b/crates/api/src/local_user/change_password_after_reset.rs @@ -20,8 +20,9 @@ pub async fn change_password_after_reset( // Fetch the user_id from the token let token = data.token.clone(); let local_user_id = PasswordResetRequest::read_from_token(&mut context.pool(), &token) - .await - .map(|p| p.local_user_id)?; + .await? + .ok_or(LemmyErrorType::TokenNotFound)? + .local_user_id; password_length_check(&data.password)?; diff --git a/crates/api/src/local_user/generate_totp_secret.rs b/crates/api/src/local_user/generate_totp_secret.rs index 285fa2ad5..e8bb0284c 100644 --- a/crates/api/src/local_user/generate_totp_secret.rs +++ b/crates/api/src/local_user/generate_totp_secret.rs @@ -17,7 +17,9 @@ pub async fn generate_totp_secret( local_user_view: LocalUserView, context: Data, ) -> LemmyResult> { - let site_view = SiteView::read_local(&mut context.pool()).await?; + let site_view = SiteView::read_local(&mut context.pool()) + .await? + .ok_or(LemmyErrorType::LocalSiteNotSetup)?; if local_user_view.local_user.totp_2fa_enabled { return Err(LemmyErrorType::TotpAlreadyEnabled)?; diff --git a/crates/api/src/local_user/login.rs b/crates/api/src/local_user/login.rs index 8e3301af9..19f84f703 100644 --- a/crates/api/src/local_user/login.rs +++ b/crates/api/src/local_user/login.rs @@ -16,7 +16,7 @@ use lemmy_db_schema::{ RegistrationMode, }; use lemmy_db_views::structs::{LocalUserView, SiteView}; -use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; +use lemmy_utils::error::{LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn login( @@ -24,14 +24,16 @@ pub async fn login( req: HttpRequest, context: Data, ) -> LemmyResult> { - let site_view = SiteView::read_local(&mut context.pool()).await?; + let site_view = SiteView::read_local(&mut context.pool()) + .await? + .ok_or(LemmyErrorType::LocalSiteNotSetup)?; // Fetch that username / email let username_or_email = data.username_or_email.clone(); let local_user_view = LocalUserView::find_by_email_or_name(&mut context.pool(), &username_or_email) - .await - .with_lemmy_type(LemmyErrorType::IncorrectLogin)?; + .await? + .ok_or(LemmyErrorType::IncorrectLogin)?; // Verify the password let valid: bool = verify( @@ -79,7 +81,9 @@ async fn check_registration_application( // Fetch the registration application. If no admin id is present its still pending. Otherwise it // was processed (either accepted or denied). let local_user_id = local_user_view.local_user.id; - let registration = RegistrationApplication::find_by_local_user_id(pool, local_user_id).await?; + let registration = RegistrationApplication::find_by_local_user_id(pool, local_user_id) + .await? + .ok_or(LemmyErrorType::CouldntFindRegistrationApplication)?; if registration.admin_id.is_some() { Err(LemmyErrorType::RegistrationDenied(registration.deny_reason))? } else { diff --git a/crates/api/src/local_user/notifications/mark_mention_read.rs b/crates/api/src/local_user/notifications/mark_mention_read.rs index 9a839b2b4..90c8efb6e 100644 --- a/crates/api/src/local_user/notifications/mark_mention_read.rs +++ b/crates/api/src/local_user/notifications/mark_mention_read.rs @@ -18,7 +18,9 @@ pub async fn mark_person_mention_as_read( local_user_view: LocalUserView, ) -> LemmyResult> { let person_mention_id = data.person_mention_id; - let read_person_mention = PersonMention::read(&mut context.pool(), person_mention_id).await?; + let read_person_mention = PersonMention::read(&mut context.pool(), person_mention_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPersonMention)?; if local_user_view.person.id != read_person_mention.recipient_id { Err(LemmyErrorType::CouldntUpdateComment)? @@ -37,7 +39,9 @@ pub async fn mark_person_mention_as_read( let person_mention_id = read_person_mention.id; let person_id = local_user_view.person.id; let person_mention_view = - PersonMentionView::read(&mut context.pool(), person_mention_id, Some(person_id)).await?; + PersonMentionView::read(&mut context.pool(), person_mention_id, Some(person_id)) + .await? + .ok_or(LemmyErrorType::CouldntFindPersonMention)?; Ok(Json(PersonMentionResponse { person_mention_view, diff --git a/crates/api/src/local_user/notifications/mark_reply_read.rs b/crates/api/src/local_user/notifications/mark_reply_read.rs index 5b263145f..fdcfa5727 100644 --- a/crates/api/src/local_user/notifications/mark_reply_read.rs +++ b/crates/api/src/local_user/notifications/mark_reply_read.rs @@ -18,7 +18,9 @@ pub async fn mark_reply_as_read( local_user_view: LocalUserView, ) -> LemmyResult> { let comment_reply_id = data.comment_reply_id; - let read_comment_reply = CommentReply::read(&mut context.pool(), comment_reply_id).await?; + let read_comment_reply = CommentReply::read(&mut context.pool(), comment_reply_id) + .await? + .ok_or(LemmyErrorType::CouldntFindCommentReply)?; if local_user_view.person.id != read_comment_reply.recipient_id { Err(LemmyErrorType::CouldntUpdateComment)? @@ -38,7 +40,9 @@ pub async fn mark_reply_as_read( let comment_reply_id = read_comment_reply.id; let person_id = local_user_view.person.id; let comment_reply_view = - CommentReplyView::read(&mut context.pool(), comment_reply_id, Some(person_id)).await?; + CommentReplyView::read(&mut context.pool(), comment_reply_id, Some(person_id)) + .await? + .ok_or(LemmyErrorType::CouldntFindCommentReply)?; Ok(Json(CommentReplyResponse { comment_reply_view })) } diff --git a/crates/api/src/local_user/reset_password.rs b/crates/api/src/local_user/reset_password.rs index 414f506ba..edb5adee6 100644 --- a/crates/api/src/local_user/reset_password.rs +++ b/crates/api/src/local_user/reset_password.rs @@ -8,7 +8,7 @@ use lemmy_api_common::{ }; use lemmy_db_schema::source::password_reset_request::PasswordResetRequest; use lemmy_db_views::structs::{LocalUserView, SiteView}; -use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; +use lemmy_utils::error::{LemmyErrorType, LemmyResult}; #[tracing::instrument(skip(context))] pub async fn reset_password( @@ -18,8 +18,8 @@ pub async fn reset_password( // Fetch that email let email = data.email.to_lowercase(); let local_user_view = LocalUserView::find_by_email(&mut context.pool(), &email) - .await - .with_lemmy_type(LemmyErrorType::IncorrectLogin)?; + .await? + .ok_or(LemmyErrorType::IncorrectLogin)?; // Check for too many attempts (to limit potential abuse) let recent_resets_count = PasswordResetRequest::get_recent_password_resets_count( @@ -30,7 +30,9 @@ pub async fn reset_password( if recent_resets_count >= 3 { Err(LemmyErrorType::PasswordResetLimitReached)? } - let site_view = SiteView::read_local(&mut context.pool()).await?; + let site_view = SiteView::read_local(&mut context.pool()) + .await? + .ok_or(LemmyErrorType::LocalSiteNotSetup)?; check_email_verified(&local_user_view, &site_view)?; // Email the pure token to the user. diff --git a/crates/api/src/local_user/save_settings.rs b/crates/api/src/local_user/save_settings.rs index 3fa835f58..0805eb697 100644 --- a/crates/api/src/local_user/save_settings.rs +++ b/crates/api/src/local_user/save_settings.rs @@ -35,7 +35,9 @@ pub async fn save_user_settings( context: Data, local_user_view: LocalUserView, ) -> LemmyResult> { - let site_view = SiteView::read_local(&mut context.pool()).await?; + let site_view = SiteView::read_local(&mut context.pool()) + .await? + .ok_or(LemmyErrorType::LocalSiteNotSetup)?; let slur_regex = local_site_to_slur_regex(&site_view.local_site); let url_blocklist = get_url_blocklist(&context).await?; diff --git a/crates/api/src/local_user/verify_email.rs b/crates/api/src/local_user/verify_email.rs index 94ddb373a..da490bf63 100644 --- a/crates/api/src/local_user/verify_email.rs +++ b/crates/api/src/local_user/verify_email.rs @@ -15,17 +15,19 @@ use lemmy_db_schema::{ RegistrationMode, }; use lemmy_db_views::structs::SiteView; -use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; +use lemmy_utils::error::{LemmyErrorType, LemmyResult}; pub async fn verify_email( data: Json, context: Data, ) -> LemmyResult> { - let site_view = SiteView::read_local(&mut context.pool()).await?; + let site_view = SiteView::read_local(&mut context.pool()) + .await? + .ok_or(LemmyErrorType::LocalSiteNotSetup)?; let token = data.token.clone(); let verification = EmailVerification::read_for_token(&mut context.pool(), &token) - .await - .with_lemmy_type(LemmyErrorType::TokenNotFound)?; + .await? + .ok_or(LemmyErrorType::TokenNotFound)?; let form = LocalUserUpdateForm { // necessary in case this is a new signup @@ -44,7 +46,10 @@ pub async fn verify_email( if site_view.local_site.registration_mode == RegistrationMode::RequireApplication && site_view.local_site.application_email_admins { - let person = Person::read(&mut context.pool(), local_user.person_id).await?; + let person = Person::read(&mut context.pool(), local_user.person_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPerson)?; + send_new_applicant_email_to_admins(&person.name, &mut context.pool(), context.settings()) .await?; } diff --git a/crates/api/src/post/feature.rs b/crates/api/src/post/feature.rs index 566ca3a0b..40cbf6794 100644 --- a/crates/api/src/post/feature.rs +++ b/crates/api/src/post/feature.rs @@ -16,7 +16,7 @@ use lemmy_db_schema::{ PostFeatureType, }; use lemmy_db_views::structs::LocalUserView; -use lemmy_utils::error::LemmyResult; +use lemmy_utils::{error::LemmyResult, LemmyErrorType}; #[tracing::instrument(skip(context))] pub async fn feature_post( @@ -25,7 +25,9 @@ pub async fn feature_post( local_user_view: LocalUserView, ) -> LemmyResult> { let post_id = data.post_id; - let orig_post = Post::read(&mut context.pool(), post_id).await?; + let orig_post = Post::read(&mut context.pool(), post_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPost)?; check_community_mod_action( &local_user_view.person, diff --git a/crates/api/src/post/like.rs b/crates/api/src/post/like.rs index 1cbdba8e2..707874ded 100644 --- a/crates/api/src/post/like.rs +++ b/crates/api/src/post/like.rs @@ -38,7 +38,9 @@ pub async fn like_post( // Check for a community ban let post_id = data.post_id; - let post = Post::read(&mut context.pool(), post_id).await?; + let post = Post::read(&mut context.pool(), post_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPost)?; check_community_user_action( &local_user_view.person, @@ -69,11 +71,15 @@ pub async fn like_post( // Mark the post as read mark_post_as_read(person_id, post_id, &mut context.pool()).await?; + let community = Community::read(&mut context.pool(), post.community_id) + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?; + ActivityChannel::submit_activity( SendActivityData::LikePostOrComment { object_id: post.ap_id, actor: local_user_view.person.clone(), - community: Community::read(&mut context.pool(), post.community_id).await?, + community, score: data.score, }, &context, diff --git a/crates/api/src/post/list_post_likes.rs b/crates/api/src/post/list_post_likes.rs index a9b302f2e..b9b2106b7 100644 --- a/crates/api/src/post/list_post_likes.rs +++ b/crates/api/src/post/list_post_likes.rs @@ -6,7 +6,7 @@ use lemmy_api_common::{ }; use lemmy_db_schema::{source::post::Post, traits::Crud}; use lemmy_db_views::structs::{LocalUserView, VoteView}; -use lemmy_utils::error::LemmyResult; +use lemmy_utils::{error::LemmyResult, LemmyErrorType}; /// Lists likes for a post #[tracing::instrument(skip(context))] @@ -15,7 +15,9 @@ pub async fn list_post_likes( context: Data, local_user_view: LocalUserView, ) -> LemmyResult> { - let post = Post::read(&mut context.pool(), data.post_id).await?; + let post = Post::read(&mut context.pool(), data.post_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPost)?; is_mod_or_admin( &mut context.pool(), &local_user_view.person, diff --git a/crates/api/src/post/lock.rs b/crates/api/src/post/lock.rs index b48c415af..05db8ebbb 100644 --- a/crates/api/src/post/lock.rs +++ b/crates/api/src/post/lock.rs @@ -15,7 +15,7 @@ use lemmy_db_schema::{ traits::Crud, }; use lemmy_db_views::structs::LocalUserView; -use lemmy_utils::error::LemmyResult; +use lemmy_utils::{error::LemmyResult, LemmyErrorType}; #[tracing::instrument(skip(context))] pub async fn lock_post( @@ -24,7 +24,9 @@ pub async fn lock_post( local_user_view: LocalUserView, ) -> LemmyResult> { let post_id = data.post_id; - let orig_post = Post::read(&mut context.pool(), post_id).await?; + let orig_post = Post::read(&mut context.pool(), post_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPost)?; check_community_mod_action( &local_user_view.person, diff --git a/crates/api/src/post/save.rs b/crates/api/src/post/save.rs index 05c7b3589..0876992ad 100644 --- a/crates/api/src/post/save.rs +++ b/crates/api/src/post/save.rs @@ -34,7 +34,9 @@ pub async fn save_post( let post_id = data.post_id; let person_id = local_user_view.person.id; - let post_view = PostView::read(&mut context.pool(), post_id, Some(person_id), false).await?; + let post_view = PostView::read(&mut context.pool(), post_id, Some(person_id), false) + .await? + .ok_or(LemmyErrorType::CouldntFindPost)?; // Mark the post as read mark_post_as_read(person_id, post_id, &mut context.pool()).await?; diff --git a/crates/api/src/post_report/create.rs b/crates/api/src/post_report/create.rs index 590c9af40..72a40f70d 100644 --- a/crates/api/src/post_report/create.rs +++ b/crates/api/src/post_report/create.rs @@ -35,7 +35,9 @@ pub async fn create_post_report( let person_id = local_user_view.person.id; let post_id = data.post_id; - let post_view = PostView::read(&mut context.pool(), post_id, None, false).await?; + let post_view = PostView::read(&mut context.pool(), post_id, None, false) + .await? + .ok_or(LemmyErrorType::CouldntFindPost)?; check_community_user_action( &local_user_view.person, @@ -59,7 +61,9 @@ pub async fn create_post_report( .await .with_lemmy_type(LemmyErrorType::CouldntCreateReport)?; - let post_report_view = PostReportView::read(&mut context.pool(), report.id, person_id).await?; + let post_report_view = PostReportView::read(&mut context.pool(), report.id, person_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPostReport)?; // Email the admins if local_site.reports_email_admins { diff --git a/crates/api/src/post_report/resolve.rs b/crates/api/src/post_report/resolve.rs index a3cb85c6c..428619674 100644 --- a/crates/api/src/post_report/resolve.rs +++ b/crates/api/src/post_report/resolve.rs @@ -17,7 +17,9 @@ pub async fn resolve_post_report( ) -> LemmyResult> { let report_id = data.report_id; let person_id = local_user_view.person.id; - let report = PostReportView::read(&mut context.pool(), report_id, person_id).await?; + let report = PostReportView::read(&mut context.pool(), report_id, person_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPostReport)?; let person_id = local_user_view.person.id; check_community_mod_action( @@ -38,7 +40,9 @@ pub async fn resolve_post_report( .with_lemmy_type(LemmyErrorType::CouldntResolveReport)?; } - let post_report_view = PostReportView::read(&mut context.pool(), report_id, person_id).await?; + let post_report_view = PostReportView::read(&mut context.pool(), report_id, person_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPostReport)?; Ok(Json(PostReportResponse { post_report_view })) } diff --git a/crates/api/src/private_message/mark_read.rs b/crates/api/src/private_message/mark_read.rs index 7c213464b..07e06fe21 100644 --- a/crates/api/src/private_message/mark_read.rs +++ b/crates/api/src/private_message/mark_read.rs @@ -18,7 +18,9 @@ pub async fn mark_pm_as_read( ) -> LemmyResult> { // Checking permissions let private_message_id = data.private_message_id; - let orig_private_message = PrivateMessage::read(&mut context.pool(), private_message_id).await?; + let orig_private_message = PrivateMessage::read(&mut context.pool(), private_message_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPrivateMessage)?; if local_user_view.person.id != orig_private_message.recipient_id { Err(LemmyErrorType::CouldntUpdatePrivateMessage)? } @@ -37,7 +39,9 @@ pub async fn mark_pm_as_read( .await .with_lemmy_type(LemmyErrorType::CouldntUpdatePrivateMessage)?; - let view = PrivateMessageView::read(&mut context.pool(), private_message_id).await?; + let view = PrivateMessageView::read(&mut context.pool(), private_message_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPrivateMessage)?; Ok(Json(PrivateMessageResponse { private_message_view: view, })) diff --git a/crates/api/src/private_message_report/create.rs b/crates/api/src/private_message_report/create.rs index de8ca390f..41ac592ae 100644 --- a/crates/api/src/private_message_report/create.rs +++ b/crates/api/src/private_message_report/create.rs @@ -29,7 +29,9 @@ pub async fn create_pm_report( let person_id = local_user_view.person.id; let private_message_id = data.private_message_id; - let private_message = PrivateMessage::read(&mut context.pool(), private_message_id).await?; + let private_message = PrivateMessage::read(&mut context.pool(), private_message_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPrivateMessage)?; // Make sure that only the recipient of the private message can create a report if person_id != private_message.recipient_id { @@ -47,8 +49,9 @@ pub async fn create_pm_report( .await .with_lemmy_type(LemmyErrorType::CouldntCreateReport)?; - let private_message_report_view = - PrivateMessageReportView::read(&mut context.pool(), report.id).await?; + let private_message_report_view = PrivateMessageReportView::read(&mut context.pool(), report.id) + .await? + .ok_or(LemmyErrorType::CouldntFindPrivateMessageReport)?; // Email the admins if local_site.reports_email_admins { diff --git a/crates/api/src/private_message_report/resolve.rs b/crates/api/src/private_message_report/resolve.rs index 7d821a60c..27847eeaf 100644 --- a/crates/api/src/private_message_report/resolve.rs +++ b/crates/api/src/private_message_report/resolve.rs @@ -28,8 +28,9 @@ pub async fn resolve_pm_report( .with_lemmy_type(LemmyErrorType::CouldntResolveReport)?; } - let private_message_report_view = - PrivateMessageReportView::read(&mut context.pool(), report_id).await?; + let private_message_report_view = PrivateMessageReportView::read(&mut context.pool(), report_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPrivateMessageReport)?; Ok(Json(PrivateMessageReportResponse { private_message_report_view, diff --git a/crates/api/src/site/federated_instances.rs b/crates/api/src/site/federated_instances.rs index 5943cfd9a..66b0ff2c1 100644 --- a/crates/api/src/site/federated_instances.rs +++ b/crates/api/src/site/federated_instances.rs @@ -5,13 +5,15 @@ use lemmy_api_common::{ utils::build_federated_instances, }; use lemmy_db_views::structs::SiteView; -use lemmy_utils::error::LemmyResult; +use lemmy_utils::{error::LemmyResult, LemmyErrorType}; #[tracing::instrument(skip(context))] pub async fn get_federated_instances( context: Data, ) -> LemmyResult> { - let site_view = SiteView::read_local(&mut context.pool()).await?; + let site_view = SiteView::read_local(&mut context.pool()) + .await? + .ok_or(LemmyErrorType::LocalSiteNotSetup)?; let federated_instances = build_federated_instances(&site_view.local_site, &mut context.pool()).await?; diff --git a/crates/api/src/site/leave_admin.rs b/crates/api/src/site/leave_admin.rs index 52b8a32ef..e7a5464f3 100644 --- a/crates/api/src/site/leave_admin.rs +++ b/crates/api/src/site/leave_admin.rs @@ -55,7 +55,9 @@ pub async fn leave_admin( ModAdd::create(&mut context.pool(), &form).await?; // Reread site and admins - let site_view = SiteView::read_local(&mut context.pool()).await?; + let site_view = SiteView::read_local(&mut context.pool()) + .await? + .ok_or(LemmyErrorType::LocalSiteNotSetup)?; let admins = PersonView::admins(&mut context.pool()).await?; let all_languages = Language::read_all(&mut context.pool()).await?; diff --git a/crates/api/src/site/purge/comment.rs b/crates/api/src/site/purge/comment.rs index cbb3637f0..70d95e160 100644 --- a/crates/api/src/site/purge/comment.rs +++ b/crates/api/src/site/purge/comment.rs @@ -15,7 +15,7 @@ use lemmy_db_schema::{ traits::Crud, }; use lemmy_db_views::structs::{CommentView, LocalUserView}; -use lemmy_utils::error::LemmyResult; +use lemmy_utils::{error::LemmyResult, LemmyErrorType}; #[tracing::instrument(skip(context))] pub async fn purge_comment( @@ -29,7 +29,9 @@ pub async fn purge_comment( let comment_id = data.comment_id; // Read the comment to get the post_id and community - let comment_view = CommentView::read(&mut context.pool(), comment_id, None).await?; + let comment_view = CommentView::read(&mut context.pool(), comment_id, None) + .await? + .ok_or(LemmyErrorType::CouldntFindComment)?; let post_id = comment_view.comment.post_id; diff --git a/crates/api/src/site/purge/community.rs b/crates/api/src/site/purge/community.rs index 96c9c19cd..14b250681 100644 --- a/crates/api/src/site/purge/community.rs +++ b/crates/api/src/site/purge/community.rs @@ -16,7 +16,7 @@ use lemmy_db_schema::{ traits::Crud, }; use lemmy_db_views::structs::LocalUserView; -use lemmy_utils::error::LemmyResult; +use lemmy_utils::{error::LemmyResult, LemmyErrorType}; #[tracing::instrument(skip(context))] pub async fn purge_community( @@ -28,7 +28,9 @@ pub async fn purge_community( is_admin(&local_user_view)?; // Read the community to get its images - let community = Community::read(&mut context.pool(), data.community_id).await?; + let community = Community::read(&mut context.pool(), data.community_id) + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?; if let Some(banner) = &community.banner { purge_image_from_pictrs(banner, &context).await.ok(); diff --git a/crates/api/src/site/purge/person.rs b/crates/api/src/site/purge/person.rs index a8233f76d..1b38752c7 100644 --- a/crates/api/src/site/purge/person.rs +++ b/crates/api/src/site/purge/person.rs @@ -16,7 +16,7 @@ use lemmy_db_schema::{ traits::Crud, }; use lemmy_db_views::structs::LocalUserView; -use lemmy_utils::error::LemmyResult; +use lemmy_utils::{error::LemmyResult, LemmyErrorType}; #[tracing::instrument(skip(context))] pub async fn purge_person( @@ -27,7 +27,9 @@ pub async fn purge_person( // Only let admin purge an item is_admin(&local_user_view)?; - let person = Person::read(&mut context.pool(), data.person_id).await?; + let person = Person::read(&mut context.pool(), data.person_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPerson)?; ban_nonlocal_user_from_local_communities( &local_user_view, &person, diff --git a/crates/api/src/site/purge/post.rs b/crates/api/src/site/purge/post.rs index ff34c471a..75cd021d1 100644 --- a/crates/api/src/site/purge/post.rs +++ b/crates/api/src/site/purge/post.rs @@ -16,7 +16,7 @@ use lemmy_db_schema::{ traits::Crud, }; use lemmy_db_views::structs::LocalUserView; -use lemmy_utils::error::LemmyResult; +use lemmy_utils::{error::LemmyResult, LemmyErrorType}; #[tracing::instrument(skip(context))] pub async fn purge_post( @@ -28,7 +28,9 @@ pub async fn purge_post( is_admin(&local_user_view)?; // Read the post to get the community_id - let post = Post::read(&mut context.pool(), data.post_id).await?; + let post = Post::read(&mut context.pool(), data.post_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPost)?; // Purge image if let Some(url) = &post.url { diff --git a/crates/api/src/site/registration_applications/approve.rs b/crates/api/src/site/registration_applications/approve.rs index df3c3b428..0fb55ffc8 100644 --- a/crates/api/src/site/registration_applications/approve.rs +++ b/crates/api/src/site/registration_applications/approve.rs @@ -13,7 +13,7 @@ use lemmy_db_schema::{ utils::diesel_option_overwrite, }; use lemmy_db_views::structs::{LocalUserView, RegistrationApplicationView}; -use lemmy_utils::error::LemmyResult; +use lemmy_utils::{error::LemmyResult, LemmyErrorType}; pub async fn approve_registration_application( data: Json, @@ -45,8 +45,9 @@ pub async fn approve_registration_application( LocalUser::update(&mut context.pool(), approved_user_id, &local_user_form).await?; if data.approve { - let approved_local_user_view = - LocalUserView::read(&mut context.pool(), approved_user_id).await?; + let approved_local_user_view = LocalUserView::read(&mut context.pool(), approved_user_id) + .await? + .ok_or(LemmyErrorType::CouldntFindLocalUser)?; if approved_local_user_view.local_user.email.is_some() { send_application_approved_email(&approved_local_user_view, context.settings()).await?; @@ -54,8 +55,9 @@ pub async fn approve_registration_application( } // Read the view - let registration_application = - RegistrationApplicationView::read(&mut context.pool(), app_id).await?; + let registration_application = RegistrationApplicationView::read(&mut context.pool(), app_id) + .await? + .ok_or(LemmyErrorType::CouldntFindRegistrationApplication)?; Ok(Json(RegistrationApplicationResponse { registration_application, diff --git a/crates/api_common/src/build_response.rs b/crates/api_common/src/build_response.rs index cd55d399c..f77a90882 100644 --- a/crates/api_common/src/build_response.rs +++ b/crates/api_common/src/build_response.rs @@ -27,6 +27,7 @@ use lemmy_db_views_actor::structs::CommunityView; use lemmy_utils::{ error::LemmyResult, utils::{markdown::markdown_to_html, mention::MentionData}, + LemmyErrorType, }; pub async fn build_comment_response( @@ -36,7 +37,9 @@ pub async fn build_comment_response( recipient_ids: Vec, ) -> LemmyResult { let person_id = local_user_view.map(|l| l.person.id); - let comment_view = CommentView::read(&mut context.pool(), comment_id, person_id).await?; + let comment_view = CommentView::read(&mut context.pool(), comment_id, person_id) + .await? + .ok_or(LemmyErrorType::CouldntFindComment)?; Ok(CommentResponse { comment_view, recipient_ids, @@ -58,7 +61,8 @@ pub async fn build_community_response( Some(person_id), is_mod_or_admin, ) - .await?; + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?; let discussion_languages = CommunityLanguage::read(&mut context.pool(), community_id).await?; Ok(Json(CommunityResponse { @@ -82,7 +86,8 @@ pub async fn build_post_response( Some(person.id), is_mod_or_admin, ) - .await?; + .await? + .ok_or(LemmyErrorType::CouldntFindPost)?; Ok(Json(PostResponse { post_view })) } @@ -99,7 +104,9 @@ pub async fn send_local_notifs( let inbox_link = format!("{}/inbox", context.settings().get_protocol_and_hostname()); // Read the comment view to get extra info - let comment_view = CommentView::read(&mut context.pool(), comment_id, None).await?; + let comment_view = CommentView::read(&mut context.pool(), comment_id, None) + .await? + .ok_or(LemmyErrorType::CouldntFindComment)?; let comment = comment_view.comment; let post = comment_view.post; let community = comment_view.community; @@ -111,7 +118,7 @@ pub async fn send_local_notifs( { let mention_name = mention.name.clone(); let user_view = LocalUserView::read_from_name(&mut context.pool(), &mention_name).await; - if let Ok(mention_user_view) = user_view { + if let Ok(Some(mention_user_view)) = user_view { // TODO // At some point, make it so you can't tag the parent creator either // Potential duplication of notifications, one for reply and the other for mention, is handled below by checking recipient ids @@ -146,7 +153,9 @@ pub async fn send_local_notifs( // Send comment_reply to the parent commenter / poster if let Some(parent_comment_id) = comment.parent_comment_id() { - let parent_comment = Comment::read(&mut context.pool(), parent_comment_id).await?; + let parent_comment = Comment::read(&mut context.pool(), parent_comment_id) + .await? + .ok_or(LemmyErrorType::CouldntFindComment)?; // Get the parent commenter local_user let parent_creator_id = parent_comment.creator_id; @@ -165,7 +174,7 @@ pub async fn send_local_notifs( // Don't send a notif to yourself if parent_comment.creator_id != person.id && !check_blocks { let user_view = LocalUserView::read_person(&mut context.pool(), parent_creator_id).await; - if let Ok(parent_user_view) = user_view { + if let Ok(Some(parent_user_view)) = user_view { // Don't duplicate notif if already mentioned by checking recipient ids if !recipient_ids.contains(&parent_user_view.local_user.id) { recipient_ids.push(parent_user_view.local_user.id); @@ -212,7 +221,7 @@ pub async fn send_local_notifs( if post.creator_id != person.id && !check_blocks { let creator_id = post.creator_id; let parent_user = LocalUserView::read_person(&mut context.pool(), creator_id).await; - if let Ok(parent_user_view) = parent_user { + if let Ok(Some(parent_user_view)) = parent_user { if !recipient_ids.contains(&parent_user_view.local_user.id) { recipient_ids.push(parent_user_view.local_user.id); diff --git a/crates/api_common/src/claims.rs b/crates/api_common/src/claims.rs index 19145488a..a926cb0ba 100644 --- a/crates/api_common/src/claims.rs +++ b/crates/api_common/src/claims.rs @@ -99,7 +99,7 @@ mod tests { async fn test_should_not_validate_user_token_after_password_change() { let pool_ = build_db_pool_for_tests().await; let pool = &mut (&pool_).into(); - let secret = Secret::init(pool).await.unwrap(); + let secret = Secret::init(pool).await.unwrap().unwrap(); let context = LemmyContext::create( pool_.clone(), ClientBuilder::new(Client::default()).build(), diff --git a/crates/api_common/src/utils.rs b/crates/api_common/src/utils.rs index 9810e2390..d75469904 100644 --- a/crates/api_common/src/utils.rs +++ b/crates/api_common/src/utils.rs @@ -139,8 +139,8 @@ pub fn is_top_mod( #[tracing::instrument(skip_all)] pub async fn get_post(post_id: PostId, pool: &mut DbPool<'_>) -> LemmyResult { Post::read(pool, post_id) - .await - .with_lemmy_type(LemmyErrorType::CouldntFindPost) + .await? + .ok_or(LemmyErrorType::CouldntFindPost.into()) } #[tracing::instrument(skip_all)] @@ -188,8 +188,8 @@ async fn check_community_deleted_removed( pool: &mut DbPool<'_>, ) -> LemmyResult<()> { let community = Community::read(pool, community_id) - .await - .with_lemmy_type(LemmyErrorType::CouldntFindCommunity)?; + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?; if community.deleted || community.removed { Err(LemmyErrorType::Deleted)? } @@ -660,7 +660,7 @@ pub async fn purge_image_posts_for_person( /// Delete a local_user's images async fn delete_local_user_images(person_id: PersonId, context: &LemmyContext) -> LemmyResult<()> { - if let Ok(local_user) = LocalUserView::read_person(&mut context.pool(), person_id).await { + if let Ok(Some(local_user)) = LocalUserView::read_person(&mut context.pool(), person_id).await { let pictrs_uploads = LocalImage::get_all_by_local_user_id(&mut context.pool(), local_user.local_user.id).await?; @@ -700,7 +700,9 @@ pub async fn remove_user_data( ) -> LemmyResult<()> { let pool = &mut context.pool(); // Purge user images - let person = Person::read(pool, banned_person_id).await?; + let person = Person::read(pool, banned_person_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPerson)?; if let Some(avatar) = person.avatar { purge_image_from_pictrs(&avatar, context).await.ok(); } @@ -813,7 +815,9 @@ pub async fn remove_user_data_in_community( pub async fn purge_user_account(person_id: PersonId, context: &LemmyContext) -> LemmyResult<()> { let pool = &mut context.pool(); - let person = Person::read(pool, person_id).await?; + let person = Person::read(pool, person_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPerson)?; // Delete their local images, if they're a local user delete_local_user_images(person_id, context).await.ok(); diff --git a/crates/api_crud/src/comment/create.rs b/crates/api_crud/src/comment/create.rs index 6b1c4ed30..6493d6803 100644 --- a/crates/api_crud/src/comment/create.rs +++ b/crates/api_crud/src/comment/create.rs @@ -70,7 +70,8 @@ pub async fn create_comment( Comment::read(&mut context.pool(), parent_id).await.ok() } else { None - }; + } + .flatten(); // If there's a parent_id, check to make sure that comment is in that post // Strange issue where sometimes the post ID of the parent comment is incorrect @@ -172,7 +173,7 @@ pub async fn create_comment( let parent_id = parent.id; let comment_reply = CommentReply::read_by_comment_and_person(&mut context.pool(), parent_id, person_id).await; - if let Ok(reply) = comment_reply { + if let Ok(Some(reply)) = comment_reply { CommentReply::update( &mut context.pool(), reply.id, @@ -185,7 +186,7 @@ pub async fn create_comment( // If the parent has PersonMentions mark them as read too let person_mention = PersonMention::read_by_comment_and_person(&mut context.pool(), parent_id, person_id).await; - if let Ok(mention) = person_mention { + if let Ok(Some(mention)) = person_mention { PersonMention::update( &mut context.pool(), mention.id, diff --git a/crates/api_crud/src/comment/delete.rs b/crates/api_crud/src/comment/delete.rs index 00a8ea0c1..2b1a20f89 100644 --- a/crates/api_crud/src/comment/delete.rs +++ b/crates/api_crud/src/comment/delete.rs @@ -21,7 +21,9 @@ pub async fn delete_comment( local_user_view: LocalUserView, ) -> LemmyResult> { let comment_id = data.comment_id; - let orig_comment = CommentView::read(&mut context.pool(), comment_id, None).await?; + let orig_comment = CommentView::read(&mut context.pool(), comment_id, None) + .await? + .ok_or(LemmyErrorType::CouldntFindComment)?; // Dont delete it if its already been deleted. if orig_comment.comment.deleted == data.deleted { diff --git a/crates/api_crud/src/comment/remove.rs b/crates/api_crud/src/comment/remove.rs index 1355a7076..02ae7b9fd 100644 --- a/crates/api_crud/src/comment/remove.rs +++ b/crates/api_crud/src/comment/remove.rs @@ -25,7 +25,9 @@ pub async fn remove_comment( local_user_view: LocalUserView, ) -> LemmyResult> { let comment_id = data.comment_id; - let orig_comment = CommentView::read(&mut context.pool(), comment_id, None).await?; + let orig_comment = CommentView::read(&mut context.pool(), comment_id, None) + .await? + .ok_or(LemmyErrorType::CouldntFindComment)?; check_community_mod_action( &local_user_view.person, diff --git a/crates/api_crud/src/comment/update.rs b/crates/api_crud/src/comment/update.rs index ff6f78804..695ededfe 100644 --- a/crates/api_crud/src/comment/update.rs +++ b/crates/api_crud/src/comment/update.rs @@ -36,7 +36,9 @@ pub async fn update_comment( let local_site = LocalSite::read(&mut context.pool()).await?; let comment_id = data.comment_id; - let orig_comment = CommentView::read(&mut context.pool(), comment_id, None).await?; + let orig_comment = CommentView::read(&mut context.pool(), comment_id, None) + .await? + .ok_or(LemmyErrorType::CouldntFindComment)?; check_community_user_action( &local_user_view.person, diff --git a/crates/api_crud/src/community/create.rs b/crates/api_crud/src/community/create.rs index 32d37d8ef..b0b6bea0e 100644 --- a/crates/api_crud/src/community/create.rs +++ b/crates/api_crud/src/community/create.rs @@ -46,7 +46,9 @@ pub async fn create_community( context: Data, local_user_view: LocalUserView, ) -> LemmyResult> { - let site_view = SiteView::read_local(&mut context.pool()).await?; + let site_view = SiteView::read_local(&mut context.pool()) + .await? + .ok_or(LemmyErrorType::LocalSiteNotSetup)?; let local_site = site_view.local_site; if local_site.community_creation_admin_only && is_admin(&local_user_view).is_err() { diff --git a/crates/api_crud/src/community/list.rs b/crates/api_crud/src/community/list.rs index 9c13ae89f..587b5cdfa 100644 --- a/crates/api_crud/src/community/list.rs +++ b/crates/api_crud/src/community/list.rs @@ -6,7 +6,7 @@ use lemmy_api_common::{ }; use lemmy_db_views::structs::{LocalUserView, SiteView}; use lemmy_db_views_actor::community_view::CommunityQuery; -use lemmy_utils::error::LemmyResult; +use lemmy_utils::{error::LemmyResult, LemmyErrorType}; #[tracing::instrument(skip(context))] pub async fn list_communities( @@ -14,7 +14,9 @@ pub async fn list_communities( context: Data, local_user_view: Option, ) -> LemmyResult> { - let local_site = SiteView::read_local(&mut context.pool()).await?; + let local_site = SiteView::read_local(&mut context.pool()) + .await? + .ok_or(LemmyErrorType::LocalSiteNotSetup)?; let is_admin = local_user_view .as_ref() .map(|luv| is_admin(luv).is_ok()) diff --git a/crates/api_crud/src/community/update.rs b/crates/api_crud/src/community/update.rs index bc0945ba1..33c6a47dd 100644 --- a/crates/api_crud/src/community/update.rs +++ b/crates/api_crud/src/community/update.rs @@ -43,7 +43,9 @@ pub async fn update_community( let description = process_markdown_opt(&data.description, &slur_regex, &url_blocklist, &context).await?; is_valid_body_field(&data.description, false)?; - let old_community = Community::read(&mut context.pool(), data.community_id).await?; + let old_community = Community::read(&mut context.pool(), data.community_id) + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?; replace_image(&data.icon, &old_community.icon, &context).await?; replace_image(&data.banner, &old_community.banner, &context).await?; diff --git a/crates/api_crud/src/post/create.rs b/crates/api_crud/src/post/create.rs index cea0d5a31..266f964fa 100644 --- a/crates/api_crud/src/post/create.rs +++ b/crates/api_crud/src/post/create.rs @@ -85,7 +85,9 @@ pub async fn create_post( .await?; let community_id = data.community_id; - let community = Community::read(&mut context.pool(), community_id).await?; + let community = Community::read(&mut context.pool(), community_id) + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?; if community.posting_restricted_to_mods { let community_id = data.community_id; let is_mod = CommunityModeratorView::is_community_moderator( diff --git a/crates/api_crud/src/post/delete.rs b/crates/api_crud/src/post/delete.rs index e07ff7723..696566c8e 100644 --- a/crates/api_crud/src/post/delete.rs +++ b/crates/api_crud/src/post/delete.rs @@ -21,7 +21,9 @@ pub async fn delete_post( local_user_view: LocalUserView, ) -> LemmyResult> { let post_id = data.post_id; - let orig_post = Post::read(&mut context.pool(), post_id).await?; + let orig_post = Post::read(&mut context.pool(), post_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPost)?; // Dont delete it if its already been deleted. if orig_post.deleted == data.deleted { diff --git a/crates/api_crud/src/post/read.rs b/crates/api_crud/src/post/read.rs index cb4ba7e9f..2a567187f 100644 --- a/crates/api_crud/src/post/read.rs +++ b/crates/api_crud/src/post/read.rs @@ -22,7 +22,9 @@ pub async fn get_post( context: Data, local_user_view: Option, ) -> LemmyResult> { - let local_site = SiteView::read_local(&mut context.pool()).await?; + let local_site = SiteView::read_local(&mut context.pool()) + .await? + .ok_or(LemmyErrorType::LocalSiteNotSetup)?; check_private_instance(&local_user_view, &local_site.local_site)?; @@ -33,15 +35,19 @@ pub async fn get_post( id } else if let Some(comment_id) = data.comment_id { Comment::read(&mut context.pool(), comment_id) - .await - .with_lemmy_type(LemmyErrorType::CouldntFindPost)? + .await? + .ok_or(LemmyErrorType::CouldntFindComment)? .post_id } else { Err(LemmyErrorType::CouldntFindPost)? }; // Check to see if the person is a mod or admin, to show deleted / removed - let community_id = Post::read(&mut context.pool(), post_id).await?.community_id; + let community_id = Post::read(&mut context.pool(), post_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPost)? + .community_id; + let is_mod_or_admin = is_mod_or_admin_opt( &mut context.pool(), local_user_view.as_ref(), @@ -51,8 +57,8 @@ pub async fn get_post( .is_ok(); let post_view = PostView::read(&mut context.pool(), post_id, person_id, is_mod_or_admin) - .await - .with_lemmy_type(LemmyErrorType::CouldntFindPost)?; + .await? + .ok_or(LemmyErrorType::CouldntFindPost)?; // Mark the post as read let post_id = post_view.post.id; @@ -67,8 +73,8 @@ pub async fn get_post( person_id, is_mod_or_admin, ) - .await - .with_lemmy_type(LemmyErrorType::CouldntFindCommunity)?; + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?; // Insert into PersonPostAggregates // to update the read_comments count diff --git a/crates/api_crud/src/post/remove.rs b/crates/api_crud/src/post/remove.rs index 37f3f6148..682ed75d3 100644 --- a/crates/api_crud/src/post/remove.rs +++ b/crates/api_crud/src/post/remove.rs @@ -16,7 +16,7 @@ use lemmy_db_schema::{ traits::{Crud, Reportable}, }; use lemmy_db_views::structs::LocalUserView; -use lemmy_utils::error::LemmyResult; +use lemmy_utils::{error::LemmyResult, LemmyErrorType}; #[tracing::instrument(skip(context))] pub async fn remove_post( @@ -25,7 +25,9 @@ pub async fn remove_post( local_user_view: LocalUserView, ) -> LemmyResult> { let post_id = data.post_id; - let orig_post = Post::read(&mut context.pool(), post_id).await?; + let orig_post = Post::read(&mut context.pool(), post_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPost)?; check_community_mod_action( &local_user_view.person, diff --git a/crates/api_crud/src/post/update.rs b/crates/api_crud/src/post/update.rs index 48a1b6523..8be97f3c1 100644 --- a/crates/api_crud/src/post/update.rs +++ b/crates/api_crud/src/post/update.rs @@ -70,7 +70,9 @@ pub async fn update_post( check_url_scheme(&custom_thumbnail)?; let post_id = data.post_id; - let orig_post = Post::read(&mut context.pool(), post_id).await?; + let orig_post = Post::read(&mut context.pool(), post_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPost)?; check_community_user_action( &local_user_view.person, diff --git a/crates/api_crud/src/private_message/create.rs b/crates/api_crud/src/private_message/create.rs index 1fe4f9b48..e977a6c86 100644 --- a/crates/api_crud/src/private_message/create.rs +++ b/crates/api_crud/src/private_message/create.rs @@ -76,12 +76,16 @@ pub async fn create_private_message( .await .with_lemmy_type(LemmyErrorType::CouldntCreatePrivateMessage)?; - let view = PrivateMessageView::read(&mut context.pool(), inserted_private_message.id).await?; + let view = PrivateMessageView::read(&mut context.pool(), inserted_private_message.id) + .await? + .ok_or(LemmyErrorType::CouldntFindPrivateMessage)?; // Send email to the local recipient, if one exists if view.recipient.local { let recipient_id = data.recipient_id; - let local_recipient = LocalUserView::read_person(&mut context.pool(), recipient_id).await?; + let local_recipient = LocalUserView::read_person(&mut context.pool(), recipient_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPerson)?; let lang = get_interface_language(&local_recipient); let inbox_link = format!("{}/inbox", context.settings().get_protocol_and_hostname()); let sender_name = &local_user_view.person.name; diff --git a/crates/api_crud/src/private_message/delete.rs b/crates/api_crud/src/private_message/delete.rs index 936ff57b8..dc028ff41 100644 --- a/crates/api_crud/src/private_message/delete.rs +++ b/crates/api_crud/src/private_message/delete.rs @@ -20,7 +20,9 @@ pub async fn delete_private_message( ) -> LemmyResult> { // Checking permissions let private_message_id = data.private_message_id; - let orig_private_message = PrivateMessage::read(&mut context.pool(), private_message_id).await?; + let orig_private_message = PrivateMessage::read(&mut context.pool(), private_message_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPrivateMessage)?; if local_user_view.person.id != orig_private_message.creator_id { Err(LemmyErrorType::EditPrivateMessageNotAllowed)? } @@ -45,7 +47,9 @@ pub async fn delete_private_message( ) .await?; - let view = PrivateMessageView::read(&mut context.pool(), private_message_id).await?; + let view = PrivateMessageView::read(&mut context.pool(), private_message_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPrivateMessage)?; Ok(Json(PrivateMessageResponse { private_message_view: view, })) diff --git a/crates/api_crud/src/private_message/update.rs b/crates/api_crud/src/private_message/update.rs index 765a33053..2842fea65 100644 --- a/crates/api_crud/src/private_message/update.rs +++ b/crates/api_crud/src/private_message/update.rs @@ -30,7 +30,9 @@ pub async fn update_private_message( // Checking permissions let private_message_id = data.private_message_id; - let orig_private_message = PrivateMessage::read(&mut context.pool(), private_message_id).await?; + let orig_private_message = PrivateMessage::read(&mut context.pool(), private_message_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPrivateMessage)?; if local_user_view.person.id != orig_private_message.creator_id { Err(LemmyErrorType::EditPrivateMessageNotAllowed)? } @@ -54,7 +56,9 @@ pub async fn update_private_message( .await .with_lemmy_type(LemmyErrorType::CouldntUpdatePrivateMessage)?; - let view = PrivateMessageView::read(&mut context.pool(), private_message_id).await?; + let view = PrivateMessageView::read(&mut context.pool(), private_message_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPrivateMessage)?; ActivityChannel::submit_activity( SendActivityData::UpdatePrivateMessage(view.clone()), diff --git a/crates/api_crud/src/site/create.rs b/crates/api_crud/src/site/create.rs index 1c2fed3ed..466c7ff1d 100644 --- a/crates/api_crud/src/site/create.rs +++ b/crates/api_crud/src/site/create.rs @@ -129,7 +129,9 @@ pub async fn create_site( LocalSiteRateLimit::update(&mut context.pool(), &local_site_rate_limit_form).await?; - let site_view = SiteView::read_local(&mut context.pool()).await?; + let site_view = SiteView::read_local(&mut context.pool()) + .await? + .ok_or(LemmyErrorType::LocalSiteNotSetup)?; let new_taglines = data.taglines.clone(); let taglines = Tagline::replace(&mut context.pool(), local_site.id, new_taglines).await?; diff --git a/crates/api_crud/src/site/read.rs b/crates/api_crud/src/site/read.rs index c8ad866a3..69e82007c 100644 --- a/crates/api_crud/src/site/read.rs +++ b/crates/api_crud/src/site/read.rs @@ -41,7 +41,9 @@ pub async fn get_site( // This data is independent from the user account so we can cache it across requests let mut site_response = CACHE .try_get_with::<_, LemmyError>((), async { - let site_view = SiteView::read_local(&mut context.pool()).await?; + let site_view = SiteView::read_local(&mut context.pool()) + .await? + .ok_or(LemmyErrorType::LocalSiteNotSetup)?; let admins = PersonView::admins(&mut context.pool()).await?; let all_languages = Language::read_all(&mut context.pool()).await?; let discussion_languages = SiteLanguage::read_local_raw(&mut context.pool()).await?; diff --git a/crates/api_crud/src/site/update.rs b/crates/api_crud/src/site/update.rs index adf44fad4..7b44b92a6 100644 --- a/crates/api_crud/src/site/update.rs +++ b/crates/api_crud/src/site/update.rs @@ -52,7 +52,9 @@ pub async fn update_site( context: Data, local_user_view: LocalUserView, ) -> LemmyResult> { - let site_view = SiteView::read_local(&mut context.pool()).await?; + let site_view = SiteView::read_local(&mut context.pool()) + .await? + .ok_or(LemmyErrorType::LocalSiteNotSetup)?; let local_site = site_view.local_site; let site = site_view.site; @@ -181,7 +183,9 @@ pub async fn update_site( let new_taglines = data.taglines.clone(); let taglines = Tagline::replace(&mut context.pool(), local_site.id, new_taglines).await?; - let site_view = SiteView::read_local(&mut context.pool()).await?; + let site_view = SiteView::read_local(&mut context.pool()) + .await? + .ok_or(LemmyErrorType::LocalSiteNotSetup)?; let rate_limit_config = local_site_rate_limit_to_rate_limit_config(&site_view.local_site_rate_limit); diff --git a/crates/api_crud/src/user/create.rs b/crates/api_crud/src/user/create.rs index 1f81d4324..6640e9e53 100644 --- a/crates/api_crud/src/user/create.rs +++ b/crates/api_crud/src/user/create.rs @@ -45,7 +45,9 @@ pub async fn register( req: HttpRequest, context: Data, ) -> LemmyResult> { - let site_view = SiteView::read_local(&mut context.pool()).await?; + let site_view = SiteView::read_local(&mut context.pool()) + .await? + .ok_or(LemmyErrorType::LocalSiteNotSetup)?; let local_site = site_view.local_site; let require_registration_application = local_site.registration_mode == RegistrationMode::RequireApplication; diff --git a/crates/apub/src/activities/block/mod.rs b/crates/apub/src/activities/block/mod.rs index 51d8bf5e0..ced50e2de 100644 --- a/crates/apub/src/activities/block/mod.rs +++ b/crates/apub/src/activities/block/mod.rs @@ -23,7 +23,10 @@ use lemmy_db_schema::{ utils::DbPool, }; use lemmy_db_views::structs::SiteView; -use lemmy_utils::error::{LemmyError, LemmyResult}; +use lemmy_utils::{ + error::{LemmyError, LemmyResult}, + LemmyErrorType, +}; use serde::Deserialize; use url::Url; @@ -134,7 +137,13 @@ pub(crate) async fn send_ban_from_site( expires: Option, context: Data, ) -> LemmyResult<()> { - let site = SiteOrCommunity::Site(SiteView::read_local(&mut context.pool()).await?.site.into()); + let site = SiteOrCommunity::Site( + SiteView::read_local(&mut context.pool()) + .await? + .ok_or(LemmyErrorType::LocalSiteNotSetup)? + .site + .into(), + ); let expires = check_expire_time(expires)?; // if the action affects a local user, federate to other instances @@ -174,6 +183,7 @@ pub(crate) async fn send_ban_from_community( ) -> LemmyResult<()> { let community: ApubCommunity = Community::read(&mut context.pool(), community_id) .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)? .into(); let expires = check_expire_time(data.expires)?; diff --git a/crates/apub/src/activities/community/collection_add.rs b/crates/apub/src/activities/community/collection_add.rs index 34c46cf6b..3d5de4128 100644 --- a/crates/apub/src/activities/community/collection_add.rs +++ b/crates/apub/src/activities/community/collection_add.rs @@ -36,7 +36,10 @@ use lemmy_db_schema::{ }, traits::{Crud, Joinable}, }; -use lemmy_utils::error::{LemmyError, LemmyResult}; +use lemmy_utils::{ + error::{LemmyError, LemmyResult}, + LemmyErrorType, +}; use url::Url; impl CollectionAdd { @@ -126,7 +129,9 @@ impl ActivityHandler for CollectionAdd { async fn receive(self, context: &Data) -> LemmyResult<()> { insert_received_activity(&self.id, context).await?; let (community, collection_type) = - Community::get_by_collection_url(&mut context.pool(), &self.target.into()).await?; + Community::get_by_collection_url(&mut context.pool(), &self.target.into()) + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?; match collection_type { CollectionType::Moderators => { let new_mod = ObjectId::::from(self.object) @@ -183,9 +188,11 @@ pub(crate) async fn send_add_mod_to_community( let actor: ApubPerson = actor.into(); let community: ApubCommunity = Community::read(&mut context.pool(), community_id) .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)? .into(); let updated_mod: ApubPerson = Person::read(&mut context.pool(), updated_mod_id) .await? + .ok_or(LemmyErrorType::CouldntFindPerson)? .into(); if added { CollectionAdd::send_add_mod(&community, &updated_mod, &actor, &context).await @@ -204,6 +211,7 @@ pub(crate) async fn send_feature_post( let post: ApubPost = post.into(); let community = Community::read(&mut context.pool(), post.community_id) .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)? .into(); if featured { CollectionAdd::send_add_featured_post(&community, &post, &actor, &context).await diff --git a/crates/apub/src/activities/community/collection_remove.rs b/crates/apub/src/activities/community/collection_remove.rs index 90df1fd14..634ca526c 100644 --- a/crates/apub/src/activities/community/collection_remove.rs +++ b/crates/apub/src/activities/community/collection_remove.rs @@ -31,7 +31,10 @@ use lemmy_db_schema::{ }, traits::{Crud, Joinable}, }; -use lemmy_utils::error::{LemmyError, LemmyResult}; +use lemmy_utils::{ + error::{LemmyError, LemmyResult}, + LemmyErrorType, +}; use url::Url; impl CollectionRemove { @@ -121,7 +124,9 @@ impl ActivityHandler for CollectionRemove { async fn receive(self, context: &Data) -> LemmyResult<()> { insert_received_activity(&self.id, context).await?; let (community, collection_type) = - Community::get_by_collection_url(&mut context.pool(), &self.target.into()).await?; + Community::get_by_collection_url(&mut context.pool(), &self.target.into()) + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?; match collection_type { CollectionType::Moderators => { let remove_mod = ObjectId::::from(self.object) diff --git a/crates/apub/src/activities/community/lock_page.rs b/crates/apub/src/activities/community/lock_page.rs index ba3e16417..bafb42a4a 100644 --- a/crates/apub/src/activities/community/lock_page.rs +++ b/crates/apub/src/activities/community/lock_page.rs @@ -31,7 +31,10 @@ use lemmy_db_schema::{ }, traits::Crud, }; -use lemmy_utils::error::{LemmyError, LemmyResult}; +use lemmy_utils::{ + error::{LemmyError, LemmyResult}, + LemmyErrorType, +}; use url::Url; #[async_trait::async_trait] @@ -109,6 +112,7 @@ pub(crate) async fn send_lock_post( ) -> LemmyResult<()> { let community: ApubCommunity = Community::read(&mut context.pool(), post.community_id) .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)? .into(); let id = generate_activity_id( LockType::Lock, diff --git a/crates/apub/src/activities/community/report.rs b/crates/apub/src/activities/community/report.rs index 4966add34..d1bec0b75 100644 --- a/crates/apub/src/activities/community/report.rs +++ b/crates/apub/src/activities/community/report.rs @@ -29,7 +29,10 @@ use lemmy_db_schema::{ }, traits::{Crud, Reportable}, }; -use lemmy_utils::error::{LemmyError, LemmyResult}; +use lemmy_utils::{ + error::{LemmyError, LemmyResult}, + LemmyErrorType, +}; use url::Url; impl Report { @@ -67,7 +70,9 @@ impl Report { PostOrComment::Post(p) => p.creator_id, PostOrComment::Comment(c) => c.creator_id, }; - let object_creator = Person::read(&mut context.pool(), object_creator_id).await?; + let object_creator = Person::read(&mut context.pool(), object_creator_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPerson)?; let object_creator_site: Option = Site::read_from_instance_id(&mut context.pool(), object_creator.instance_id) .await? diff --git a/crates/apub/src/activities/create_or_update/comment.rs b/crates/apub/src/activities/create_or_update/comment.rs index 8fbbe42b3..7f1532087 100644 --- a/crates/apub/src/activities/create_or_update/comment.rs +++ b/crates/apub/src/activities/create_or_update/comment.rs @@ -42,6 +42,7 @@ use lemmy_db_schema::{ use lemmy_utils::{ error::{LemmyError, LemmyResult}, utils::mention::scrape_text_for_mentions, + LemmyErrorType, }; use url::Url; @@ -55,11 +56,17 @@ impl CreateOrUpdateNote { ) -> LemmyResult<()> { // TODO: might be helpful to add a comment method to retrieve community directly let post_id = comment.post_id; - let post = Post::read(&mut context.pool(), post_id).await?; + let post = Post::read(&mut context.pool(), post_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPost)?; let community_id = post.community_id; - let person: ApubPerson = Person::read(&mut context.pool(), person_id).await?.into(); + let person: ApubPerson = Person::read(&mut context.pool(), person_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPerson)? + .into(); let community: ApubCommunity = Community::read(&mut context.pool(), community_id) .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)? .into(); let id = generate_activity_id( diff --git a/crates/apub/src/activities/create_or_update/post.rs b/crates/apub/src/activities/create_or_update/post.rs index eb59e054a..2ca7e52cc 100644 --- a/crates/apub/src/activities/create_or_update/post.rs +++ b/crates/apub/src/activities/create_or_update/post.rs @@ -68,9 +68,13 @@ impl CreateOrUpdatePage { ) -> LemmyResult<()> { let post = ApubPost(post); let community_id = post.community_id; - let person: ApubPerson = Person::read(&mut context.pool(), person_id).await?.into(); + let person: ApubPerson = Person::read(&mut context.pool(), person_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPerson)? + .into(); let community: ApubCommunity = Community::read(&mut context.pool(), community_id) .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)? .into(); let create_or_update = diff --git a/crates/apub/src/activities/deletion/mod.rs b/crates/apub/src/activities/deletion/mod.rs index b12532087..c9d268e74 100644 --- a/crates/apub/src/activities/deletion/mod.rs +++ b/crates/apub/src/activities/deletion/mod.rs @@ -39,7 +39,7 @@ use lemmy_db_schema::{ }, traits::Crud, }; -use lemmy_utils::error::LemmyResult; +use lemmy_utils::{error::LemmyResult, LemmyErrorType}; use std::ops::Deref; use url::Url; @@ -87,6 +87,7 @@ pub(crate) async fn send_apub_delete_private_message( let recipient_id = pm.recipient_id; let recipient: ApubPerson = Person::read(&mut context.pool(), recipient_id) .await? + .ok_or(LemmyErrorType::CouldntFindPerson)? .into(); let deletable = DeletableObjects::PrivateMessage(pm.into()); diff --git a/crates/apub/src/activities/mod.rs b/crates/apub/src/activities/mod.rs index 6547b957d..d81e7cabf 100644 --- a/crates/apub/src/activities/mod.rs +++ b/crates/apub/src/activities/mod.rs @@ -245,7 +245,9 @@ pub async fn match_outgoing_activities( CreateOrUpdatePage::send(post, creator_id, CreateOrUpdateType::Update, context).await } DeletePost(post, person, data) => { - let community = Community::read(&mut context.pool(), post.community_id).await?; + let community = Community::read(&mut context.pool(), post.community_id) + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?; send_apub_delete_in_community( person, community, @@ -262,7 +264,9 @@ pub async fn match_outgoing_activities( reason, removed, } => { - let community = Community::read(&mut context.pool(), post.community_id).await?; + let community = Community::read(&mut context.pool(), post.community_id) + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?; send_apub_delete_in_community( moderator, community, diff --git a/crates/apub/src/api/list_comments.rs b/crates/apub/src/api/list_comments.rs index a231b9080..25d197007 100644 --- a/crates/apub/src/api/list_comments.rs +++ b/crates/apub/src/api/list_comments.rs @@ -58,7 +58,12 @@ pub async fn list_comments( // If a parent_id is given, fetch the comment to get the path let parent_path = if let Some(parent_id) = parent_id { - Some(Comment::read(&mut context.pool(), parent_id).await?.path) + Some( + Comment::read(&mut context.pool(), parent_id) + .await? + .ok_or(LemmyErrorType::CouldntFindComment)? + .path, + ) } else { None }; diff --git a/crates/apub/src/api/list_posts.rs b/crates/apub/src/api/list_posts.rs index 87e4bc679..ec5412de8 100644 --- a/crates/apub/src/api/list_posts.rs +++ b/crates/apub/src/api/list_posts.rs @@ -23,7 +23,9 @@ pub async fn list_posts( context: Data, local_user_view: Option, ) -> LemmyResult> { - let local_site = SiteView::read_local(&mut context.pool()).await?; + let local_site = SiteView::read_local(&mut context.pool()) + .await? + .ok_or(LemmyErrorType::LocalSiteNotSetup)?; check_private_instance(&local_user_view, &local_site.local_site)?; diff --git a/crates/apub/src/api/read_community.rs b/crates/apub/src/api/read_community.rs index 0d32a0b49..dae7719ae 100644 --- a/crates/apub/src/api/read_community.rs +++ b/crates/apub/src/api/read_community.rs @@ -56,8 +56,8 @@ pub async fn get_community( person_id, is_mod_or_admin, ) - .await - .with_lemmy_type(LemmyErrorType::CouldntFindCommunity)?; + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?; let moderators = CommunityModeratorView::for_community(&mut context.pool(), community_id) .await diff --git a/crates/apub/src/api/read_person.rs b/crates/apub/src/api/read_person.rs index d4015f62d..0d65ab4f7 100644 --- a/crates/apub/src/api/read_person.rs +++ b/crates/apub/src/api/read_person.rs @@ -26,7 +26,9 @@ pub async fn read_person( Err(LemmyErrorType::NoIdGiven)? } - let local_site = SiteView::read_local(&mut context.pool()).await?; + let local_site = SiteView::read_local(&mut context.pool()) + .await? + .ok_or(LemmyErrorType::LocalSiteNotSetup)?; check_private_instance(&local_user_view, &local_site.local_site)?; @@ -46,7 +48,9 @@ pub async fn read_person( // You don't need to return settings for the user, since this comes back with GetSite // `my_user` - let person_view = PersonView::read(&mut context.pool(), person_details_id).await?; + let person_view = PersonView::read(&mut context.pool(), person_details_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPerson)?; let sort = data.sort; let page = data.page; diff --git a/crates/apub/src/api/resolve_object.rs b/crates/apub/src/api/resolve_object.rs index 6ab98a052..47f6c5d06 100644 --- a/crates/apub/src/api/resolve_object.rs +++ b/crates/apub/src/api/resolve_object.rs @@ -53,20 +53,36 @@ async fn convert_response( match object { Post(p) => { removed_or_deleted = p.deleted || p.removed; - res.post = Some(PostView::read(pool, p.id, user_id, false).await?) + res.post = Some( + PostView::read(pool, p.id, user_id, false) + .await? + .ok_or(LemmyErrorType::CouldntFindPost)?, + ) } Comment(c) => { removed_or_deleted = c.deleted || c.removed; - res.comment = Some(CommentView::read(pool, c.id, user_id).await?) + res.comment = Some( + CommentView::read(pool, c.id, user_id) + .await? + .ok_or(LemmyErrorType::CouldntFindComment)?, + ) } PersonOrCommunity(p) => match *p { UserOrCommunity::User(u) => { removed_or_deleted = u.deleted; - res.person = Some(PersonView::read(pool, u.id).await?) + res.person = Some( + PersonView::read(pool, u.id) + .await? + .ok_or(LemmyErrorType::CouldntFindPerson)?, + ) } UserOrCommunity::Community(c) => { removed_or_deleted = c.deleted || c.removed; - res.community = Some(CommunityView::read(pool, c.id, user_id, false).await?) + res.community = Some( + CommunityView::read(pool, c.id, user_id, false) + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?, + ) } }, }; diff --git a/crates/apub/src/api/search.rs b/crates/apub/src/api/search.rs index 0cac8351a..f3cd36faf 100644 --- a/crates/apub/src/api/search.rs +++ b/crates/apub/src/api/search.rs @@ -13,7 +13,7 @@ use lemmy_db_views::{ structs::{LocalUserView, SiteView}, }; use lemmy_db_views_actor::{community_view::CommunityQuery, person_view::PersonQuery}; -use lemmy_utils::error::LemmyResult; +use lemmy_utils::{error::LemmyResult, LemmyErrorType}; #[tracing::instrument(skip(context))] pub async fn search( @@ -21,7 +21,9 @@ pub async fn search( context: Data, local_user_view: Option, ) -> LemmyResult> { - let local_site = SiteView::read_local(&mut context.pool()).await?; + let local_site = SiteView::read_local(&mut context.pool()) + .await? + .ok_or(LemmyErrorType::LocalSiteNotSetup)?; check_private_instance(&local_user_view, &local_site.local_site)?; diff --git a/crates/apub/src/api/user_settings_backup.rs b/crates/apub/src/api/user_settings_backup.rs index 8053d66a0..57e1d0f97 100644 --- a/crates/apub/src/api/user_settings_backup.rs +++ b/crates/apub/src/api/user_settings_backup.rs @@ -363,7 +363,11 @@ mod tests { .build(); let local_user = LocalUser::create(&mut context.pool(), &user_form, vec![]).await?; - Ok(LocalUserView::read(&mut context.pool(), local_user.id).await?) + Ok( + LocalUserView::read(&mut context.pool(), local_user.id) + .await? + .ok_or(LemmyErrorType::CouldntFindLocalUser)?, + ) } #[tokio::test] @@ -396,8 +400,9 @@ mod tests { // wait for background task to finish sleep(Duration::from_millis(1000)).await; - let import_user_updated = - LocalUserView::read(&mut context.pool(), import_user.local_user.id).await?; + let import_user_updated = LocalUserView::read(&mut context.pool(), import_user.local_user.id) + .await? + .ok_or(LemmyErrorType::CouldntFindLocalUser)?; assert_eq!( export_user.person.display_name, diff --git a/crates/apub/src/collections/community_outbox.rs b/crates/apub/src/collections/community_outbox.rs index f56708d09..71985f946 100644 --- a/crates/apub/src/collections/community_outbox.rs +++ b/crates/apub/src/collections/community_outbox.rs @@ -23,7 +23,10 @@ use lemmy_db_schema::{ traits::Crud, utils::FETCH_LIMIT_MAX, }; -use lemmy_utils::error::{LemmyError, LemmyResult}; +use lemmy_utils::{ + error::{LemmyError, LemmyResult}, + LemmyErrorType, +}; use url::Url; #[derive(Clone, Debug)] @@ -47,6 +50,7 @@ impl Collection for ApubCommunityOutbox { for post in post_list { let person = Person::read(&mut data.pool(), post.creator_id) .await? + .ok_or(LemmyErrorType::CouldntFindPerson)? .into(); let create = CreateOrUpdatePage::new(post, &person, owner, CreateOrUpdateType::Create, data).await?; diff --git a/crates/apub/src/fetcher/mod.rs b/crates/apub/src/fetcher/mod.rs index 928656924..68fc07d30 100644 --- a/crates/apub/src/fetcher/mod.rs +++ b/crates/apub/src/fetcher/mod.rs @@ -42,9 +42,12 @@ where .splitn(2, '@') .collect_tuple() .expect("invalid query"); - let actor = DbActor::read_from_name_and_domain(&mut context.pool(), name, domain).await; - if actor.is_ok() { - Ok(actor?.into()) + let actor = DbActor::read_from_name_and_domain(&mut context.pool(), name, domain) + .await + .ok() + .flatten(); + if let Some(actor) = actor { + Ok(actor.into()) } else if local_user_view.is_some() { // Fetch the actor from its home instance using webfinger let actor: ActorType = webfinger_resolve_actor(&identifier.to_lowercase(), context).await?; @@ -59,6 +62,7 @@ where Ok( DbActor::read_from_name(&mut context.pool(), &identifier, include_deleted) .await? + .ok_or(NotFound)? .into(), ) } diff --git a/crates/apub/src/fetcher/post_or_comment.rs b/crates/apub/src/fetcher/post_or_comment.rs index 9df0a04fb..083369b9d 100644 --- a/crates/apub/src/fetcher/post_or_comment.rs +++ b/crates/apub/src/fetcher/post_or_comment.rs @@ -12,7 +12,10 @@ use lemmy_db_schema::{ source::{community::Community, post::Post}, traits::Crud, }; -use lemmy_utils::error::{LemmyError, LemmyResult}; +use lemmy_utils::{ + error::{LemmyError, LemmyResult}, + LemmyErrorType, +}; use serde::Deserialize; use url::Url; @@ -91,9 +94,15 @@ impl InCommunity for PostOrComment { PostOrComment::Comment(c) => { Post::read(&mut context.pool(), c.post_id) .await? + .ok_or(LemmyErrorType::CouldntFindPost)? .community_id } }; - Ok(Community::read(&mut context.pool(), cid).await?.into()) + Ok( + Community::read(&mut context.pool(), cid) + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)? + .into(), + ) } } diff --git a/crates/apub/src/http/comment.rs b/crates/apub/src/http/comment.rs index d6b3c818d..17711817e 100644 --- a/crates/apub/src/http/comment.rs +++ b/crates/apub/src/http/comment.rs @@ -15,7 +15,7 @@ use lemmy_db_schema::{ source::{comment::Comment, community::Community, post::Post}, traits::Crud, }; -use lemmy_utils::error::LemmyResult; +use lemmy_utils::{error::LemmyResult, LemmyErrorType}; use serde::Deserialize; #[derive(Deserialize)] @@ -31,9 +31,16 @@ pub(crate) async fn get_apub_comment( ) -> LemmyResult { let id = CommentId(info.comment_id.parse::()?); // Can't use CommentView here because it excludes deleted/removed/local-only items - let comment: ApubComment = Comment::read(&mut context.pool(), id).await?.into(); - let post = Post::read(&mut context.pool(), comment.post_id).await?; - let community = Community::read(&mut context.pool(), post.community_id).await?; + let comment: ApubComment = Comment::read(&mut context.pool(), id) + .await? + .ok_or(LemmyErrorType::CouldntFindComment)? + .into(); + let post = Post::read(&mut context.pool(), comment.post_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPost)?; + let community = Community::read(&mut context.pool(), post.community_id) + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?; check_community_public(&community)?; if !comment.local { diff --git a/crates/apub/src/http/community.rs b/crates/apub/src/http/community.rs index 2085ed1ac..c7a1f9eda 100644 --- a/crates/apub/src/http/community.rs +++ b/crates/apub/src/http/community.rs @@ -18,7 +18,7 @@ use activitypub_federation::{ use actix_web::{web, web::Bytes, HttpRequest, HttpResponse}; use lemmy_api_common::context::LemmyContext; use lemmy_db_schema::{source::community::Community, traits::ApubActor}; -use lemmy_utils::error::LemmyResult; +use lemmy_utils::{error::LemmyResult, LemmyErrorType}; use serde::Deserialize; #[derive(Deserialize, Clone)] @@ -35,6 +35,7 @@ pub(crate) async fn get_apub_community_http( let community: ApubCommunity = Community::read_from_name(&mut context.pool(), &info.community_name, true) .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)? .into(); if community.deleted || community.removed { @@ -64,8 +65,9 @@ pub(crate) async fn get_apub_community_followers( info: web::Path, context: Data, ) -> LemmyResult { - let community = - Community::read_from_name(&mut context.pool(), &info.community_name, false).await?; + let community = Community::read_from_name(&mut context.pool(), &info.community_name, false) + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?; check_community_public(&community)?; let followers = ApubCommunityFollower::read_local(&community.into(), &context).await?; create_apub_response(&followers) @@ -80,6 +82,7 @@ pub(crate) async fn get_apub_community_outbox( let community: ApubCommunity = Community::read_from_name(&mut context.pool(), &info.community_name, false) .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)? .into(); check_community_public(&community)?; let outbox = ApubCommunityOutbox::read_local(&community, &context).await?; @@ -94,6 +97,7 @@ pub(crate) async fn get_apub_community_moderators( let community: ApubCommunity = Community::read_from_name(&mut context.pool(), &info.community_name, false) .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)? .into(); check_community_public(&community)?; let moderators = ApubCommunityModerators::read_local(&community, &context).await?; @@ -108,6 +112,7 @@ pub(crate) async fn get_apub_community_featured( let community: ApubCommunity = Community::read_from_name(&mut context.pool(), &info.community_name, false) .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)? .into(); check_community_public(&community)?; let featured = ApubCommunityFeatured::read_local(&community, &context).await?; diff --git a/crates/apub/src/http/mod.rs b/crates/apub/src/http/mod.rs index 86c51338a..8aba7832f 100644 --- a/crates/apub/src/http/mod.rs +++ b/crates/apub/src/http/mod.rs @@ -97,7 +97,9 @@ pub(crate) async fn get_activity( info.id ))? .into(); - let activity = SentActivity::read_from_apub_id(&mut context.pool(), &activity_id).await?; + let activity = SentActivity::read_from_apub_id(&mut context.pool(), &activity_id) + .await? + .ok_or(LemmyErrorType::CouldntFindActivity)?; let sensitive = activity.sensitive; if sensitive { diff --git a/crates/apub/src/http/person.rs b/crates/apub/src/http/person.rs index b34f166b0..ba2372fe8 100644 --- a/crates/apub/src/http/person.rs +++ b/crates/apub/src/http/person.rs @@ -14,7 +14,7 @@ use activitypub_federation::{ use actix_web::{web, web::Bytes, HttpRequest, HttpResponse}; use lemmy_api_common::{context::LemmyContext, utils::generate_outbox_url}; use lemmy_db_schema::{source::person::Person, traits::ApubActor}; -use lemmy_utils::error::LemmyResult; +use lemmy_utils::{error::LemmyResult, LemmyErrorType}; use serde::Deserialize; #[derive(Deserialize)] @@ -32,6 +32,7 @@ pub(crate) async fn get_apub_person_http( // TODO: this needs to be able to read deleted persons, so that it can send tombstones let person: ApubPerson = Person::read_from_name(&mut context.pool(), &user_name, true) .await? + .ok_or(LemmyErrorType::CouldntFindPerson)? .into(); if !person.deleted { @@ -60,7 +61,9 @@ pub(crate) async fn get_apub_person_outbox( info: web::Path, context: Data, ) -> LemmyResult { - let person = Person::read_from_name(&mut context.pool(), &info.user_name, false).await?; + let person = Person::read_from_name(&mut context.pool(), &info.user_name, false) + .await? + .ok_or(LemmyErrorType::CouldntFindPerson)?; let outbox_id = generate_outbox_url(&person.actor_id)?.into(); let outbox = EmptyOutbox::new(outbox_id)?; create_apub_response(&outbox) diff --git a/crates/apub/src/http/post.rs b/crates/apub/src/http/post.rs index ce6612826..513cba7ea 100644 --- a/crates/apub/src/http/post.rs +++ b/crates/apub/src/http/post.rs @@ -15,7 +15,7 @@ use lemmy_db_schema::{ source::{community::Community, post::Post}, traits::Crud, }; -use lemmy_utils::error::LemmyResult; +use lemmy_utils::{error::LemmyResult, LemmyErrorType}; use serde::Deserialize; #[derive(Deserialize)] @@ -31,8 +31,13 @@ pub(crate) async fn get_apub_post( ) -> LemmyResult { let id = PostId(info.post_id.parse::()?); // Can't use PostView here because it excludes deleted/removed/local-only items - let post: ApubPost = Post::read(&mut context.pool(), id).await?.into(); - let community = Community::read(&mut context.pool(), post.community_id).await?; + let post: ApubPost = Post::read(&mut context.pool(), id) + .await? + .ok_or(LemmyErrorType::CouldntFindPost)? + .into(); + let community = Community::read(&mut context.pool(), post.community_id) + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?; check_community_public(&community)?; if !post.local { diff --git a/crates/apub/src/http/site.rs b/crates/apub/src/http/site.rs index 622c0f676..54d3c0e32 100644 --- a/crates/apub/src/http/site.rs +++ b/crates/apub/src/http/site.rs @@ -7,11 +7,15 @@ use activitypub_federation::{config::Data, traits::Object}; use actix_web::HttpResponse; use lemmy_api_common::context::LemmyContext; use lemmy_db_views::structs::SiteView; -use lemmy_utils::error::LemmyResult; +use lemmy_utils::{error::LemmyResult, LemmyErrorType}; use url::Url; pub(crate) async fn get_apub_site_http(context: Data) -> LemmyResult { - let site: ApubSite = SiteView::read_local(&mut context.pool()).await?.site.into(); + let site: ApubSite = SiteView::read_local(&mut context.pool()) + .await? + .ok_or(LemmyErrorType::LocalSiteNotSetup)? + .site + .into(); let apub = site.into_json(&context).await?; create_apub_response(&apub) diff --git a/crates/apub/src/mentions.rs b/crates/apub/src/mentions.rs index 92b07db8e..4f4edc76d 100644 --- a/crates/apub/src/mentions.rs +++ b/crates/apub/src/mentions.rs @@ -11,7 +11,7 @@ use lemmy_db_schema::{ traits::Crud, utils::DbPool, }; -use lemmy_utils::{error::LemmyResult, utils::mention::scrape_text_for_mentions}; +use lemmy_utils::{error::LemmyResult, utils::mention::scrape_text_for_mentions, LemmyErrorType}; use serde::{Deserialize, Serialize}; use serde_json::Value; use url::Url; @@ -96,12 +96,21 @@ async fn get_comment_parent_creator( comment: &Comment, ) -> LemmyResult { let parent_creator_id = if let Some(parent_comment_id) = comment.parent_comment_id() { - let parent_comment = Comment::read(pool, parent_comment_id).await?; + let parent_comment = Comment::read(pool, parent_comment_id) + .await? + .ok_or(LemmyErrorType::CouldntFindComment)?; parent_comment.creator_id } else { let parent_post_id = comment.post_id; - let parent_post = Post::read(pool, parent_post_id).await?; + let parent_post = Post::read(pool, parent_post_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPost)?; parent_post.creator_id }; - Ok(Person::read(pool, parent_creator_id).await?.into()) + Ok( + Person::read(pool, parent_creator_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPerson)? + .into(), + ) } diff --git a/crates/apub/src/objects/comment.rs b/crates/apub/src/objects/comment.rs index ce0430cc0..02de96f20 100644 --- a/crates/apub/src/objects/comment.rs +++ b/crates/apub/src/objects/comment.rs @@ -91,15 +91,23 @@ impl Object for ApubComment { #[tracing::instrument(skip_all)] async fn into_json(self, context: &Data) -> LemmyResult { let creator_id = self.creator_id; - let creator = Person::read(&mut context.pool(), creator_id).await?; + let creator = Person::read(&mut context.pool(), creator_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPerson)?; let post_id = self.post_id; - let post = Post::read(&mut context.pool(), post_id).await?; + let post = Post::read(&mut context.pool(), post_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPost)?; let community_id = post.community_id; - let community = Community::read(&mut context.pool(), community_id).await?; + let community = Community::read(&mut context.pool(), community_id) + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?; let in_reply_to = if let Some(comment_id) = self.parent_comment_id() { - let parent_comment = Comment::read(&mut context.pool(), comment_id).await?; + let parent_comment = Comment::read(&mut context.pool(), comment_id) + .await? + .ok_or(LemmyErrorType::CouldntFindComment)?; parent_comment.ap_id.into() } else { post.ap_id.into() diff --git a/crates/apub/src/objects/post.rs b/crates/apub/src/objects/post.rs index 55af850e5..c7fa4acb1 100644 --- a/crates/apub/src/objects/post.rs +++ b/crates/apub/src/objects/post.rs @@ -45,7 +45,7 @@ use lemmy_db_schema::{ }; use lemmy_db_views_actor::structs::CommunityModeratorView; use lemmy_utils::{ - error::{LemmyError, LemmyResult}, + error::{LemmyError, LemmyErrorType, LemmyResult}, utils::{markdown::markdown_to_html, slurs::check_slurs_opt, validation::check_url_scheme}, }; use std::ops::Deref; @@ -108,9 +108,13 @@ impl Object for ApubPost { #[tracing::instrument(skip_all)] async fn into_json(self, context: &Data) -> LemmyResult { let creator_id = self.creator_id; - let creator = Person::read(&mut context.pool(), creator_id).await?; + let creator = Person::read(&mut context.pool(), creator_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPerson)?; let community_id = self.community_id; - let community = Community::read(&mut context.pool(), community_id).await?; + let community = Community::read(&mut context.pool(), community_id) + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?; let language = LanguageTag::new_single(self.language_id, &mut context.pool()).await?; let attachment = self diff --git a/crates/apub/src/objects/private_message.rs b/crates/apub/src/objects/private_message.rs index 4600c997a..35f2fe418 100644 --- a/crates/apub/src/objects/private_message.rs +++ b/crates/apub/src/objects/private_message.rs @@ -79,10 +79,14 @@ impl Object for ApubPrivateMessage { #[tracing::instrument(skip_all)] async fn into_json(self, context: &Data) -> LemmyResult { let creator_id = self.creator_id; - let creator = Person::read(&mut context.pool(), creator_id).await?; + let creator = Person::read(&mut context.pool(), creator_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPerson)?; let recipient_id = self.recipient_id; - let recipient = Person::read(&mut context.pool(), recipient_id).await?; + let recipient = Person::read(&mut context.pool(), recipient_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPerson)?; let note = ChatMessage { r#type: ChatMessageType::ChatMessage, diff --git a/crates/apub/src/protocol/activities/community/collection_add.rs b/crates/apub/src/protocol/activities/community/collection_add.rs index 777ad8b62..0e2ab75a6 100644 --- a/crates/apub/src/protocol/activities/community/collection_add.rs +++ b/crates/apub/src/protocol/activities/community/collection_add.rs @@ -11,7 +11,7 @@ use activitypub_federation::{ }; use lemmy_api_common::context::LemmyContext; use lemmy_db_schema::source::community::Community; -use lemmy_utils::error::LemmyResult; +use lemmy_utils::{error::LemmyResult, LemmyErrorType}; use serde::{Deserialize, Serialize}; use url::Url; @@ -35,7 +35,9 @@ pub struct CollectionAdd { impl InCommunity for CollectionAdd { async fn community(&self, context: &Data) -> LemmyResult { let (community, _) = - Community::get_by_collection_url(&mut context.pool(), &self.clone().target.into()).await?; + Community::get_by_collection_url(&mut context.pool(), &self.clone().target.into()) + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?; if let Some(audience) = &self.audience { verify_community_matches(audience, community.actor_id.clone())?; } diff --git a/crates/apub/src/protocol/activities/community/collection_remove.rs b/crates/apub/src/protocol/activities/community/collection_remove.rs index afc0c24a0..51c4761ba 100644 --- a/crates/apub/src/protocol/activities/community/collection_remove.rs +++ b/crates/apub/src/protocol/activities/community/collection_remove.rs @@ -11,7 +11,7 @@ use activitypub_federation::{ }; use lemmy_api_common::context::LemmyContext; use lemmy_db_schema::source::community::Community; -use lemmy_utils::error::LemmyResult; +use lemmy_utils::{error::LemmyResult, LemmyErrorType}; use serde::{Deserialize, Serialize}; use url::Url; @@ -35,7 +35,9 @@ pub struct CollectionRemove { impl InCommunity for CollectionRemove { async fn community(&self, context: &Data) -> LemmyResult { let (community, _) = - Community::get_by_collection_url(&mut context.pool(), &self.clone().target.into()).await?; + Community::get_by_collection_url(&mut context.pool(), &self.clone().target.into()) + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?; if let Some(audience) = &self.audience { verify_community_matches(audience, community.actor_id.clone())?; } diff --git a/crates/apub/src/protocol/activities/community/lock_page.rs b/crates/apub/src/protocol/activities/community/lock_page.rs index 0a4a2ff75..c60b86cf8 100644 --- a/crates/apub/src/protocol/activities/community/lock_page.rs +++ b/crates/apub/src/protocol/activities/community/lock_page.rs @@ -11,7 +11,7 @@ use activitypub_federation::{ }; use lemmy_api_common::context::LemmyContext; use lemmy_db_schema::{source::community::Community, traits::Crud}; -use lemmy_utils::error::LemmyResult; +use lemmy_utils::{error::LemmyResult, LemmyErrorType}; use serde::{Deserialize, Serialize}; use strum_macros::Display; use url::Url; @@ -55,7 +55,9 @@ pub struct UndoLockPage { impl InCommunity for LockPage { async fn community(&self, context: &Data) -> LemmyResult { let post = self.object.dereference(context).await?; - let community = Community::read(&mut context.pool(), post.community_id).await?; + let community = Community::read(&mut context.pool(), post.community_id) + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?; if let Some(audience) = &self.audience { verify_community_matches(audience, community.actor_id.clone())?; } diff --git a/crates/apub/src/protocol/activities/create_or_update/note.rs b/crates/apub/src/protocol/activities/create_or_update/note.rs index ff0728174..43ffeb291 100644 --- a/crates/apub/src/protocol/activities/create_or_update/note.rs +++ b/crates/apub/src/protocol/activities/create_or_update/note.rs @@ -11,7 +11,7 @@ use activitypub_federation::{ }; use lemmy_api_common::context::LemmyContext; use lemmy_db_schema::{source::community::Community, traits::Crud}; -use lemmy_utils::error::LemmyResult; +use lemmy_utils::{error::LemmyResult, LemmyErrorType}; use serde::{Deserialize, Serialize}; use url::Url; @@ -36,7 +36,9 @@ pub struct CreateOrUpdateNote { impl InCommunity for CreateOrUpdateNote { async fn community(&self, context: &Data) -> LemmyResult { let post = self.object.get_parents(context).await?.0; - let community = Community::read(&mut context.pool(), post.community_id).await?; + let community = Community::read(&mut context.pool(), post.community_id) + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?; if let Some(audience) = &self.audience { verify_community_matches(audience, community.actor_id.clone())?; } diff --git a/crates/apub/src/protocol/activities/deletion/delete.rs b/crates/apub/src/protocol/activities/deletion/delete.rs index 3a29da069..3b9aad079 100644 --- a/crates/apub/src/protocol/activities/deletion/delete.rs +++ b/crates/apub/src/protocol/activities/deletion/delete.rs @@ -15,7 +15,7 @@ use lemmy_db_schema::{ source::{community::Community, post::Post}, traits::Crud, }; -use lemmy_utils::error::LemmyResult; +use lemmy_utils::{error::LemmyResult, LemmyErrorType}; use serde::{Deserialize, Serialize}; use serde_with::skip_serializing_none; use url::Url; @@ -51,7 +51,9 @@ impl InCommunity for Delete { let community_id = match DeletableObjects::read_from_db(self.object.id(), context).await? { DeletableObjects::Community(c) => c.id, DeletableObjects::Comment(c) => { - let post = Post::read(&mut context.pool(), c.post_id).await?; + let post = Post::read(&mut context.pool(), c.post_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPost)?; post.community_id } DeletableObjects::Post(p) => p.community_id, @@ -60,7 +62,9 @@ impl InCommunity for Delete { return Err(anyhow!("Private message is not part of community").into()) } }; - let community = Community::read(&mut context.pool(), community_id).await?; + let community = Community::read(&mut context.pool(), community_id) + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?; if let Some(audience) = &self.audience { verify_community_matches(audience, community.actor_id.clone())?; } diff --git a/crates/apub/src/protocol/objects/note.rs b/crates/apub/src/protocol/objects/note.rs index a092cec9f..b0ae00037 100644 --- a/crates/apub/src/protocol/objects/note.rs +++ b/crates/apub/src/protocol/objects/note.rs @@ -20,7 +20,7 @@ use lemmy_db_schema::{ source::{community::Community, post::Post}, traits::Crud, }; -use lemmy_utils::error::LemmyResult; +use lemmy_utils::{error::LemmyResult, LemmyErrorType}; use serde::{Deserialize, Serialize}; use serde_with::skip_serializing_none; use std::ops::Deref; @@ -64,7 +64,9 @@ impl Note { PostOrComment::Post(p) => Ok((p.clone(), None)), PostOrComment::Comment(c) => { let post_id = c.post_id; - let post = Post::read(&mut context.pool(), post_id).await?; + let post = Post::read(&mut context.pool(), post_id) + .await? + .ok_or(LemmyErrorType::CouldntFindPost)?; Ok((post.into(), Some(c.clone()))) } } @@ -75,7 +77,9 @@ impl Note { impl InCommunity for Note { async fn community(&self, context: &Data) -> LemmyResult { let (post, _) = self.get_parents(context).await?; - let community = Community::read(&mut context.pool(), post.community_id).await?; + let community = Community::read(&mut context.pool(), post.community_id) + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?; if let Some(audience) = &self.audience { verify_community_matches(audience, community.actor_id.clone())?; } diff --git a/crates/db_schema/src/aggregates/comment_aggregates.rs b/crates/db_schema/src/aggregates/comment_aggregates.rs index 2120c7f38..915d17b1d 100644 --- a/crates/db_schema/src/aggregates/comment_aggregates.rs +++ b/crates/db_schema/src/aggregates/comment_aggregates.rs @@ -1,5 +1,6 @@ use crate::{ aggregates::structs::CommentAggregates, + diesel::OptionalExtension, newtypes::CommentId, schema::comment_aggregates, utils::{functions::hot_rank, get_conn, DbPool}, @@ -8,12 +9,13 @@ use diesel::{result::Error, ExpressionMethods, QueryDsl}; use diesel_async::RunQueryDsl; impl CommentAggregates { - pub async fn read(pool: &mut DbPool<'_>, comment_id: CommentId) -> Result { + pub async fn read(pool: &mut DbPool<'_>, comment_id: CommentId) -> Result, Error> { let conn = &mut get_conn(pool).await?; comment_aggregates::table .find(comment_id) - .first::(conn) + .first(conn) .await + .optional() } pub async fn update_hot_rank( @@ -125,6 +127,7 @@ mod tests { let comment_aggs_before_delete = CommentAggregates::read(pool, inserted_comment.id) .await + .unwrap() .unwrap(); assert_eq!(1, comment_aggs_before_delete.score); @@ -143,6 +146,7 @@ mod tests { let comment_aggs_after_dislike = CommentAggregates::read(pool, inserted_comment.id) .await + .unwrap() .unwrap(); assert_eq!(0, comment_aggs_after_dislike.score); @@ -155,6 +159,7 @@ mod tests { .unwrap(); let after_like_remove = CommentAggregates::read(pool, inserted_comment.id) .await + .unwrap() .unwrap(); assert_eq!(-1, after_like_remove.score); assert_eq!(0, after_like_remove.upvotes); @@ -164,8 +169,10 @@ mod tests { Post::delete(pool, inserted_post.id).await.unwrap(); // Should be none found, since the post was deleted - let after_delete = CommentAggregates::read(pool, inserted_comment.id).await; - assert!(after_delete.is_err()); + let after_delete = CommentAggregates::read(pool, inserted_comment.id) + .await + .unwrap(); + assert!(after_delete.is_none()); // This should delete all the associated rows, and fire triggers Person::delete(pool, another_inserted_person.id) diff --git a/crates/db_schema/src/aggregates/community_aggregates.rs b/crates/db_schema/src/aggregates/community_aggregates.rs index f1f54663b..0cf63809d 100644 --- a/crates/db_schema/src/aggregates/community_aggregates.rs +++ b/crates/db_schema/src/aggregates/community_aggregates.rs @@ -1,5 +1,6 @@ use crate::{ aggregates::structs::CommunityAggregates, + diesel::OptionalExtension, newtypes::CommunityId, schema::{community_aggregates, community_aggregates::subscribers}, utils::{get_conn, DbPool}, @@ -8,12 +9,16 @@ use diesel::{result::Error, ExpressionMethods, QueryDsl}; use diesel_async::RunQueryDsl; impl CommunityAggregates { - pub async fn read(pool: &mut DbPool<'_>, for_community_id: CommunityId) -> Result { + pub async fn read( + pool: &mut DbPool<'_>, + for_community_id: CommunityId, + ) -> Result, Error> { let conn = &mut get_conn(pool).await?; community_aggregates::table .find(for_community_id) - .first::(conn) + .first(conn) .await + .optional() } pub async fn update_federated_followers( @@ -25,7 +30,7 @@ impl CommunityAggregates { let new_subscribers: i64 = new_subscribers.into(); diesel::update(community_aggregates::table.find(for_community_id)) .set(subscribers.eq(new_subscribers)) - .get_result::(conn) + .get_result(conn) .await } } @@ -153,6 +158,7 @@ mod tests { let community_aggregates_before_delete = CommunityAggregates::read(pool, inserted_community.id) .await + .unwrap() .unwrap(); assert_eq!(2, community_aggregates_before_delete.subscribers); @@ -163,6 +169,7 @@ mod tests { // Test the other community let another_community_aggs = CommunityAggregates::read(pool, another_inserted_community.id) .await + .unwrap() .unwrap(); assert_eq!(1, another_community_aggs.subscribers); assert_eq!(1, another_community_aggs.subscribers_local); @@ -175,6 +182,7 @@ mod tests { .unwrap(); let after_unfollow = CommunityAggregates::read(pool, inserted_community.id) .await + .unwrap() .unwrap(); assert_eq!(1, after_unfollow.subscribers); assert_eq!(1, after_unfollow.subscribers_local); @@ -185,6 +193,7 @@ mod tests { .unwrap(); let after_follow_again = CommunityAggregates::read(pool, inserted_community.id) .await + .unwrap() .unwrap(); assert_eq!(2, after_follow_again.subscribers); assert_eq!(2, after_follow_again.subscribers_local); @@ -193,6 +202,7 @@ mod tests { Post::delete(pool, inserted_post.id).await.unwrap(); let after_parent_post_delete = CommunityAggregates::read(pool, inserted_community.id) .await + .unwrap() .unwrap(); assert_eq!(0, after_parent_post_delete.comments); assert_eq!(0, after_parent_post_delete.posts); @@ -203,6 +213,7 @@ mod tests { .unwrap(); let after_person_delete = CommunityAggregates::read(pool, inserted_community.id) .await + .unwrap() .unwrap(); assert_eq!(1, after_person_delete.subscribers); assert_eq!(1, after_person_delete.subscribers_local); @@ -223,7 +234,9 @@ mod tests { assert_eq!(1, another_community_num_deleted); // Should be none found, since the creator was deleted - let after_delete = CommunityAggregates::read(pool, inserted_community.id).await; - assert!(after_delete.is_err()); + let after_delete = CommunityAggregates::read(pool, inserted_community.id) + .await + .unwrap(); + assert!(after_delete.is_none()); } } diff --git a/crates/db_schema/src/aggregates/person_aggregates.rs b/crates/db_schema/src/aggregates/person_aggregates.rs index 520b45225..03295173f 100644 --- a/crates/db_schema/src/aggregates/person_aggregates.rs +++ b/crates/db_schema/src/aggregates/person_aggregates.rs @@ -1,3 +1,4 @@ +pub(crate) use crate::diesel::OptionalExtension; use crate::{ aggregates::structs::PersonAggregates, newtypes::PersonId, @@ -8,12 +9,13 @@ use diesel::{result::Error, QueryDsl}; use diesel_async::RunQueryDsl; impl PersonAggregates { - pub async fn read(pool: &mut DbPool<'_>, person_id: PersonId) -> Result { + pub async fn read(pool: &mut DbPool<'_>, person_id: PersonId) -> Result, Error> { let conn = &mut get_conn(pool).await?; person_aggregates::table .find(person_id) - .first::(conn) + .first(conn) .await + .optional() } } @@ -127,6 +129,7 @@ mod tests { let person_aggregates_before_delete = PersonAggregates::read(pool, inserted_person.id) .await + .unwrap() .unwrap(); assert_eq!(1, person_aggregates_before_delete.post_count); @@ -140,6 +143,7 @@ mod tests { .unwrap(); let after_post_like_remove = PersonAggregates::read(pool, inserted_person.id) .await + .unwrap() .unwrap(); assert_eq!(0, after_post_like_remove.post_score); @@ -166,6 +170,7 @@ mod tests { let after_parent_comment_removed = PersonAggregates::read(pool, inserted_person.id) .await + .unwrap() .unwrap(); assert_eq!(0, after_parent_comment_removed.comment_count); // TODO: fix person aggregate comment score calculation @@ -178,6 +183,7 @@ mod tests { .unwrap(); let after_parent_comment_delete = PersonAggregates::read(pool, inserted_person.id) .await + .unwrap() .unwrap(); assert_eq!(0, after_parent_comment_delete.comment_count); // TODO: fix person aggregate comment score calculation @@ -193,6 +199,7 @@ mod tests { CommentLike::like(pool, &comment_like).await.unwrap(); let after_comment_add = PersonAggregates::read(pool, inserted_person.id) .await + .unwrap() .unwrap(); assert_eq!(2, after_comment_add.comment_count); // TODO: fix person aggregate comment score calculation @@ -201,6 +208,7 @@ mod tests { Post::delete(pool, inserted_post.id).await.unwrap(); let after_post_delete = PersonAggregates::read(pool, inserted_person.id) .await + .unwrap() .unwrap(); // TODO: fix person aggregate comment score calculation // assert_eq!(0, after_post_delete.comment_score); @@ -222,8 +230,10 @@ mod tests { assert_eq!(1, community_num_deleted); // Should be none found - let after_delete = PersonAggregates::read(pool, inserted_person.id).await; - assert!(after_delete.is_err()); + let after_delete = PersonAggregates::read(pool, inserted_person.id) + .await + .unwrap(); + assert!(after_delete.is_none()); Instance::delete(pool, inserted_instance.id).await.unwrap(); } diff --git a/crates/db_schema/src/aggregates/person_post_aggregates.rs b/crates/db_schema/src/aggregates/person_post_aggregates.rs index 7657dae9e..f6e108ee9 100644 --- a/crates/db_schema/src/aggregates/person_post_aggregates.rs +++ b/crates/db_schema/src/aggregates/person_post_aggregates.rs @@ -1,5 +1,6 @@ use crate::{ aggregates::structs::{PersonPostAggregates, PersonPostAggregatesForm}, + diesel::OptionalExtension, newtypes::{PersonId, PostId}, schema::person_post_aggregates::dsl::{person_id, person_post_aggregates, post_id}, utils::{get_conn, DbPool}, @@ -25,11 +26,12 @@ impl PersonPostAggregates { pool: &mut DbPool<'_>, person_id_: PersonId, post_id_: PostId, - ) -> Result { + ) -> Result, Error> { let conn = &mut get_conn(pool).await?; person_post_aggregates .find((person_id_, post_id_)) - .first::(conn) + .first(conn) .await + .optional() } } diff --git a/crates/db_schema/src/aggregates/post_aggregates.rs b/crates/db_schema/src/aggregates/post_aggregates.rs index 7f95dc05a..cb8227795 100644 --- a/crates/db_schema/src/aggregates/post_aggregates.rs +++ b/crates/db_schema/src/aggregates/post_aggregates.rs @@ -1,5 +1,6 @@ use crate::{ aggregates::structs::PostAggregates, + diesel::OptionalExtension, newtypes::PostId, schema::{community_aggregates, post, post_aggregates}, utils::{ @@ -12,12 +13,13 @@ use diesel::{result::Error, ExpressionMethods, JoinOnDsl, QueryDsl}; use diesel_async::RunQueryDsl; impl PostAggregates { - pub async fn read(pool: &mut DbPool<'_>, post_id: PostId) -> Result { + pub async fn read(pool: &mut DbPool<'_>, post_id: PostId) -> Result, Error> { let conn = &mut get_conn(pool).await?; post_aggregates::table .find(post_id) - .first::(conn) + .first(conn) .await + .optional() } pub async fn update_ranks(pool: &mut DbPool<'_>, post_id: PostId) -> Result { @@ -141,7 +143,10 @@ mod tests { PostLike::like(pool, &post_like).await.unwrap(); - let post_aggs_before_delete = PostAggregates::read(pool, inserted_post.id).await.unwrap(); + let post_aggs_before_delete = PostAggregates::read(pool, inserted_post.id) + .await + .unwrap() + .unwrap(); assert_eq!(2, post_aggs_before_delete.comments); assert_eq!(1, post_aggs_before_delete.score); @@ -157,7 +162,10 @@ mod tests { PostLike::like(pool, &post_dislike).await.unwrap(); - let post_aggs_after_dislike = PostAggregates::read(pool, inserted_post.id).await.unwrap(); + let post_aggs_after_dislike = PostAggregates::read(pool, inserted_post.id) + .await + .unwrap() + .unwrap(); assert_eq!(2, post_aggs_after_dislike.comments); assert_eq!(0, post_aggs_after_dislike.score); @@ -169,7 +177,10 @@ mod tests { Comment::delete(pool, inserted_child_comment.id) .await .unwrap(); - let after_comment_delete = PostAggregates::read(pool, inserted_post.id).await.unwrap(); + let after_comment_delete = PostAggregates::read(pool, inserted_post.id) + .await + .unwrap() + .unwrap(); assert_eq!(0, after_comment_delete.comments); assert_eq!(0, after_comment_delete.score); assert_eq!(1, after_comment_delete.upvotes); @@ -179,7 +190,10 @@ mod tests { PostLike::remove(pool, inserted_person.id, inserted_post.id) .await .unwrap(); - let after_like_remove = PostAggregates::read(pool, inserted_post.id).await.unwrap(); + let after_like_remove = PostAggregates::read(pool, inserted_post.id) + .await + .unwrap() + .unwrap(); assert_eq!(0, after_like_remove.comments); assert_eq!(-1, after_like_remove.score); assert_eq!(0, after_like_remove.upvotes); @@ -199,8 +213,8 @@ mod tests { assert_eq!(1, community_num_deleted); // Should be none found, since the creator was deleted - let after_delete = PostAggregates::read(pool, inserted_post.id).await; - assert!(after_delete.is_err()); + let after_delete = PostAggregates::read(pool, inserted_post.id).await.unwrap(); + assert!(after_delete.is_none()); Instance::delete(pool, inserted_instance.id).await.unwrap(); } @@ -248,7 +262,10 @@ mod tests { let inserted_comment = Comment::create(pool, &comment_form, None).await.unwrap(); - let post_aggregates_before = PostAggregates::read(pool, inserted_post.id).await.unwrap(); + let post_aggregates_before = PostAggregates::read(pool, inserted_post.id) + .await + .unwrap() + .unwrap(); assert_eq!(1, post_aggregates_before.comments); Comment::update( @@ -262,7 +279,10 @@ mod tests { .await .unwrap(); - let post_aggregates_after_remove = PostAggregates::read(pool, inserted_post.id).await.unwrap(); + let post_aggregates_after_remove = PostAggregates::read(pool, inserted_post.id) + .await + .unwrap() + .unwrap(); assert_eq!(0, post_aggregates_after_remove.comments); Comment::update( @@ -287,7 +307,10 @@ mod tests { .await .unwrap(); - let post_aggregates_after_delete = PostAggregates::read(pool, inserted_post.id).await.unwrap(); + let post_aggregates_after_delete = PostAggregates::read(pool, inserted_post.id) + .await + .unwrap() + .unwrap(); assert_eq!(0, post_aggregates_after_delete.comments); Comment::update( @@ -301,8 +324,10 @@ mod tests { .await .unwrap(); - let post_aggregates_after_delete_remove = - PostAggregates::read(pool, inserted_post.id).await.unwrap(); + let post_aggregates_after_delete_remove = PostAggregates::read(pool, inserted_post.id) + .await + .unwrap() + .unwrap(); assert_eq!(0, post_aggregates_after_delete_remove.comments); Comment::delete(pool, inserted_comment.id).await.unwrap(); diff --git a/crates/db_schema/src/aggregates/site_aggregates.rs b/crates/db_schema/src/aggregates/site_aggregates.rs index b179ff7c7..268a37aac 100644 --- a/crates/db_schema/src/aggregates/site_aggregates.rs +++ b/crates/db_schema/src/aggregates/site_aggregates.rs @@ -1,5 +1,6 @@ use crate::{ aggregates::structs::SiteAggregates, + diesel::OptionalExtension, schema::site_aggregates, utils::{get_conn, DbPool}, }; @@ -7,9 +8,9 @@ use diesel::result::Error; use diesel_async::RunQueryDsl; impl SiteAggregates { - pub async fn read(pool: &mut DbPool<'_>) -> Result { + pub async fn read(pool: &mut DbPool<'_>) -> Result, Error> { let conn = &mut get_conn(pool).await?; - site_aggregates::table.first::(conn).await + site_aggregates::table.first(conn).await.optional() } } @@ -111,7 +112,7 @@ mod tests { .await .unwrap(); - let site_aggregates_before_delete = SiteAggregates::read(pool).await.unwrap(); + let site_aggregates_before_delete = SiteAggregates::read(pool).await.unwrap().unwrap(); // TODO: this is unstable, sometimes it returns 0 users, sometimes 1 //assert_eq!(0, site_aggregates_before_delete.users); @@ -121,7 +122,7 @@ mod tests { // Try a post delete Post::delete(pool, inserted_post.id).await.unwrap(); - let site_aggregates_after_post_delete = SiteAggregates::read(pool).await.unwrap(); + let site_aggregates_after_post_delete = SiteAggregates::read(pool).await.unwrap().unwrap(); assert_eq!(1, site_aggregates_after_post_delete.posts); assert_eq!(0, site_aggregates_after_post_delete.comments); @@ -140,8 +141,8 @@ mod tests { assert!(after_delete_creator.is_ok()); Site::delete(pool, inserted_site.id).await.unwrap(); - let after_delete_site = SiteAggregates::read(pool).await; - assert!(after_delete_site.is_err()); + let after_delete_site = SiteAggregates::read(pool).await.unwrap(); + assert!(after_delete_site.is_none()); Instance::delete(pool, inserted_instance.id).await.unwrap(); } @@ -155,7 +156,7 @@ mod tests { let (inserted_instance, inserted_person, inserted_site, inserted_community) = prepare_site_with_community(pool).await; - let site_aggregates_before = SiteAggregates::read(pool).await.unwrap(); + let site_aggregates_before = SiteAggregates::read(pool).await.unwrap().unwrap(); assert_eq!(1, site_aggregates_before.communities); Community::update( @@ -169,7 +170,7 @@ mod tests { .await .unwrap(); - let site_aggregates_after_delete = SiteAggregates::read(pool).await.unwrap(); + let site_aggregates_after_delete = SiteAggregates::read(pool).await.unwrap().unwrap(); assert_eq!(0, site_aggregates_after_delete.communities); Community::update( @@ -194,7 +195,7 @@ mod tests { .await .unwrap(); - let site_aggregates_after_remove = SiteAggregates::read(pool).await.unwrap(); + let site_aggregates_after_remove = SiteAggregates::read(pool).await.unwrap().unwrap(); assert_eq!(0, site_aggregates_after_remove.communities); Community::update( @@ -208,7 +209,7 @@ mod tests { .await .unwrap(); - let site_aggregates_after_remove_delete = SiteAggregates::read(pool).await.unwrap(); + let site_aggregates_after_remove_delete = SiteAggregates::read(pool).await.unwrap().unwrap(); assert_eq!(0, site_aggregates_after_remove_delete.communities); Community::delete(pool, inserted_community.id) diff --git a/crates/db_schema/src/impls/activity.rs b/crates/db_schema/src/impls/activity.rs index e1802c7c5..adcdf8ad5 100644 --- a/crates/db_schema/src/impls/activity.rs +++ b/crates/db_schema/src/impls/activity.rs @@ -22,18 +22,22 @@ impl SentActivity { .await } - pub async fn read_from_apub_id(pool: &mut DbPool<'_>, object_id: &DbUrl) -> Result { + pub async fn read_from_apub_id( + pool: &mut DbPool<'_>, + object_id: &DbUrl, + ) -> Result, Error> { use crate::schema::sent_activity::dsl::{ap_id, sent_activity}; let conn = &mut get_conn(pool).await?; sent_activity .filter(ap_id.eq(object_id)) - .first::(conn) + .first(conn) .await + .optional() } - pub async fn read(pool: &mut DbPool<'_>, object_id: ActivityId) -> Result { + pub async fn read(pool: &mut DbPool<'_>, object_id: ActivityId) -> Result, Error> { use crate::schema::sent_activity::dsl::sent_activity; let conn = &mut get_conn(pool).await?; - sent_activity.find(object_id).first::(conn).await + sent_activity.find(object_id).first(conn).await.optional() } } @@ -118,7 +122,10 @@ mod tests { SentActivity::create(pool, form).await.unwrap(); - let res = SentActivity::read_from_apub_id(pool, &ap_id).await.unwrap(); + let res = SentActivity::read_from_apub_id(pool, &ap_id) + .await + .unwrap() + .unwrap(); assert_eq!(res.ap_id, ap_id); assert_eq!(res.data, data); assert_eq!(res.sensitive, sensitive); diff --git a/crates/db_schema/src/impls/comment.rs b/crates/db_schema/src/impls/comment.rs index c0dad0ad3..30c058b89 100644 --- a/crates/db_schema/src/impls/comment.rs +++ b/crates/db_schema/src/impls/comment.rs @@ -1,5 +1,5 @@ use crate::{ - diesel::DecoratableTarget, + diesel::{DecoratableTarget, OptionalExtension}, newtypes::{CommentId, DbUrl, PersonId}, schema::comment, source::comment::{ @@ -155,14 +155,11 @@ where ca.comment_id = c.id" ) -> Result, Error> { let conn = &mut get_conn(pool).await?; let object_id: DbUrl = object_id.into(); - Ok( - comment::table - .filter(comment::ap_id.eq(object_id)) - .first::(conn) - .await - .ok() - .map(Into::into), - ) + comment::table + .filter(comment::ap_id.eq(object_id)) + .first(conn) + .await + .optional() } pub fn parent_comment_id(&self) -> Option { @@ -400,7 +397,10 @@ mod tests { .await .unwrap(); - let read_comment = Comment::read(pool, inserted_comment.id).await.unwrap(); + let read_comment = Comment::read(pool, inserted_comment.id) + .await + .unwrap() + .unwrap(); let like_removed = CommentLike::remove(pool, inserted_person.id, inserted_comment.id) .await .unwrap(); diff --git a/crates/db_schema/src/impls/comment_reply.rs b/crates/db_schema/src/impls/comment_reply.rs index e6d0915e9..4a4a49a13 100644 --- a/crates/db_schema/src/impls/comment_reply.rs +++ b/crates/db_schema/src/impls/comment_reply.rs @@ -1,4 +1,5 @@ use crate::{ + diesel::OptionalExtension, newtypes::{CommentId, CommentReplyId, PersonId}, schema::comment_reply, source::comment_reply::{CommentReply, CommentReplyInsertForm, CommentReplyUpdateForm}, @@ -63,25 +64,27 @@ impl CommentReply { pub async fn read_by_comment( pool: &mut DbPool<'_>, for_comment_id: CommentId, - ) -> Result { + ) -> Result, Error> { let conn = &mut get_conn(pool).await?; comment_reply::table .filter(comment_reply::comment_id.eq(for_comment_id)) - .first::(conn) + .first(conn) .await + .optional() } pub async fn read_by_comment_and_person( pool: &mut DbPool<'_>, for_comment_id: CommentId, for_recipient_id: PersonId, - ) -> Result { + ) -> Result, Error> { let conn = &mut get_conn(pool).await?; comment_reply::table .filter(comment_reply::comment_id.eq(for_comment_id)) .filter(comment_reply::recipient_id.eq(for_recipient_id)) - .first::(conn) + .first(conn) .await + .optional() } } @@ -174,7 +177,10 @@ mod tests { published: inserted_reply.published, }; - let read_reply = CommentReply::read(pool, inserted_reply.id).await.unwrap(); + let read_reply = CommentReply::read(pool, inserted_reply.id) + .await + .unwrap() + .unwrap(); let comment_reply_update_form = CommentReplyUpdateForm { read: Some(false) }; let updated_reply = CommentReply::update(pool, inserted_reply.id, &comment_reply_update_form) diff --git a/crates/db_schema/src/impls/community.rs b/crates/db_schema/src/impls/community.rs index 4dc45c09b..e886098ce 100644 --- a/crates/db_schema/src/impls/community.rs +++ b/crates/db_schema/src/impls/community.rs @@ -1,5 +1,5 @@ use crate::{ - diesel::DecoratableTarget, + diesel::{DecoratableTarget, OptionalExtension}, newtypes::{CommunityId, DbUrl, PersonId}, schema::{community, community_follower, instance}, source::{ @@ -145,25 +145,30 @@ impl Community { pub async fn get_by_collection_url( pool: &mut DbPool<'_>, url: &DbUrl, - ) -> Result<(Community, CollectionType), Error> { + ) -> Result, Error> { use crate::schema::community::dsl::{featured_url, moderators_url}; use CollectionType::*; let conn = &mut get_conn(pool).await?; let res = community::table .filter(moderators_url.eq(url)) - .first::(conn) - .await; - if let Ok(c) = res { - return Ok((c, Moderators)); + .first(conn) + .await + .optional()?; + + if let Some(c) = res { + Ok(Some((c, Moderators))) + } else { + let res = community::table + .filter(featured_url.eq(url)) + .first(conn) + .await + .optional()?; + if let Some(c) = res { + Ok(Some((c, Featured))) + } else { + Ok(None) + } } - let res = community::table - .filter(featured_url.eq(url)) - .first::(conn) - .await; - if let Ok(c) = res { - return Ok((c, Featured)); - } - Err(diesel::NotFound) } pub async fn set_featured_posts( @@ -348,21 +353,18 @@ impl ApubActor for Community { object_id: &DbUrl, ) -> Result, Error> { let conn = &mut get_conn(pool).await?; - Ok( - community::table - .filter(community::actor_id.eq(object_id)) - .first::(conn) - .await - .ok() - .map(Into::into), - ) + community::table + .filter(community::actor_id.eq(object_id)) + .first(conn) + .await + .optional() } async fn read_from_name( pool: &mut DbPool<'_>, community_name: &str, include_deleted: bool, - ) -> Result { + ) -> Result, Error> { let conn = &mut get_conn(pool).await?; let mut q = community::table .into_boxed() @@ -373,22 +375,23 @@ impl ApubActor for Community { .filter(community::deleted.eq(false)) .filter(community::removed.eq(false)); } - q.first::(conn).await + q.first(conn).await.optional() } async fn read_from_name_and_domain( pool: &mut DbPool<'_>, community_name: &str, for_domain: &str, - ) -> Result { + ) -> Result, Error> { let conn = &mut get_conn(pool).await?; community::table .inner_join(instance::table) .filter(lower(community::name).eq(community_name.to_lowercase())) .filter(lower(instance::domain).eq(for_domain.to_lowercase())) .select(community::all_columns) - .first::(conn) + .first(conn) .await + .optional() } } @@ -524,7 +527,10 @@ mod tests { expires: None, }; - let read_community = Community::read(pool, inserted_community.id).await.unwrap(); + let read_community = Community::read(pool, inserted_community.id) + .await + .unwrap() + .unwrap(); let update_community_form = CommunityUpdateForm { title: Some("nada".to_owned()), diff --git a/crates/db_schema/src/impls/email_verification.rs b/crates/db_schema/src/impls/email_verification.rs index c5a8792fb..b4951cf73 100644 --- a/crates/db_schema/src/impls/email_verification.rs +++ b/crates/db_schema/src/impls/email_verification.rs @@ -16,6 +16,7 @@ use diesel::{ sql_types::Timestamptz, ExpressionMethods, IntoSql, + OptionalExtension, QueryDsl, }; use diesel_async::RunQueryDsl; @@ -25,17 +26,18 @@ impl EmailVerification { let conn = &mut get_conn(pool).await?; insert_into(email_verification) .values(form) - .get_result::(conn) + .get_result(conn) .await } - pub async fn read_for_token(pool: &mut DbPool<'_>, token: &str) -> Result { + pub async fn read_for_token(pool: &mut DbPool<'_>, token: &str) -> Result, Error> { let conn = &mut get_conn(pool).await?; email_verification .filter(verification_token.eq(token)) .filter(published.gt(now.into_sql::() - 7.days())) - .first::(conn) + .first(conn) .await + .optional() } pub async fn delete_old_tokens_for_local_user( pool: &mut DbPool<'_>, diff --git a/crates/db_schema/src/impls/instance.rs b/crates/db_schema/src/impls/instance.rs index c329d8cc0..2e309efb9 100644 --- a/crates/db_schema/src/impls/instance.rs +++ b/crates/db_schema/src/impls/instance.rs @@ -26,6 +26,7 @@ use diesel::{ result::Error, ExpressionMethods, NullableExpressionMethods, + OptionalExtension, QueryDsl, SelectableHelper, }; @@ -41,11 +42,14 @@ impl Instance { // First try to read the instance row and return directly if found let instance = instance::table .filter(lower(domain).eq(&domain_.to_lowercase())) - .first::(conn) - .await; + .first(conn) + .await + .optional()?; + + // TODO could convert this to unwrap_or_else once async closures are stable match instance { - Ok(i) => Ok(i), - Err(diesel::NotFound) => { + Some(i) => Ok(i), + None => { // Instance not in database yet, insert it let form = InstanceForm::builder() .domain(domain_) @@ -61,7 +65,6 @@ impl Instance { .get_result::(conn) .await } - e => e, } } pub async fn update( diff --git a/crates/db_schema/src/impls/language.rs b/crates/db_schema/src/impls/language.rs index 905221402..6a7b4e9ac 100644 --- a/crates/db_schema/src/impls/language.rs +++ b/crates/db_schema/src/impls/language.rs @@ -1,7 +1,7 @@ use crate::{ diesel::ExpressionMethods, newtypes::LanguageId, - schema::language::dsl::{code, language}, + schema::language, source::language::Language, utils::{get_conn, DbPool}, }; @@ -9,14 +9,14 @@ use diesel::{result::Error, QueryDsl}; use diesel_async::RunQueryDsl; impl Language { - pub async fn read_all(pool: &mut DbPool<'_>) -> Result, Error> { + pub async fn read_all(pool: &mut DbPool<'_>) -> Result, Error> { let conn = &mut get_conn(pool).await?; - language.load::(conn).await + language::table.load(conn).await } - pub async fn read_from_id(pool: &mut DbPool<'_>, id_: LanguageId) -> Result { + pub async fn read_from_id(pool: &mut DbPool<'_>, id_: LanguageId) -> Result { let conn = &mut get_conn(pool).await?; - language.find(id_).first::(conn).await + language::table.find(id_).first(conn).await } /// Attempts to find the given language code and return its ID. If not found, returns none. @@ -27,8 +27,8 @@ impl Language { if let Some(code_) = code_ { let conn = &mut get_conn(pool).await?; Ok( - language - .filter(code.eq(code_)) + language::table + .filter(language::code.eq(code_)) .first::(conn) .await .map(|l| l.id) diff --git a/crates/db_schema/src/impls/local_site.rs b/crates/db_schema/src/impls/local_site.rs index 39ed624ef..602dfe1f4 100644 --- a/crates/db_schema/src/impls/local_site.rs +++ b/crates/db_schema/src/impls/local_site.rs @@ -28,7 +28,7 @@ impl LocalSite { CACHE .try_get_with((), async { let conn = &mut get_conn(pool).await?; - local_site::table.first::(conn).await + local_site::table.first(conn).await }) .await?, ) diff --git a/crates/db_schema/src/impls/local_site_rate_limit.rs b/crates/db_schema/src/impls/local_site_rate_limit.rs index 0c9e96e0b..6ab9ca8b8 100644 --- a/crates/db_schema/src/impls/local_site_rate_limit.rs +++ b/crates/db_schema/src/impls/local_site_rate_limit.rs @@ -1,4 +1,5 @@ use crate::{ + diesel::OptionalExtension, schema::local_site_rate_limit, source::local_site_rate_limit::{ LocalSiteRateLimit, @@ -11,9 +12,9 @@ use diesel::{dsl::insert_into, result::Error}; use diesel_async::RunQueryDsl; impl LocalSiteRateLimit { - pub async fn read(pool: &mut DbPool<'_>) -> Result { + pub async fn read(pool: &mut DbPool<'_>) -> Result, Error> { let conn = &mut get_conn(pool).await?; - local_site_rate_limit::table.first::(conn).await + local_site_rate_limit::table.first(conn).await.optional() } pub async fn create( diff --git a/crates/db_schema/src/impls/local_user_vote_display_mode.rs b/crates/db_schema/src/impls/local_user_vote_display_mode.rs index 4458fc1b6..d77502335 100644 --- a/crates/db_schema/src/impls/local_user_vote_display_mode.rs +++ b/crates/db_schema/src/impls/local_user_vote_display_mode.rs @@ -1,4 +1,5 @@ use crate::{ + diesel::OptionalExtension, newtypes::LocalUserId, schema::local_user_vote_display_mode, source::local_user_vote_display_mode::{ @@ -12,11 +13,12 @@ use diesel::{dsl::insert_into, result::Error, QueryDsl}; use diesel_async::RunQueryDsl; impl LocalUserVoteDisplayMode { - pub async fn read(pool: &mut DbPool<'_>) -> Result { + pub async fn read(pool: &mut DbPool<'_>) -> Result, Error> { let conn = &mut get_conn(pool).await?; local_user_vote_display_mode::table - .first::(conn) + .first(conn) .await + .optional() } pub async fn create( diff --git a/crates/db_schema/src/impls/moderator.rs b/crates/db_schema/src/impls/moderator.rs index 99f117878..125bbcd51 100644 --- a/crates/db_schema/src/impls/moderator.rs +++ b/crates/db_schema/src/impls/moderator.rs @@ -568,6 +568,7 @@ mod tests { .unwrap(); let read_mod_remove_post = ModRemovePost::read(pool, inserted_mod_remove_post.id) .await + .unwrap() .unwrap(); let expected_mod_remove_post = ModRemovePost { id: inserted_mod_remove_post.id, @@ -590,6 +591,7 @@ mod tests { .unwrap(); let read_mod_lock_post = ModLockPost::read(pool, inserted_mod_lock_post.id) .await + .unwrap() .unwrap(); let expected_mod_lock_post = ModLockPost { id: inserted_mod_lock_post.id, @@ -612,6 +614,7 @@ mod tests { .unwrap(); let read_mod_feature_post = ModFeaturePost::read(pool, inserted_mod_feature_post.id) .await + .unwrap() .unwrap(); let expected_mod_feature_post = ModFeaturePost { id: inserted_mod_feature_post.id, @@ -635,6 +638,7 @@ mod tests { .unwrap(); let read_mod_remove_comment = ModRemoveComment::read(pool, inserted_mod_remove_comment.id) .await + .unwrap() .unwrap(); let expected_mod_remove_comment = ModRemoveComment { id: inserted_mod_remove_comment.id, @@ -660,6 +664,7 @@ mod tests { let read_mod_remove_community = ModRemoveCommunity::read(pool, inserted_mod_remove_community.id) .await + .unwrap() .unwrap(); let expected_mod_remove_community = ModRemoveCommunity { id: inserted_mod_remove_community.id, @@ -687,6 +692,7 @@ mod tests { let read_mod_ban_from_community = ModBanFromCommunity::read(pool, inserted_mod_ban_from_community.id) .await + .unwrap() .unwrap(); let expected_mod_ban_from_community = ModBanFromCommunity { id: inserted_mod_ban_from_community.id, @@ -709,7 +715,10 @@ mod tests { expires: None, }; let inserted_mod_ban = ModBan::create(pool, &mod_ban_form).await.unwrap(); - let read_mod_ban = ModBan::read(pool, inserted_mod_ban.id).await.unwrap(); + let read_mod_ban = ModBan::read(pool, inserted_mod_ban.id) + .await + .unwrap() + .unwrap(); let expected_mod_ban = ModBan { id: inserted_mod_ban.id, mod_person_id: inserted_mod.id, @@ -733,6 +742,7 @@ mod tests { .unwrap(); let read_mod_add_community = ModAddCommunity::read(pool, inserted_mod_add_community.id) .await + .unwrap() .unwrap(); let expected_mod_add_community = ModAddCommunity { id: inserted_mod_add_community.id, @@ -751,7 +761,10 @@ mod tests { removed: None, }; let inserted_mod_add = ModAdd::create(pool, &mod_add_form).await.unwrap(); - let read_mod_add = ModAdd::read(pool, inserted_mod_add.id).await.unwrap(); + let read_mod_add = ModAdd::read(pool, inserted_mod_add.id) + .await + .unwrap() + .unwrap(); let expected_mod_add = ModAdd { id: inserted_mod_add.id, mod_person_id: inserted_mod.id, diff --git a/crates/db_schema/src/impls/password_reset_request.rs b/crates/db_schema/src/impls/password_reset_request.rs index 491097135..762aa4656 100644 --- a/crates/db_schema/src/impls/password_reset_request.rs +++ b/crates/db_schema/src/impls/password_reset_request.rs @@ -1,4 +1,5 @@ use crate::{ + diesel::OptionalExtension, newtypes::LocalUserId, schema::password_reset_request::dsl::{local_user_id, password_reset_request, published, token}, source::password_reset_request::{PasswordResetRequest, PasswordResetRequestForm}, @@ -54,16 +55,14 @@ impl PasswordResetRequest { Self::create(pool, &form).await } - pub async fn read_from_token( - pool: &mut DbPool<'_>, - token_: &str, - ) -> Result { + pub async fn read_from_token(pool: &mut DbPool<'_>, token_: &str) -> Result, Error> { let conn = &mut get_conn(pool).await?; password_reset_request .filter(token.eq(token_)) .filter(published.gt(now.into_sql::() - 1.days())) - .first::(conn) + .first(conn) .await + .optional() } pub async fn get_recent_password_resets_count( @@ -141,6 +140,7 @@ mod tests { let read_password_reset_request = PasswordResetRequest::read_from_token(pool, token) .await + .unwrap() .unwrap(); let num_deleted = Person::delete(pool, inserted_person.id).await.unwrap(); Instance::delete(pool, inserted_instance.id).await.unwrap(); diff --git a/crates/db_schema/src/impls/person.rs b/crates/db_schema/src/impls/person.rs index c90f67891..68a9b3d59 100644 --- a/crates/db_schema/src/impls/person.rs +++ b/crates/db_schema/src/impls/person.rs @@ -1,4 +1,5 @@ use crate::{ + diesel::OptionalExtension, newtypes::{CommunityId, DbUrl, InstanceId, PersonId}, schema::{comment, community, instance, local_user, person, person_follower, post}, source::person::{ @@ -19,13 +20,16 @@ impl Crud for Person { type InsertForm = PersonInsertForm; type UpdateForm = PersonUpdateForm; type IdType = PersonId; - async fn read(pool: &mut DbPool<'_>, person_id: PersonId) -> Result { + + // Override this, so that you don't get back deleted + async fn read(pool: &mut DbPool<'_>, person_id: PersonId) -> Result, Error> { let conn = &mut get_conn(pool).await?; person::table .filter(person::deleted.eq(false)) .find(person_id) - .first::(conn) + .first(conn) .await + .optional() } async fn create(pool: &mut DbPool<'_>, form: &PersonInsertForm) -> Result { @@ -126,22 +130,19 @@ impl ApubActor for Person { object_id: &DbUrl, ) -> Result, Error> { let conn = &mut get_conn(pool).await?; - Ok( - person::table - .filter(person::deleted.eq(false)) - .filter(person::actor_id.eq(object_id)) - .first::(conn) - .await - .ok() - .map(Into::into), - ) + person::table + .filter(person::deleted.eq(false)) + .filter(person::actor_id.eq(object_id)) + .first(conn) + .await + .optional() } async fn read_from_name( pool: &mut DbPool<'_>, from_name: &str, include_deleted: bool, - ) -> Result { + ) -> Result, Error> { let conn = &mut get_conn(pool).await?; let mut q = person::table .into_boxed() @@ -150,14 +151,14 @@ impl ApubActor for Person { if !include_deleted { q = q.filter(person::deleted.eq(false)) } - q.first::(conn).await + q.first(conn).await.optional() } async fn read_from_name_and_domain( pool: &mut DbPool<'_>, person_name: &str, for_domain: &str, - ) -> Result { + ) -> Result, Error> { let conn = &mut get_conn(pool).await?; person::table @@ -165,8 +166,9 @@ impl ApubActor for Person { .filter(lower(person::name).eq(person_name.to_lowercase())) .filter(lower(instance::domain).eq(for_domain.to_lowercase())) .select(person::all_columns) - .first::(conn) + .first(conn) .await + .optional() } } @@ -269,7 +271,10 @@ mod tests { instance_id: inserted_instance.id, }; - let read_person = Person::read(pool, inserted_person.id).await.unwrap(); + let read_person = Person::read(pool, inserted_person.id) + .await + .unwrap() + .unwrap(); let update_person_form = PersonUpdateForm { actor_id: Some(inserted_person.actor_id.clone()), diff --git a/crates/db_schema/src/impls/person_mention.rs b/crates/db_schema/src/impls/person_mention.rs index 5524f87ee..8566d31b1 100644 --- a/crates/db_schema/src/impls/person_mention.rs +++ b/crates/db_schema/src/impls/person_mention.rs @@ -1,4 +1,5 @@ use crate::{ + diesel::OptionalExtension, newtypes::{CommentId, PersonId, PersonMentionId}, schema::person_mention, source::person_mention::{PersonMention, PersonMentionInsertForm, PersonMentionUpdateForm}, @@ -63,13 +64,14 @@ impl PersonMention { pool: &mut DbPool<'_>, for_comment_id: CommentId, for_recipient_id: PersonId, - ) -> Result { + ) -> Result, Error> { let conn = &mut get_conn(pool).await?; person_mention::table .filter(person_mention::comment_id.eq(for_comment_id)) .filter(person_mention::recipient_id.eq(for_recipient_id)) - .first::(conn) + .first(conn) .await + .optional() } } @@ -164,6 +166,7 @@ mod tests { let read_mention = PersonMention::read(pool, inserted_mention.id) .await + .unwrap() .unwrap(); let person_mention_update_form = PersonMentionUpdateForm { read: Some(false) }; diff --git a/crates/db_schema/src/impls/post.rs b/crates/db_schema/src/impls/post.rs index 596eb62bf..2d055b1a8 100644 --- a/crates/db_schema/src/impls/post.rs +++ b/crates/db_schema/src/impls/post.rs @@ -1,4 +1,5 @@ use crate::{ + diesel::OptionalExtension, newtypes::{CommunityId, DbUrl, PersonId, PostId}, schema::{post, post_hide, post_like, post_read, post_saved}, source::post::{ @@ -182,14 +183,11 @@ impl Post { ) -> Result, Error> { let conn = &mut get_conn(pool).await?; let object_id: DbUrl = object_id.into(); - Ok( - post::table - .filter(post::ap_id.eq(object_id)) - .first::(conn) - .await - .ok() - .map(Into::into), - ) + post::table + .filter(post::ap_id.eq(object_id)) + .first(conn) + .await + .optional() } pub async fn fetch_pictrs_posts_for_creator( @@ -517,7 +515,7 @@ mod tests { .unwrap(); assert_eq!(2, marked_as_read); - let read_post = Post::read(pool, inserted_post.id).await.unwrap(); + let read_post = Post::read(pool, inserted_post.id).await.unwrap().unwrap(); let new_post_update = PostUpdateForm { name: Some("A test post".into()), diff --git a/crates/db_schema/src/impls/private_message.rs b/crates/db_schema/src/impls/private_message.rs index e3ad03972..75c7ce9bc 100644 --- a/crates/db_schema/src/impls/private_message.rs +++ b/crates/db_schema/src/impls/private_message.rs @@ -1,5 +1,5 @@ use crate::{ - diesel::DecoratableTarget, + diesel::{DecoratableTarget, OptionalExtension}, newtypes::{DbUrl, PersonId, PrivateMessageId}, schema::private_message, source::private_message::{PrivateMessage, PrivateMessageInsertForm, PrivateMessageUpdateForm}, @@ -9,7 +9,6 @@ use crate::{ use chrono::{DateTime, Utc}; use diesel::{dsl::insert_into, result::Error, ExpressionMethods, QueryDsl}; use diesel_async::RunQueryDsl; -use lemmy_utils::error::LemmyResult; use url::Url; #[async_trait] @@ -74,17 +73,14 @@ impl PrivateMessage { pub async fn read_from_apub_id( pool: &mut DbPool<'_>, object_id: Url, - ) -> LemmyResult> { + ) -> Result, Error> { let conn = &mut get_conn(pool).await?; let object_id: DbUrl = object_id.into(); - Ok( - private_message::table - .filter(private_message::ap_id.eq(object_id)) - .first::(conn) - .await - .ok() - .map(Into::into), - ) + private_message::table + .filter(private_message::ap_id.eq(object_id)) + .first(conn) + .await + .optional() } } @@ -156,6 +152,7 @@ mod tests { let read_private_message = PrivateMessage::read(pool, inserted_private_message.id) .await + .unwrap() .unwrap(); let private_message_update_form = PrivateMessageUpdateForm { diff --git a/crates/db_schema/src/impls/registration_application.rs b/crates/db_schema/src/impls/registration_application.rs index c4df7ba69..46b7d4bee 100644 --- a/crates/db_schema/src/impls/registration_application.rs +++ b/crates/db_schema/src/impls/registration_application.rs @@ -1,4 +1,5 @@ use crate::{ + diesel::OptionalExtension, newtypes::LocalUserId, schema::registration_application::dsl::{local_user_id, registration_application}, source::registration_application::{ @@ -43,11 +44,12 @@ impl RegistrationApplication { pub async fn find_by_local_user_id( pool: &mut DbPool<'_>, local_user_id_: LocalUserId, - ) -> Result { + ) -> Result, Error> { let conn = &mut get_conn(pool).await?; registration_application .filter(local_user_id.eq(local_user_id_)) - .first::(conn) + .first(conn) .await + .optional() } } diff --git a/crates/db_schema/src/impls/secret.rs b/crates/db_schema/src/impls/secret.rs index f21c6c487..1365ea838 100644 --- a/crates/db_schema/src/impls/secret.rs +++ b/crates/db_schema/src/impls/secret.rs @@ -1,4 +1,5 @@ use crate::{ + diesel::OptionalExtension, schema::secret::dsl::secret, source::secret::Secret, utils::{get_conn, DbPool}, @@ -9,12 +10,12 @@ use diesel_async::RunQueryDsl; impl Secret { /// Initialize the Secrets from the DB. /// Warning: You should only call this once. - pub async fn init(pool: &mut DbPool<'_>) -> Result { + pub async fn init(pool: &mut DbPool<'_>) -> Result, Error> { Self::read_secrets(pool).await } - async fn read_secrets(pool: &mut DbPool<'_>) -> Result { + async fn read_secrets(pool: &mut DbPool<'_>) -> Result, Error> { let conn = &mut get_conn(pool).await?; - secret.first::(conn).await + secret.first(conn).await.optional() } } diff --git a/crates/db_schema/src/impls/site.rs b/crates/db_schema/src/impls/site.rs index 7e9329afb..a371f9e07 100644 --- a/crates/db_schema/src/impls/site.rs +++ b/crates/db_schema/src/impls/site.rs @@ -1,6 +1,6 @@ use crate::{ newtypes::{DbUrl, InstanceId, SiteId}, - schema::site::dsl::{actor_id, id, instance_id, site}, + schema::site, source::{ actor_language::SiteLanguage, site::{Site, SiteInsertForm, SiteUpdateForm}, @@ -19,7 +19,7 @@ impl Crud for Site { type IdType = SiteId; /// Use SiteView::read_local, or Site::read_from_apub_id instead - async fn read(_pool: &mut DbPool<'_>, _site_id: SiteId) -> Result { + async fn read(_pool: &mut DbPool<'_>, _site_id: SiteId) -> Result, Error> { unimplemented!() } @@ -31,9 +31,9 @@ impl Crud for Site { let conn = &mut get_conn(pool).await?; // Can't do separate insert/update commands because InsertForm/UpdateForm aren't convertible - let site_ = insert_into(site) + let site_ = insert_into(site::table) .values(form) - .on_conflict(actor_id) + .on_conflict(site::actor_id) .do_update() .set(form) .get_result::(conn) @@ -53,7 +53,7 @@ impl Crud for Site { new_site: &Self::UpdateForm, ) -> Result { let conn = &mut get_conn(pool).await?; - diesel::update(site.find(site_id)) + diesel::update(site::table.find(site_id)) .set(new_site) .get_result::(conn) .await @@ -66,9 +66,9 @@ impl Site { _instance_id: InstanceId, ) -> Result, Error> { let conn = &mut get_conn(pool).await?; - site - .filter(instance_id.eq(_instance_id)) - .get_result(conn) + site::table + .filter(site::instance_id.eq(_instance_id)) + .first(conn) .await .optional() } @@ -78,17 +78,20 @@ impl Site { ) -> Result, Error> { let conn = &mut get_conn(pool).await?; - site - .filter(actor_id.eq(object_id)) - .first::(conn) + site::table + .filter(site::actor_id.eq(object_id)) + .first(conn) .await .optional() - .map(Into::into) } pub async fn read_remote_sites(pool: &mut DbPool<'_>) -> Result, Error> { let conn = &mut get_conn(pool).await?; - site.order_by(id).offset(1).get_results::(conn).await + site::table + .order_by(site::id) + .offset(1) + .get_results::(conn) + .await } /// Instance actor is at the root path, so we simply need to clear the path and other unnecessary diff --git a/crates/db_schema/src/traits.rs b/crates/db_schema/src/traits.rs index b0434a65c..139ec0e15 100644 --- a/crates/db_schema/src/traits.rs +++ b/crates/db_schema/src/traits.rs @@ -1,4 +1,5 @@ use crate::{ + diesel::OptionalExtension, newtypes::{CommunityId, DbUrl, PersonId}, utils::{get_conn, DbPool}, }; @@ -42,10 +43,10 @@ where async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result; - async fn read(pool: &mut DbPool<'_>, id: Self::IdType) -> Result { + async fn read(pool: &mut DbPool<'_>, id: Self::IdType) -> Result, Error> { let query: Find = Self::table().find(id); let conn = &mut *get_conn(pool).await?; - query.first::(conn).await + query.first(conn).await.optional() } /// when you want to null out a column, you have to send Some(None)), since sending None means you just don't want to update that column. @@ -185,14 +186,14 @@ pub trait ApubActor { pool: &mut DbPool<'_>, actor_name: &str, include_deleted: bool, - ) -> Result + ) -> Result, Error> where Self: Sized; async fn read_from_name_and_domain( pool: &mut DbPool<'_>, actor_name: &str, protocol_domain: &str, - ) -> Result + ) -> Result, Error> where Self: Sized; } diff --git a/crates/db_schema/src/utils.rs b/crates/db_schema/src/utils.rs index f0b294c04..dcd208881 100644 --- a/crates/db_schema/src/utils.rs +++ b/crates/db_schema/src/utils.rs @@ -13,9 +13,14 @@ use diesel::{ pg::Pg, query_builder::{Query, QueryFragment}, query_dsl::methods::LimitDsl, - result::{ConnectionError, ConnectionResult, Error as DieselError, Error::QueryBuilderError}, + result::{ + ConnectionError, + ConnectionResult, + Error::{self as DieselError, QueryBuilderError}, + }, sql_types::{self, Timestamptz}, IntoSql, + OptionalExtension, PgConnection, }; use diesel_async::{ @@ -510,12 +515,12 @@ impl Queries { self, pool: &'a mut DbPool<'_>, args: Args, - ) -> Result + ) -> Result, DieselError> where RF: ReadFn<'a, T, Args>, { let conn = get_conn(pool).await?; - (self.read_fn)(conn, args).await + (self.read_fn)(conn, args).await.optional() } pub async fn list<'a, T, Args>( diff --git a/crates/db_views/src/comment_report_view.rs b/crates/db_views/src/comment_report_view.rs index 0da5b3cff..e524e9a30 100644 --- a/crates/db_views/src/comment_report_view.rs +++ b/crates/db_views/src/comment_report_view.rs @@ -134,7 +134,7 @@ fn queries<'a>() -> Queries< comment_report::table.find(report_id).into_boxed(), my_person_id, ) - .first::(&mut conn) + .first(&mut conn) .await }; @@ -191,7 +191,7 @@ impl CommentReportView { pool: &mut DbPool<'_>, report_id: CommentReportId, my_person_id: PersonId, - ) -> Result { + ) -> Result, Error> { queries().read(pool, (report_id, my_person_id)).await } @@ -396,11 +396,13 @@ mod tests { let agg = CommentAggregates::read(pool, inserted_comment.id) .await + .unwrap() .unwrap(); let read_jessica_report_view = CommentReportView::read(pool, inserted_jessica_report.id, inserted_timmy.id) .await + .unwrap() .unwrap(); let expected_jessica_report_view = CommentReportView { comment_report: inserted_jessica_report.clone(), @@ -554,6 +556,7 @@ mod tests { let read_jessica_report_view_after_resolve = CommentReportView::read(pool, inserted_jessica_report.id, inserted_timmy.id) .await + .unwrap() .unwrap(); let mut expected_jessica_report_view_after_resolve = expected_jessica_report_view; diff --git a/crates/db_views/src/comment_view.rs b/crates/db_views/src/comment_view.rs index 01ff394eb..e8957e1e9 100644 --- a/crates/db_views/src/comment_view.rs +++ b/crates/db_views/src/comment_view.rs @@ -191,7 +191,7 @@ fn queries<'a>() -> Queries< if my_person_id.is_none() { query = query.filter(community::visibility.eq(CommunityVisibility::Public)); } - query.first::(&mut conn).await + query.first(&mut conn).await }; let list = move |mut conn: DbConn<'a>, options: CommentQuery<'a>| async move { @@ -375,17 +375,21 @@ impl CommentView { pool: &mut DbPool<'_>, comment_id: CommentId, my_person_id: Option, - ) -> Result { + ) -> Result, Error> { // If a person is given, then my_vote (res.9), if None, should be 0, not null // Necessary to differentiate between other person's votes - let mut res = queries().read(pool, (comment_id, my_person_id)).await?; - if my_person_id.is_some() && res.my_vote.is_none() { - res.my_vote = Some(0); + if let Ok(Some(res)) = queries().read(pool, (comment_id, my_person_id)).await { + let mut new_view = res.clone(); + if my_person_id.is_some() && res.my_vote.is_none() { + new_view.my_vote = Some(0); + } + if res.comment.deleted || res.comment.removed { + new_view.comment.content = String::new(); + } + Ok(Some(new_view)) + } else { + Ok(None) } - if res.comment.deleted || res.comment.removed { - res.comment.content = String::new(); - } - Ok(res) } } @@ -472,7 +476,7 @@ mod tests { CommunityVisibility, SubscribedType, }; - use lemmy_utils::error::LemmyResult; + use lemmy_utils::{error::LemmyResult, LemmyErrorType}; use pretty_assertions::assert_eq; use serial_test::serial; @@ -700,7 +704,8 @@ mod tests { data.inserted_comment_1.id, Some(data.timmy_local_user_view.person.id), ) - .await?; + .await? + .unwrap(); // Make sure block set the creator blocked assert!(read_comment_from_blocked_person.creator_blocked); @@ -1009,7 +1014,9 @@ mod tests { } async fn expected_comment_view(data: &Data, pool: &mut DbPool<'_>) -> LemmyResult { - let agg = CommentAggregates::read(pool, data.inserted_comment_0.id).await?; + let agg = CommentAggregates::read(pool, data.inserted_comment_0.id) + .await? + .ok_or(LemmyErrorType::CouldntFindComment)?; Ok(CommentView { creator_banned_from_community: false, banned_from_community: false, @@ -1154,8 +1161,8 @@ mod tests { .await?; assert_eq!(5, authenticated_query.len()); - let unauthenticated_comment = CommentView::read(pool, data.inserted_comment_0.id, None).await; - assert!(unauthenticated_comment.is_err()); + let unauthenticated_comment = CommentView::read(pool, data.inserted_comment_0.id, None).await?; + assert!(unauthenticated_comment.is_none()); let authenticated_comment = CommentView::read( pool, @@ -1202,7 +1209,8 @@ mod tests { data.inserted_comment_0.id, Some(inserted_banned_from_comm_local_user.person_id), ) - .await?; + .await? + .ok_or(LemmyErrorType::CouldntFindComment)?; assert!(comment_view.banned_from_community); @@ -1222,7 +1230,8 @@ mod tests { data.inserted_comment_0.id, Some(data.timmy_local_user_view.person.id), ) - .await?; + .await? + .ok_or(LemmyErrorType::CouldntFindComment)?; assert!(!comment_view.banned_from_community); diff --git a/crates/db_views/src/local_user_view.rs b/crates/db_views/src/local_user_view.rs index 96d6a3530..0c13b0a68 100644 --- a/crates/db_views/src/local_user_view.rs +++ b/crates/db_views/src/local_user_view.rs @@ -62,7 +62,7 @@ fn queries<'a>( .inner_join(local_user_vote_display_mode::table) .inner_join(person_aggregates::table.on(person::id.eq(person_aggregates::person_id))) .select(selection) - .first::(&mut conn) + .first(&mut conn) .await }; @@ -86,28 +86,37 @@ fn queries<'a>( } impl LocalUserView { - pub async fn read(pool: &mut DbPool<'_>, local_user_id: LocalUserId) -> Result { + pub async fn read( + pool: &mut DbPool<'_>, + local_user_id: LocalUserId, + ) -> Result, Error> { queries().read(pool, ReadBy::Id(local_user_id)).await } - pub async fn read_person(pool: &mut DbPool<'_>, person_id: PersonId) -> Result { + pub async fn read_person( + pool: &mut DbPool<'_>, + person_id: PersonId, + ) -> Result, Error> { queries().read(pool, ReadBy::Person(person_id)).await } - pub async fn read_from_name(pool: &mut DbPool<'_>, name: &str) -> Result { + pub async fn read_from_name(pool: &mut DbPool<'_>, name: &str) -> Result, Error> { queries().read(pool, ReadBy::Name(name)).await } pub async fn find_by_email_or_name( pool: &mut DbPool<'_>, name_or_email: &str, - ) -> Result { + ) -> Result, Error> { queries() .read(pool, ReadBy::NameOrEmail(name_or_email)) .await } - pub async fn find_by_email(pool: &mut DbPool<'_>, from_email: &str) -> Result { + pub async fn find_by_email( + pool: &mut DbPool<'_>, + from_email: &str, + ) -> Result, Error> { queries().read(pool, ReadBy::Email(from_email)).await } diff --git a/crates/db_views/src/post_report_view.rs b/crates/db_views/src/post_report_view.rs index 878937d01..76679df1e 100644 --- a/crates/db_views/src/post_report_view.rs +++ b/crates/db_views/src/post_report_view.rs @@ -163,7 +163,7 @@ fn queries<'a>() -> Queries< post_report::table.find(report_id).into_boxed(), my_person_id, ) - .first::(&mut conn) + .first(&mut conn) .await }; @@ -219,7 +219,7 @@ impl PostReportView { pool: &mut DbPool<'_>, report_id: PostReportId, my_person_id: PersonId, - ) -> Result { + ) -> Result, Error> { queries().read(pool, (report_id, my_person_id)).await } @@ -421,6 +421,7 @@ mod tests { let read_jessica_report_view = PostReportView::read(pool, inserted_jessica_report.id, inserted_timmy.id) .await + .unwrap() .unwrap(); assert_eq!( @@ -458,6 +459,7 @@ mod tests { let read_jessica_report_view_after_resolve = PostReportView::read(pool, inserted_jessica_report.id, inserted_timmy.id) .await + .unwrap() .unwrap(); assert!(read_jessica_report_view_after_resolve.post_report.resolved); assert_eq!( diff --git a/crates/db_views/src/post_view.rs b/crates/db_views/src/post_view.rs index b323437d5..e66912190 100644 --- a/crates/db_views/src/post_view.rs +++ b/crates/db_views/src/post_view.rs @@ -305,7 +305,7 @@ fn queries<'a>() -> Queries< Commented::new(query) .text("PostView::read") - .first::(&mut conn) + .first(&mut conn) .await }; @@ -581,12 +581,10 @@ impl PostView { post_id: PostId, my_person_id: Option, is_mod_or_admin: bool, - ) -> Result { - let res = queries() + ) -> Result, Error> { + queries() .read(pool, (post_id, my_person_id, is_mod_or_admin)) - .await?; - - Ok(res) + .await } } @@ -597,19 +595,21 @@ impl PaginationCursor { PaginationCursor(format!("P{:x}", view.counts.post_id.0)) } pub async fn read(&self, pool: &mut DbPool<'_>) -> Result { - Ok(PaginationCursorData( - PostAggregates::read( - pool, - PostId( - self - .0 - .get(1..) - .and_then(|e| i32::from_str_radix(e, 16).ok()) - .ok_or_else(|| Error::QueryBuilderError("Could not parse pagination token".into()))?, - ), - ) - .await?, - )) + let err_msg = || Error::QueryBuilderError("Could not parse pagination token".into()); + let token = PostAggregates::read( + pool, + PostId( + self + .0 + .get(1..) + .and_then(|e| i32::from_str_radix(e, 16).ok()) + .ok_or_else(err_msg)?, + ), + ) + .await? + .ok_or_else(err_msg)?; + + Ok(PaginationCursorData(token)) } } @@ -783,7 +783,7 @@ mod tests { SortType, SubscribedType, }; - use lemmy_utils::error::LemmyResult; + use lemmy_utils::error::{LemmyErrorType, LemmyResult}; use pretty_assertions::assert_eq; use serial_test::serial; use std::{collections::HashSet, time::Duration}; @@ -964,7 +964,8 @@ mod tests { Some(data.local_user_view.person.id), false, ) - .await?; + .await? + .ok_or(LemmyErrorType::CouldntFindPost)?; let expected_post_listing_with_user = expected_post_view(&data, pool).await?; @@ -1014,7 +1015,9 @@ mod tests { .await?; let read_post_listing_single_no_person = - PostView::read(pool, data.inserted_post.id, None, false).await?; + PostView::read(pool, data.inserted_post.id, None, false) + .await? + .ok_or(LemmyErrorType::CouldntFindPost)?; let expected_post_listing_no_person = expected_post_view(&data, pool).await?; @@ -1091,7 +1094,8 @@ mod tests { Some(data.local_user_view.person.id), false, ) - .await?; + .await? + .ok_or(LemmyErrorType::CouldntFindPost)?; let mut expected_post_with_upvote = expected_post_view(&data, pool).await?; expected_post_with_upvote.my_vote = Some(1); @@ -1573,7 +1577,9 @@ mod tests { &data.inserted_community, &data.inserted_post, ); - let agg = PostAggregates::read(pool, inserted_post.id).await?; + let agg = PostAggregates::read(pool, inserted_post.id) + .await? + .ok_or(LemmyErrorType::CouldntFindPost)?; Ok(PostView { post: Post { @@ -1716,8 +1722,8 @@ mod tests { .await?; assert_eq!(2, authenticated_query.len()); - let unauthenticated_post = PostView::read(pool, data.inserted_post.id, None, false).await; - assert!(unauthenticated_post.is_err()); + let unauthenticated_post = PostView::read(pool, data.inserted_post.id, None, false).await?; + assert!(unauthenticated_post.is_none()); let authenticated_post = PostView::read( pool, @@ -1767,7 +1773,8 @@ mod tests { Some(inserted_banned_from_comm_local_user.person_id), false, ) - .await?; + .await? + .ok_or(LemmyErrorType::CouldntFindPost)?; assert!(post_view.banned_from_community); @@ -1788,7 +1795,8 @@ mod tests { Some(data.local_user_view.person.id), false, ) - .await?; + .await? + .ok_or(LemmyErrorType::CouldntFindPost)?; assert!(!post_view.banned_from_community); diff --git a/crates/db_views/src/private_message_report_view.rs b/crates/db_views/src/private_message_report_view.rs index dff9820d9..a402d0d4f 100644 --- a/crates/db_views/src/private_message_report_view.rs +++ b/crates/db_views/src/private_message_report_view.rs @@ -42,7 +42,7 @@ fn queries<'a>() -> Queries< let read = move |mut conn: DbConn<'a>, report_id: PrivateMessageReportId| async move { all_joins(private_message_report::table.find(report_id).into_boxed()) - .first::(&mut conn) + .first(&mut conn) .await }; @@ -77,7 +77,7 @@ impl PrivateMessageReportView { pub async fn read( pool: &mut DbPool<'_>, report_id: PrivateMessageReportId, - ) -> Result { + ) -> Result, Error> { queries().read(pool, report_id).await } diff --git a/crates/db_views/src/private_message_view.rs b/crates/db_views/src/private_message_view.rs index 466f3bdf0..764ef1dcb 100644 --- a/crates/db_views/src/private_message_view.rs +++ b/crates/db_views/src/private_message_view.rs @@ -53,7 +53,7 @@ fn queries<'a>() -> Queries< all_joins(private_message::table.find(private_message_id).into_boxed()) .order_by(private_message::published.desc()) .select(selection) - .first::(&mut conn) + .first(&mut conn) .await }; @@ -113,7 +113,7 @@ impl PrivateMessageView { pub async fn read( pool: &mut DbPool<'_>, private_message_id: PrivateMessageId, - ) -> Result { + ) -> Result, Error> { queries().read(pool, private_message_id).await } diff --git a/crates/db_views/src/registration_application_view.rs b/crates/db_views/src/registration_application_view.rs index 85916bb90..7346dcd0d 100644 --- a/crates/db_views/src/registration_application_view.rs +++ b/crates/db_views/src/registration_application_view.rs @@ -42,7 +42,7 @@ fn queries<'a>() -> Queries< .find(registration_application_id) .into_boxed(), ) - .first::(&mut conn) + .first(&mut conn) .await }; @@ -76,7 +76,7 @@ impl RegistrationApplicationView { pub async fn read( pool: &mut DbPool<'_>, registration_application_id: i32, - ) -> Result { + ) -> Result, Error> { queries().read(pool, registration_application_id).await } @@ -209,6 +209,7 @@ mod tests { let read_sara_app_view = RegistrationApplicationView::read(pool, sara_app.id) .await + .unwrap() .unwrap(); let jess_person_form = PersonInsertForm::builder() @@ -240,6 +241,7 @@ mod tests { let read_jess_app_view = RegistrationApplicationView::read(pool, jess_app.id) .await + .unwrap() .unwrap(); let mut expected_sara_app_view = RegistrationApplicationView { @@ -343,6 +345,7 @@ mod tests { let read_sara_app_view_after_approve = RegistrationApplicationView::read(pool, sara_app.id) .await + .unwrap() .unwrap(); // Make sure the columns changed diff --git a/crates/db_views/src/site_view.rs b/crates/db_views/src/site_view.rs index 52074c982..8f0722318 100644 --- a/crates/db_views/src/site_view.rs +++ b/crates/db_views/src/site_view.rs @@ -1,5 +1,5 @@ use crate::structs::SiteView; -use diesel::{result::Error, ExpressionMethods, JoinOnDsl, QueryDsl}; +use diesel::{result::Error, ExpressionMethods, JoinOnDsl, OptionalExtension, QueryDsl}; use diesel_async::RunQueryDsl; use lemmy_db_schema::{ schema::{local_site, local_site_rate_limit, site, site_aggregates}, @@ -7,7 +7,7 @@ use lemmy_db_schema::{ }; impl SiteView { - pub async fn read_local(pool: &mut DbPool<'_>) -> Result { + pub async fn read_local(pool: &mut DbPool<'_>) -> Result, Error> { let conn = &mut get_conn(pool).await?; site::table .inner_join(local_site::table) @@ -21,7 +21,8 @@ impl SiteView { local_site_rate_limit::all_columns, site_aggregates::all_columns, )) - .first::(conn) + .first(conn) .await + .optional() } } diff --git a/crates/db_views_actor/src/comment_reply_view.rs b/crates/db_views_actor/src/comment_reply_view.rs index 77f744a97..baa4f5601 100644 --- a/crates/db_views_actor/src/comment_reply_view.rs +++ b/crates/db_views_actor/src/comment_reply_view.rs @@ -188,7 +188,7 @@ fn queries<'a>() -> Queries< comment_reply::table.find(comment_reply_id).into_boxed(), my_person_id, ) - .first::(&mut conn) + .first(&mut conn) .await }; @@ -234,7 +234,7 @@ impl CommentReplyView { pool: &mut DbPool<'_>, comment_reply_id: CommentReplyId, my_person_id: Option, - ) -> Result { + ) -> Result, Error> { queries().read(pool, (comment_reply_id, my_person_id)).await } diff --git a/crates/db_views_actor/src/community_view.rs b/crates/db_views_actor/src/community_view.rs index 3107478dc..b5c23c6ef 100644 --- a/crates/db_views_actor/src/community_view.rs +++ b/crates/db_views_actor/src/community_view.rs @@ -102,7 +102,7 @@ fn queries<'a>() -> Queries< query = query.filter(community::visibility.eq(CommunityVisibility::Public)); } - query.first::(&mut conn).await + query.first(&mut conn).await }; let list = move |mut conn: DbConn<'a>, (options, site): (CommunityQuery<'a>, &'a Site)| async move { @@ -194,7 +194,7 @@ impl CommunityView { community_id: CommunityId, my_person_id: Option, is_mod_or_admin: bool, - ) -> Result { + ) -> Result, Error> { queries() .read(pool, (community_id, my_person_id, is_mod_or_admin)) .await @@ -209,9 +209,10 @@ impl CommunityView { CommunityModeratorView::is_community_moderator(pool, community_id, person_id).await?; if is_mod { Ok(true) + } else if let Ok(Some(person_view)) = PersonView::read(pool, person_id).await { + Ok(person_view.is_admin) } else { - let is_admin = PersonView::read(pool, person_id).await?.is_admin; - Ok(is_admin) + Ok(false) } } @@ -223,11 +224,12 @@ impl CommunityView { let is_mod_of_any = CommunityModeratorView::is_community_moderator_of_any(pool, person_id).await?; if is_mod_of_any { - return Ok(true); + Ok(true) + } else if let Ok(Some(person_view)) = PersonView::read(pool, person_id).await { + Ok(person_view.is_admin) + } else { + Ok(false) } - - let is_admin = PersonView::read(pool, person_id).await?.is_admin; - Ok(is_admin) } } @@ -384,8 +386,10 @@ mod tests { assert_eq!(1, authenticated_query.len()); let unauthenticated_community = - CommunityView::read(pool, data.inserted_community.id, None, false).await; - assert!(unauthenticated_community.is_err()); + CommunityView::read(pool, data.inserted_community.id, None, false) + .await + .unwrap(); + assert!(unauthenticated_community.is_none()); let authenticated_community = CommunityView::read( pool, diff --git a/crates/db_views_actor/src/person_mention_view.rs b/crates/db_views_actor/src/person_mention_view.rs index 399850292..65c0bd0e6 100644 --- a/crates/db_views_actor/src/person_mention_view.rs +++ b/crates/db_views_actor/src/person_mention_view.rs @@ -187,7 +187,7 @@ fn queries<'a>() -> Queries< person_mention::table.find(person_mention_id).into_boxed(), my_person_id, ) - .first::(&mut conn) + .first(&mut conn) .await }; @@ -233,7 +233,7 @@ impl PersonMentionView { pool: &mut DbPool<'_>, person_mention_id: PersonMentionId, my_person_id: Option, - ) -> Result { + ) -> Result, Error> { queries() .read(pool, (person_mention_id, my_person_id)) .await diff --git a/crates/db_views_actor/src/person_view.rs b/crates/db_views_actor/src/person_view.rs index b3eac296d..5734bc812 100644 --- a/crates/db_views_actor/src/person_view.rs +++ b/crates/db_views_actor/src/person_view.rs @@ -72,7 +72,7 @@ fn queries<'a>( let read = move |mut conn: DbConn<'a>, person_id: PersonId| async move { all_joins(person::table.find(person_id).into_boxed()) - .first::(&mut conn) + .first(&mut conn) .await }; @@ -134,7 +134,7 @@ fn queries<'a>( } impl PersonView { - pub async fn read(pool: &mut DbPool<'_>, person_id: PersonId) -> Result { + pub async fn read(pool: &mut DbPool<'_>, person_id: PersonId) -> Result, Error> { queries().read(pool, person_id).await } @@ -163,12 +163,10 @@ impl PersonQuery { } #[cfg(test)] -#[allow(clippy::unwrap_used)] #[allow(clippy::indexing_slicing)] mod tests { use super::*; - use diesel::NotFound; use lemmy_db_schema::{ assert_length, source::{ @@ -179,7 +177,7 @@ mod tests { traits::Crud, utils::build_db_pool_for_tests, }; - use lemmy_utils::error::LemmyResult; + use lemmy_utils::{error::LemmyResult, LemmyErrorType}; use pretty_assertions::assert_eq; use serial_test::serial; @@ -254,8 +252,8 @@ mod tests { ) .await?; - let read = PersonView::read(pool, data.alice.id).await; - assert_eq!(read.err(), Some(NotFound)); + let read = PersonView::read(pool, data.alice.id).await?; + assert!(read.is_none()); let list = PersonQuery { sort: Some(SortType::New), @@ -314,10 +312,16 @@ mod tests { assert_length!(1, list); assert_eq!(list[0].person.id, data.alice.id); - let is_admin = PersonView::read(pool, data.alice.id).await?.is_admin; + let is_admin = PersonView::read(pool, data.alice.id) + .await? + .ok_or(LemmyErrorType::CouldntFindPerson)? + .is_admin; assert!(is_admin); - let is_admin = PersonView::read(pool, data.bob.id).await?.is_admin; + let is_admin = PersonView::read(pool, data.bob.id) + .await? + .ok_or(LemmyErrorType::CouldntFindPerson)? + .is_admin; assert!(!is_admin); cleanup(data, pool).await diff --git a/crates/federate/src/util.rs b/crates/federate/src/util.rs index cedf3387f..b057ab0fe 100644 --- a/crates/federate/src/util.rs +++ b/crates/federate/src/util.rs @@ -151,7 +151,6 @@ pub(crate) async fn get_activity_cached( .try_get_with(activity_id, async { let row = SentActivity::read(pool, activity_id) .await - .optional() .context("could not read activity")?; let Some(mut row) = row else { return anyhow::Result::<_, anyhow::Error>::Ok(None); diff --git a/crates/routes/src/feeds.rs b/crates/routes/src/feeds.rs index 2c29f192e..5e3db357a 100644 --- a/crates/routes/src/feeds.rs +++ b/crates/routes/src/feeds.rs @@ -152,7 +152,9 @@ async fn get_feed_data( limit: i64, page: i64, ) -> LemmyResult { - let site_view = SiteView::read_local(&mut context.pool()).await?; + let site_view = SiteView::read_local(&mut context.pool()) + .await? + .ok_or(LemmyErrorType::LocalSiteNotSetup)?; check_private_instance(&None, &site_view.local_site)?; @@ -257,8 +259,12 @@ async fn get_feed_user( page: &i64, user_name: &str, ) -> LemmyResult { - let site_view = SiteView::read_local(&mut context.pool()).await?; - let person = Person::read_from_name(&mut context.pool(), user_name, false).await?; + let site_view = SiteView::read_local(&mut context.pool()) + .await? + .ok_or(LemmyErrorType::LocalSiteNotSetup)?; + let person = Person::read_from_name(&mut context.pool(), user_name, false) + .await? + .ok_or(LemmyErrorType::CouldntFindPerson)?; check_private_instance(&None, &site_view.local_site)?; @@ -293,8 +299,12 @@ async fn get_feed_community( page: &i64, community_name: &str, ) -> LemmyResult { - let site_view = SiteView::read_local(&mut context.pool()).await?; - let community = Community::read_from_name(&mut context.pool(), community_name, false).await?; + let site_view = SiteView::read_local(&mut context.pool()) + .await? + .ok_or(LemmyErrorType::LocalSiteNotSetup)?; + let community = Community::read_from_name(&mut context.pool(), community_name, false) + .await? + .ok_or(LemmyErrorType::CouldntFindCommunity)?; if community.visibility != CommunityVisibility::Public { return Err(LemmyErrorType::CouldntFindCommunity.into()); } @@ -336,7 +346,9 @@ async fn get_feed_front( page: &i64, jwt: &str, ) -> LemmyResult { - let site_view = SiteView::read_local(&mut context.pool()).await?; + let site_view = SiteView::read_local(&mut context.pool()) + .await? + .ok_or(LemmyErrorType::LocalSiteNotSetup)?; let local_user = local_user_view_from_jwt(jwt, context).await?; check_private_instance(&Some(local_user.clone()), &site_view.local_site)?; @@ -371,7 +383,9 @@ async fn get_feed_front( #[tracing::instrument(skip_all)] async fn get_feed_inbox(context: &LemmyContext, jwt: &str) -> LemmyResult { - let site_view = SiteView::read_local(&mut context.pool()).await?; + let site_view = SiteView::read_local(&mut context.pool()) + .await? + .ok_or(LemmyErrorType::LocalSiteNotSetup)?; let local_user = local_user_view_from_jwt(jwt, context).await?; let person_id = local_user.local_user.person_id; let show_bot_accounts = local_user.local_user.show_bot_accounts; diff --git a/crates/routes/src/lib.rs b/crates/routes/src/lib.rs index a88225622..4f8d60246 100644 --- a/crates/routes/src/lib.rs +++ b/crates/routes/src/lib.rs @@ -1,6 +1,6 @@ use lemmy_api_common::{claims::Claims, context::LemmyContext, utils::check_user_valid}; use lemmy_db_views::structs::LocalUserView; -use lemmy_utils::error::LemmyResult; +use lemmy_utils::{error::LemmyResult, LemmyErrorType}; pub mod feeds; pub mod images; @@ -10,7 +10,9 @@ pub mod webfinger; #[tracing::instrument(skip_all)] async fn local_user_view_from_jwt(jwt: &str, context: &LemmyContext) -> LemmyResult { let local_user_id = Claims::validate(jwt, context).await?; - let local_user_view = LocalUserView::read(&mut context.pool(), local_user_id).await?; + let local_user_view = LocalUserView::read(&mut context.pool(), local_user_id) + .await? + .ok_or(LemmyErrorType::CouldntFindLocalUser)?; check_user_valid(&local_user_view.person)?; Ok(local_user_view) diff --git a/crates/routes/src/nodeinfo.rs b/crates/routes/src/nodeinfo.rs index b5db4e965..dbb2ef68a 100644 --- a/crates/routes/src/nodeinfo.rs +++ b/crates/routes/src/nodeinfo.rs @@ -40,7 +40,8 @@ async fn node_info_well_known(context: web::Data) -> LemmyResult) -> Result { let site_view = SiteView::read_local(&mut context.pool()) .await - .map_err(|_| ErrorBadRequest(LemmyError::from(anyhow!("not_found"))))?; + .map_err(|_| ErrorBadRequest(LemmyError::from(anyhow!("not_found"))))? + .ok_or(ErrorBadRequest(LemmyError::from(anyhow!("not_found"))))?; let protocols = if site_view.local_site.federation_enabled { Some(vec!["activitypub".to_string()]) diff --git a/crates/routes/src/webfinger.rs b/crates/routes/src/webfinger.rs index 36dd97079..6c630df4c 100644 --- a/crates/routes/src/webfinger.rs +++ b/crates/routes/src/webfinger.rs @@ -47,10 +47,12 @@ async fn get_webfinger_response( let user_id: Option = Person::read_from_name(&mut context.pool(), name, false) .await .ok() + .flatten() .map(|c| c.actor_id.into()); let community_id: Option = Community::read_from_name(&mut context.pool(), name, false) .await .ok() + .flatten() .and_then(|c| { if c.visibility == CommunityVisibility::Public { let id: Url = c.actor_id.into(); diff --git a/crates/utils/src/error.rs b/crates/utils/src/error.rs index cc6897edd..a687f5136 100644 --- a/crates/utils/src/error.rs +++ b/crates/utils/src/error.rs @@ -43,6 +43,16 @@ pub enum LemmyErrorType { BannedFromCommunity, CouldntFindCommunity, CouldntFindPerson, + CouldntFindComment, + CouldntFindCommentReport, + CouldntFindPostReport, + CouldntFindPrivateMessageReport, + CouldntFindLocalUser, + CouldntFindPersonMention, + CouldntFindRegistrationApplication, + CouldntFindCommentReply, + CouldntFindPrivateMessage, + CouldntFindActivity, PersonIsBlocked, CommunityIsBlocked, InstanceIsBlocked, @@ -92,6 +102,7 @@ pub enum LemmyErrorType { PageDoesNotSpecifyGroup, NoCommunityFoundInCc, NoEmailSetup, + LocalSiteNotSetup, EmailSmtpServerNeedsAPort, MissingAnEmail, RateLimitError, diff --git a/src/code_migrations.rs b/src/code_migrations.rs index a2325971b..05b564f47 100644 --- a/src/code_migrations.rs +++ b/src/code_migrations.rs @@ -345,7 +345,7 @@ async fn instance_actor_2022_01_28( settings: &Settings, ) -> LemmyResult<()> { info!("Running instance_actor_2021_09_29"); - if let Ok(site_view) = SiteView::read_local(pool).await { + if let Ok(Some(site_view)) = SiteView::read_local(pool).await { let site = site_view.site; // if site already has public key, we dont need to do anything here if !site.public_key.is_empty() { diff --git a/src/lib.rs b/src/lib.rs index 00960826a..12a0f4a7d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -124,12 +124,12 @@ pub async fn start_lemmy_server(args: CmdArgs) -> LemmyResult<()> { // Initialize the secrets let secret = Secret::init(&mut (&pool).into()) - .await + .await? .expect("Couldn't initialize secrets."); // Make sure the local site is set up. let site_view = SiteView::read_local(&mut (&pool).into()) - .await + .await? .expect("local site not set up"); let local_site = site_view.local_site; let federation_enabled = local_site.federation_enabled; diff --git a/src/session_middleware.rs b/src/session_middleware.rs index 2bee64ca0..f4535249c 100644 --- a/src/session_middleware.rs +++ b/src/session_middleware.rs @@ -130,7 +130,7 @@ mod tests { let pool_ = build_db_pool_for_tests().await; let pool = &mut (&pool_).into(); - let secret = Secret::init(pool).await.unwrap(); + let secret = Secret::init(pool).await.unwrap().unwrap(); let context = LemmyContext::create( pool_.clone(), ClientBuilder::new(Client::default()).build(), From 6efab9aab10dbd16a897d4045324d0cf5d0cfdab Mon Sep 17 00:00:00 2001 From: Dessalines Date: Tue, 16 Apr 2024 19:20:44 -0400 Subject: [PATCH 24/26] Creating a LocalImageView, so that front ends have the Person struct. (#4631) * Creating a LocalImageView, so that front ends have the Person struct. * Removing local_user from LocalImageView. * Add uploader check. --- api_tests/package.json | 3 +- api_tests/pnpm-lock.yaml | 3574 +++++++++++++---------- api_tests/src/image.spec.ts | 7 +- api_tests/src/shared.ts | 4 +- crates/api/src/local_user/list_media.rs | 5 +- crates/api/src/site/list_all_media.rs | 5 +- crates/api_common/src/person.rs | 6 +- crates/api_common/src/utils.rs | 20 +- crates/db_schema/src/impls/images.rs | 53 +- crates/db_views/src/lib.rs | 2 + crates/db_views/src/local_image_view.rs | 61 + crates/db_views/src/structs.rs | 11 + 12 files changed, 2089 insertions(+), 1662 deletions(-) create mode 100644 crates/db_views/src/local_image_view.rs diff --git a/api_tests/package.json b/api_tests/package.json index 60adac43c..3cd854a73 100644 --- a/api_tests/package.json +++ b/api_tests/package.json @@ -6,6 +6,7 @@ "repository": "https://github.com/LemmyNet/lemmy", "author": "Dessalines", "license": "AGPL-3.0", + "packageManager": "pnpm@9.0.1+sha256.46d50ee2afecb42b185ebbd662dc7bdd52ef5be56bf035bb615cab81a75345df", "scripts": { "lint": "tsc --noEmit && eslint --report-unused-disable-directives --ext .js,.ts,.tsx src && prettier --check 'src/**/*.ts'", "fix": "prettier --write src && eslint --fix src", @@ -27,7 +28,7 @@ "eslint": "^8.57.0", "eslint-plugin-prettier": "^5.1.3", "jest": "^29.5.0", - "lemmy-js-client": "0.19.4-alpha.16", + "lemmy-js-client": "0.19.4-alpha.18", "prettier": "^3.2.5", "ts-jest": "^29.1.0", "typescript": "^5.4.4" diff --git a/api_tests/pnpm-lock.yaml b/api_tests/pnpm-lock.yaml index 81508d740..a4c3ce603 100644 --- a/api_tests/pnpm-lock.yaml +++ b/api_tests/pnpm-lock.yaml @@ -1,78 +1,1623 @@ -lockfileVersion: '6.0' +lockfileVersion: '9.0' settings: autoInstallPeers: true excludeLinksFromLockfile: false -devDependencies: - '@types/jest': - specifier: ^29.5.12 - version: 29.5.12 - '@types/node': - specifier: ^20.12.4 - version: 20.12.4 - '@typescript-eslint/eslint-plugin': - specifier: ^7.5.0 - version: 7.5.0(@typescript-eslint/parser@7.5.0)(eslint@8.57.0)(typescript@5.4.4) - '@typescript-eslint/parser': - specifier: ^7.5.0 - version: 7.5.0(eslint@8.57.0)(typescript@5.4.4) - download-file-sync: - specifier: ^1.0.4 - version: 1.0.4 - eslint: - specifier: ^8.57.0 - version: 8.57.0 - eslint-plugin-prettier: - specifier: ^5.1.3 - version: 5.1.3(eslint@8.57.0)(prettier@3.2.5) - jest: - specifier: ^29.5.0 - version: 29.7.0(@types/node@20.12.4) - lemmy-js-client: - specifier: 0.19.4-alpha.16 - version: 0.19.4-alpha.16 - prettier: - specifier: ^3.2.5 - version: 3.2.5 - ts-jest: - specifier: ^29.1.0 - version: 29.1.2(@babel/core@7.23.9)(jest@29.7.0)(typescript@5.4.4) - typescript: - specifier: ^5.4.4 - version: 5.4.4 +importers: + + .: + devDependencies: + '@types/jest': + specifier: ^29.5.12 + version: 29.5.12 + '@types/node': + specifier: ^20.12.4 + version: 20.12.4 + '@typescript-eslint/eslint-plugin': + specifier: ^7.5.0 + version: 7.5.0(@typescript-eslint/parser@7.5.0(eslint@8.57.0)(typescript@5.4.4))(eslint@8.57.0)(typescript@5.4.4) + '@typescript-eslint/parser': + specifier: ^7.5.0 + version: 7.5.0(eslint@8.57.0)(typescript@5.4.4) + download-file-sync: + specifier: ^1.0.4 + version: 1.0.4 + eslint: + specifier: ^8.57.0 + version: 8.57.0 + eslint-plugin-prettier: + specifier: ^5.1.3 + version: 5.1.3(eslint@8.57.0)(prettier@3.2.5) + jest: + specifier: ^29.5.0 + version: 29.7.0(@types/node@20.12.4) + lemmy-js-client: + specifier: 0.19.4-alpha.18 + version: 0.19.4-alpha.18 + prettier: + specifier: ^3.2.5 + version: 3.2.5 + ts-jest: + specifier: ^29.1.0 + version: 29.1.2(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(jest@29.7.0(@types/node@20.12.4))(typescript@5.4.4) + typescript: + specifier: ^5.4.4 + version: 5.4.4 packages: - /@aashutoshrathi/word-wrap@1.2.6: + '@aashutoshrathi/word-wrap@1.2.6': resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} engines: {node: '>=0.10.0'} - dev: true - /@ampproject/remapping@2.2.1: + '@ampproject/remapping@2.2.1': resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} engines: {node: '>=6.0.0'} + + '@babel/code-frame@7.23.5': + resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.23.5': + resolution: {integrity: sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.23.9': + resolution: {integrity: sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.23.6': + resolution: {integrity: sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.23.6': + resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-environment-visitor@7.22.20': + resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-function-name@7.23.0': + resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-hoist-variables@7.22.5': + resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.22.15': + resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.23.3': + resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.22.5': + resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-simple-access@7.22.5': + resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-split-export-declaration@7.22.6': + resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.23.4': + resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.22.20': + resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.23.5': + resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.23.9': + resolution: {integrity: sha512-87ICKgU5t5SzOT7sBMfCOZQ2rHjRU+Pcb9BoILMYz600W6DkVRLFBPwQ18gwUVvggqXivaUakpnxWQGbpywbBQ==} + engines: {node: '>=6.9.0'} + + '@babel/highlight@7.23.4': + resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.23.9': + resolution: {integrity: sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-syntax-async-generators@7.8.4': + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-bigint@7.8.3': + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-class-properties@7.12.13': + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-meta@7.10.4': + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-json-strings@7.8.3': + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-jsx@7.23.3': + resolution: {integrity: sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4': + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3': + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-numeric-separator@7.10.4': + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-object-rest-spread@7.8.3': + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3': + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-chaining@7.8.3': + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-top-level-await@7.14.5': + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.23.3': + resolution: {integrity: sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/template@7.23.9': + resolution: {integrity: sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.23.9': + resolution: {integrity: sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.23.9': + resolution: {integrity: sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==} + engines: {node: '>=6.9.0'} + + '@bcoe/v8-coverage@0.2.3': + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + + '@eslint-community/eslint-utils@4.4.0': + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.10.0': + resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/eslintrc@2.1.4': + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@eslint/js@8.57.0': + resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@humanwhocodes/config-array@0.11.14': + resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} + engines: {node: '>=10.10.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/object-schema@2.0.2': + resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==} + + '@istanbuljs/load-nyc-config@1.1.0': + resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} + engines: {node: '>=8'} + + '@istanbuljs/schema@0.1.3': + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + + '@jest/console@29.7.0': + resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/core@29.7.0': + resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/environment@29.7.0': + resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/expect-utils@29.7.0': + resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/expect@29.7.0': + resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/fake-timers@29.7.0': + resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/globals@29.7.0': + resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/reporters@29.7.0': + resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/schemas@29.6.3': + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/source-map@29.6.3': + resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/test-result@29.7.0': + resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/test-sequencer@29.7.0': + resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/transform@29.7.0': + resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/types@29.6.3': + resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jridgewell/gen-mapping@0.3.3': + resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} + engines: {node: '>=6.0.0'} + + '@jridgewell/resolve-uri@3.1.1': + resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} + engines: {node: '>=6.0.0'} + + '@jridgewell/set-array@1.1.2': + resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.4.15': + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + + '@jridgewell/trace-mapping@0.3.22': + resolution: {integrity: sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@pkgr/core@0.1.1': + resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + + '@sinclair/typebox@0.27.8': + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + + '@sinonjs/commons@3.0.1': + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + + '@sinonjs/fake-timers@10.3.0': + resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.6.8': + resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.20.5': + resolution: {integrity: sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==} + + '@types/graceful-fs@4.1.9': + resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} + + '@types/istanbul-lib-coverage@2.0.6': + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + + '@types/istanbul-lib-report@3.0.3': + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + + '@types/istanbul-reports@3.0.4': + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + + '@types/jest@29.5.12': + resolution: {integrity: sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/node@20.12.4': + resolution: {integrity: sha512-E+Fa9z3wSQpzgYQdYmme5X3OTuejnnTx88A6p6vkkJosR3KBz+HpE3kqNm98VE6cfLFcISx7zW7MsJkH6KwbTw==} + + '@types/semver@7.5.8': + resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} + + '@types/stack-utils@2.0.3': + resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + + '@types/yargs-parser@21.0.3': + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + + '@types/yargs@17.0.32': + resolution: {integrity: sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==} + + '@typescript-eslint/eslint-plugin@7.5.0': + resolution: {integrity: sha512-HpqNTH8Du34nLxbKgVMGljZMG0rJd2O9ecvr2QLYp+7512ty1j42KnsFwspPXg1Vh8an9YImf6CokUBltisZFQ==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + '@typescript-eslint/parser': ^7.0.0 + eslint: ^8.56.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/parser@7.5.0': + resolution: {integrity: sha512-cj+XGhNujfD2/wzR1tabNsidnYRaFfEkcULdcIyVBYcXjBvBKOes+mpMBP7hMpOyk+gBcfXsrg4NBGAStQyxjQ==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + eslint: ^8.56.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/scope-manager@7.5.0': + resolution: {integrity: sha512-Z1r7uJY0MDeUlql9XJ6kRVgk/sP11sr3HKXn268HZyqL7i4cEfrdFuSSY/0tUqT37l5zT0tJOsuDP16kio85iA==} + engines: {node: ^18.18.0 || >=20.0.0} + + '@typescript-eslint/type-utils@7.5.0': + resolution: {integrity: sha512-A021Rj33+G8mx2Dqh0nMO9GyjjIBK3MqgVgZ2qlKf6CJy51wY/lkkFqq3TqqnH34XyAHUkq27IjlUkWlQRpLHw==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + eslint: ^8.56.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/types@7.5.0': + resolution: {integrity: sha512-tv5B4IHeAdhR7uS4+bf8Ov3k793VEVHd45viRRkehIUZxm0WF82VPiLgHzA/Xl4TGPg1ZD49vfxBKFPecD5/mg==} + engines: {node: ^18.18.0 || >=20.0.0} + + '@typescript-eslint/typescript-estree@7.5.0': + resolution: {integrity: sha512-YklQQfe0Rv2PZEueLTUffiQGKQneiIEKKnfIqPIOxgM9lKSZFCjT5Ad4VqRKj/U4+kQE3fa8YQpskViL7WjdPQ==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/utils@7.5.0': + resolution: {integrity: sha512-3vZl9u0R+/FLQcpy2EHyRGNqAS/ofJ3Ji8aebilfJe+fobK8+LbIFmrHciLVDxjDoONmufDcnVSF38KwMEOjzw==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + eslint: ^8.56.0 + + '@typescript-eslint/visitor-keys@7.5.0': + resolution: {integrity: sha512-mcuHM/QircmA6O7fy6nn2w/3ditQkj+SgtOc8DW3uQ10Yfj42amm2i+6F2K4YAOPNNTmE6iM1ynM6lrSwdendA==} + engines: {node: ^18.18.0 || >=20.0.0} + + '@ungap/structured-clone@1.2.0': + resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.11.3: + resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + + babel-jest@29.7.0: + resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.8.0 + + babel-plugin-istanbul@6.1.1: + resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} + engines: {node: '>=8'} + + babel-plugin-jest-hoist@29.6.3: + resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + babel-preset-current-node-syntax@1.0.1: + resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} + peerDependencies: + '@babel/core': ^7.0.0 + + babel-preset-jest@29.6.3: + resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.0.0 + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + + browserslist@4.22.3: + resolution: {integrity: sha512-UAp55yfwNv0klWNapjs/ktHoguxuQNGnOzxYmfnXIS+8AsRDZkSDxg7R1AX3GKzn078SBI5dzwzj/Yx0Or0e3A==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + bs-logger@0.2.6: + resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} + engines: {node: '>= 6'} + + bser@2.1.1: + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + + caniuse-lite@1.0.30001581: + resolution: {integrity: sha512-whlTkwhqV2tUmP3oYhtNfaWGYHDdS3JYFQBKXxcUR9qqPWsRhFHhoISO2Xnl/g0xyKzht9mI1LZpiNWfMzHixQ==} + + chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + char-regex@1.0.2: + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} + + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + + cjs-module-lexer@1.2.3: + resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + co@4.6.0: + resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + + collect-v8-coverage@1.0.2: + resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} + + color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + create-jest@29.7.0: + resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + + cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + + debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + dedent@1.5.1: + resolution: {integrity: sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + detect-newline@3.1.0: + resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} + engines: {node: '>=8'} + + diff-sequences@29.6.3: + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + + doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + + download-file-sync@1.0.4: + resolution: {integrity: sha512-vH92qNH508jZZA12HQNq/aiMDfagr4JvjFiI17Bi8oYjsxwv5ZVIi7iHkYmUXxOQUr90tcVX+8EPePjAqG1Y0w==} + + electron-to-chromium@1.4.648: + resolution: {integrity: sha512-EmFMarXeqJp9cUKu/QEciEApn0S/xRcpZWuAm32U7NgoZCimjsilKXHRO9saeEW55eHZagIDg6XTUOv32w9pjg==} + + emittery@0.13.1: + resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} + engines: {node: '>=12'} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + + escalade@3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} + + escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-plugin-prettier@5.1.3: + resolution: {integrity: sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + '@types/eslint': '>=8.0.0' + eslint: '>=8.0.0' + eslint-config-prettier: '*' + prettier: '>=3.0.0' + peerDependenciesMeta: + '@types/eslint': + optional: true + eslint-config-prettier: + optional: true + + eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint@8.57.0: + resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + + espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + esquery@1.5.0: + resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + + exit@0.1.2: + resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} + engines: {node: '>= 0.8.0'} + + expect@29.7.0: + resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + + fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fastq@1.17.1: + resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + + fb-watchman@2.0.2: + resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + + file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + + fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@3.2.0: + resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} + engines: {node: ^10.12.0 || >=12.0.0} + + flatted@3.3.1: + resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-package-type@0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + + get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + + globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + + globals@13.24.0: + resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} + engines: {node: '>=8'} + + globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + hasown@2.0.0: + resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} + engines: {node: '>= 0.4'} + + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + + human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + + ignore@5.3.1: + resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} + engines: {node: '>= 4'} + + import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + + import-local@3.1.0: + resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} + engines: {node: '>=8'} + hasBin: true + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-core-module@2.13.1: + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-generator-fn@2.1.0: + resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} + engines: {node: '>=6'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + + istanbul-lib-instrument@5.2.1: + resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} + engines: {node: '>=8'} + + istanbul-lib-instrument@6.0.1: + resolution: {integrity: sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA==} + engines: {node: '>=10'} + + istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + + istanbul-lib-source-maps@4.0.1: + resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} + engines: {node: '>=10'} + + istanbul-reports@3.1.6: + resolution: {integrity: sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==} + engines: {node: '>=8'} + + jest-changed-files@29.7.0: + resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-circus@29.7.0: + resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-cli@29.7.0: + resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + jest-config@29.7.0: + resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@types/node': '*' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + ts-node: + optional: true + + jest-diff@29.7.0: + resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-docblock@29.7.0: + resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-each@29.7.0: + resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-environment-node@29.7.0: + resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-get-type@29.6.3: + resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-haste-map@29.7.0: + resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-leak-detector@29.7.0: + resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-matcher-utils@29.7.0: + resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-message-util@29.7.0: + resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-mock@29.7.0: + resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-pnp-resolver@1.2.3: + resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} + engines: {node: '>=6'} + peerDependencies: + jest-resolve: '*' + peerDependenciesMeta: + jest-resolve: + optional: true + + jest-regex-util@29.6.3: + resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-resolve-dependencies@29.7.0: + resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-resolve@29.7.0: + resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-runner@29.7.0: + resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-runtime@29.7.0: + resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-snapshot@29.7.0: + resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-util@29.7.0: + resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-validate@29.7.0: + resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-watcher@29.7.0: + resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-worker@29.7.0: + resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest@29.7.0: + resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + jsesc@2.5.2: + resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} + engines: {node: '>=4'} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + + lemmy-js-client@0.19.4-alpha.18: + resolution: {integrity: sha512-CUKRIiINZF2zOfK5WzBDF071LjMmRBFHwiSYBMGJyQP1zu8sPKCb/ptg25WWrf79Y4uOaVLctgHg3oEUXmSUmQ==} + + leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.memoize@4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + + make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + + makeerror@1.0.12: + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} + + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@9.0.3: + resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} + engines: {node: '>=16 || 14 >=14.17'} + + ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + node-int64@0.4.0: + resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + + node-releases@2.0.14: + resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + + optionator@0.9.3: + resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} + engines: {node: '>= 0.8.0'} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + engines: {node: '>= 6'} + + pkg-dir@4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier-linter-helpers@1.0.0: + resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + engines: {node: '>=6.0.0'} + + prettier@3.2.5: + resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} + engines: {node: '>=14'} + hasBin: true + + pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + pure-rand@6.0.4: + resolution: {integrity: sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + react-is@18.2.0: + resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + resolve-cwd@3.0.0: + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + resolve.exports@2.0.2: + resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} + engines: {node: '>=10'} + + resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + + reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + engines: {node: '>=10'} + hasBin: true + + semver@7.6.0: + resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} + engines: {node: '>=10'} + hasBin: true + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + source-map-support@0.5.13: + resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + + string-length@4.0.2: + resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} + engines: {node: '>=10'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-bom@4.0.0: + resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} + engines: {node: '>=8'} + + strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + synckit@0.8.8: + resolution: {integrity: sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==} + engines: {node: ^14.18.0 || >=16.0.0} + + test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + + text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + + tmpl@1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + + to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + ts-api-utils@1.3.0: + resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} + engines: {node: '>=16'} + peerDependencies: + typescript: '>=4.2.0' + + ts-jest@29.1.2: + resolution: {integrity: sha512-br6GJoH/WUX4pu7FbZXuWGKGNDuU7b8Uj77g/Sp7puZV6EXzuByl6JrECvm0MzVzSTkSHWTihsXt+5XYER5b+g==} + engines: {node: ^16.10.0 || ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@babel/core': '>=7.0.0-beta.0 <8' + '@jest/types': ^29.0.0 + babel-jest: ^29.0.0 + esbuild: '*' + jest: ^29.0.0 + typescript: '>=4.3 <6' + peerDependenciesMeta: + '@babel/core': + optional: true + '@jest/types': + optional: true + babel-jest: + optional: true + esbuild: + optional: true + + tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + + type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + + type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + + typescript@5.4.4: + resolution: {integrity: sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + + update-browserslist-db@1.0.13: + resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + v8-to-istanbul@9.2.0: + resolution: {integrity: sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==} + engines: {node: '>=10.12.0'} + + walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + write-file-atomic@4.0.2: + resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + +snapshots: + + '@aashutoshrathi/word-wrap@1.2.6': {} + + '@ampproject/remapping@2.2.1': dependencies: '@jridgewell/gen-mapping': 0.3.3 '@jridgewell/trace-mapping': 0.3.22 - dev: true - /@babel/code-frame@7.23.5: - resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==} - engines: {node: '>=6.9.0'} + '@babel/code-frame@7.23.5': dependencies: '@babel/highlight': 7.23.4 chalk: 2.4.2 - dev: true - /@babel/compat-data@7.23.5: - resolution: {integrity: sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==} - engines: {node: '>=6.9.0'} - dev: true + '@babel/compat-data@7.23.5': {} - /@babel/core@7.23.9: - resolution: {integrity: sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==} - engines: {node: '>=6.9.0'} + '@babel/core@7.23.9': dependencies: '@ampproject/remapping': 2.2.1 '@babel/code-frame': 7.23.5 @@ -91,61 +1636,38 @@ packages: semver: 6.3.1 transitivePeerDependencies: - supports-color - dev: true - /@babel/generator@7.23.6: - resolution: {integrity: sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==} - engines: {node: '>=6.9.0'} + '@babel/generator@7.23.6': dependencies: '@babel/types': 7.23.9 '@jridgewell/gen-mapping': 0.3.3 '@jridgewell/trace-mapping': 0.3.22 jsesc: 2.5.2 - dev: true - /@babel/helper-compilation-targets@7.23.6: - resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==} - engines: {node: '>=6.9.0'} + '@babel/helper-compilation-targets@7.23.6': dependencies: '@babel/compat-data': 7.23.5 '@babel/helper-validator-option': 7.23.5 browserslist: 4.22.3 lru-cache: 5.1.1 semver: 6.3.1 - dev: true - /@babel/helper-environment-visitor@7.22.20: - resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} - engines: {node: '>=6.9.0'} - dev: true + '@babel/helper-environment-visitor@7.22.20': {} - /@babel/helper-function-name@7.23.0: - resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} - engines: {node: '>=6.9.0'} + '@babel/helper-function-name@7.23.0': dependencies: '@babel/template': 7.23.9 '@babel/types': 7.23.9 - dev: true - /@babel/helper-hoist-variables@7.22.5: - resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} - engines: {node: '>=6.9.0'} + '@babel/helper-hoist-variables@7.22.5': dependencies: '@babel/types': 7.23.9 - dev: true - /@babel/helper-module-imports@7.22.15: - resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} - engines: {node: '>=6.9.0'} + '@babel/helper-module-imports@7.22.15': dependencies: '@babel/types': 7.23.9 - dev: true - /@babel/helper-module-transforms@7.23.3(@babel/core@7.23.9): - resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 + '@babel/helper-module-transforms@7.23.3(@babel/core@7.23.9)': dependencies: '@babel/core': 7.23.9 '@babel/helper-environment-visitor': 7.22.20 @@ -153,211 +1675,118 @@ packages: '@babel/helper-simple-access': 7.22.5 '@babel/helper-split-export-declaration': 7.22.6 '@babel/helper-validator-identifier': 7.22.20 - dev: true - /@babel/helper-plugin-utils@7.22.5: - resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} - engines: {node: '>=6.9.0'} - dev: true + '@babel/helper-plugin-utils@7.22.5': {} - /@babel/helper-simple-access@7.22.5: - resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} - engines: {node: '>=6.9.0'} + '@babel/helper-simple-access@7.22.5': dependencies: '@babel/types': 7.23.9 - dev: true - /@babel/helper-split-export-declaration@7.22.6: - resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} - engines: {node: '>=6.9.0'} + '@babel/helper-split-export-declaration@7.22.6': dependencies: '@babel/types': 7.23.9 - dev: true - /@babel/helper-string-parser@7.23.4: - resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} - engines: {node: '>=6.9.0'} - dev: true + '@babel/helper-string-parser@7.23.4': {} - /@babel/helper-validator-identifier@7.22.20: - resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} - engines: {node: '>=6.9.0'} - dev: true + '@babel/helper-validator-identifier@7.22.20': {} - /@babel/helper-validator-option@7.23.5: - resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} - engines: {node: '>=6.9.0'} - dev: true + '@babel/helper-validator-option@7.23.5': {} - /@babel/helpers@7.23.9: - resolution: {integrity: sha512-87ICKgU5t5SzOT7sBMfCOZQ2rHjRU+Pcb9BoILMYz600W6DkVRLFBPwQ18gwUVvggqXivaUakpnxWQGbpywbBQ==} - engines: {node: '>=6.9.0'} + '@babel/helpers@7.23.9': dependencies: '@babel/template': 7.23.9 '@babel/traverse': 7.23.9 '@babel/types': 7.23.9 transitivePeerDependencies: - supports-color - dev: true - /@babel/highlight@7.23.4: - resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} - engines: {node: '>=6.9.0'} + '@babel/highlight@7.23.4': dependencies: '@babel/helper-validator-identifier': 7.22.20 chalk: 2.4.2 js-tokens: 4.0.0 - dev: true - /@babel/parser@7.23.9: - resolution: {integrity: sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==} - engines: {node: '>=6.0.0'} - hasBin: true + '@babel/parser@7.23.9': dependencies: '@babel/types': 7.23.9 - dev: true - /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.23.9): - resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.23.9)': dependencies: '@babel/core': 7.23.9 '@babel/helper-plugin-utils': 7.22.5 - dev: true - /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.23.9): - resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.23.9)': dependencies: '@babel/core': 7.23.9 '@babel/helper-plugin-utils': 7.22.5 - dev: true - /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.23.9): - resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.23.9)': dependencies: '@babel/core': 7.23.9 '@babel/helper-plugin-utils': 7.22.5 - dev: true - /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.23.9): - resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.23.9)': dependencies: '@babel/core': 7.23.9 '@babel/helper-plugin-utils': 7.22.5 - dev: true - /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.9): - resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.9)': dependencies: '@babel/core': 7.23.9 '@babel/helper-plugin-utils': 7.22.5 - dev: true - /@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.23.9): - resolution: {integrity: sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.23.9)': dependencies: '@babel/core': 7.23.9 '@babel/helper-plugin-utils': 7.22.5 - dev: true - /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.9): - resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.9)': dependencies: '@babel/core': 7.23.9 '@babel/helper-plugin-utils': 7.22.5 - dev: true - /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.9): - resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.9)': dependencies: '@babel/core': 7.23.9 '@babel/helper-plugin-utils': 7.22.5 - dev: true - /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.9): - resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.9)': dependencies: '@babel/core': 7.23.9 '@babel/helper-plugin-utils': 7.22.5 - dev: true - /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.9): - resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.9)': dependencies: '@babel/core': 7.23.9 '@babel/helper-plugin-utils': 7.22.5 - dev: true - /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.9): - resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.9)': dependencies: '@babel/core': 7.23.9 '@babel/helper-plugin-utils': 7.22.5 - dev: true - /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.9): - resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.9)': dependencies: '@babel/core': 7.23.9 '@babel/helper-plugin-utils': 7.22.5 - dev: true - /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.9): - resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.9)': dependencies: '@babel/core': 7.23.9 '@babel/helper-plugin-utils': 7.22.5 - dev: true - /@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.23.9): - resolution: {integrity: sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.23.9)': dependencies: '@babel/core': 7.23.9 '@babel/helper-plugin-utils': 7.22.5 - dev: true - /@babel/template@7.23.9: - resolution: {integrity: sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==} - engines: {node: '>=6.9.0'} + '@babel/template@7.23.9': dependencies: '@babel/code-frame': 7.23.5 '@babel/parser': 7.23.9 '@babel/types': 7.23.9 - dev: true - /@babel/traverse@7.23.9: - resolution: {integrity: sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==} - engines: {node: '>=6.9.0'} + '@babel/traverse@7.23.9': dependencies: '@babel/code-frame': 7.23.5 '@babel/generator': 7.23.6 @@ -371,39 +1800,23 @@ packages: globals: 11.12.0 transitivePeerDependencies: - supports-color - dev: true - /@babel/types@7.23.9: - resolution: {integrity: sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==} - engines: {node: '>=6.9.0'} + '@babel/types@7.23.9': dependencies: '@babel/helper-string-parser': 7.23.4 '@babel/helper-validator-identifier': 7.22.20 to-fast-properties: 2.0.0 - dev: true - /@bcoe/v8-coverage@0.2.3: - resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} - dev: true + '@bcoe/v8-coverage@0.2.3': {} - /@eslint-community/eslint-utils@4.4.0(eslint@8.57.0): - resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + '@eslint-community/eslint-utils@4.4.0(eslint@8.57.0)': dependencies: eslint: 8.57.0 eslint-visitor-keys: 3.4.3 - dev: true - /@eslint-community/regexpp@4.10.0: - resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - dev: true + '@eslint-community/regexpp@4.10.0': {} - /@eslint/eslintrc@2.1.4: - resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/eslintrc@2.1.4': dependencies: ajv: 6.12.6 debug: 4.3.4 @@ -416,52 +1829,32 @@ packages: strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color - dev: true - /@eslint/js@8.57.0: - resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true + '@eslint/js@8.57.0': {} - /@humanwhocodes/config-array@0.11.14: - resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} - engines: {node: '>=10.10.0'} + '@humanwhocodes/config-array@0.11.14': dependencies: '@humanwhocodes/object-schema': 2.0.2 debug: 4.3.4 minimatch: 3.1.2 transitivePeerDependencies: - supports-color - dev: true - /@humanwhocodes/module-importer@1.0.1: - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} - dev: true + '@humanwhocodes/module-importer@1.0.1': {} - /@humanwhocodes/object-schema@2.0.2: - resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==} - dev: true + '@humanwhocodes/object-schema@2.0.2': {} - /@istanbuljs/load-nyc-config@1.1.0: - resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} - engines: {node: '>=8'} + '@istanbuljs/load-nyc-config@1.1.0': dependencies: camelcase: 5.3.1 find-up: 4.1.0 get-package-type: 0.1.0 js-yaml: 3.14.1 resolve-from: 5.0.0 - dev: true - /@istanbuljs/schema@0.1.3: - resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} - engines: {node: '>=8'} - dev: true + '@istanbuljs/schema@0.1.3': {} - /@jest/console@29.7.0: - resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/console@29.7.0': dependencies: '@jest/types': 29.6.3 '@types/node': 20.12.4 @@ -469,16 +1862,8 @@ packages: jest-message-util: 29.7.0 jest-util: 29.7.0 slash: 3.0.0 - dev: true - /@jest/core@29.7.0: - resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true + '@jest/core@29.7.0': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0 @@ -512,38 +1897,26 @@ packages: - babel-plugin-macros - supports-color - ts-node - dev: true - /@jest/environment@29.7.0: - resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/environment@29.7.0': dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 '@types/node': 20.12.4 jest-mock: 29.7.0 - dev: true - /@jest/expect-utils@29.7.0: - resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/expect-utils@29.7.0': dependencies: jest-get-type: 29.6.3 - dev: true - /@jest/expect@29.7.0: - resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/expect@29.7.0': dependencies: expect: 29.7.0 jest-snapshot: 29.7.0 transitivePeerDependencies: - supports-color - dev: true - /@jest/fake-timers@29.7.0: - resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/fake-timers@29.7.0': dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 @@ -551,11 +1924,8 @@ packages: jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 - dev: true - /@jest/globals@29.7.0: - resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/globals@29.7.0': dependencies: '@jest/environment': 29.7.0 '@jest/expect': 29.7.0 @@ -563,16 +1933,8 @@ packages: jest-mock: 29.7.0 transitivePeerDependencies: - supports-color - dev: true - /@jest/reporters@29.7.0: - resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true + '@jest/reporters@29.7.0': dependencies: '@bcoe/v8-coverage': 0.2.3 '@jest/console': 29.7.0 @@ -600,47 +1962,32 @@ packages: v8-to-istanbul: 9.2.0 transitivePeerDependencies: - supports-color - dev: true - /@jest/schemas@29.6.3: - resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/schemas@29.6.3': dependencies: '@sinclair/typebox': 0.27.8 - dev: true - /@jest/source-map@29.6.3: - resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/source-map@29.6.3': dependencies: '@jridgewell/trace-mapping': 0.3.22 callsites: 3.1.0 graceful-fs: 4.2.11 - dev: true - /@jest/test-result@29.7.0: - resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/test-result@29.7.0': dependencies: '@jest/console': 29.7.0 '@jest/types': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 collect-v8-coverage: 1.0.2 - dev: true - /@jest/test-sequencer@29.7.0: - resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/test-sequencer@29.7.0': dependencies: '@jest/test-result': 29.7.0 graceful-fs: 4.2.11 jest-haste-map: 29.7.0 slash: 3.0.0 - dev: true - /@jest/transform@29.7.0: - resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/transform@29.7.0': dependencies: '@babel/core': 7.23.9 '@jest/types': 29.6.3 @@ -659,11 +2006,8 @@ packages: write-file-atomic: 4.0.2 transitivePeerDependencies: - supports-color - dev: true - /@jest/types@29.6.3: - resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/types@29.6.3': dependencies: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 @@ -671,176 +2015,105 @@ packages: '@types/node': 20.12.4 '@types/yargs': 17.0.32 chalk: 4.1.2 - dev: true - /@jridgewell/gen-mapping@0.3.3: - resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} - engines: {node: '>=6.0.0'} + '@jridgewell/gen-mapping@0.3.3': dependencies: '@jridgewell/set-array': 1.1.2 '@jridgewell/sourcemap-codec': 1.4.15 '@jridgewell/trace-mapping': 0.3.22 - dev: true - /@jridgewell/resolve-uri@3.1.1: - resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} - engines: {node: '>=6.0.0'} - dev: true + '@jridgewell/resolve-uri@3.1.1': {} - /@jridgewell/set-array@1.1.2: - resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} - engines: {node: '>=6.0.0'} - dev: true + '@jridgewell/set-array@1.1.2': {} - /@jridgewell/sourcemap-codec@1.4.15: - resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} - dev: true + '@jridgewell/sourcemap-codec@1.4.15': {} - /@jridgewell/trace-mapping@0.3.22: - resolution: {integrity: sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==} + '@jridgewell/trace-mapping@0.3.22': dependencies: '@jridgewell/resolve-uri': 3.1.1 '@jridgewell/sourcemap-codec': 1.4.15 - dev: true - /@nodelib/fs.scandir@2.1.5: - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 run-parallel: 1.2.0 - dev: true - /@nodelib/fs.stat@2.0.5: - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - dev: true + '@nodelib/fs.stat@2.0.5': {} - /@nodelib/fs.walk@1.2.8: - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} + '@nodelib/fs.walk@1.2.8': dependencies: '@nodelib/fs.scandir': 2.1.5 fastq: 1.17.1 - dev: true - /@pkgr/core@0.1.1: - resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} - engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - dev: true + '@pkgr/core@0.1.1': {} - /@sinclair/typebox@0.27.8: - resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} - dev: true + '@sinclair/typebox@0.27.8': {} - /@sinonjs/commons@3.0.1: - resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + '@sinonjs/commons@3.0.1': dependencies: type-detect: 4.0.8 - dev: true - /@sinonjs/fake-timers@10.3.0: - resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + '@sinonjs/fake-timers@10.3.0': dependencies: '@sinonjs/commons': 3.0.1 - dev: true - /@types/babel__core@7.20.5: - resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.23.9 '@babel/types': 7.23.9 '@types/babel__generator': 7.6.8 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.20.5 - dev: true - /@types/babel__generator@7.6.8: - resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} + '@types/babel__generator@7.6.8': dependencies: '@babel/types': 7.23.9 - dev: true - /@types/babel__template@7.4.4: - resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + '@types/babel__template@7.4.4': dependencies: '@babel/parser': 7.23.9 '@babel/types': 7.23.9 - dev: true - /@types/babel__traverse@7.20.5: - resolution: {integrity: sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==} + '@types/babel__traverse@7.20.5': dependencies: '@babel/types': 7.23.9 - dev: true - /@types/graceful-fs@4.1.9: - resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} + '@types/graceful-fs@4.1.9': dependencies: '@types/node': 20.12.4 - dev: true - /@types/istanbul-lib-coverage@2.0.6: - resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} - dev: true + '@types/istanbul-lib-coverage@2.0.6': {} - /@types/istanbul-lib-report@3.0.3: - resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + '@types/istanbul-lib-report@3.0.3': dependencies: '@types/istanbul-lib-coverage': 2.0.6 - dev: true - /@types/istanbul-reports@3.0.4: - resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + '@types/istanbul-reports@3.0.4': dependencies: '@types/istanbul-lib-report': 3.0.3 - dev: true - /@types/jest@29.5.12: - resolution: {integrity: sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==} + '@types/jest@29.5.12': dependencies: expect: 29.7.0 pretty-format: 29.7.0 - dev: true - /@types/json-schema@7.0.15: - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - dev: true + '@types/json-schema@7.0.15': {} - /@types/node@20.12.4: - resolution: {integrity: sha512-E+Fa9z3wSQpzgYQdYmme5X3OTuejnnTx88A6p6vkkJosR3KBz+HpE3kqNm98VE6cfLFcISx7zW7MsJkH6KwbTw==} + '@types/node@20.12.4': dependencies: undici-types: 5.26.5 - dev: true - /@types/semver@7.5.8: - resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} - dev: true + '@types/semver@7.5.8': {} - /@types/stack-utils@2.0.3: - resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} - dev: true + '@types/stack-utils@2.0.3': {} - /@types/yargs-parser@21.0.3: - resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} - dev: true + '@types/yargs-parser@21.0.3': {} - /@types/yargs@17.0.32: - resolution: {integrity: sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==} + '@types/yargs@17.0.32': dependencies: '@types/yargs-parser': 21.0.3 - dev: true - /@typescript-eslint/eslint-plugin@7.5.0(@typescript-eslint/parser@7.5.0)(eslint@8.57.0)(typescript@5.4.4): - resolution: {integrity: sha512-HpqNTH8Du34nLxbKgVMGljZMG0rJd2O9ecvr2QLYp+7512ty1j42KnsFwspPXg1Vh8an9YImf6CokUBltisZFQ==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - '@typescript-eslint/parser': ^7.0.0 - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/eslint-plugin@7.5.0(@typescript-eslint/parser@7.5.0(eslint@8.57.0)(typescript@5.4.4))(eslint@8.57.0)(typescript@5.4.4)': dependencies: '@eslint-community/regexpp': 4.10.0 '@typescript-eslint/parser': 7.5.0(eslint@8.57.0)(typescript@5.4.4) @@ -855,20 +2128,12 @@ packages: natural-compare: 1.4.0 semver: 7.6.0 ts-api-utils: 1.3.0(typescript@5.4.4) + optionalDependencies: typescript: 5.4.4 transitivePeerDependencies: - supports-color - dev: true - /@typescript-eslint/parser@7.5.0(eslint@8.57.0)(typescript@5.4.4): - resolution: {integrity: sha512-cj+XGhNujfD2/wzR1tabNsidnYRaFfEkcULdcIyVBYcXjBvBKOes+mpMBP7hMpOyk+gBcfXsrg4NBGAStQyxjQ==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/parser@7.5.0(eslint@8.57.0)(typescript@5.4.4)': dependencies: '@typescript-eslint/scope-manager': 7.5.0 '@typescript-eslint/types': 7.5.0 @@ -876,52 +2141,31 @@ packages: '@typescript-eslint/visitor-keys': 7.5.0 debug: 4.3.4 eslint: 8.57.0 + optionalDependencies: typescript: 5.4.4 transitivePeerDependencies: - supports-color - dev: true - /@typescript-eslint/scope-manager@7.5.0: - resolution: {integrity: sha512-Z1r7uJY0MDeUlql9XJ6kRVgk/sP11sr3HKXn268HZyqL7i4cEfrdFuSSY/0tUqT37l5zT0tJOsuDP16kio85iA==} - engines: {node: ^18.18.0 || >=20.0.0} + '@typescript-eslint/scope-manager@7.5.0': dependencies: '@typescript-eslint/types': 7.5.0 '@typescript-eslint/visitor-keys': 7.5.0 - dev: true - /@typescript-eslint/type-utils@7.5.0(eslint@8.57.0)(typescript@5.4.4): - resolution: {integrity: sha512-A021Rj33+G8mx2Dqh0nMO9GyjjIBK3MqgVgZ2qlKf6CJy51wY/lkkFqq3TqqnH34XyAHUkq27IjlUkWlQRpLHw==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/type-utils@7.5.0(eslint@8.57.0)(typescript@5.4.4)': dependencies: '@typescript-eslint/typescript-estree': 7.5.0(typescript@5.4.4) '@typescript-eslint/utils': 7.5.0(eslint@8.57.0)(typescript@5.4.4) debug: 4.3.4 eslint: 8.57.0 ts-api-utils: 1.3.0(typescript@5.4.4) + optionalDependencies: typescript: 5.4.4 transitivePeerDependencies: - supports-color - dev: true - /@typescript-eslint/types@7.5.0: - resolution: {integrity: sha512-tv5B4IHeAdhR7uS4+bf8Ov3k793VEVHd45viRRkehIUZxm0WF82VPiLgHzA/Xl4TGPg1ZD49vfxBKFPecD5/mg==} - engines: {node: ^18.18.0 || >=20.0.0} - dev: true + '@typescript-eslint/types@7.5.0': {} - /@typescript-eslint/typescript-estree@7.5.0(typescript@5.4.4): - resolution: {integrity: sha512-YklQQfe0Rv2PZEueLTUffiQGKQneiIEKKnfIqPIOxgM9lKSZFCjT5Ad4VqRKj/U4+kQE3fa8YQpskViL7WjdPQ==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/typescript-estree@7.5.0(typescript@5.4.4)': dependencies: '@typescript-eslint/types': 7.5.0 '@typescript-eslint/visitor-keys': 7.5.0 @@ -931,16 +2175,12 @@ packages: minimatch: 9.0.3 semver: 7.6.0 ts-api-utils: 1.3.0(typescript@5.4.4) + optionalDependencies: typescript: 5.4.4 transitivePeerDependencies: - supports-color - dev: true - /@typescript-eslint/utils@7.5.0(eslint@8.57.0)(typescript@5.4.4): - resolution: {integrity: sha512-3vZl9u0R+/FLQcpy2EHyRGNqAS/ofJ3Ji8aebilfJe+fobK8+LbIFmrHciLVDxjDoONmufDcnVSF38KwMEOjzw==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - eslint: ^8.56.0 + '@typescript-eslint/utils@7.5.0(eslint@8.57.0)(typescript@5.4.4)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@types/json-schema': 7.0.15 @@ -953,102 +2193,57 @@ packages: transitivePeerDependencies: - supports-color - typescript - dev: true - /@typescript-eslint/visitor-keys@7.5.0: - resolution: {integrity: sha512-mcuHM/QircmA6O7fy6nn2w/3ditQkj+SgtOc8DW3uQ10Yfj42amm2i+6F2K4YAOPNNTmE6iM1ynM6lrSwdendA==} - engines: {node: ^18.18.0 || >=20.0.0} + '@typescript-eslint/visitor-keys@7.5.0': dependencies: '@typescript-eslint/types': 7.5.0 eslint-visitor-keys: 3.4.3 - dev: true - /@ungap/structured-clone@1.2.0: - resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} - dev: true + '@ungap/structured-clone@1.2.0': {} - /acorn-jsx@5.3.2(acorn@8.11.3): - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + acorn-jsx@5.3.2(acorn@8.11.3): dependencies: acorn: 8.11.3 - dev: true - /acorn@8.11.3: - resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} - engines: {node: '>=0.4.0'} - hasBin: true - dev: true + acorn@8.11.3: {} - /ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 fast-json-stable-stringify: 2.1.0 json-schema-traverse: 0.4.1 uri-js: 4.4.1 - dev: true - /ansi-escapes@4.3.2: - resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} - engines: {node: '>=8'} + ansi-escapes@4.3.2: dependencies: type-fest: 0.21.3 - dev: true - /ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - dev: true + ansi-regex@5.0.1: {} - /ansi-styles@3.2.1: - resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} - engines: {node: '>=4'} + ansi-styles@3.2.1: dependencies: color-convert: 1.9.3 - dev: true - /ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 - dev: true - /ansi-styles@5.2.0: - resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} - engines: {node: '>=10'} - dev: true + ansi-styles@5.2.0: {} - /anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} + anymatch@3.1.3: dependencies: normalize-path: 3.0.0 picomatch: 2.3.1 - dev: true - /argparse@1.0.10: - resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + argparse@1.0.10: dependencies: sprintf-js: 1.0.3 - dev: true - /argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - dev: true + argparse@2.0.1: {} - /array-union@2.1.0: - resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} - engines: {node: '>=8'} - dev: true + array-union@2.1.0: {} - /babel-jest@29.7.0(@babel/core@7.23.9): - resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@babel/core': ^7.8.0 + babel-jest@29.7.0(@babel/core@7.23.9): dependencies: '@babel/core': 7.23.9 '@jest/transform': 29.7.0 @@ -1060,11 +2255,8 @@ packages: slash: 3.0.0 transitivePeerDependencies: - supports-color - dev: true - /babel-plugin-istanbul@6.1.1: - resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} - engines: {node: '>=8'} + babel-plugin-istanbul@6.1.1: dependencies: '@babel/helper-plugin-utils': 7.22.5 '@istanbuljs/load-nyc-config': 1.1.0 @@ -1073,22 +2265,15 @@ packages: test-exclude: 6.0.0 transitivePeerDependencies: - supports-color - dev: true - /babel-plugin-jest-hoist@29.6.3: - resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + babel-plugin-jest-hoist@29.6.3: dependencies: '@babel/template': 7.23.9 '@babel/types': 7.23.9 '@types/babel__core': 7.20.5 '@types/babel__traverse': 7.20.5 - dev: true - /babel-preset-current-node-syntax@1.0.1(@babel/core@7.23.9): - resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} - peerDependencies: - '@babel/core': ^7.0.0 + babel-preset-current-node-syntax@1.0.1(@babel/core@7.23.9): dependencies: '@babel/core': 7.23.9 '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.9) @@ -1103,172 +2288,97 @@ packages: '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.9) '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.9) '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.23.9) - dev: true - /babel-preset-jest@29.6.3(@babel/core@7.23.9): - resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@babel/core': ^7.0.0 + babel-preset-jest@29.6.3(@babel/core@7.23.9): dependencies: '@babel/core': 7.23.9 babel-plugin-jest-hoist: 29.6.3 babel-preset-current-node-syntax: 1.0.1(@babel/core@7.23.9) - dev: true - /balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: true + balanced-match@1.0.2: {} - /brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - dev: true - /brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + brace-expansion@2.0.1: dependencies: balanced-match: 1.0.2 - dev: true - /braces@3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} - engines: {node: '>=8'} + braces@3.0.2: dependencies: fill-range: 7.0.1 - dev: true - /browserslist@4.22.3: - resolution: {integrity: sha512-UAp55yfwNv0klWNapjs/ktHoguxuQNGnOzxYmfnXIS+8AsRDZkSDxg7R1AX3GKzn078SBI5dzwzj/Yx0Or0e3A==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true + browserslist@4.22.3: dependencies: caniuse-lite: 1.0.30001581 electron-to-chromium: 1.4.648 node-releases: 2.0.14 update-browserslist-db: 1.0.13(browserslist@4.22.3) - dev: true - /bs-logger@0.2.6: - resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} - engines: {node: '>= 6'} + bs-logger@0.2.6: dependencies: fast-json-stable-stringify: 2.1.0 - dev: true - /bser@2.1.1: - resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + bser@2.1.1: dependencies: node-int64: 0.4.0 - dev: true - /buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - dev: true + buffer-from@1.1.2: {} - /callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - dev: true + callsites@3.1.0: {} - /camelcase@5.3.1: - resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} - engines: {node: '>=6'} - dev: true + camelcase@5.3.1: {} - /camelcase@6.3.0: - resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} - engines: {node: '>=10'} - dev: true + camelcase@6.3.0: {} - /caniuse-lite@1.0.30001581: - resolution: {integrity: sha512-whlTkwhqV2tUmP3oYhtNfaWGYHDdS3JYFQBKXxcUR9qqPWsRhFHhoISO2Xnl/g0xyKzht9mI1LZpiNWfMzHixQ==} - dev: true + caniuse-lite@1.0.30001581: {} - /chalk@2.4.2: - resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} - engines: {node: '>=4'} + chalk@2.4.2: dependencies: ansi-styles: 3.2.1 escape-string-regexp: 1.0.5 supports-color: 5.5.0 - dev: true - /chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 - dev: true - /char-regex@1.0.2: - resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} - engines: {node: '>=10'} - dev: true + char-regex@1.0.2: {} - /ci-info@3.9.0: - resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} - engines: {node: '>=8'} - dev: true + ci-info@3.9.0: {} - /cjs-module-lexer@1.2.3: - resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==} - dev: true + cjs-module-lexer@1.2.3: {} - /cliui@8.0.1: - resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} - engines: {node: '>=12'} + cliui@8.0.1: dependencies: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 7.0.0 - dev: true - /co@4.6.0: - resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} - engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} - dev: true + co@4.6.0: {} - /collect-v8-coverage@1.0.2: - resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} - dev: true + collect-v8-coverage@1.0.2: {} - /color-convert@1.9.3: - resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + color-convert@1.9.3: dependencies: color-name: 1.1.3 - dev: true - /color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} + color-convert@2.0.1: dependencies: color-name: 1.1.4 - dev: true - /color-name@1.1.3: - resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - dev: true + color-name@1.1.3: {} - /color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: true + color-name@1.1.4: {} - /concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - dev: true + concat-map@0.0.1: {} - /convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - dev: true + convert-source-map@2.0.0: {} - /create-jest@29.7.0(@types/node@20.12.4): - resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true + create-jest@29.7.0(@types/node@20.12.4): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 @@ -1282,151 +2392,70 @@ packages: - babel-plugin-macros - supports-color - ts-node - dev: true - /cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} - engines: {node: '>= 8'} + cross-spawn@7.0.3: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 - dev: true - /debug@4.3.4: - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true + debug@4.3.4: dependencies: ms: 2.1.2 - dev: true - /dedent@1.5.1: - resolution: {integrity: sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==} - peerDependencies: - babel-plugin-macros: ^3.1.0 - peerDependenciesMeta: - babel-plugin-macros: - optional: true - dev: true + dedent@1.5.1: {} - /deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - dev: true + deep-is@0.1.4: {} - /deepmerge@4.3.1: - resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} - engines: {node: '>=0.10.0'} - dev: true + deepmerge@4.3.1: {} - /detect-newline@3.1.0: - resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} - engines: {node: '>=8'} - dev: true + detect-newline@3.1.0: {} - /diff-sequences@29.6.3: - resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dev: true + diff-sequences@29.6.3: {} - /dir-glob@3.0.1: - resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} - engines: {node: '>=8'} + dir-glob@3.0.1: dependencies: path-type: 4.0.0 - dev: true - /doctrine@3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} + doctrine@3.0.0: dependencies: esutils: 2.0.3 - dev: true - /download-file-sync@1.0.4: - resolution: {integrity: sha512-vH92qNH508jZZA12HQNq/aiMDfagr4JvjFiI17Bi8oYjsxwv5ZVIi7iHkYmUXxOQUr90tcVX+8EPePjAqG1Y0w==} - dev: true + download-file-sync@1.0.4: {} - /electron-to-chromium@1.4.648: - resolution: {integrity: sha512-EmFMarXeqJp9cUKu/QEciEApn0S/xRcpZWuAm32U7NgoZCimjsilKXHRO9saeEW55eHZagIDg6XTUOv32w9pjg==} - dev: true + electron-to-chromium@1.4.648: {} - /emittery@0.13.1: - resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} - engines: {node: '>=12'} - dev: true + emittery@0.13.1: {} - /emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - dev: true + emoji-regex@8.0.0: {} - /error-ex@1.3.2: - resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + error-ex@1.3.2: dependencies: is-arrayish: 0.2.1 - dev: true - /escalade@3.1.1: - resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} - engines: {node: '>=6'} - dev: true + escalade@3.1.1: {} - /escape-string-regexp@1.0.5: - resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} - engines: {node: '>=0.8.0'} - dev: true + escape-string-regexp@1.0.5: {} - /escape-string-regexp@2.0.0: - resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} - engines: {node: '>=8'} - dev: true + escape-string-regexp@2.0.0: {} - /escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - dev: true + escape-string-regexp@4.0.0: {} - /eslint-plugin-prettier@5.1.3(eslint@8.57.0)(prettier@3.2.5): - resolution: {integrity: sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - '@types/eslint': '>=8.0.0' - eslint: '>=8.0.0' - eslint-config-prettier: '*' - prettier: '>=3.0.0' - peerDependenciesMeta: - '@types/eslint': - optional: true - eslint-config-prettier: - optional: true + eslint-plugin-prettier@5.1.3(eslint@8.57.0)(prettier@3.2.5): dependencies: eslint: 8.57.0 prettier: 3.2.5 prettier-linter-helpers: 1.0.0 synckit: 0.8.8 - dev: true - /eslint-scope@7.2.2: - resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + eslint-scope@7.2.2: dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 - dev: true - /eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true + eslint-visitor-keys@3.4.3: {} - /eslint@8.57.0: - resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - hasBin: true + eslint@8.57.0: dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@eslint-community/regexpp': 4.10.0 @@ -1468,50 +2497,28 @@ packages: text-table: 0.2.0 transitivePeerDependencies: - supports-color - dev: true - /espree@9.6.1: - resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + espree@9.6.1: dependencies: acorn: 8.11.3 acorn-jsx: 5.3.2(acorn@8.11.3) eslint-visitor-keys: 3.4.3 - dev: true - /esprima@4.0.1: - resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} - engines: {node: '>=4'} - hasBin: true - dev: true + esprima@4.0.1: {} - /esquery@1.5.0: - resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} - engines: {node: '>=0.10'} + esquery@1.5.0: dependencies: estraverse: 5.3.0 - dev: true - /esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} + esrecurse@4.3.0: dependencies: estraverse: 5.3.0 - dev: true - /estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - dev: true + estraverse@5.3.0: {} - /esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - dev: true + esutils@2.0.3: {} - /execa@5.1.1: - resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} - engines: {node: '>=10'} + execa@5.1.1: dependencies: cross-spawn: 7.0.3 get-stream: 6.0.1 @@ -1522,158 +2529,91 @@ packages: onetime: 5.1.2 signal-exit: 3.0.7 strip-final-newline: 2.0.0 - dev: true - /exit@0.1.2: - resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} - engines: {node: '>= 0.8.0'} - dev: true + exit@0.1.2: {} - /expect@29.7.0: - resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + expect@29.7.0: dependencies: '@jest/expect-utils': 29.7.0 jest-get-type: 29.6.3 jest-matcher-utils: 29.7.0 jest-message-util: 29.7.0 jest-util: 29.7.0 - dev: true - /fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - dev: true + fast-deep-equal@3.1.3: {} - /fast-diff@1.3.0: - resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} - dev: true + fast-diff@1.3.0: {} - /fast-glob@3.3.2: - resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} - engines: {node: '>=8.6.0'} + fast-glob@3.3.2: dependencies: '@nodelib/fs.stat': 2.0.5 '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 micromatch: 4.0.5 - dev: true - /fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - dev: true + fast-json-stable-stringify@2.1.0: {} - /fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - dev: true + fast-levenshtein@2.0.6: {} - /fastq@1.17.1: - resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + fastq@1.17.1: dependencies: reusify: 1.0.4 - dev: true - /fb-watchman@2.0.2: - resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + fb-watchman@2.0.2: dependencies: bser: 2.1.1 - dev: true - /file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} + file-entry-cache@6.0.1: dependencies: flat-cache: 3.2.0 - dev: true - /fill-range@7.0.1: - resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} - engines: {node: '>=8'} + fill-range@7.0.1: dependencies: to-regex-range: 5.0.1 - dev: true - /find-up@4.1.0: - resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} - engines: {node: '>=8'} + find-up@4.1.0: dependencies: locate-path: 5.0.0 path-exists: 4.0.0 - dev: true - /find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} + find-up@5.0.0: dependencies: locate-path: 6.0.0 path-exists: 4.0.0 - dev: true - /flat-cache@3.2.0: - resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} - engines: {node: ^10.12.0 || >=12.0.0} + flat-cache@3.2.0: dependencies: flatted: 3.3.1 keyv: 4.5.4 rimraf: 3.0.2 - dev: true - /flatted@3.3.1: - resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} - dev: true + flatted@3.3.1: {} - /fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - dev: true + fs.realpath@1.0.0: {} - /fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - requiresBuild: true - dev: true + fsevents@2.3.3: optional: true - /function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - dev: true + function-bind@1.1.2: {} - /gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - dev: true + gensync@1.0.0-beta.2: {} - /get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - dev: true + get-caller-file@2.0.5: {} - /get-package-type@0.1.0: - resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} - engines: {node: '>=8.0.0'} - dev: true + get-package-type@0.1.0: {} - /get-stream@6.0.1: - resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} - engines: {node: '>=10'} - dev: true + get-stream@6.0.1: {} - /glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 - dev: true - /glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} + glob-parent@6.0.2: dependencies: is-glob: 4.0.3 - dev: true - /glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + glob@7.2.3: dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 @@ -1681,23 +2621,14 @@ packages: minimatch: 3.1.2 once: 1.4.0 path-is-absolute: 1.0.1 - dev: true - /globals@11.12.0: - resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} - engines: {node: '>=4'} - dev: true + globals@11.12.0: {} - /globals@13.24.0: - resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} - engines: {node: '>=8'} + globals@13.24.0: dependencies: type-fest: 0.20.2 - dev: true - /globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} + globby@11.1.0: dependencies: array-union: 2.1.0 dir-glob: 3.0.1 @@ -1705,139 +2636,71 @@ packages: ignore: 5.3.1 merge2: 1.4.1 slash: 3.0.0 - dev: true - /graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - dev: true + graceful-fs@4.2.11: {} - /graphemer@1.4.0: - resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - dev: true + graphemer@1.4.0: {} - /has-flag@3.0.0: - resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} - engines: {node: '>=4'} - dev: true + has-flag@3.0.0: {} - /has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - dev: true + has-flag@4.0.0: {} - /hasown@2.0.0: - resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} - engines: {node: '>= 0.4'} + hasown@2.0.0: dependencies: function-bind: 1.1.2 - dev: true - /html-escaper@2.0.2: - resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} - dev: true + html-escaper@2.0.2: {} - /human-signals@2.1.0: - resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} - engines: {node: '>=10.17.0'} - dev: true + human-signals@2.1.0: {} - /ignore@5.3.1: - resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} - engines: {node: '>= 4'} - dev: true + ignore@5.3.1: {} - /import-fresh@3.3.0: - resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} - engines: {node: '>=6'} + import-fresh@3.3.0: dependencies: parent-module: 1.0.1 resolve-from: 4.0.0 - dev: true - /import-local@3.1.0: - resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} - engines: {node: '>=8'} - hasBin: true + import-local@3.1.0: dependencies: pkg-dir: 4.2.0 resolve-cwd: 3.0.0 - dev: true - /imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - dev: true + imurmurhash@0.1.4: {} - /inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + inflight@1.0.6: dependencies: once: 1.4.0 wrappy: 1.0.2 - dev: true - /inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - dev: true + inherits@2.0.4: {} - /is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - dev: true + is-arrayish@0.2.1: {} - /is-core-module@2.13.1: - resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + is-core-module@2.13.1: dependencies: hasown: 2.0.0 - dev: true - /is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - dev: true + is-extglob@2.1.1: {} - /is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - dev: true + is-fullwidth-code-point@3.0.0: {} - /is-generator-fn@2.1.0: - resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} - engines: {node: '>=6'} - dev: true + is-generator-fn@2.1.0: {} - /is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} + is-glob@4.0.3: dependencies: is-extglob: 2.1.1 - dev: true - /is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - dev: true + is-number@7.0.0: {} - /is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - engines: {node: '>=8'} - dev: true + is-path-inside@3.0.3: {} - /is-stream@2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} - dev: true + is-stream@2.0.1: {} - /isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - dev: true + isexe@2.0.0: {} - /istanbul-lib-coverage@3.2.2: - resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} - engines: {node: '>=8'} - dev: true + istanbul-lib-coverage@3.2.2: {} - /istanbul-lib-instrument@5.2.1: - resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} - engines: {node: '>=8'} + istanbul-lib-instrument@5.2.1: dependencies: '@babel/core': 7.23.9 '@babel/parser': 7.23.9 @@ -1846,11 +2709,8 @@ packages: semver: 6.3.1 transitivePeerDependencies: - supports-color - dev: true - /istanbul-lib-instrument@6.0.1: - resolution: {integrity: sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA==} - engines: {node: '>=10'} + istanbul-lib-instrument@6.0.1: dependencies: '@babel/core': 7.23.9 '@babel/parser': 7.23.9 @@ -1859,48 +2719,33 @@ packages: semver: 7.5.4 transitivePeerDependencies: - supports-color - dev: true - /istanbul-lib-report@3.0.1: - resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} - engines: {node: '>=10'} + istanbul-lib-report@3.0.1: dependencies: istanbul-lib-coverage: 3.2.2 make-dir: 4.0.0 supports-color: 7.2.0 - dev: true - /istanbul-lib-source-maps@4.0.1: - resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} - engines: {node: '>=10'} + istanbul-lib-source-maps@4.0.1: dependencies: debug: 4.3.4 istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: - supports-color - dev: true - /istanbul-reports@3.1.6: - resolution: {integrity: sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==} - engines: {node: '>=8'} + istanbul-reports@3.1.6: dependencies: html-escaper: 2.0.2 istanbul-lib-report: 3.0.1 - dev: true - /jest-changed-files@29.7.0: - resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-changed-files@29.7.0: dependencies: execa: 5.1.1 jest-util: 29.7.0 p-limit: 3.1.0 - dev: true - /jest-circus@29.7.0: - resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-circus@29.7.0: dependencies: '@jest/environment': 29.7.0 '@jest/expect': 29.7.0 @@ -1925,17 +2770,8 @@ packages: transitivePeerDependencies: - babel-plugin-macros - supports-color - dev: true - /jest-cli@29.7.0(@types/node@20.12.4): - resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true + jest-cli@29.7.0(@types/node@20.12.4): dependencies: '@jest/core': 29.7.0 '@jest/test-result': 29.7.0 @@ -1953,24 +2789,12 @@ packages: - babel-plugin-macros - supports-color - ts-node - dev: true - /jest-config@29.7.0(@types/node@20.12.4): - resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@types/node': '*' - ts-node: '>=9.0.0' - peerDependenciesMeta: - '@types/node': - optional: true - ts-node: - optional: true + jest-config@29.7.0(@types/node@20.12.4): dependencies: '@babel/core': 7.23.9 '@jest/test-sequencer': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.12.4 babel-jest: 29.7.0(@babel/core@7.23.9) chalk: 4.1.2 ci-info: 3.9.0 @@ -1990,42 +2814,32 @@ packages: pretty-format: 29.7.0 slash: 3.0.0 strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 20.12.4 transitivePeerDependencies: - babel-plugin-macros - supports-color - dev: true - /jest-diff@29.7.0: - resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-diff@29.7.0: dependencies: chalk: 4.1.2 diff-sequences: 29.6.3 jest-get-type: 29.6.3 pretty-format: 29.7.0 - dev: true - /jest-docblock@29.7.0: - resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-docblock@29.7.0: dependencies: detect-newline: 3.1.0 - dev: true - /jest-each@29.7.0: - resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-each@29.7.0: dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 jest-get-type: 29.6.3 jest-util: 29.7.0 pretty-format: 29.7.0 - dev: true - /jest-environment-node@29.7.0: - resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-environment-node@29.7.0: dependencies: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 @@ -2033,16 +2847,10 @@ packages: '@types/node': 20.12.4 jest-mock: 29.7.0 jest-util: 29.7.0 - dev: true - /jest-get-type@29.6.3: - resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dev: true + jest-get-type@29.6.3: {} - /jest-haste-map@29.7.0: - resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-haste-map@29.7.0: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.9 @@ -2057,29 +2865,20 @@ packages: walker: 1.0.8 optionalDependencies: fsevents: 2.3.3 - dev: true - /jest-leak-detector@29.7.0: - resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-leak-detector@29.7.0: dependencies: jest-get-type: 29.6.3 pretty-format: 29.7.0 - dev: true - /jest-matcher-utils@29.7.0: - resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-matcher-utils@29.7.0: dependencies: chalk: 4.1.2 jest-diff: 29.7.0 jest-get-type: 29.6.3 pretty-format: 29.7.0 - dev: true - /jest-message-util@29.7.0: - resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-message-util@29.7.0: dependencies: '@babel/code-frame': 7.23.5 '@jest/types': 29.6.3 @@ -2090,47 +2889,27 @@ packages: pretty-format: 29.7.0 slash: 3.0.0 stack-utils: 2.0.6 - dev: true - /jest-mock@29.7.0: - resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-mock@29.7.0: dependencies: '@jest/types': 29.6.3 '@types/node': 20.12.4 jest-util: 29.7.0 - dev: true - /jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): - resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} - engines: {node: '>=6'} - peerDependencies: - jest-resolve: '*' - peerDependenciesMeta: - jest-resolve: - optional: true - dependencies: + jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): + optionalDependencies: jest-resolve: 29.7.0 - dev: true - /jest-regex-util@29.6.3: - resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dev: true + jest-regex-util@29.6.3: {} - /jest-resolve-dependencies@29.7.0: - resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-resolve-dependencies@29.7.0: dependencies: jest-regex-util: 29.6.3 jest-snapshot: 29.7.0 transitivePeerDependencies: - supports-color - dev: true - /jest-resolve@29.7.0: - resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-resolve@29.7.0: dependencies: chalk: 4.1.2 graceful-fs: 4.2.11 @@ -2141,11 +2920,8 @@ packages: resolve: 1.22.8 resolve.exports: 2.0.2 slash: 3.0.0 - dev: true - /jest-runner@29.7.0: - resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-runner@29.7.0: dependencies: '@jest/console': 29.7.0 '@jest/environment': 29.7.0 @@ -2170,11 +2946,8 @@ packages: source-map-support: 0.5.13 transitivePeerDependencies: - supports-color - dev: true - /jest-runtime@29.7.0: - resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-runtime@29.7.0: dependencies: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 @@ -2200,11 +2973,8 @@ packages: strip-bom: 4.0.0 transitivePeerDependencies: - supports-color - dev: true - /jest-snapshot@29.7.0: - resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-snapshot@29.7.0: dependencies: '@babel/core': 7.23.9 '@babel/generator': 7.23.6 @@ -2228,11 +2998,8 @@ packages: semver: 7.5.4 transitivePeerDependencies: - supports-color - dev: true - /jest-util@29.7.0: - resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 '@types/node': 20.12.4 @@ -2240,11 +3007,8 @@ packages: ci-info: 3.9.0 graceful-fs: 4.2.11 picomatch: 2.3.1 - dev: true - /jest-validate@29.7.0: - resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-validate@29.7.0: dependencies: '@jest/types': 29.6.3 camelcase: 6.3.0 @@ -2252,11 +3016,8 @@ packages: jest-get-type: 29.6.3 leven: 3.1.0 pretty-format: 29.7.0 - dev: true - /jest-watcher@29.7.0: - resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-watcher@29.7.0: dependencies: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 @@ -2266,27 +3027,15 @@ packages: emittery: 0.13.1 jest-util: 29.7.0 string-length: 4.0.2 - dev: true - /jest-worker@29.7.0: - resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-worker@29.7.0: dependencies: '@types/node': 20.12.4 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 - dev: true - /jest@29.7.0(@types/node@20.12.4): - resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true + jest@29.7.0(@types/node@20.12.4): dependencies: '@jest/core': 29.7.0 '@jest/types': 29.6.3 @@ -2297,218 +3046,119 @@ packages: - babel-plugin-macros - supports-color - ts-node - dev: true - /js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - dev: true + js-tokens@4.0.0: {} - /js-yaml@3.14.1: - resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} - hasBin: true + js-yaml@3.14.1: dependencies: argparse: 1.0.10 esprima: 4.0.1 - dev: true - /js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} - hasBin: true + js-yaml@4.1.0: dependencies: argparse: 2.0.1 - dev: true - /jsesc@2.5.2: - resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} - engines: {node: '>=4'} - hasBin: true - dev: true + jsesc@2.5.2: {} - /json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - dev: true + json-buffer@3.0.1: {} - /json-parse-even-better-errors@2.3.1: - resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - dev: true + json-parse-even-better-errors@2.3.1: {} - /json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - dev: true + json-schema-traverse@0.4.1: {} - /json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - dev: true + json-stable-stringify-without-jsonify@1.0.1: {} - /json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - dev: true + json5@2.2.3: {} - /keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + keyv@4.5.4: dependencies: json-buffer: 3.0.1 - dev: true - /kleur@3.0.3: - resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} - engines: {node: '>=6'} - dev: true + kleur@3.0.3: {} - /lemmy-js-client@0.19.4-alpha.16: - resolution: {integrity: sha512-9BKCpZeH5+dDkSuYLVPvJnRGOSa3/jBUqYlQH3r1p8TyCCBrxstIC2I+h9dZZtOg4RmK7ShcuZdk9LSMe1ZMyw==} - dev: true + lemmy-js-client@0.19.4-alpha.18: {} - /leven@3.1.0: - resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} - engines: {node: '>=6'} - dev: true + leven@3.1.0: {} - /levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} + levn@0.4.1: dependencies: prelude-ls: 1.2.1 type-check: 0.4.0 - dev: true - /lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - dev: true + lines-and-columns@1.2.4: {} - /locate-path@5.0.0: - resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} - engines: {node: '>=8'} + locate-path@5.0.0: dependencies: p-locate: 4.1.0 - dev: true - /locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} + locate-path@6.0.0: dependencies: p-locate: 5.0.0 - dev: true - /lodash.memoize@4.1.2: - resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} - dev: true + lodash.memoize@4.1.2: {} - /lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - dev: true + lodash.merge@4.6.2: {} - /lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lru-cache@5.1.1: dependencies: yallist: 3.1.1 - dev: true - /lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} + lru-cache@6.0.0: dependencies: yallist: 4.0.0 - dev: true - /make-dir@4.0.0: - resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} - engines: {node: '>=10'} + make-dir@4.0.0: dependencies: semver: 7.5.4 - dev: true - /make-error@1.3.6: - resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - dev: true + make-error@1.3.6: {} - /makeerror@1.0.12: - resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + makeerror@1.0.12: dependencies: tmpl: 1.0.5 - dev: true - /merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - dev: true + merge-stream@2.0.0: {} - /merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - dev: true + merge2@1.4.1: {} - /micromatch@4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} - engines: {node: '>=8.6'} + micromatch@4.0.5: dependencies: braces: 3.0.2 picomatch: 2.3.1 - dev: true - /mimic-fn@2.1.0: - resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} - engines: {node: '>=6'} - dev: true + mimic-fn@2.1.0: {} - /minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 - dev: true - /minimatch@9.0.3: - resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} - engines: {node: '>=16 || 14 >=14.17'} + minimatch@9.0.3: dependencies: brace-expansion: 2.0.1 - dev: true - /ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - dev: true + ms@2.1.2: {} - /natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - dev: true + natural-compare@1.4.0: {} - /node-int64@0.4.0: - resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - dev: true + node-int64@0.4.0: {} - /node-releases@2.0.14: - resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} - dev: true + node-releases@2.0.14: {} - /normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - dev: true + normalize-path@3.0.0: {} - /npm-run-path@4.0.1: - resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} - engines: {node: '>=8'} + npm-run-path@4.0.1: dependencies: path-key: 3.1.1 - dev: true - /once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + once@1.4.0: dependencies: wrappy: 1.0.2 - dev: true - /onetime@5.1.2: - resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} - engines: {node: '>=6'} + onetime@5.1.2: dependencies: mimic-fn: 2.1.0 - dev: true - /optionator@0.9.3: - resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} - engines: {node: '>= 0.8.0'} + optionator@0.9.3: dependencies: '@aashutoshrathi/word-wrap': 1.2.6 deep-is: 0.1.4 @@ -2516,411 +3166,208 @@ packages: levn: 0.4.1 prelude-ls: 1.2.1 type-check: 0.4.0 - dev: true - /p-limit@2.3.0: - resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} - engines: {node: '>=6'} + p-limit@2.3.0: dependencies: p-try: 2.2.0 - dev: true - /p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 - dev: true - /p-locate@4.1.0: - resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} - engines: {node: '>=8'} + p-locate@4.1.0: dependencies: p-limit: 2.3.0 - dev: true - /p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} + p-locate@5.0.0: dependencies: p-limit: 3.1.0 - dev: true - /p-try@2.2.0: - resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} - engines: {node: '>=6'} - dev: true + p-try@2.2.0: {} - /parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} + parent-module@1.0.1: dependencies: callsites: 3.1.0 - dev: true - /parse-json@5.2.0: - resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} - engines: {node: '>=8'} + parse-json@5.2.0: dependencies: '@babel/code-frame': 7.23.5 error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 - dev: true - /path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - dev: true + path-exists@4.0.0: {} - /path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - dev: true + path-is-absolute@1.0.1: {} - /path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - dev: true + path-key@3.1.1: {} - /path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - dev: true + path-parse@1.0.7: {} - /path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} - dev: true + path-type@4.0.0: {} - /picocolors@1.0.0: - resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} - dev: true + picocolors@1.0.0: {} - /picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - dev: true + picomatch@2.3.1: {} - /pirates@4.0.6: - resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} - engines: {node: '>= 6'} - dev: true + pirates@4.0.6: {} - /pkg-dir@4.2.0: - resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} - engines: {node: '>=8'} + pkg-dir@4.2.0: dependencies: find-up: 4.1.0 - dev: true - /prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - dev: true + prelude-ls@1.2.1: {} - /prettier-linter-helpers@1.0.0: - resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} - engines: {node: '>=6.0.0'} + prettier-linter-helpers@1.0.0: dependencies: fast-diff: 1.3.0 - dev: true - /prettier@3.2.5: - resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} - engines: {node: '>=14'} - hasBin: true - dev: true + prettier@3.2.5: {} - /pretty-format@29.7.0: - resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + pretty-format@29.7.0: dependencies: '@jest/schemas': 29.6.3 ansi-styles: 5.2.0 react-is: 18.2.0 - dev: true - /prompts@2.4.2: - resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} - engines: {node: '>= 6'} + prompts@2.4.2: dependencies: kleur: 3.0.3 sisteransi: 1.0.5 - dev: true - /punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - dev: true + punycode@2.3.1: {} - /pure-rand@6.0.4: - resolution: {integrity: sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==} - dev: true + pure-rand@6.0.4: {} - /queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - dev: true + queue-microtask@1.2.3: {} - /react-is@18.2.0: - resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} - dev: true + react-is@18.2.0: {} - /require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - dev: true + require-directory@2.1.1: {} - /resolve-cwd@3.0.0: - resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} - engines: {node: '>=8'} + resolve-cwd@3.0.0: dependencies: resolve-from: 5.0.0 - dev: true - /resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - dev: true + resolve-from@4.0.0: {} - /resolve-from@5.0.0: - resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} - engines: {node: '>=8'} - dev: true + resolve-from@5.0.0: {} - /resolve.exports@2.0.2: - resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} - engines: {node: '>=10'} - dev: true + resolve.exports@2.0.2: {} - /resolve@1.22.8: - resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} - hasBin: true + resolve@1.22.8: dependencies: is-core-module: 2.13.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - dev: true - /reusify@1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - dev: true + reusify@1.0.4: {} - /rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - hasBin: true + rimraf@3.0.2: dependencies: glob: 7.2.3 - dev: true - /run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 - dev: true - /semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - dev: true + semver@6.3.1: {} - /semver@7.5.4: - resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} - engines: {node: '>=10'} - hasBin: true + semver@7.5.4: dependencies: lru-cache: 6.0.0 - dev: true - /semver@7.6.0: - resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} - engines: {node: '>=10'} - hasBin: true + semver@7.6.0: dependencies: lru-cache: 6.0.0 - dev: true - /shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 - dev: true - /shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - dev: true + shebang-regex@3.0.0: {} - /signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - dev: true + signal-exit@3.0.7: {} - /sisteransi@1.0.5: - resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - dev: true + sisteransi@1.0.5: {} - /slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} - dev: true + slash@3.0.0: {} - /source-map-support@0.5.13: - resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} + source-map-support@0.5.13: dependencies: buffer-from: 1.1.2 source-map: 0.6.1 - dev: true - /source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - dev: true + source-map@0.6.1: {} - /sprintf-js@1.0.3: - resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - dev: true + sprintf-js@1.0.3: {} - /stack-utils@2.0.6: - resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} - engines: {node: '>=10'} + stack-utils@2.0.6: dependencies: escape-string-regexp: 2.0.0 - dev: true - /string-length@4.0.2: - resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} - engines: {node: '>=10'} + string-length@4.0.2: dependencies: char-regex: 1.0.2 strip-ansi: 6.0.1 - dev: true - /string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - dev: true - /strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 - dev: true - /strip-bom@4.0.0: - resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} - engines: {node: '>=8'} - dev: true + strip-bom@4.0.0: {} - /strip-final-newline@2.0.0: - resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} - engines: {node: '>=6'} - dev: true + strip-final-newline@2.0.0: {} - /strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - dev: true + strip-json-comments@3.1.1: {} - /supports-color@5.5.0: - resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} - engines: {node: '>=4'} + supports-color@5.5.0: dependencies: has-flag: 3.0.0 - dev: true - /supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} + supports-color@7.2.0: dependencies: has-flag: 4.0.0 - dev: true - /supports-color@8.1.1: - resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} - engines: {node: '>=10'} + supports-color@8.1.1: dependencies: has-flag: 4.0.0 - dev: true - /supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - dev: true + supports-preserve-symlinks-flag@1.0.0: {} - /synckit@0.8.8: - resolution: {integrity: sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==} - engines: {node: ^14.18.0 || >=16.0.0} + synckit@0.8.8: dependencies: '@pkgr/core': 0.1.1 tslib: 2.6.2 - dev: true - /test-exclude@6.0.0: - resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} - engines: {node: '>=8'} + test-exclude@6.0.0: dependencies: '@istanbuljs/schema': 0.1.3 glob: 7.2.3 minimatch: 3.1.2 - dev: true - /text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - dev: true + text-table@0.2.0: {} - /tmpl@1.0.5: - resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} - dev: true + tmpl@1.0.5: {} - /to-fast-properties@2.0.0: - resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} - engines: {node: '>=4'} - dev: true + to-fast-properties@2.0.0: {} - /to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 - dev: true - /ts-api-utils@1.3.0(typescript@5.4.4): - resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} - engines: {node: '>=16'} - peerDependencies: - typescript: '>=4.2.0' + ts-api-utils@1.3.0(typescript@5.4.4): dependencies: typescript: 5.4.4 - dev: true - /ts-jest@29.1.2(@babel/core@7.23.9)(jest@29.7.0)(typescript@5.4.4): - resolution: {integrity: sha512-br6GJoH/WUX4pu7FbZXuWGKGNDuU7b8Uj77g/Sp7puZV6EXzuByl6JrECvm0MzVzSTkSHWTihsXt+5XYER5b+g==} - engines: {node: ^16.10.0 || ^18.0.0 || >=20.0.0} - hasBin: true - peerDependencies: - '@babel/core': '>=7.0.0-beta.0 <8' - '@jest/types': ^29.0.0 - babel-jest: ^29.0.0 - esbuild: '*' - jest: ^29.0.0 - typescript: '>=4.3 <6' - peerDependenciesMeta: - '@babel/core': - optional: true - '@jest/types': - optional: true - babel-jest: - optional: true - esbuild: - optional: true + ts-jest@29.1.2(@babel/core@7.23.9)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(jest@29.7.0(@types/node@20.12.4))(typescript@5.4.4): dependencies: - '@babel/core': 7.23.9 bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 jest: 29.7.0(@types/node@20.12.4) @@ -2931,126 +3378,73 @@ packages: semver: 7.5.4 typescript: 5.4.4 yargs-parser: 21.1.1 - dev: true + optionalDependencies: + '@babel/core': 7.23.9 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.23.9) - /tslib@2.6.2: - resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} - dev: true + tslib@2.6.2: {} - /type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 - dev: true - /type-detect@4.0.8: - resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} - engines: {node: '>=4'} - dev: true + type-detect@4.0.8: {} - /type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} - dev: true + type-fest@0.20.2: {} - /type-fest@0.21.3: - resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} - engines: {node: '>=10'} - dev: true + type-fest@0.21.3: {} - /typescript@5.4.4: - resolution: {integrity: sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw==} - engines: {node: '>=14.17'} - hasBin: true - dev: true + typescript@5.4.4: {} - /undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - dev: true + undici-types@5.26.5: {} - /update-browserslist-db@1.0.13(browserslist@4.22.3): - resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' + update-browserslist-db@1.0.13(browserslist@4.22.3): dependencies: browserslist: 4.22.3 escalade: 3.1.1 picocolors: 1.0.0 - dev: true - /uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + uri-js@4.4.1: dependencies: punycode: 2.3.1 - dev: true - /v8-to-istanbul@9.2.0: - resolution: {integrity: sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==} - engines: {node: '>=10.12.0'} + v8-to-istanbul@9.2.0: dependencies: '@jridgewell/trace-mapping': 0.3.22 '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 - dev: true - /walker@1.0.8: - resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + walker@1.0.8: dependencies: makeerror: 1.0.12 - dev: true - /which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true + which@2.0.2: dependencies: isexe: 2.0.0 - dev: true - /wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 - dev: true - /wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - dev: true + wrappy@1.0.2: {} - /write-file-atomic@4.0.2: - resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + write-file-atomic@4.0.2: dependencies: imurmurhash: 0.1.4 signal-exit: 3.0.7 - dev: true - /y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - dev: true + y18n@5.0.8: {} - /yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - dev: true + yallist@3.1.1: {} - /yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - dev: true + yallist@4.0.0: {} - /yargs-parser@21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} - dev: true + yargs-parser@21.1.1: {} - /yargs@17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} - engines: {node: '>=12'} + yargs@17.7.2: dependencies: cliui: 8.0.1 escalade: 3.1.1 @@ -3059,9 +3453,5 @@ packages: string-width: 4.2.3 y18n: 5.0.8 yargs-parser: 21.1.1 - dev: true - /yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - dev: true + yocto-queue@0.1.0: {} diff --git a/api_tests/src/image.spec.ts b/api_tests/src/image.spec.ts index 055c498e0..2bdc3f4a5 100644 --- a/api_tests/src/image.spec.ts +++ b/api_tests/src/image.spec.ts @@ -71,9 +71,14 @@ test("Upload image and delete it", async () => { // The deleteUrl is a combination of the endpoint, delete token, and alias let firstImage = listMediaRes.images[0]; - let deleteUrl = `${alphaUrl}/pictrs/image/delete/${firstImage.pictrs_delete_token}/${firstImage.pictrs_alias}`; + let deleteUrl = `${alphaUrl}/pictrs/image/delete/${firstImage.local_image.pictrs_delete_token}/${firstImage.local_image.pictrs_alias}`; expect(deleteUrl).toBe(upload.delete_url); + // Make sure the uploader is correct + expect(firstImage.person.actor_id).toBe( + `http://lemmy-alpha:8541/u/lemmy_alpha`, + ); + // delete image const delete_form: DeleteImage = { token: upload.files![0].delete_token, diff --git a/api_tests/src/shared.ts b/api_tests/src/shared.ts index e363fffa4..c6f39f787 100644 --- a/api_tests/src/shared.ts +++ b/api_tests/src/shared.ts @@ -887,8 +887,8 @@ export async function deleteAllImages(api: LemmyHttp) { for (const image of imagesRes.images) { const form: DeleteImage = { - token: image.pictrs_delete_token, - filename: image.pictrs_alias, + token: image.local_image.pictrs_delete_token, + filename: image.local_image.pictrs_alias, }; await api.deleteImage(form); } diff --git a/crates/api/src/local_user/list_media.rs b/crates/api/src/local_user/list_media.rs index bf69c4a34..779558dab 100644 --- a/crates/api/src/local_user/list_media.rs +++ b/crates/api/src/local_user/list_media.rs @@ -3,8 +3,7 @@ use lemmy_api_common::{ context::LemmyContext, person::{ListMedia, ListMediaResponse}, }; -use lemmy_db_schema::source::images::LocalImage; -use lemmy_db_views::structs::LocalUserView; +use lemmy_db_views::structs::{LocalImageView, LocalUserView}; use lemmy_utils::error::LemmyResult; #[tracing::instrument(skip(context))] @@ -15,7 +14,7 @@ pub async fn list_media( ) -> LemmyResult> { let page = data.page; let limit = data.limit; - let images = LocalImage::get_all_paged_by_local_user_id( + let images = LocalImageView::get_all_paged_by_local_user_id( &mut context.pool(), local_user_view.local_user.id, page, diff --git a/crates/api/src/site/list_all_media.rs b/crates/api/src/site/list_all_media.rs index 49132cd64..4d8d2dc2a 100644 --- a/crates/api/src/site/list_all_media.rs +++ b/crates/api/src/site/list_all_media.rs @@ -4,8 +4,7 @@ use lemmy_api_common::{ person::{ListMedia, ListMediaResponse}, utils::is_admin, }; -use lemmy_db_schema::source::images::LocalImage; -use lemmy_db_views::structs::LocalUserView; +use lemmy_db_views::structs::{LocalImageView, LocalUserView}; use lemmy_utils::error::LemmyResult; #[tracing::instrument(skip(context))] @@ -19,6 +18,6 @@ pub async fn list_all_media( let page = data.page; let limit = data.limit; - let images = LocalImage::get_all(&mut context.pool(), page, limit).await?; + let images = LocalImageView::get_all(&mut context.pool(), page, limit).await?; Ok(Json(ListMediaResponse { images })) } diff --git a/crates/api_common/src/person.rs b/crates/api_common/src/person.rs index a4f9b64d9..4f5aea2be 100644 --- a/crates/api_common/src/person.rs +++ b/crates/api_common/src/person.rs @@ -1,13 +1,13 @@ use crate::sensitive::Sensitive; use lemmy_db_schema::{ newtypes::{CommentReplyId, CommunityId, LanguageId, PersonId, PersonMentionId}, - source::{images::LocalImage, site::Site}, + source::site::Site, CommentSortType, ListingType, PostListingMode, SortType, }; -use lemmy_db_views::structs::{CommentView, PostView}; +use lemmy_db_views::structs::{CommentView, LocalImageView, PostView}; use lemmy_db_views_actor::structs::{ CommentReplyView, CommunityModeratorView, @@ -437,5 +437,5 @@ pub struct ListMedia { #[cfg_attr(feature = "full", derive(TS))] #[cfg_attr(feature = "full", ts(export))] pub struct ListMediaResponse { - pub images: Vec, + pub images: Vec, } diff --git a/crates/api_common/src/utils.rs b/crates/api_common/src/utils.rs index d75469904..3cd7902e1 100644 --- a/crates/api_common/src/utils.rs +++ b/crates/api_common/src/utils.rs @@ -12,7 +12,7 @@ use lemmy_db_schema::{ community::{Community, CommunityModerator, CommunityUpdateForm}, community_block::CommunityBlock, email_verification::{EmailVerification, EmailVerificationForm}, - images::{LocalImage, RemoteImage}, + images::RemoteImage, instance::Instance, instance_block::InstanceBlock, local_site::LocalSite, @@ -27,7 +27,10 @@ use lemmy_db_schema::{ traits::Crud, utils::DbPool, }; -use lemmy_db_views::{comment_view::CommentQuery, structs::LocalUserView}; +use lemmy_db_views::{ + comment_view::CommentQuery, + structs::{LocalImageView, LocalUserView}, +}; use lemmy_db_views_actor::structs::{ CommunityModeratorView, CommunityPersonBanView, @@ -662,13 +665,18 @@ pub async fn purge_image_posts_for_person( async fn delete_local_user_images(person_id: PersonId, context: &LemmyContext) -> LemmyResult<()> { if let Ok(Some(local_user)) = LocalUserView::read_person(&mut context.pool(), person_id).await { let pictrs_uploads = - LocalImage::get_all_by_local_user_id(&mut context.pool(), local_user.local_user.id).await?; + LocalImageView::get_all_by_local_user_id(&mut context.pool(), local_user.local_user.id) + .await?; // Delete their images for upload in pictrs_uploads { - delete_image_from_pictrs(&upload.pictrs_alias, &upload.pictrs_delete_token, context) - .await - .ok(); + delete_image_from_pictrs( + &upload.local_image.pictrs_alias, + &upload.local_image.pictrs_delete_token, + context, + ) + .await + .ok(); } } Ok(()) diff --git a/crates/db_schema/src/impls/images.rs b/crates/db_schema/src/impls/images.rs index a9aeb1f16..9589aeee3 100644 --- a/crates/db_schema/src/impls/images.rs +++ b/crates/db_schema/src/impls/images.rs @@ -1,8 +1,8 @@ use crate::{ - newtypes::{DbUrl, LocalUserId}, + newtypes::DbUrl, schema::{local_image, remote_image}, source::images::{LocalImage, LocalImageForm, RemoteImage, RemoteImageForm}, - utils::{get_conn, limit_and_offset, DbPool}, + utils::{get_conn, DbPool}, }; use diesel::{ dsl::exists, @@ -25,55 +25,6 @@ impl LocalImage { .await } - pub async fn get_all_paged_by_local_user_id( - pool: &mut DbPool<'_>, - user_id: LocalUserId, - page: Option, - limit: Option, - ) -> Result, Error> { - Self::get_all_helper(pool, Some(user_id), page, limit, false).await - } - - pub async fn get_all_by_local_user_id( - pool: &mut DbPool<'_>, - user_id: LocalUserId, - ) -> Result, Error> { - Self::get_all_helper(pool, Some(user_id), None, None, true).await - } - - pub async fn get_all( - pool: &mut DbPool<'_>, - page: Option, - limit: Option, - ) -> Result, Error> { - Self::get_all_helper(pool, None, page, limit, false).await - } - - async fn get_all_helper( - pool: &mut DbPool<'_>, - user_id: Option, - page: Option, - limit: Option, - ignore_page_limits: bool, - ) -> Result, Error> { - let conn = &mut get_conn(pool).await?; - let mut query = local_image::table - .select(local_image::all_columns) - .order_by(local_image::published.desc()) - .into_boxed(); - - if let Some(user_id) = user_id { - query = query.filter(local_image::local_user_id.eq(user_id)) - } - - if !ignore_page_limits { - let (limit, offset) = limit_and_offset(page, limit)?; - query = query.limit(limit).offset(offset); - } - - query.load::(conn).await - } - pub async fn delete_by_alias(pool: &mut DbPool<'_>, alias: &str) -> Result { let conn = &mut get_conn(pool).await?; diesel::delete(local_image::table.filter(local_image::pictrs_alias.eq(alias))) diff --git a/crates/db_views/src/lib.rs b/crates/db_views/src/lib.rs index 73310d743..e93c7409d 100644 --- a/crates/db_views/src/lib.rs +++ b/crates/db_views/src/lib.rs @@ -8,6 +8,8 @@ pub mod comment_view; #[cfg(feature = "full")] pub mod custom_emoji_view; #[cfg(feature = "full")] +pub mod local_image_view; +#[cfg(feature = "full")] pub mod local_user_view; #[cfg(feature = "full")] pub mod post_report_view; diff --git a/crates/db_views/src/local_image_view.rs b/crates/db_views/src/local_image_view.rs new file mode 100644 index 000000000..7b5b97095 --- /dev/null +++ b/crates/db_views/src/local_image_view.rs @@ -0,0 +1,61 @@ +use crate::structs::LocalImageView; +use diesel::{result::Error, ExpressionMethods, JoinOnDsl, QueryDsl}; +use diesel_async::RunQueryDsl; +use lemmy_db_schema::{ + newtypes::LocalUserId, + schema::{local_image, local_user, person}, + utils::{get_conn, limit_and_offset, DbPool}, +}; + +impl LocalImageView { + async fn get_all_helper( + pool: &mut DbPool<'_>, + user_id: Option, + page: Option, + limit: Option, + ignore_page_limits: bool, + ) -> Result, Error> { + let conn = &mut get_conn(pool).await?; + let mut query = local_image::table + .inner_join(local_user::table) + .inner_join(person::table.on(local_user::person_id.eq(person::id))) + .select((local_image::all_columns, person::all_columns)) + .order_by(local_image::published.desc()) + .into_boxed(); + + if let Some(user_id) = user_id { + query = query.filter(local_image::local_user_id.eq(user_id)) + } + + if !ignore_page_limits { + let (limit, offset) = limit_and_offset(page, limit)?; + query = query.limit(limit).offset(offset); + } + + query.load::(conn).await + } + + pub async fn get_all_paged_by_local_user_id( + pool: &mut DbPool<'_>, + user_id: LocalUserId, + page: Option, + limit: Option, + ) -> Result, Error> { + Self::get_all_helper(pool, Some(user_id), page, limit, false).await + } + + pub async fn get_all_by_local_user_id( + pool: &mut DbPool<'_>, + user_id: LocalUserId, + ) -> Result, Error> { + Self::get_all_helper(pool, Some(user_id), None, None, true).await + } + + pub async fn get_all( + pool: &mut DbPool<'_>, + page: Option, + limit: Option, + ) -> Result, Error> { + Self::get_all_helper(pool, None, page, limit, false).await + } +} diff --git a/crates/db_views/src/structs.rs b/crates/db_views/src/structs.rs index a290ca4a1..4311710ab 100644 --- a/crates/db_views/src/structs.rs +++ b/crates/db_views/src/structs.rs @@ -8,6 +8,7 @@ use lemmy_db_schema::{ community::Community, custom_emoji::CustomEmoji, custom_emoji_keyword::CustomEmojiKeyword, + images::LocalImage, local_site::LocalSite, local_site_rate_limit::LocalSiteRateLimit, local_user::LocalUser, @@ -214,3 +215,13 @@ pub struct VoteView { pub creator_banned_from_community: bool, pub score: i16, } + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[cfg_attr(feature = "full", derive(TS, Queryable))] +#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))] +#[cfg_attr(feature = "full", ts(export))] +/// A local image view. +pub struct LocalImageView { + pub local_image: LocalImage, + pub person: Person, +} From b0370ae2fd28250ccebdb61e9fddb3a14ebcbd81 Mon Sep 17 00:00:00 2001 From: TechVest <166724172+TechVest@users.noreply.github.com> Date: Wed, 17 Apr 2024 20:35:54 +0800 Subject: [PATCH 25/26] chore: fix some comments (#4637) Signed-off-by: TechVest --- api_tests/src/community.spec.ts | 6 +++--- api_tests/src/image.spec.ts | 8 ++++---- config/defaults.hjson | 2 +- crates/apub/src/activities/voting/mod.rs | 2 +- crates/apub/src/lib.rs | 2 +- crates/apub/src/objects/comment.rs | 2 +- crates/apub/src/objects/community.rs | 2 +- crates/apub/src/protocol/activities/community/announce.rs | 2 +- crates/db_schema/src/impls/comment_reply.rs | 2 +- crates/db_schema/src/impls/instance.rs | 2 +- crates/db_schema/src/impls/person.rs | 2 +- crates/db_schema/src/impls/person_mention.rs | 2 +- crates/db_schema/src/impls/private_message_report.rs | 2 +- crates/db_schema/src/newtypes.rs | 2 +- crates/db_views/src/post_view.rs | 2 +- crates/routes/src/images.rs | 2 +- crates/routes/src/webfinger.rs | 2 +- crates/utils/src/settings/structs.rs | 2 +- docker/docker-compose.yml | 2 +- src/scheduled_tasks.rs | 2 +- 20 files changed, 25 insertions(+), 25 deletions(-) diff --git a/api_tests/src/community.spec.ts b/api_tests/src/community.spec.ts index aa96f563c..5aa9fdfc8 100644 --- a/api_tests/src/community.spec.ts +++ b/api_tests/src/community.spec.ts @@ -242,7 +242,7 @@ test("Admin actions in remote community are not federated to origin", async () = ); expect(banRes.banned).toBe(true); - // ban doesnt federate to community's origin instance alpha + // ban doesn't federate to community's origin instance alpha let alphaPost = (await resolvePost(alpha, gammaPost.post)).post; expect(alphaPost?.creator_banned_from_community).toBe(false); @@ -452,7 +452,7 @@ test("Dont receive community activities after unsubscribe", async () => { ); expect(communityRes1.community_view.counts.subscribers).toBe(2); - // temporarily block alpha, so that it doesnt know about unfollow + // temporarily block alpha, so that it doesn't know about unfollow let editSiteForm: EditSite = {}; editSiteForm.allowed_instances = ["lemmy-epsilon"]; await beta.editSite(editSiteForm); @@ -513,7 +513,7 @@ test("Fetch community, includes posts", async () => { expect(post_listing.posts[0].post.ap_id).toBe(postRes.post_view.post.ap_id); }); -test("Content in local-only community doesnt federate", async () => { +test("Content in local-only community doesn't federate", async () => { // create a community and set it local-only let communityRes = (await createCommunity(alpha)).community_view.community; let form: EditCommunity = { diff --git a/api_tests/src/image.spec.ts b/api_tests/src/image.spec.ts index 2bdc3f4a5..cf6692960 100644 --- a/api_tests/src/image.spec.ts +++ b/api_tests/src/image.spec.ts @@ -41,7 +41,7 @@ test("Upload image and delete it", async () => { // Before running this test, you need to delete all previous images in the DB await deleteAllImages(alpha); - // Upload test image. We use a simple string buffer as pictrs doesnt require an actual image + // Upload test image. We use a simple string buffer as pictrs doesn't require an actual image // in testing mode. const upload_form: UploadImage = { image: Buffer.from("test"), @@ -235,7 +235,7 @@ test("No image proxying if setting is disabled", async () => { ); expect(post.post_view.post).toBeDefined(); - // remote image doesnt get proxied after upload + // remote image doesn't get proxied after upload expect( post.post_view.post.url?.startsWith("http://127.0.0.1:8551/pictrs/image/"), ).toBeTruthy(); @@ -248,7 +248,7 @@ test("No image proxying if setting is disabled", async () => { ); expect(betaPost.post).toBeDefined(); - // remote image doesnt get proxied after federation + // remote image doesn't get proxied after federation expect( betaPost.post.url?.startsWith("http://127.0.0.1:8551/pictrs/image/"), ).toBeTruthy(); @@ -295,7 +295,7 @@ test("Make regular post, and give it a custom thumbnail", async () => { expect(post.post_view.post.thumbnail_url).toBe(upload1.url); }); -test("Create an image post, and make sure a custom thumbnail doesnt overwrite it", async () => { +test("Create an image post, and make sure a custom thumbnail doesn't overwrite it", async () => { const uploadForm1: UploadImage = { image: Buffer.from("test1"), }; diff --git a/config/defaults.hjson b/config/defaults.hjson index c52f9055e..1fbab1fb9 100644 --- a/config/defaults.hjson +++ b/config/defaults.hjson @@ -49,7 +49,7 @@ cache_external_link_previews: true # Specifies how to handle remote images, so that users don't have to connect directly to remote servers. image_mode: - # Leave images unchanged, don't generate any local thumbnails for post urls. Instead the the + # Leave images unchanged, don't generate any local thumbnails for post urls. Instead the # Opengraph image is directly returned as thumbnail "None" diff --git a/crates/apub/src/activities/voting/mod.rs b/crates/apub/src/activities/voting/mod.rs index 2022252c1..3e59cb7d0 100644 --- a/crates/apub/src/activities/voting/mod.rs +++ b/crates/apub/src/activities/voting/mod.rs @@ -44,7 +44,7 @@ pub(crate) async fn send_like_activity( let activity = AnnouncableActivities::Vote(vote); send_activity_in_community(activity, &actor, &community, empty, false, &context).await } else { - // Lemmy API doesnt distinguish between Undo/Like and Undo/Dislike, so we hardcode it here. + // Lemmy API doesn't distinguish between Undo/Like and Undo/Dislike, so we hardcode it here. let vote = Vote::new(object_id, &actor, &community, VoteType::Like, &context)?; let undo_vote = UndoVote::new(vote, &actor, &community, &context)?; let activity = AnnouncableActivities::UndoVote(undo_vote); diff --git a/crates/apub/src/lib.rs b/crates/apub/src/lib.rs index 29c9a12eb..f500c41ee 100644 --- a/crates/apub/src/lib.rs +++ b/crates/apub/src/lib.rs @@ -195,7 +195,7 @@ pub(crate) async fn check_apub_id_valid_with_strictness( /// Store received activities in the database. /// -/// This ensures that the same activity doesnt get received and processed more than once, which +/// This ensures that the same activity doesn't get received and processed more than once, which /// would be a waste of resources. #[tracing::instrument(skip(data))] async fn insert_received_activity(ap_id: &Url, data: &Data) -> LemmyResult<()> { diff --git a/crates/apub/src/objects/comment.rs b/crates/apub/src/objects/comment.rs index 02de96f20..466094b7f 100644 --- a/crates/apub/src/objects/comment.rs +++ b/crates/apub/src/objects/comment.rs @@ -228,7 +228,7 @@ pub(crate) mod tests { url: &Url, context: &Data, ) -> LemmyResult<(ApubPerson, ApubCommunity, ApubPost, ApubSite)> { - // use separate counter so this doesnt affect tests + // use separate counter so this doesn't affect tests let context2 = context.reset_request_count(); let (person, site) = parse_lemmy_person(&context2).await?; let community = parse_lemmy_community(&context2).await?; diff --git a/crates/apub/src/objects/community.rs b/crates/apub/src/objects/community.rs index 6638cc68d..1526a1a37 100644 --- a/crates/apub/src/objects/community.rs +++ b/crates/apub/src/objects/community.rs @@ -269,7 +269,7 @@ pub(crate) mod tests { pub(crate) async fn parse_lemmy_community( context: &Data, ) -> LemmyResult { - // use separate counter so this doesnt affect tests + // use separate counter so this doesn't affect tests let context2 = context.reset_request_count(); let mut json: Group = file_to_json_object("assets/lemmy/objects/group.json")?; // change these links so they dont fetch over the network diff --git a/crates/apub/src/protocol/activities/community/announce.rs b/crates/apub/src/protocol/activities/community/announce.rs index e149e5fd1..60720365a 100644 --- a/crates/apub/src/protocol/activities/community/announce.rs +++ b/crates/apub/src/protocol/activities/community/announce.rs @@ -23,7 +23,7 @@ pub struct AnnounceActivity { } /// Use this to receive community inbox activities, and then announce them if valid. This -/// ensures that all json fields are kept, even if Lemmy doesnt understand them. +/// ensures that all json fields are kept, even if Lemmy doesn't understand them. #[derive(Clone, Debug, Deserialize, Serialize)] pub struct RawAnnouncableActivities { pub(crate) id: Url, diff --git a/crates/db_schema/src/impls/comment_reply.rs b/crates/db_schema/src/impls/comment_reply.rs index 4a4a49a13..bfea74a5a 100644 --- a/crates/db_schema/src/impls/comment_reply.rs +++ b/crates/db_schema/src/impls/comment_reply.rs @@ -22,7 +22,7 @@ impl Crud for CommentReply { let conn = &mut get_conn(pool).await?; // since the return here isnt utilized, we dont need to do an update - // but get_result doesnt return the existing row here + // but get_result doesn't return the existing row here insert_into(comment_reply::table) .values(comment_reply_form) .on_conflict((comment_reply::recipient_id, comment_reply::comment_id)) diff --git a/crates/db_schema/src/impls/instance.rs b/crates/db_schema/src/impls/instance.rs index 2e309efb9..67da14823 100644 --- a/crates/db_schema/src/impls/instance.rs +++ b/crates/db_schema/src/impls/instance.rs @@ -33,7 +33,7 @@ use diesel::{ use diesel_async::RunQueryDsl; impl Instance { - /// Attempt to read Instance column for the given domain. If it doesnt exist, insert a new one. + /// Attempt to read Instance column for the given domain. If it doesn't exist, insert a new one. /// There is no need for update as the domain of an existing instance cant change. pub async fn read_or_create(pool: &mut DbPool<'_>, domain_: String) -> Result { use crate::schema::instance::domain; diff --git a/crates/db_schema/src/impls/person.rs b/crates/db_schema/src/impls/person.rs index 68a9b3d59..a4c7073da 100644 --- a/crates/db_schema/src/impls/person.rs +++ b/crates/db_schema/src/impls/person.rs @@ -55,7 +55,7 @@ impl Crud for Person { impl Person { /// Update or insert the person. /// - /// This is necessary for federation, because Activitypub doesnt distinguish between these actions. + /// This is necessary for federation, because Activitypub doesn't distinguish between these actions. pub async fn upsert(pool: &mut DbPool<'_>, form: &PersonInsertForm) -> Result { let conn = &mut get_conn(pool).await?; insert_into(person::table) diff --git a/crates/db_schema/src/impls/person_mention.rs b/crates/db_schema/src/impls/person_mention.rs index 8566d31b1..c08019170 100644 --- a/crates/db_schema/src/impls/person_mention.rs +++ b/crates/db_schema/src/impls/person_mention.rs @@ -21,7 +21,7 @@ impl Crud for PersonMention { ) -> Result { let conn = &mut get_conn(pool).await?; // since the return here isnt utilized, we dont need to do an update - // but get_result doesnt return the existing row here + // but get_result doesn't return the existing row here insert_into(person_mention::table) .values(person_mention_form) .on_conflict((person_mention::recipient_id, person_mention::comment_id)) diff --git a/crates/db_schema/src/impls/private_message_report.rs b/crates/db_schema/src/impls/private_message_report.rs index c20783db0..b5d8fd039 100644 --- a/crates/db_schema/src/impls/private_message_report.rs +++ b/crates/db_schema/src/impls/private_message_report.rs @@ -46,7 +46,7 @@ impl Reportable for PrivateMessageReport { .await } - // TODO: this is unused because private message doesnt have remove handler + // TODO: this is unused because private message doesn't have remove handler async fn resolve_all_for_object( _pool: &mut DbPool<'_>, _pm_id_: PrivateMessageId, diff --git a/crates/db_schema/src/newtypes.rs b/crates/db_schema/src/newtypes.rs index 96fc23ac6..e0c516037 100644 --- a/crates/db_schema/src/newtypes.rs +++ b/crates/db_schema/src/newtypes.rs @@ -176,7 +176,7 @@ impl Display for DbUrl { } } -// the project doesnt compile with From +// the project doesn't compile with From #[allow(clippy::from_over_into)] impl Into for Url { fn into(self) -> DbUrl { diff --git a/crates/db_views/src/post_view.rs b/crates/db_views/src/post_view.rs index e66912190..257bcc76c 100644 --- a/crates/db_views/src/post_view.rs +++ b/crates/db_views/src/post_view.rs @@ -646,7 +646,7 @@ impl<'a> PostQuery<'a> { site: &Site, pool: &mut DbPool<'_>, ) -> Result>, Error> { - // first get one page for the most popular community to get an upper bound for the the page end for the real query + // first get one page for the most popular community to get an upper bound for the page end for the real query // the reason this is needed is that when fetching posts for a single community PostgreSQL can optimize // the query to use an index on e.g. (=, >=, >=, >=) and fetch only LIMIT rows // but for the followed-communities query it has to query the index on (IN, >=, >=, >=) diff --git a/crates/routes/src/images.rs b/crates/routes/src/images.rs index 58ca9c8ef..671aa223e 100644 --- a/crates/routes/src/images.rs +++ b/crates/routes/src/images.rs @@ -66,7 +66,7 @@ fn adapt_request( client: &ClientWithMiddleware, url: String, ) -> RequestBuilder { - // remove accept-encoding header so that pictrs doesnt compress the response + // remove accept-encoding header so that pictrs doesn't compress the response const INVALID_HEADERS: &[HeaderName] = &[ACCEPT_ENCODING, HOST]; let client_request = client diff --git a/crates/routes/src/webfinger.rs b/crates/routes/src/webfinger.rs index 6c630df4c..f2a67c0fc 100644 --- a/crates/routes/src/webfinger.rs +++ b/crates/routes/src/webfinger.rs @@ -63,7 +63,7 @@ async fn get_webfinger_response( }); // Mastodon seems to prioritize the last webfinger item in case of duplicates. Put - // community last so that it gets prioritized. For Lemmy the order doesnt matter. + // community last so that it gets prioritized. For Lemmy the order doesn't matter. vec![ webfinger_link_for_actor(user_id, "Person", &context), webfinger_link_for_actor(community_id, "Group", &context), diff --git a/crates/utils/src/settings/structs.rs b/crates/utils/src/settings/structs.rs index 4a8d8afb6..91a5b37f4 100644 --- a/crates/utils/src/settings/structs.rs +++ b/crates/utils/src/settings/structs.rs @@ -97,7 +97,7 @@ pub struct PictrsConfig { #[derive(Debug, Deserialize, Serialize, Clone, SmartDefault, Document, PartialEq)] #[serde(deny_unknown_fields)] pub enum PictrsImageMode { - /// Leave images unchanged, don't generate any local thumbnails for post urls. Instead the the + /// Leave images unchanged, don't generate any local thumbnails for post urls. Instead the /// Opengraph image is directly returned as thumbnail None, /// Generate thumbnails for external post urls and store them persistently in pict-rs. This diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 1bf38863f..eeeb9e24e 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -117,7 +117,7 @@ services: "track_activity_query_size=1048576", ] ports: - # use a different port so it doesnt conflict with potential postgres db running on the host + # use a different port so it doesn't conflict with potential postgres db running on the host - "5433:5432" environment: - POSTGRES_USER=lemmy diff --git a/src/scheduled_tasks.rs b/src/scheduled_tasks.rs index 8c4cf9311..ccbe00267 100644 --- a/src/scheduled_tasks.rs +++ b/src/scheduled_tasks.rs @@ -477,7 +477,7 @@ async fn update_instance_software( .build(); let form = match client.get(&node_info_url).send().await { Ok(res) if res.status().is_client_error() => { - // Instance doesnt have nodeinfo but sent a response, consider it alive + // Instance doesn't have nodeinfo but sent a response, consider it alive Some(default_form) } Ok(res) => match res.json::().await { From 31829b6c051ca172fcfd7da843172e33e521a8fc Mon Sep 17 00:00:00 2001 From: Nutomic Date: Wed, 17 Apr 2024 16:36:45 +0200 Subject: [PATCH 26/26] Untangle thumbnail generation logic (ref #4604) (#4615) * Untangle thumbnail generation logic (ref #4604) * prettier * test cleanup * fix tests * also consider opengraph image for local thumbnail generation --- api_tests/src/image.spec.ts | 36 ++----- api_tests/src/shared.ts | 19 ++-- crates/api/src/post/get_link_metadata.rs | 2 +- crates/api_common/src/post.rs | 2 - crates/api_common/src/request.rs | 123 +++++++---------------- crates/api_crud/src/post/create.rs | 1 + crates/api_crud/src/post/update.rs | 1 + crates/apub/src/objects/post.rs | 1 + 8 files changed, 65 insertions(+), 120 deletions(-) diff --git a/api_tests/src/image.spec.ts b/api_tests/src/image.spec.ts index cf6692960..a1b3c3f3e 100644 --- a/api_tests/src/image.spec.ts +++ b/api_tests/src/image.spec.ts @@ -27,9 +27,10 @@ import { setupLogins, waitForPost, unfollows, - editPostThumbnail, getPost, waitUntil, + randomString, + createPostWithThumbnail, } from "./shared"; const downloadFileSync = require("download-file-sync"); @@ -269,10 +270,11 @@ test("Make regular post, and give it a custom thumbnail", async () => { // Use wikipedia since it has an opengraph image const wikipediaUrl = "https://wikipedia.org/"; - let post = await createPost( + let post = await createPostWithThumbnail( alphaImage, community.community_view.community.id, wikipediaUrl, + upload1.url!, ); // Wait for the metadata to get fetched, since this is backgrounded now @@ -281,17 +283,7 @@ test("Make regular post, and give it a custom thumbnail", async () => { p => p.post_view.post.thumbnail_url != undefined, ); expect(post.post_view.post.url).toBe(wikipediaUrl); - expect(post.post_view.post.thumbnail_url).toBeDefined(); - - // Edit the thumbnail - await editPostThumbnail(alphaImage, post.post_view.post, upload1.url!); - - post = await waitUntil( - () => getPost(alphaImage, post.post_view.post.id), - p => p.post_view.post.thumbnail_url == upload1.url, - ); - - // Make sure the thumbnail got edited. + // Make sure it uses custom thumbnail expect(post.post_view.post.thumbnail_url).toBe(upload1.url); }); @@ -308,23 +300,17 @@ test("Create an image post, and make sure a custom thumbnail doesn't overwrite i const community = await createCommunity(alphaImage); - let post = await createPost( + let post = await createPostWithThumbnail( alphaImage, community.community_view.community.id, - upload1.url, + upload1.url!, + upload2.url!, ); - expect(post.post_view.post.url).toBe(upload1.url); - - // Edit the post - await editPostThumbnail(alphaImage, post.post_view.post, upload2.url!); - - // Wait for the metadata to get fetched post = await waitUntil( () => getPost(alphaImage, post.post_view.post.id), - p => p.post_view.post.thumbnail_url == upload1.url, + p => p.post_view.post.thumbnail_url != undefined, ); - - // Make sure the new custom thumbnail is ignored, and doesn't overwrite the image post expect(post.post_view.post.url).toBe(upload1.url); - expect(post.post_view.post.thumbnail_url).toBe(upload1.url); + // Make sure the custom thumbnail is ignored + expect(post.post_view.post.thumbnail_url == upload2.url).toBe(false); }); diff --git a/api_tests/src/shared.ts b/api_tests/src/shared.ts index c6f39f787..1a8a9afaf 100644 --- a/api_tests/src/shared.ts +++ b/api_tests/src/shared.ts @@ -203,6 +203,7 @@ export async function createPost( // use example.com for consistent title and embed description name: string = randomString(5), alt_text = randomString(10), + custom_thumbnail: string | undefined = undefined, ): Promise { let form: CreatePost = { name, @@ -210,6 +211,7 @@ export async function createPost( body, alt_text, community_id, + custom_thumbnail, }; return api.createPost(form); } @@ -226,16 +228,19 @@ export async function editPost( return api.editPost(form); } -export async function editPostThumbnail( +export async function createPostWithThumbnail( api: LemmyHttp, - post: Post, - customThumbnail: string, + community_id: number, + url: string, + custom_thumbnail: string, ): Promise { - let form: EditPost = { - post_id: post.id, - custom_thumbnail: customThumbnail, + let form: CreatePost = { + name: randomString(10), + url, + community_id, + custom_thumbnail, }; - return api.editPost(form); + return api.createPost(form); } export async function deletePost( diff --git a/crates/api/src/post/get_link_metadata.rs b/crates/api/src/post/get_link_metadata.rs index 8bc425125..17346790a 100644 --- a/crates/api/src/post/get_link_metadata.rs +++ b/crates/api/src/post/get_link_metadata.rs @@ -11,7 +11,7 @@ pub async fn get_link_metadata( data: Query, context: Data, ) -> LemmyResult> { - let metadata = fetch_link_metadata(&data.url, false, &context).await?; + let metadata = fetch_link_metadata(&data.url, &context).await?; Ok(Json(GetSiteMetadataResponse { metadata })) } diff --git a/crates/api_common/src/post.rs b/crates/api_common/src/post.rs index 4993fc6e5..49327dac1 100644 --- a/crates/api_common/src/post.rs +++ b/crates/api_common/src/post.rs @@ -270,8 +270,6 @@ pub struct LinkMetadata { #[serde(flatten)] pub opengraph_data: OpenGraphData, pub content_type: Option, - #[serde(skip)] - pub thumbnail: Option, } #[skip_serializing_none] diff --git a/crates/api_common/src/request.rs b/crates/api_common/src/request.rs index 912fbc67e..ddb2a4551 100644 --- a/crates/api_common/src/request.rs +++ b/crates/api_common/src/request.rs @@ -42,11 +42,7 @@ pub fn client_builder(settings: &Settings) -> ClientBuilder { /// Fetches metadata for the given link and optionally generates thumbnail. #[tracing::instrument(skip_all)] -pub async fn fetch_link_metadata( - url: &Url, - generate_thumbnail: bool, - context: &LemmyContext, -) -> LemmyResult { +pub async fn fetch_link_metadata(url: &Url, context: &LemmyContext) -> LemmyResult { info!("Fetching site metadata for url: {}", url); let response = context.client().get(url.as_str()).send().await?; @@ -63,71 +59,61 @@ pub async fn fetch_link_metadata( let opengraph_data = extract_opengraph_data(&html_bytes, url) .map_err(|e| info!("{e}")) .unwrap_or_default(); - let thumbnail = - extract_thumbnail_from_opengraph_data(url, &opengraph_data, generate_thumbnail, context).await; - Ok(LinkMetadata { opengraph_data, content_type: content_type.map(|c| c.to_string()), - thumbnail, }) } -#[tracing::instrument(skip_all)] -pub async fn fetch_link_metadata_opt( - url: Option<&Url>, - generate_thumbnail: bool, - context: &LemmyContext, -) -> LinkMetadata { - match &url { - Some(url) => fetch_link_metadata(url, generate_thumbnail, context) - .await - .unwrap_or_default(), - _ => Default::default(), - } -} /// Generate post thumbnail in background task, because some sites can be very slow to respond. /// /// Takes a callback to generate a send activity task, so that post can be federated with metadata. +/// +/// TODO: `federated_thumbnail` param can be removed once we federate full metadata and can +/// write it to db directly, without calling this function. +/// https://github.com/LemmyNet/lemmy/issues/4598 pub fn generate_post_link_metadata( post: Post, custom_thumbnail: Option, + federated_thumbnail: Option, send_activity: impl FnOnce(Post) -> Option + Send + 'static, local_site: Option, context: Data, ) { spawn_try_task(async move { - // Decide if the thumbnail should be generated - let allow_sensitive = local_site_opt_to_sensitive(&local_site); - let page_is_sensitive = post.nsfw; - let allow_generate_thumbnail = allow_sensitive || !page_is_sensitive; - let do_generate_thumbnail = - allow_generate_thumbnail && custom_thumbnail.is_none() && post.thumbnail_url.is_none(); - - // Generate local thumbnail only if no thumbnail was federated and 'sensitive' attributes allow it. - let metadata = fetch_link_metadata_opt( - post.url.as_ref().map(DbUrl::inner), - do_generate_thumbnail, - &context, - ) - .await; - - // If its an image post, it needs to overwrite the thumbnail, and take precedence - let image_url = if metadata - .content_type - .as_ref() - .is_some_and(|content_type| content_type.starts_with("image")) - { - post.url.map(Into::into) - } else { - None + let metadata = match &post.url { + Some(url) => fetch_link_metadata(url, &context).await.unwrap_or_default(), + _ => Default::default(), }; - // Build the thumbnail url based on either the post image url, custom thumbnail, metadata fetch, or existing thumbnail. - let thumbnail_url = image_url - .or(custom_thumbnail) - .or(metadata.thumbnail.map(Into::into)) - .or(post.thumbnail_url.map(Into::into)); + let is_image_post = metadata + .content_type + .as_ref() + .is_some_and(|content_type| content_type.starts_with("image")); + + // Decide if we are allowed to generate local thumbnail + let allow_sensitive = local_site_opt_to_sensitive(&local_site); + let allow_generate_thumbnail = allow_sensitive || !post.nsfw; + + // Use custom thumbnail if available and its not an image post + let thumbnail_url = if !is_image_post && custom_thumbnail.is_some() { + custom_thumbnail + } + // Use federated thumbnail if available + else if federated_thumbnail.is_some() { + federated_thumbnail + } + // Generate local thumbnail if allowed + else if allow_generate_thumbnail { + match post.url.or(metadata.opengraph_data.image) { + Some(url) => generate_pictrs_thumbnail(&url, &context).await.ok(), + None => None, + } + } + // Otherwise use opengraph preview image directly + else { + metadata.opengraph_data.image.map(Into::into) + }; // Proxy the image fetch if necessary let proxied_thumbnail_url = proxy_image_link_opt_apub(thumbnail_url, &context).await?; @@ -213,28 +199,6 @@ fn extract_opengraph_data(html_bytes: &[u8], url: &Url) -> LemmyResult Option { - if generate_thumbnail { - let image_url = opengraph_data - .image - .as_ref() - .map(DbUrl::inner) - .unwrap_or(url); - generate_pictrs_thumbnail(image_url, context) - .await - .ok() - .map(Into::into) - } else { - opengraph_data.image.clone() - } -} - #[derive(Deserialize, Debug)] struct PictrsResponse { files: Vec, @@ -414,9 +378,7 @@ mod tests { async fn test_link_metadata() { let context = LemmyContext::init_test_context().await; let sample_url = Url::parse("https://gitlab.com/IzzyOnDroid/repo/-/wikis/FAQ").unwrap(); - let sample_res = fetch_link_metadata(&sample_url, false, &context) - .await - .unwrap(); + let sample_res = fetch_link_metadata(&sample_url, &context).await.unwrap(); assert_eq!( Some("FAQ · Wiki · IzzyOnDroid / repo · GitLab".to_string()), sample_res.opengraph_data.title @@ -438,17 +400,8 @@ mod tests { Some(mime::TEXT_HTML_UTF_8.to_string()), sample_res.content_type ); - assert!(sample_res.thumbnail.is_some()); } - // #[test] - // fn test_pictshare() { - // let res = fetch_pictshare("https://upload.wikimedia.org/wikipedia/en/2/27/The_Mandalorian_logo.jpg"); - // assert!(res.is_ok()); - // let res_other = fetch_pictshare("https://upload.wikimedia.org/wikipedia/en/2/27/The_Mandalorian_logo.jpgaoeu"); - // assert!(res_other.is_err()); - // } - #[test] fn test_resolve_image_url() { // url that lists the opengraph fields diff --git a/crates/api_crud/src/post/create.rs b/crates/api_crud/src/post/create.rs index 266f964fa..fcd274c03 100644 --- a/crates/api_crud/src/post/create.rs +++ b/crates/api_crud/src/post/create.rs @@ -159,6 +159,7 @@ pub async fn create_post( generate_post_link_metadata( updated_post.clone(), custom_thumbnail, + None, |post| Some(SendActivityData::CreatePost(post)), Some(local_site), context.reset_request_count(), diff --git a/crates/api_crud/src/post/update.rs b/crates/api_crud/src/post/update.rs index 8be97f3c1..74e0c0d47 100644 --- a/crates/api_crud/src/post/update.rs +++ b/crates/api_crud/src/post/update.rs @@ -118,6 +118,7 @@ pub async fn update_post( generate_post_link_metadata( updated_post.clone(), custom_thumbnail, + None, |post| Some(SendActivityData::UpdatePost(post)), Some(local_site), context.reset_request_count(), diff --git a/crates/apub/src/objects/post.rs b/crates/apub/src/objects/post.rs index c7fa4acb1..ff11c985c 100644 --- a/crates/apub/src/objects/post.rs +++ b/crates/apub/src/objects/post.rs @@ -280,6 +280,7 @@ impl Object for ApubPost { generate_post_link_metadata( post.clone(), + None, page.image.map(|i| i.url), |_| None, local_site,