diff --git a/.woodpecker.yml b/.woodpecker.yml index 7e61e88f7..517640d6e 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -2,9 +2,14 @@ # See https://github.com/woodpecker-ci/woodpecker/issues/1677 variables: - - &rust_image "rust:1.78" + - &rust_image "rust:1.80" - &rust_nightly_image "rustlang/rust:nightly" - &install_pnpm "corepack enable pnpm" + - &install_binstall "wget -O- https://github.com/cargo-bins/cargo-binstall/releases/latest/download/cargo-binstall-x86_64-unknown-linux-musl.tgz | tar -xvz -C /usr/local/cargo/bin" + - install_diesel_cli: &install_diesel_cli + - apt-get update && apt-get install -y postgresql-client + - cargo install diesel_cli --no-default-features --features postgres + - export PATH="$CARGO_HOME/bin:$PATH" - &slow_check_paths - event: pull_request path: @@ -25,17 +30,6 @@ variables: "diesel.toml", ".gitmodules", ] - - install_binstall: &install_binstall - - wget https://github.com/cargo-bins/cargo-binstall/releases/latest/download/cargo-binstall-x86_64-unknown-linux-musl.tgz - - tar -xvf cargo-binstall-x86_64-unknown-linux-musl.tgz - - cp cargo-binstall /usr/local/cargo/bin - - install_diesel_cli: &install_diesel_cli - - apt update && apt install -y lsb-release build-essential - - sh -c 'echo "deb https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list' - - wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - - - apt update && apt install -y postgresql-client-16 - - cargo install diesel_cli --no-default-features --features postgres - - export PATH="$CARGO_HOME/bin:$PATH" steps: prepare_repo: @@ -82,7 +76,7 @@ steps: cargo_machete: image: *rust_nightly_image commands: - - <<: *install_binstall + - *install_binstall - cargo binstall -y cargo-machete - cargo machete when: @@ -214,7 +208,7 @@ steps: DO_WRITE_HOSTS_FILE: "1" commands: - *install_pnpm - - apt update && apt install -y bash curl postgresql-client + - apt-get update && apt-get install -y bash curl postgresql-client - bash api_tests/prepare-drone-federation-test.sh - cd api_tests/ - pnpm i @@ -261,7 +255,7 @@ steps: publish_to_crates_io: image: *rust_image commands: - - <<: *install_binstall + - *install_binstall # Install cargo-workspaces - cargo binstall -y cargo-workspaces - cp -r migrations crates/db_schema/ @@ -289,7 +283,8 @@ steps: services: database: - image: pgautoupgrade/pgautoupgrade:16-alpine + # 15-alpine image necessary because of diesel tests + image: pgautoupgrade/pgautoupgrade:15-alpine environment: POSTGRES_DB: lemmy POSTGRES_USER: postgres diff --git a/Cargo.lock b/Cargo.lock index db6469ac2..e5d8ec578 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -219,7 +219,7 @@ dependencies = [ "actix-utils", "futures-core", "futures-util", - "mio", + "mio 0.8.11", "socket2", "tokio", "tracing", @@ -373,7 +373,7 @@ dependencies = [ "getrandom", "once_cell", "version_check", - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -423,9 +423,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.14" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", @@ -438,33 +438,33 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", "windows-sys 0.52.0", @@ -592,9 +592,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.20.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e89b6941c2d1a7045538884d6e760ccfffdf8e1ffc2613d8efa74305e1f3752" +checksum = "0f0e249228c6ad2d240c2dc94b714d711629d52bad946075d8e9b2f5391f0703" dependencies = [ "bindgen", "cc", @@ -612,7 +612,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" dependencies = [ "async-trait", - "axum-core", + "axum-core 0.3.4", "bitflags 1.3.2", "bytes", "futures-util", @@ -633,6 +633,33 @@ dependencies = [ "tower-service", ] +[[package]] +name = "axum" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" +dependencies = [ + "async-trait", + "axum-core 0.4.3", + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "itoa", + "matchit 0.7.3", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper 1.0.1", + "tower", + "tower-layer", + "tower-service", +] + [[package]] name = "axum-core" version = "0.3.4" @@ -650,6 +677,26 @@ dependencies = [ "tower-service", ] +[[package]] +name = "axum-core" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper 0.1.2", + "tower-layer", + "tower-service", +] + [[package]] name = "backtrace" version = "0.3.71" @@ -852,9 +899,9 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytemuck" -version = "1.16.1" +version = "1.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e" +checksum = "102087e286b4677862ea56cf8fc58bb2cdfa8725c40ffb80fe3a008eb7f2fc83" [[package]] name = "byteorder" @@ -864,9 +911,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952" +checksum = "fca2be1d5c43812bae364ee3f30b3afcb7877cf59f4aeb94c66f313a41d2fac9" [[package]] name = "bytestring" @@ -893,9 +940,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f" +checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" dependencies = [ "jobserver", "libc", @@ -970,9 +1017,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.9" +version = "4.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64acc1846d54c1fe936a78dc189c34e28d3f5afc348403f28ecf53660b9b8462" +checksum = "0fbb260a053428790f3de475e304ff84cdbc4face759ea7a3e64c1edd938a7fc" dependencies = [ "clap_builder", "clap_derive", @@ -980,9 +1027,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.9" +version = "4.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8393d67ba2e7bfaf28a23458e4e2b543cc73a99595511eb207fdb8aede942" +checksum = "64b17d7ea74e9f833c7dbf2cbe4fb12ff26783eda4782a8975b72f895c9b4d99" dependencies = [ "anstream", "anstyle", @@ -992,9 +1039,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.8" +version = "4.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085" +checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -1004,9 +1051,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "clokwerk" @@ -1061,9 +1108,9 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "colorchoice" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "combine" @@ -1096,7 +1143,7 @@ dependencies = [ "ron", "serde", "serde_json", - "toml 0.8.15", + "toml 0.8.19", "yaml-rust", ] @@ -1108,21 +1155,21 @@ checksum = "fd326812b3fd01da5bb1af7d340d0d555fd3d4b641e7f1dfcf5962a902952787" dependencies = [ "futures-core", "prost 0.12.6", - "prost-types", + "prost-types 0.12.6", "tonic 0.10.2", "tracing-core", ] [[package]] name = "console-api" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a257c22cd7e487dd4a13d413beabc512c5052f0bc048db0da6a84c3d8a6142fd" +checksum = "86ed14aa9c9f927213c6e4f3ef75faaad3406134efe84ba2cb7983431d5f0931" dependencies = [ "futures-core", - "prost 0.12.6", - "prost-types", - "tonic 0.11.0", + "prost 0.13.1", + "prost-types 0.13.1", + "tonic 0.12.1", "tracing-core", ] @@ -1138,7 +1185,7 @@ dependencies = [ "futures-task", "hdrhistogram", "humantime", - "prost-types", + "prost-types 0.12.6", "serde", "serde_json", "thread_local", @@ -1152,24 +1199,25 @@ dependencies = [ [[package]] name = "console-subscriber" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c4cc54bae66f7d9188996404abdf7fdfa23034ef8e43478c8810828abad758" +checksum = "e2e3a111a37f3333946ebf9da370ba5c5577b18eb342ec683eb488dd21980302" dependencies = [ - "console-api 0.7.0", + "console-api 0.8.0", "crossbeam-channel", "crossbeam-utils", "futures-task", "hdrhistogram", "humantime", - "prost 0.12.6", - "prost-types", + "hyper-util", + "prost 0.13.1", + "prost-types 0.13.1", "serde", "serde_json", "thread_local", "tokio", "tokio-stream", - "tonic 0.11.0", + "tonic 0.12.1", "tracing", "tracing-core", "tracing-subscriber", @@ -1717,9 +1765,9 @@ dependencies = [ [[package]] name = "email_address" -version = "0.2.7" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46b7a0ac6570e31bfe2c6cf575a576a55af9893d1a6b30b4444e6e90b216bb84" +checksum = "e079f19b08ca6239f47f8ba8509c11cf3ea30095831f7fed61441475edd8c449" [[package]] name = "encoding_rs" @@ -2090,7 +2138,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.2.6", + "indexmap 2.3.0", "slab", "tokio", "tokio-util", @@ -2109,7 +2157,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.1.0", - "indexmap 2.2.6", + "indexmap 2.3.0", "slab", "tokio", "tokio-util", @@ -2435,7 +2483,7 @@ dependencies = [ "http 1.1.0", "hyper 1.4.1", "hyper-util", - "rustls 0.23.11", + "rustls 0.23.12", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", @@ -2455,6 +2503,19 @@ dependencies = [ "tokio-io-timeout", ] +[[package]] +name = "hyper-timeout" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3203a961e5c83b6f5498933e78b6b263e208c197b63e9c6c53cc82ffd3f63793" +dependencies = [ + "hyper 1.4.1", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", +] + [[package]] name = "hyper-tls" version = "0.5.0" @@ -2595,9 +2656,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0" dependencies = [ "equivalent", "hashbrown 0.14.5", @@ -2630,9 +2691,9 @@ checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "is_terminal_polyfill" -version = "1.70.0" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" @@ -2689,9 +2750,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" dependencies = [ "libc", ] @@ -2743,7 +2804,7 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "lemmy_api" -version = "0.19.5" +version = "0.19.6-beta.6" dependencies = [ "activitypub_federation", "actix-web", @@ -2756,6 +2817,7 @@ dependencies = [ "elementtree", "hound", "lemmy_api_common", + "lemmy_api_crud", "lemmy_db_schema", "lemmy_db_views", "lemmy_db_views_actor", @@ -2772,7 +2834,7 @@ dependencies = [ [[package]] name = "lemmy_api_common" -version = "0.19.5" +version = "0.19.6-beta.6" dependencies = [ "activitypub_federation", "actix-web", @@ -2790,7 +2852,6 @@ dependencies = [ "lemmy_utils", "mime", "moka", - "once_cell", "pretty_assertions", "regex", "reqwest 0.11.27", @@ -2810,7 +2871,7 @@ dependencies = [ [[package]] name = "lemmy_api_crud" -version = "0.19.5" +version = "0.19.6-beta.6" dependencies = [ "accept-language", "activitypub_federation", @@ -2824,7 +2885,6 @@ dependencies = [ "lemmy_db_views_actor", "lemmy_utils", "moka", - "once_cell", "tracing", "url", "uuid", @@ -2833,7 +2893,7 @@ dependencies = [ [[package]] name = "lemmy_apub" -version = "0.19.5" +version = "0.19.6-beta.6" dependencies = [ "activitypub_federation", "actix-web", @@ -2854,7 +2914,6 @@ dependencies = [ "lemmy_db_views_actor", "lemmy_utils", "moka", - "once_cell", "pretty_assertions", "reqwest 0.11.27", "serde", @@ -2871,7 +2930,7 @@ dependencies = [ [[package]] name = "lemmy_db_perf" -version = "0.19.5" +version = "0.19.6-beta.6" dependencies = [ "anyhow", "clap", @@ -2886,7 +2945,7 @@ dependencies = [ [[package]] name = "lemmy_db_schema" -version = "0.19.5" +version = "0.19.6-beta.6" dependencies = [ "activitypub_federation", "anyhow", @@ -2906,10 +2965,9 @@ dependencies = [ "i-love-jesus", "lemmy_utils", "moka", - "once_cell", "pretty_assertions", "regex", - "rustls 0.23.11", + "rustls 0.23.12", "serde", "serde_json", "serde_with", @@ -2927,7 +2985,7 @@ dependencies = [ [[package]] name = "lemmy_db_views" -version = "0.19.5" +version = "0.19.6-beta.6" dependencies = [ "actix-web", "chrono", @@ -2949,7 +3007,7 @@ dependencies = [ [[package]] name = "lemmy_db_views_actor" -version = "0.19.5" +version = "0.19.6-beta.6" dependencies = [ "chrono", "diesel", @@ -2969,7 +3027,7 @@ dependencies = [ [[package]] name = "lemmy_db_views_moderator" -version = "0.19.5" +version = "0.19.6-beta.6" dependencies = [ "diesel", "diesel-async", @@ -2981,7 +3039,7 @@ dependencies = [ [[package]] name = "lemmy_federate" -version = "0.19.5" +version = "0.19.6-beta.6" dependencies = [ "activitypub_federation", "actix-web", @@ -2998,7 +3056,6 @@ dependencies = [ "lemmy_utils", "mockall", "moka", - "once_cell", "reqwest 0.11.27", "serde_json", "serial_test", @@ -3013,7 +3070,7 @@ dependencies = [ [[package]] name = "lemmy_routes" -version = "0.19.5" +version = "0.19.6-beta.6" dependencies = [ "activitypub_federation", "actix-web", @@ -3025,7 +3082,6 @@ dependencies = [ "lemmy_db_views", "lemmy_db_views_actor", "lemmy_utils", - "once_cell", "reqwest 0.11.27", "reqwest-middleware 0.2.5", "rss", @@ -3038,7 +3094,7 @@ dependencies = [ [[package]] name = "lemmy_server" -version = "0.19.5" +version = "0.19.6-beta.6" dependencies = [ "activitypub_federation", "actix-cors", @@ -3047,7 +3103,7 @@ dependencies = [ "chrono", "clap", "clokwerk", - "console-subscriber 0.3.0", + "console-subscriber 0.4.0", "diesel", "diesel-async", "futures-util", @@ -3067,7 +3123,7 @@ dependencies = [ "reqwest 0.11.27", "reqwest-middleware 0.2.5", "reqwest-tracing 0.4.8", - "rustls 0.23.11", + "rustls 0.23.12", "serde_json", "serial_test", "tokio", @@ -3082,7 +3138,7 @@ dependencies = [ [[package]] name = "lemmy_utils" -version = "0.19.5" +version = "0.19.6-beta.6" dependencies = [ "actix-web", "anyhow", @@ -3097,7 +3153,6 @@ dependencies = [ "itertools 0.13.0", "lettre", "markdown-it", - "once_cell", "pretty_assertions", "regex", "reqwest 0.11.27", @@ -3137,7 +3192,7 @@ dependencies = [ "nom", "percent-encoding", "quoted_printable", - "rustls 0.23.11", + "rustls 0.23.12", "rustls-pemfile 2.1.2", "socket2", "tokio", @@ -3384,7 +3439,7 @@ dependencies = [ "http-body-util", "hyper 1.4.1", "hyper-util", - "indexmap 2.2.6", + "indexmap 2.3.0", "ipnet", "metrics", "metrics-util", @@ -3474,6 +3529,18 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "mio" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" +dependencies = [ + "hermit-abi", + "libc", + "wasi", + "windows-sys 0.52.0", +] + [[package]] name = "mirai-annotations" version = "1.12.0" @@ -3482,14 +3549,13 @@ checksum = "c9be0862c1b3f26a88803c4a49de6889c10e608b3ee9344e6ef5b45fb37ad3d1" [[package]] name = "mockall" -version = "0.12.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43766c2b5203b10de348ffe19f7e54564b64f3d6018ff7648d1e2d6d3a0f0a48" +checksum = "d4c28b3fb6d753d28c20e826cd46ee611fda1cf3cde03a443a974043247c065a" dependencies = [ "cfg-if", "downcast", "fragile", - "lazy_static", "mockall_derive", "predicates", "predicates-tree", @@ -3497,9 +3563,9 @@ dependencies = [ [[package]] name = "mockall_derive" -version = "0.12.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af7cbce79ec385a1d4f54baa90a76401eb15d9cab93685f62e7e9f942aa00ae2" +checksum = "341014e7f530314e9a1fdbc7400b244efea7122662c96bfa248c31da5bfb2020" dependencies = [ "cfg-if", "proc-macro2", @@ -3888,9 +3954,9 @@ dependencies = [ [[package]] name = "ordered-float" -version = "4.2.1" +version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ff2cf528c6c03d9ed653d6c4ce1dc0582dc4af309790ad92f07c1cd551b0be" +checksum = "4a91171844676f8c7990ce64959210cd2eaef32c2612c50f9fae9f8aaa6065a6" dependencies = [ "num-traits", ] @@ -4109,7 +4175,7 @@ dependencies = [ "reqwest 0.12.5", "reqwest-middleware 0.3.2", "reqwest-tracing 0.5.2", - "rustls 0.23.11", + "rustls 0.23.12", "rustls-channel-resolver", "rustls-pemfile 2.1.2", "rusty-s3", @@ -4127,7 +4193,7 @@ dependencies = [ "tokio-postgres", "tokio-postgres-generic-rustls", "tokio-util", - "toml 0.8.15", + "toml 0.8.19", "tracing", "tracing-actix-web", "tracing-error", @@ -4205,7 +4271,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" dependencies = [ "base64 0.22.1", - "indexmap 2.2.6", + "indexmap 2.3.0", "quick-xml 0.32.0", "serde", "time", @@ -4285,9 +4351,12 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "dee4364d9f3b902ef14fab8a1ddffb783a1cb6b4bba3bfc1fa3922732c7de97f" +dependencies = [ + "zerocopy 0.6.6", +] [[package]] name = "pq-sys" @@ -4306,9 +4375,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "predicates" -version = "3.1.0" +version = "3.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b87bfd4605926cdfefc1c3b5f8fe560e3feca9d5552cf68c466d3d8236c7e8" +checksum = "7e9086cc7640c29a356d1a29fd134380bee9d8f79a17410aa76e7ad295f42c97" dependencies = [ "anstyle", "predicates-core", @@ -4316,15 +4385,15 @@ dependencies = [ [[package]] name = "predicates-core" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" +checksum = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931" [[package]] name = "predicates-tree" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" +checksum = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13" dependencies = [ "predicates-core", "termtree", @@ -4419,6 +4488,16 @@ dependencies = [ "prost-derive 0.12.6", ] +[[package]] +name = "prost" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13db3d3fde688c61e2446b4d843bc27a7e8af269a69440c0308021dc92333cc" +dependencies = [ + "bytes", + "prost-derive 0.13.1", +] + [[package]] name = "prost-derive" version = "0.11.9" @@ -4445,6 +4524,19 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "prost-derive" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18bec9b0adc4eba778b33684b7ba3e7137789434769ee3ce3930463ef904cfca" +dependencies = [ + "anyhow", + "itertools 0.13.0", + "proc-macro2", + "quote", + "syn 2.0.72", +] + [[package]] name = "prost-types" version = "0.12.6" @@ -4454,6 +4546,15 @@ dependencies = [ "prost 0.12.6", ] +[[package]] +name = "prost-types" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cee5168b05f49d4b0ca581206eb14a7b22fafd963efe729ac48eb03266e25cc2" +dependencies = [ + "prost 0.13.1", +] + [[package]] name = "protobuf" version = "2.28.0" @@ -4524,7 +4625,7 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash", - "rustls 0.23.11", + "rustls 0.23.12", "thiserror", "tokio", "tracing", @@ -4540,7 +4641,7 @@ dependencies = [ "rand", "ring", "rustc-hash", - "rustls 0.23.11", + "rustls 0.23.12", "slab", "thiserror", "tinyvec", @@ -4549,9 +4650,9 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25a78e6f726d84fcf960409f509ae354a32648f090c8d32a2ea8b1a1bc3bab14" +checksum = "8bffec3605b73c6f1754535084a85229fa8a30f86014e6c81aeec4abb68b0285" dependencies = [ "libc", "once_cell", @@ -4678,7 +4779,7 @@ dependencies = [ "time", "tokio", "tokio-postgres", - "toml 0.8.15", + "toml 0.8.19", "url", "walkdir", ] @@ -4819,7 +4920,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.11", + "rustls 0.23.12", "rustls-pemfile 2.1.2", "rustls-pki-types", "serde", @@ -5045,9 +5146,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.11" +version = "0.23.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4828ea528154ae444e5a642dbb7d5623354030dc9822b83fd9bb79683c7399d0" +checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" dependencies = [ "aws-lc-rs", "log", @@ -5066,7 +5167,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fede2a247359da6b4998f7723ec6468c2d6a577a5d8c17e54f21806426ad2290" dependencies = [ "nanorand", - "rustls 0.23.11", + "rustls 0.23.12", ] [[package]] @@ -5158,9 +5259,9 @@ dependencies = [ [[package]] name = "scc" -version = "2.1.4" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4465c22496331e20eb047ff46e7366455bc01c0c02015c4a376de0b2cd3a1af" +checksum = "05ccfb12511cdb770157ace92d7dda771e498445b78f9886e8cdbc5140a4eced" dependencies = [ "sdd", ] @@ -5202,9 +5303,9 @@ dependencies = [ [[package]] name = "sdd" -version = "1.7.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85f05a494052771fc5bd0619742363b5e24e5ad72ab3111ec2e27925b8edc5f3" +checksum = "177258b64c0faaa9ffd3c65cd3262c2bc7e2588dbbd9c1641d0346145c1bbda8" [[package]] name = "security-framework" @@ -5277,12 +5378,13 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.120" +version = "1.0.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +checksum = "4ab380d7d9f22ef3f21ad3e6c1ebe8e4fc7a2000ccba2e4d71fc96f15b2cb609" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.3.0", "itoa", + "memchr", "ryu", "serde", ] @@ -5298,9 +5400,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" dependencies = [ "serde", ] @@ -5327,7 +5429,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.2.6", + "indexmap 2.3.0", "serde", "serde_derive", "serde_json", @@ -5910,22 +6012,21 @@ dependencies = [ [[package]] name = "tokio" -version = "1.38.1" +version = "1.39.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb2caba9f80616f438e09748d5acda951967e1ea58508ef53d9c6402485a46df" +checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" dependencies = [ "backtrace", "bytes", "libc", - "mio", - "num_cpus", + "mio 1.0.1", "parking_lot 0.12.3", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", "tracing", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -5940,9 +6041,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", @@ -5992,7 +6093,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8e98c31c29b2666fb28720739e11476166be4ead1610a37dcd7414bb124413a" dependencies = [ "aws-lc-rs", - "rustls 0.23.11", + "rustls 0.23.12", "tokio", "tokio-postgres", "tokio-rustls 0.26.0", @@ -6006,7 +6107,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04fb792ccd6bbcd4bba408eb8a292f70fc4a3589e5d793626f45190e6454b6ab" dependencies = [ "ring", - "rustls 0.23.11", + "rustls 0.23.12", "tokio", "tokio-postgres", "tokio-rustls 0.26.0", @@ -6029,7 +6130,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.11", + "rustls 0.23.12", "rustls-pki-types", "tokio", ] @@ -6072,21 +6173,21 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.15" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac2caab0bf757388c6c0ae23b3293fdb463fee59434529014f85e3263b995c28" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.16", + "toml_edit 0.22.20", ] [[package]] name = "toml_datetime" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] @@ -6097,7 +6198,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.3.0", "serde", "serde_spanned", "toml_datetime", @@ -6106,15 +6207,15 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.16" +version = "0.22.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "278f3d518e152219c994ce877758516bca5e118eaed6996192a774fb9fbf0788" +checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.3.0", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.14", + "winnow 0.6.18", ] [[package]] @@ -6125,7 +6226,7 @@ checksum = "8f219fad3b929bef19b1f86fbc0358d35daed8f2cac972037ac0dc10bbb8d5fb" dependencies = [ "async-stream", "async-trait", - "axum", + "axum 0.6.20", "base64 0.13.1", "bytes", "futures-core", @@ -6134,7 +6235,7 @@ dependencies = [ "http 0.2.12", "http-body 0.4.6", "hyper 0.14.30", - "hyper-timeout", + "hyper-timeout 0.4.1", "percent-encoding", "pin-project", "prost 0.11.9", @@ -6157,14 +6258,14 @@ checksum = "d560933a0de61cf715926b9cac824d4c883c2c43142f787595e48280c40a1d0e" dependencies = [ "async-stream", "async-trait", - "axum", + "axum 0.6.20", "base64 0.21.7", "bytes", "h2 0.3.26", "http 0.2.12", "http-body 0.4.6", "hyper 0.14.30", - "hyper-timeout", + "hyper-timeout 0.4.1", "percent-encoding", "pin-project", "prost 0.12.6", @@ -6184,14 +6285,14 @@ checksum = "76c4eb7a4e9ef9d4763600161f12f5070b92a578e1b634db88a6887844c91a13" dependencies = [ "async-stream", "async-trait", - "axum", + "axum 0.6.20", "base64 0.21.7", "bytes", "h2 0.3.26", "http 0.2.12", "http-body 0.4.6", "hyper 0.14.30", - "hyper-timeout", + "hyper-timeout 0.4.1", "percent-encoding", "pin-project", "prost 0.12.6", @@ -6204,10 +6305,40 @@ dependencies = [ ] [[package]] -name = "totp-rs" -version = "5.5.1" +name = "tonic" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c4ae9724c5888c0417d2396037ed3b60665925624766416e3e342b6ba5dbd3f" +checksum = "38659f4a91aba8598d27821589f5db7dddd94601e7a01b1e485a50e5484c7401" +dependencies = [ + "async-stream", + "async-trait", + "axum 0.7.5", + "base64 0.22.1", + "bytes", + "h2 0.4.5", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.4.1", + "hyper-timeout 0.5.1", + "hyper-util", + "percent-encoding", + "pin-project", + "prost 0.13.1", + "socket2", + "tokio", + "tokio-stream", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "totp-rs" +version = "5.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b2f27dad992486c26b4e7455f38aa487e838d6d61b57e72906ee2b8c287a90" dependencies = [ "base32", "constant_time_eq", @@ -6476,18 +6607,18 @@ dependencies = [ [[package]] name = "typed-builder" -version = "0.18.2" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77739c880e00693faef3d65ea3aad725f196da38b22fdc7ea6ded6e1ce4d3add" +checksum = "a06fbd5b8de54c5f7c91f6fe4cebb949be2125d7758e630bb58b1d831dbce600" dependencies = [ "typed-builder-macro", ] [[package]] name = "typed-builder-macro" -version = "0.18.2" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f718dfaf347dcb5b983bfc87608144b0bad87970aebcbea5ce44d2a30c08e63" +checksum = "f9534daa9fd3ed0bd911d462a37f172228077e7abf18c18a5f67199d959205f8" dependencies = [ "proc-macro2", "quote", @@ -6626,9 +6757,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "walkdir" @@ -7016,9 +7147,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.14" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374ec40a2d767a3c1b4972d9475ecd557356637be906f2cb3f7fe17a6eb5e22f" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" dependencies = [ "memchr", ] @@ -7117,13 +7248,34 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +[[package]] +name = "zerocopy" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854e949ac82d619ee9a14c66a1b674ac730422372ccb759ce0c39cabcf2bf8e6" +dependencies = [ + "byteorder", + "zerocopy-derive 0.6.6", +] + [[package]] name = "zerocopy" version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ - "zerocopy-derive", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy-derive" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "125139de3f6b9d625c39e2efdd73d41bdac468ccd556556440e322be0e1bbd91" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 96c4e2800..dcd389186 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace.package] -version = "0.19.5" +version = "0.19.6-beta.6" edition = "2021" description = "A link aggregator for the fediverse" license = "AGPL-3.0" @@ -86,28 +86,29 @@ suspicious = { level = "deny", priority = -1 } uninlined_format_args = "allow" unused_self = "deny" unwrap_used = "deny" +unimplemented = "deny" [workspace.dependencies] -lemmy_api = { version = "=0.19.5", path = "./crates/api" } -lemmy_api_crud = { version = "=0.19.5", path = "./crates/api_crud" } -lemmy_apub = { version = "=0.19.5", path = "./crates/apub" } -lemmy_utils = { version = "=0.19.5", path = "./crates/utils", default-features = false } -lemmy_db_schema = { version = "=0.19.5", path = "./crates/db_schema" } -lemmy_api_common = { version = "=0.19.5", path = "./crates/api_common" } -lemmy_routes = { version = "=0.19.5", path = "./crates/routes" } -lemmy_db_views = { version = "=0.19.5", path = "./crates/db_views" } -lemmy_db_views_actor = { version = "=0.19.5", path = "./crates/db_views_actor" } -lemmy_db_views_moderator = { version = "=0.19.5", path = "./crates/db_views_moderator" } -lemmy_federate = { version = "=0.19.5", path = "./crates/federate" } +lemmy_api = { version = "=0.19.6-beta.6", path = "./crates/api" } +lemmy_api_crud = { version = "=0.19.6-beta.6", path = "./crates/api_crud" } +lemmy_apub = { version = "=0.19.6-beta.6", path = "./crates/apub" } +lemmy_utils = { version = "=0.19.6-beta.6", path = "./crates/utils", default-features = false } +lemmy_db_schema = { version = "=0.19.6-beta.6", path = "./crates/db_schema" } +lemmy_api_common = { version = "=0.19.6-beta.6", path = "./crates/api_common" } +lemmy_routes = { version = "=0.19.6-beta.6", path = "./crates/routes" } +lemmy_db_views = { version = "=0.19.6-beta.6", path = "./crates/db_views" } +lemmy_db_views_actor = { version = "=0.19.6-beta.6", path = "./crates/db_views_actor" } +lemmy_db_views_moderator = { version = "=0.19.6-beta.6", path = "./crates/db_views_moderator" } +lemmy_federate = { version = "=0.19.6-beta.6", path = "./crates/federate" } activitypub_federation = { version = "0.5.8", default-features = false, features = [ "actix-web", ] } diesel = "2.1.6" diesel_migrations = "2.1.0" diesel-async = "0.4.1" -serde = { version = "1.0.203", features = ["derive"] } -serde_with = "3.8.1" -actix-web = { version = "4.6.0", default-features = false, features = [ +serde = { version = "1.0.204", features = ["derive"] } +serde_with = "3.9.0" +actix-web = { version = "4.8.0", default-features = false, features = [ "macros", "rustls-0_23", "compress-brotli", @@ -120,7 +121,7 @@ tracing-actix-web = { version = "0.7.11", default-features = false } tracing-error = "0.2.0" tracing-log = "0.2.0" tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } -url = { version = "2.5.0", features = ["serde"] } +url = { version = "2.5.2", features = ["serde"] } reqwest = { version = "0.11.27", default-features = false, features = [ "json", "blocking", @@ -133,20 +134,19 @@ clokwerk = "0.4.0" doku = { version = "0.21.1", features = ["url-2"] } bcrypt = "0.15.1" chrono = { version = "0.4.38", features = ["serde"], default-features = false } -serde_json = { version = "1.0.117", features = ["preserve_order"] } +serde_json = { version = "1.0.121", features = ["preserve_order"] } base64 = "0.22.1" -uuid = { version = "1.8.0", features = ["serde", "v4"] } -async-trait = "0.1.80" +uuid = { version = "1.10.0", features = ["serde", "v4"] } +async-trait = "0.1.81" captcha = "0.0.9" anyhow = { version = "1.0.86", features = [ "backtrace", ] } # backtrace is on by default on nightly, but not stable rust diesel_ltree = "0.3.1" -typed-builder = "0.18.2" +typed-builder = "0.19.1" serial_test = "3.1.1" -tokio = { version = "1.38.0", features = ["full"] } -regex = "1.10.4" -once_cell = "1.19.0" +tokio = { version = "1.39.2", features = ["full"] } +regex = "1.10.5" diesel-derive-newtype = "2.1.2" diesel-derive-enum = { version = "2.1.0", features = ["postgres"] } strum = { version = "0.26.3", features = ["derive"] } @@ -161,15 +161,15 @@ ts-rs = { version = "7.1.1", features = [ "chrono-impl", "no-serde-warnings", ] } -rustls = { version = "0.23.9", features = ["ring"] } +rustls = { version = "0.23.12", features = ["ring"] } futures-util = "0.3.30" -tokio-postgres = "0.7.10" +tokio-postgres = "0.7.11" tokio-postgres-rustls = "0.12.0" urlencoding = "2.1.3" enum-map = "2.7" -moka = { version = "0.12.7", features = ["future"] } +moka = { version = "0.12.8", features = ["future"] } i-love-jesus = { version = "0.1.0" } -clap = { version = "4.5.6", features = ["derive", "env"] } +clap = { version = "4.5.13", features = ["derive", "env"] } pretty_assertions = "1.4.0" derive-new = "0.6.0" @@ -199,9 +199,9 @@ clokwerk = { workspace = true } serde_json = { workspace = true } tracing-opentelemetry = { workspace = true, optional = true } opentelemetry = { workspace = true, optional = true } -console-subscriber = { version = "0.3.0", optional = true } +console-subscriber = { version = "0.4.0", optional = true } opentelemetry-otlp = { version = "0.12.0", optional = true } -pict-rs = { version = "0.5.15", optional = true } +pict-rs = { version = "0.5.16", optional = true } rustls = { workspace = true } tokio.workspace = true actix-cors = "0.7.0" diff --git a/api_tests/package.json b/api_tests/package.json index 6a14bded7..4fe5a40bd 100644 --- a/api_tests/package.json +++ b/api_tests/package.json @@ -6,7 +6,7 @@ "repository": "https://github.com/LemmyNet/lemmy", "author": "Dessalines", "license": "AGPL-3.0", - "packageManager": "pnpm@9.4.0", + "packageManager": "pnpm@9.6.0", "scripts": { "lint": "tsc --noEmit && eslint --report-unused-disable-directives && prettier --check 'src/**/*.ts'", "fix": "prettier --write src && eslint --fix src", @@ -21,17 +21,16 @@ }, "devDependencies": { "@types/jest": "^29.5.12", - "@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": "^9.0.0", + "@types/node": "^22.0.2", + "@typescript-eslint/eslint-plugin": "^8.0.0", + "@typescript-eslint/parser": "^8.0.0", + "eslint": "^9.8.0", "eslint-plugin-prettier": "^5.1.3", "jest": "^29.5.0", "lemmy-js-client": "0.19.5-alpha.1", "prettier": "^3.2.5", "ts-jest": "^29.1.0", - "typescript": "^5.4.4", - "typescript-eslint": "^7.13.0" + "typescript": "^5.5.4", + "typescript-eslint": "^8.0.0" } } diff --git a/api_tests/pnpm-lock.yaml b/api_tests/pnpm-lock.yaml index 31ec952c1..3da842f5d 100644 --- a/api_tests/pnpm-lock.yaml +++ b/api_tests/pnpm-lock.yaml @@ -12,41 +12,38 @@ importers: specifier: ^29.5.12 version: 29.5.12 '@types/node': - specifier: ^20.12.4 - version: 20.14.5 + specifier: ^22.0.2 + version: 22.0.2 '@typescript-eslint/eslint-plugin': - specifier: ^7.5.0 - version: 7.13.1(@typescript-eslint/parser@7.13.1(eslint@9.5.0)(typescript@5.4.5))(eslint@9.5.0)(typescript@5.4.5) + specifier: ^8.0.0 + version: 8.0.0(@typescript-eslint/parser@8.0.0(eslint@9.8.0)(typescript@5.5.4))(eslint@9.8.0)(typescript@5.5.4) '@typescript-eslint/parser': - specifier: ^7.5.0 - version: 7.13.1(eslint@9.5.0)(typescript@5.4.5) - download-file-sync: - specifier: ^1.0.4 - version: 1.0.4 + specifier: ^8.0.0 + version: 8.0.0(eslint@9.8.0)(typescript@5.5.4) eslint: - specifier: ^9.0.0 - version: 9.5.0 + specifier: ^9.8.0 + version: 9.8.0 eslint-plugin-prettier: specifier: ^5.1.3 - version: 5.1.3(eslint@9.5.0)(prettier@3.3.2) + version: 5.2.1(eslint@9.8.0)(prettier@3.3.3) jest: specifier: ^29.5.0 - version: 29.7.0(@types/node@20.14.5) + version: 29.7.0(@types/node@22.0.2) lemmy-js-client: specifier: 0.19.5-alpha.1 version: 0.19.5-alpha.1 prettier: specifier: ^3.2.5 - version: 3.3.2 + version: 3.3.3 ts-jest: specifier: ^29.1.0 - version: 29.1.5(@babel/core@7.23.9)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(jest@29.7.0(@types/node@20.14.5))(typescript@5.4.5) + version: 29.2.4(@babel/core@7.23.9)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(jest@29.7.0(@types/node@22.0.2))(typescript@5.5.4) typescript: - specifier: ^5.4.4 - version: 5.4.5 + specifier: ^5.5.4 + version: 5.5.4 typescript-eslint: - specifier: ^7.13.0 - version: 7.13.0(eslint@9.5.0)(typescript@5.4.5) + specifier: ^8.0.0 + version: 8.0.0(eslint@9.8.0)(typescript@5.5.4) packages: @@ -231,24 +228,20 @@ packages: peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - '@eslint-community/regexpp@4.10.0': - resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==} + '@eslint-community/regexpp@4.11.0': + resolution: {integrity: sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint-community/regexpp@4.10.1': - resolution: {integrity: sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - - '@eslint/config-array@0.16.0': - resolution: {integrity: sha512-/jmuSd74i4Czf1XXn7wGRWZCuyaUZ330NH1Bek0Pplatt4Sy1S5haN21SCLLdbeKslQ+S0wEJ+++v5YibSi+Lg==} + '@eslint/config-array@0.17.1': + resolution: {integrity: sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/eslintrc@3.1.0': resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.5.0': - resolution: {integrity: sha512-A7+AOT2ICkodvtsWnxZP4Xxk3NbZ3VMHd8oihydLRGrJgqqdEz1qSeEgXYyT/Cu8h1TWWsQRejIx48mtjZ5y1w==} + '@eslint/js@9.8.0': + resolution: {integrity: sha512-MfluB7EUfxXtv3i/++oh89uzAr4PDI4nn201hsp+qaXqsjAWzinlZEHEfPgAX4doIlKvPG/i0A9dpKxOLII8yA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/object-schema@2.1.4': @@ -407,8 +400,8 @@ packages: '@types/jest@29.5.12': resolution: {integrity: sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==} - '@types/node@20.14.5': - resolution: {integrity: sha512-aoRR+fJkZT2l0aGOJhuA8frnCSoNX6W7U2mpNq63+BxBIj5BQFt8rHy627kijCmm63ijdSdwvGgpUsU6MBsZZA==} + '@types/node@22.0.2': + resolution: {integrity: sha512-yPL6DyFwY5PiMVEwymNeqUTKsDczQBJ/5T7W/46RwLU/VH+AA8aT5TZkvBviLKLbbm0hlfftEkGrNzfRk/fofQ==} '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} @@ -419,129 +412,70 @@ packages: '@types/yargs@17.0.32': resolution: {integrity: sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==} - '@typescript-eslint/eslint-plugin@7.13.0': - resolution: {integrity: sha512-FX1X6AF0w8MdVFLSdqwqN/me2hyhuQg4ykN6ZpVhh1ij/80pTvDKclX1sZB9iqex8SjQfVhwMKs3JtnnMLzG9w==} - engines: {node: ^18.18.0 || >=20.0.0} + '@typescript-eslint/eslint-plugin@8.0.0': + resolution: {integrity: sha512-STIZdwEQRXAHvNUS6ILDf5z3u95Gc8jzywunxSNqX00OooIemaaNIA0vEgynJlycL5AjabYLLrIyHd4iazyvtg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^7.0.0 - eslint: ^8.56.0 + '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 + eslint: ^8.57.0 || ^9.0.0 typescript: '*' peerDependenciesMeta: typescript: optional: true - '@typescript-eslint/eslint-plugin@7.13.1': - resolution: {integrity: sha512-kZqi+WZQaZfPKnsflLJQCz6Ze9FFSMfXrrIOcyargekQxG37ES7DJNpJUE9Q/X5n3yTIP/WPutVNzgknQ7biLg==} - engines: {node: ^18.18.0 || >=20.0.0} + '@typescript-eslint/parser@8.0.0': + resolution: {integrity: sha512-pS1hdZ+vnrpDIxuFXYQpLTILglTjSYJ9MbetZctrUawogUsPdz31DIIRZ9+rab0LhYNTsk88w4fIzVheiTbWOQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^7.0.0 - eslint: ^8.56.0 + eslint: ^8.57.0 || ^9.0.0 typescript: '*' peerDependenciesMeta: typescript: optional: true - '@typescript-eslint/parser@7.13.0': - resolution: {integrity: sha512-EjMfl69KOS9awXXe83iRN7oIEXy9yYdqWfqdrFAYAAr6syP8eLEFI7ZE4939antx2mNgPRW/o1ybm2SFYkbTVA==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/scope-manager@8.0.0': + resolution: {integrity: sha512-V0aa9Csx/ZWWv2IPgTfY7T4agYwJyILESu/PVqFtTFz9RIS823mAze+NbnBI8xiwdX3iqeQbcTYlvB04G9wyQw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/parser@7.13.1': - resolution: {integrity: sha512-1ELDPlnLvDQ5ybTSrMhRTFDfOQEOXNM+eP+3HT/Yq7ruWpciQw+Avi73pdEbA4SooCawEWo3dtYbF68gN7Ed1A==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/scope-manager@7.13.0': - resolution: {integrity: sha512-ZrMCe1R6a01T94ilV13egvcnvVJ1pxShkE0+NDjDzH4nvG1wXpwsVI5bZCvE7AEDH1mXEx5tJSVR68bLgG7Dng==} - engines: {node: ^18.18.0 || >=20.0.0} - - '@typescript-eslint/scope-manager@7.13.1': - resolution: {integrity: sha512-adbXNVEs6GmbzaCpymHQ0MB6E4TqoiVbC0iqG3uijR8ZYfpAXMGttouQzF4Oat3P2GxDVIrg7bMI/P65LiQZdg==} - engines: {node: ^18.18.0 || >=20.0.0} - - '@typescript-eslint/type-utils@7.13.0': - resolution: {integrity: sha512-xMEtMzxq9eRkZy48XuxlBFzpVMDurUAfDu5Rz16GouAtXm0TaAoTFzqWUFPPuQYXI/CDaH/Bgx/fk/84t/Bc9A==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/type-utils@7.13.1': - resolution: {integrity: sha512-aWDbLu1s9bmgPGXSzNCxELu+0+HQOapV/y+60gPXafR8e2g1Bifxzevaa+4L2ytCWm+CHqpELq4CSoN9ELiwCg==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - eslint: ^8.56.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/types@7.13.0': - resolution: {integrity: sha512-QWuwm9wcGMAuTsxP+qz6LBBd3Uq8I5Nv8xb0mk54jmNoCyDspnMvVsOxI6IsMmway5d1S9Su2+sCKv1st2l6eA==} - engines: {node: ^18.18.0 || >=20.0.0} - - '@typescript-eslint/types@7.13.1': - resolution: {integrity: sha512-7K7HMcSQIAND6RBL4kDl24sG/xKM13cA85dc7JnmQXw2cBDngg7c19B++JzvJHRG3zG36n9j1i451GBzRuHchw==} - engines: {node: ^18.18.0 || >=20.0.0} - - '@typescript-eslint/typescript-estree@7.13.0': - resolution: {integrity: sha512-cAvBvUoobaoIcoqox1YatXOnSl3gx92rCZoMRPzMNisDiM12siGilSM4+dJAekuuHTibI2hVC2fYK79iSFvWjw==} - engines: {node: ^18.18.0 || >=20.0.0} + '@typescript-eslint/type-utils@8.0.0': + resolution: {integrity: sha512-mJAFP2mZLTBwAn5WI4PMakpywfWFH5nQZezUQdSKV23Pqo6o9iShQg1hP2+0hJJXP2LnZkWPphdIq4juYYwCeg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '*' peerDependenciesMeta: typescript: optional: true - '@typescript-eslint/typescript-estree@7.13.1': - resolution: {integrity: sha512-uxNr51CMV7npU1BxZzYjoVz9iyjckBduFBP0S5sLlh1tXYzHzgZ3BR9SVsNed+LmwKrmnqN3Kdl5t7eZ5TS1Yw==} - engines: {node: ^18.18.0 || >=20.0.0} + '@typescript-eslint/types@8.0.0': + resolution: {integrity: sha512-wgdSGs9BTMWQ7ooeHtu5quddKKs5Z5dS+fHLbrQI+ID0XWJLODGMHRfhwImiHoeO2S5Wir2yXuadJN6/l4JRxw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.0.0': + resolution: {integrity: sha512-5b97WpKMX+Y43YKi4zVcCVLtK5F98dFls3Oxui8LbnmRsseKenbbDinmvxrWegKDMmlkIq/XHuyy0UGLtpCDKg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '*' peerDependenciesMeta: typescript: optional: true - '@typescript-eslint/utils@7.13.0': - resolution: {integrity: sha512-jceD8RgdKORVnB4Y6BqasfIkFhl4pajB1wVxrF4akxD2QPM8GNYjgGwEzYS+437ewlqqrg7Dw+6dhdpjMpeBFQ==} - engines: {node: ^18.18.0 || >=20.0.0} + '@typescript-eslint/utils@8.0.0': + resolution: {integrity: sha512-k/oS/A/3QeGLRvOWCg6/9rATJL5rec7/5s1YmdS0ZU6LHveJyGFwBvLhSRBv6i9xaj7etmosp+l+ViN1I9Aj/Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.56.0 + eslint: ^8.57.0 || ^9.0.0 - '@typescript-eslint/utils@7.13.1': - resolution: {integrity: sha512-h5MzFBD5a/Gh/fvNdp9pTfqJAbuQC4sCN2WzuXme71lqFJsZtLbjxfSk4r3p02WIArOF9N94pdsLiGutpDbrXQ==} - engines: {node: ^18.18.0 || >=20.0.0} - peerDependencies: - eslint: ^8.56.0 - - '@typescript-eslint/visitor-keys@7.13.0': - resolution: {integrity: sha512-nxn+dozQx+MK61nn/JP+M4eCkHDSxSLDpgE3WcQo0+fkjEolnaB5jswvIKC4K56By8MMgIho7f1PVxERHEo8rw==} - engines: {node: ^18.18.0 || >=20.0.0} - - '@typescript-eslint/visitor-keys@7.13.1': - resolution: {integrity: sha512-k/Bfne7lrP7hcb7m9zSsgcBmo+8eicqqfNAJ7uUY+jkTFpKeH2FSkWpFRtimBxgkyvqfu9jTPRbYOvud6isdXA==} - engines: {node: ^18.18.0 || >=20.0.0} + '@typescript-eslint/visitor-keys@8.0.0': + resolution: {integrity: sha512-oN0K4nkHuOyF3PVMyETbpP5zp6wfyOvm7tWhTMfoqxSSsPmJIh6JNASuZDlODE8eE+0EB9uar+6+vxr9DBTYOA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 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==} + acorn@8.12.1: + resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} engines: {node: '>=0.4.0'} hasBin: true @@ -582,6 +516,9 @@ packages: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} + async@3.2.5: + resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==} + babel-jest@29.7.0: resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -721,8 +658,8 @@ packages: supports-color: optional: true - debug@4.3.5: - resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==} + debug@4.3.6: + resolution: {integrity: sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' @@ -757,8 +694,10 @@ packages: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} - download-file-sync@1.0.4: - resolution: {integrity: sha512-vH92qNH508jZZA12HQNq/aiMDfagr4JvjFiI17Bi8oYjsxwv5ZVIi7iHkYmUXxOQUr90tcVX+8EPePjAqG1Y0w==} + ejs@3.1.10: + resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} + engines: {node: '>=0.10.0'} + hasBin: true electron-to-chromium@1.4.648: resolution: {integrity: sha512-EmFMarXeqJp9cUKu/QEciEApn0S/xRcpZWuAm32U7NgoZCimjsilKXHRO9saeEW55eHZagIDg6XTUOv32w9pjg==} @@ -789,8 +728,8 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} - eslint-plugin-prettier@5.1.3: - resolution: {integrity: sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==} + eslint-plugin-prettier@5.2.1: + resolution: {integrity: sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: '@types/eslint': '>=8.0.0' @@ -803,8 +742,8 @@ packages: eslint-config-prettier: optional: true - eslint-scope@8.0.1: - resolution: {integrity: sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==} + eslint-scope@8.0.2: + resolution: {integrity: sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} eslint-visitor-keys@3.4.3: @@ -815,13 +754,13 @@ packages: resolution: {integrity: sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.5.0: - resolution: {integrity: sha512-+NAOZFrW/jFTS3dASCGBxX1pkFD0/fsO+hfAkJ4TyYKwgsXZbqzrw+seCYFCcPCYXvnD67tAnglU7GQTz6kcVw==} + eslint@9.8.0: + resolution: {integrity: sha512-K8qnZ/QJzT2dLKdZJVX6W4XOwBzutMYmt0lqUS+JdXgd+HTYFlonFgkJ8s44d/zMPPCnOOk0kMWCApCPhiOy9A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true - espree@10.0.1: - resolution: {integrity: sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==} + espree@10.1.0: + resolution: {integrity: sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} esprima@4.0.1: @@ -883,6 +822,9 @@ packages: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} + filelist@1.0.4: + resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} + fill-range@7.0.1: resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} engines: {node: '>=8'} @@ -1067,6 +1009,11 @@ packages: resolution: {integrity: sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==} engines: {node: '>=8'} + jake@10.9.2: + resolution: {integrity: sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==} + engines: {node: '>=10'} + hasBin: 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} @@ -1299,8 +1246,12 @@ packages: minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - minimatch@9.0.4: - resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==} + minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} ms@2.1.2: @@ -1404,8 +1355,8 @@ packages: resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} engines: {node: '>=6.0.0'} - prettier@3.3.2: - resolution: {integrity: sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==} + prettier@3.3.3: + resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} engines: {node: '>=14'} hasBin: true @@ -1470,6 +1421,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + engines: {node: '>=10'} + hasBin: true + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -1542,8 +1498,8 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - synckit@0.8.8: - resolution: {integrity: sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==} + synckit@0.9.1: + resolution: {integrity: sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==} engines: {node: ^14.18.0 || >=16.0.0} test-exclude@6.0.0: @@ -1570,8 +1526,8 @@ packages: peerDependencies: typescript: '>=4.2.0' - ts-jest@29.1.5: - resolution: {integrity: sha512-UuClSYxM7byvvYfyWdFI+/2UxMmwNyJb0NPkZPQE2hew3RurV7l7zURgOHAd/1I1ZdPpe3GUsXNXAcN8TFKSIg==} + ts-jest@29.2.4: + resolution: {integrity: sha512-3d6tgDyhCI29HlpwIq87sNuI+3Q6GLTTCeYRHCs7vDz+/3GCMwEtV9jezLyl4ZtnBgx00I7hm8PCP8cTksMGrw==} engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -1594,8 +1550,8 @@ packages: esbuild: optional: true - tslib@2.6.2: - resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + tslib@2.6.3: + resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} @@ -1609,23 +1565,22 @@ packages: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} engines: {node: '>=10'} - typescript-eslint@7.13.0: - resolution: {integrity: sha512-upO0AXxyBwJ4BbiC6CRgAJKtGYha2zw4m1g7TIVPSonwYEuf7vCicw3syjS1OxdDMTz96sZIXl3Jx3vWJLLKFw==} - engines: {node: ^18.18.0 || >=20.0.0} + typescript-eslint@8.0.0: + resolution: {integrity: sha512-yQWBJutWL1PmpmDddIOl9/Mi6vZjqNCjqSGBMQ4vsc2Aiodk0SnbQQWPXbSy0HNuKCuGkw1+u4aQ2mO40TdhDQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.56.0 typescript: '*' peerDependenciesMeta: typescript: optional: true - typescript@5.4.5: - resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} + typescript@5.5.4: + resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==} engines: {node: '>=14.17'} hasBin: true - undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + undici-types@6.11.1: + resolution: {integrity: sha512-mIDEX2ek50x0OlRgxryxsenE5XaQD4on5U2inY7RApK3SOJpofyw7uW2AyfMKkhAxXIceo2DeWGVGwyvng1GNQ==} update-browserslist-db@1.0.13: resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} @@ -1707,7 +1662,7 @@ snapshots: '@babel/traverse': 7.23.9 '@babel/types': 7.23.9 convert-source-map: 2.0.0 - debug: 4.3.5 + debug: 4.3.6 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -1873,7 +1828,7 @@ snapshots: '@babel/helper-split-export-declaration': 7.22.6 '@babel/parser': 7.23.9 '@babel/types': 7.23.9 - debug: 4.3.5 + debug: 4.3.6 globals: 11.12.0 transitivePeerDependencies: - supports-color @@ -1886,16 +1841,14 @@ snapshots: '@bcoe/v8-coverage@0.2.3': {} - '@eslint-community/eslint-utils@4.4.0(eslint@9.5.0)': + '@eslint-community/eslint-utils@4.4.0(eslint@9.8.0)': dependencies: - eslint: 9.5.0 + eslint: 9.8.0 eslint-visitor-keys: 3.4.3 - '@eslint-community/regexpp@4.10.0': {} + '@eslint-community/regexpp@4.11.0': {} - '@eslint-community/regexpp@4.10.1': {} - - '@eslint/config-array@0.16.0': + '@eslint/config-array@0.17.1': dependencies: '@eslint/object-schema': 2.1.4 debug: 4.3.4 @@ -1907,7 +1860,7 @@ snapshots: dependencies: ajv: 6.12.6 debug: 4.3.4 - espree: 10.0.1 + espree: 10.1.0 globals: 14.0.0 ignore: 5.3.1 import-fresh: 3.3.0 @@ -1917,7 +1870,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@9.5.0': {} + '@eslint/js@9.8.0': {} '@eslint/object-schema@2.1.4': {} @@ -1938,7 +1891,7 @@ snapshots: '@jest/console@29.7.0': dependencies: '@jest/types': 29.6.3 - '@types/node': 20.14.5 + '@types/node': 22.0.2 chalk: 4.1.2 jest-message-util: 29.7.0 jest-util: 29.7.0 @@ -1951,14 +1904,14 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.14.5 + '@types/node': 22.0.2 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.14.5) + jest-config: 29.7.0(@types/node@22.0.2) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -1983,7 +1936,7 @@ snapshots: dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.14.5 + '@types/node': 22.0.2 jest-mock: 29.7.0 '@jest/expect-utils@29.7.0': @@ -2001,7 +1954,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 20.14.5 + '@types/node': 22.0.2 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -2023,7 +1976,7 @@ snapshots: '@jest/transform': 29.7.0 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.22 - '@types/node': 20.14.5 + '@types/node': 22.0.2 chalk: 4.1.2 collect-v8-coverage: 1.0.2 exit: 0.1.2 @@ -2093,7 +2046,7 @@ snapshots: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 20.14.5 + '@types/node': 22.0.2 '@types/yargs': 17.0.32 chalk: 4.1.2 @@ -2161,7 +2114,7 @@ snapshots: '@types/graceful-fs@4.1.9': dependencies: - '@types/node': 20.14.5 + '@types/node': 22.0.2 '@types/istanbul-lib-coverage@2.0.6': {} @@ -2178,9 +2131,9 @@ snapshots: expect: 29.7.0 pretty-format: 29.7.0 - '@types/node@20.14.5': + '@types/node@22.0.2': dependencies: - undici-types: 5.26.5 + undici-types: 6.11.1 '@types/stack-utils@2.0.3': {} @@ -2190,173 +2143,92 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@7.13.0(@typescript-eslint/parser@7.13.0(eslint@9.5.0)(typescript@5.4.5))(eslint@9.5.0)(typescript@5.4.5)': + '@typescript-eslint/eslint-plugin@8.0.0(@typescript-eslint/parser@8.0.0(eslint@9.8.0)(typescript@5.5.4))(eslint@9.8.0)(typescript@5.5.4)': dependencies: - '@eslint-community/regexpp': 4.10.1 - '@typescript-eslint/parser': 7.13.0(eslint@9.5.0)(typescript@5.4.5) - '@typescript-eslint/scope-manager': 7.13.0 - '@typescript-eslint/type-utils': 7.13.0(eslint@9.5.0)(typescript@5.4.5) - '@typescript-eslint/utils': 7.13.0(eslint@9.5.0)(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.13.0 - eslint: 9.5.0 + '@eslint-community/regexpp': 4.11.0 + '@typescript-eslint/parser': 8.0.0(eslint@9.8.0)(typescript@5.5.4) + '@typescript-eslint/scope-manager': 8.0.0 + '@typescript-eslint/type-utils': 8.0.0(eslint@9.8.0)(typescript@5.5.4) + '@typescript-eslint/utils': 8.0.0(eslint@9.8.0)(typescript@5.5.4) + '@typescript-eslint/visitor-keys': 8.0.0 + eslint: 9.8.0 graphemer: 1.4.0 ignore: 5.3.1 natural-compare: 1.4.0 - ts-api-utils: 1.3.0(typescript@5.4.5) + ts-api-utils: 1.3.0(typescript@5.5.4) optionalDependencies: - typescript: 5.4.5 + typescript: 5.5.4 transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@7.13.1(@typescript-eslint/parser@7.13.1(eslint@9.5.0)(typescript@5.4.5))(eslint@9.5.0)(typescript@5.4.5)': + '@typescript-eslint/parser@8.0.0(eslint@9.8.0)(typescript@5.5.4)': dependencies: - '@eslint-community/regexpp': 4.10.1 - '@typescript-eslint/parser': 7.13.1(eslint@9.5.0)(typescript@5.4.5) - '@typescript-eslint/scope-manager': 7.13.1 - '@typescript-eslint/type-utils': 7.13.1(eslint@9.5.0)(typescript@5.4.5) - '@typescript-eslint/utils': 7.13.1(eslint@9.5.0)(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.13.1 - eslint: 9.5.0 - graphemer: 1.4.0 - ignore: 5.3.1 - natural-compare: 1.4.0 - ts-api-utils: 1.3.0(typescript@5.4.5) + '@typescript-eslint/scope-manager': 8.0.0 + '@typescript-eslint/types': 8.0.0 + '@typescript-eslint/typescript-estree': 8.0.0(typescript@5.5.4) + '@typescript-eslint/visitor-keys': 8.0.0 + debug: 4.3.6 + eslint: 9.8.0 optionalDependencies: - typescript: 5.4.5 + typescript: 5.5.4 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@7.13.0(eslint@9.5.0)(typescript@5.4.5)': + '@typescript-eslint/scope-manager@8.0.0': dependencies: - '@typescript-eslint/scope-manager': 7.13.0 - '@typescript-eslint/types': 7.13.0 - '@typescript-eslint/typescript-estree': 7.13.0(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.13.0 - debug: 4.3.5 - eslint: 9.5.0 + '@typescript-eslint/types': 8.0.0 + '@typescript-eslint/visitor-keys': 8.0.0 + + '@typescript-eslint/type-utils@8.0.0(eslint@9.8.0)(typescript@5.5.4)': + dependencies: + '@typescript-eslint/typescript-estree': 8.0.0(typescript@5.5.4) + '@typescript-eslint/utils': 8.0.0(eslint@9.8.0)(typescript@5.5.4) + debug: 4.3.6 + ts-api-utils: 1.3.0(typescript@5.5.4) optionalDependencies: - typescript: 5.4.5 + typescript: 5.5.4 transitivePeerDependencies: + - eslint - supports-color - '@typescript-eslint/parser@7.13.1(eslint@9.5.0)(typescript@5.4.5)': + '@typescript-eslint/types@8.0.0': {} + + '@typescript-eslint/typescript-estree@8.0.0(typescript@5.5.4)': dependencies: - '@typescript-eslint/scope-manager': 7.13.1 - '@typescript-eslint/types': 7.13.1 - '@typescript-eslint/typescript-estree': 7.13.1(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.13.1 - debug: 4.3.5 - eslint: 9.5.0 - optionalDependencies: - typescript: 5.4.5 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/scope-manager@7.13.0': - dependencies: - '@typescript-eslint/types': 7.13.0 - '@typescript-eslint/visitor-keys': 7.13.0 - - '@typescript-eslint/scope-manager@7.13.1': - dependencies: - '@typescript-eslint/types': 7.13.1 - '@typescript-eslint/visitor-keys': 7.13.1 - - '@typescript-eslint/type-utils@7.13.0(eslint@9.5.0)(typescript@5.4.5)': - dependencies: - '@typescript-eslint/typescript-estree': 7.13.0(typescript@5.4.5) - '@typescript-eslint/utils': 7.13.0(eslint@9.5.0)(typescript@5.4.5) - debug: 4.3.5 - eslint: 9.5.0 - ts-api-utils: 1.3.0(typescript@5.4.5) - optionalDependencies: - typescript: 5.4.5 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/type-utils@7.13.1(eslint@9.5.0)(typescript@5.4.5)': - dependencies: - '@typescript-eslint/typescript-estree': 7.13.1(typescript@5.4.5) - '@typescript-eslint/utils': 7.13.1(eslint@9.5.0)(typescript@5.4.5) - debug: 4.3.5 - eslint: 9.5.0 - ts-api-utils: 1.3.0(typescript@5.4.5) - optionalDependencies: - typescript: 5.4.5 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/types@7.13.0': {} - - '@typescript-eslint/types@7.13.1': {} - - '@typescript-eslint/typescript-estree@7.13.0(typescript@5.4.5)': - dependencies: - '@typescript-eslint/types': 7.13.0 - '@typescript-eslint/visitor-keys': 7.13.0 - debug: 4.3.5 + '@typescript-eslint/types': 8.0.0 + '@typescript-eslint/visitor-keys': 8.0.0 + debug: 4.3.6 globby: 11.1.0 is-glob: 4.0.3 - minimatch: 9.0.4 - semver: 7.6.2 - ts-api-utils: 1.3.0(typescript@5.4.5) + minimatch: 9.0.5 + semver: 7.6.3 + ts-api-utils: 1.3.0(typescript@5.5.4) optionalDependencies: - typescript: 5.4.5 + typescript: 5.5.4 transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@7.13.1(typescript@5.4.5)': + '@typescript-eslint/utils@8.0.0(eslint@9.8.0)(typescript@5.5.4)': dependencies: - '@typescript-eslint/types': 7.13.1 - '@typescript-eslint/visitor-keys': 7.13.1 - debug: 4.3.5 - globby: 11.1.0 - is-glob: 4.0.3 - minimatch: 9.0.4 - semver: 7.6.2 - ts-api-utils: 1.3.0(typescript@5.4.5) - optionalDependencies: - typescript: 5.4.5 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/utils@7.13.0(eslint@9.5.0)(typescript@5.4.5)': - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.5.0) - '@typescript-eslint/scope-manager': 7.13.0 - '@typescript-eslint/types': 7.13.0 - '@typescript-eslint/typescript-estree': 7.13.0(typescript@5.4.5) - eslint: 9.5.0 + '@eslint-community/eslint-utils': 4.4.0(eslint@9.8.0) + '@typescript-eslint/scope-manager': 8.0.0 + '@typescript-eslint/types': 8.0.0 + '@typescript-eslint/typescript-estree': 8.0.0(typescript@5.5.4) + eslint: 9.8.0 transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/utils@7.13.1(eslint@9.5.0)(typescript@5.4.5)': + '@typescript-eslint/visitor-keys@8.0.0': dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.5.0) - '@typescript-eslint/scope-manager': 7.13.1 - '@typescript-eslint/types': 7.13.1 - '@typescript-eslint/typescript-estree': 7.13.1(typescript@5.4.5) - eslint: 9.5.0 - transitivePeerDependencies: - - supports-color - - typescript - - '@typescript-eslint/visitor-keys@7.13.0': - dependencies: - '@typescript-eslint/types': 7.13.0 + '@typescript-eslint/types': 8.0.0 eslint-visitor-keys: 3.4.3 - '@typescript-eslint/visitor-keys@7.13.1': + acorn-jsx@5.3.2(acorn@8.12.1): dependencies: - '@typescript-eslint/types': 7.13.1 - eslint-visitor-keys: 3.4.3 + acorn: 8.12.1 - acorn-jsx@5.3.2(acorn@8.11.3): - dependencies: - acorn: 8.11.3 - - acorn@8.11.3: {} + acorn@8.12.1: {} ajv@6.12.6: dependencies: @@ -2394,6 +2266,8 @@ snapshots: array-union@2.1.0: {} + async@3.2.5: {} + babel-jest@29.7.0(@babel/core@7.23.9): dependencies: '@babel/core': 7.23.9 @@ -2533,13 +2407,13 @@ snapshots: convert-source-map@2.0.0: {} - create-jest@29.7.0(@types/node@20.14.5): + create-jest@29.7.0(@types/node@22.0.2): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@20.14.5) + jest-config: 29.7.0(@types/node@22.0.2) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -2558,7 +2432,7 @@ snapshots: dependencies: ms: 2.1.2 - debug@4.3.5: + debug@4.3.6: dependencies: ms: 2.1.2 @@ -2576,7 +2450,9 @@ snapshots: dependencies: path-type: 4.0.0 - download-file-sync@1.0.4: {} + ejs@3.1.10: + dependencies: + jake: 10.9.2 electron-to-chromium@1.4.648: {} @@ -2596,14 +2472,14 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-plugin-prettier@5.1.3(eslint@9.5.0)(prettier@3.3.2): + eslint-plugin-prettier@5.2.1(eslint@9.8.0)(prettier@3.3.3): dependencies: - eslint: 9.5.0 - prettier: 3.3.2 + eslint: 9.8.0 + prettier: 3.3.3 prettier-linter-helpers: 1.0.0 - synckit: 0.8.8 + synckit: 0.9.1 - eslint-scope@8.0.1: + eslint-scope@8.0.2: dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 @@ -2612,13 +2488,13 @@ snapshots: eslint-visitor-keys@4.0.0: {} - eslint@9.5.0: + eslint@9.8.0: dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@9.5.0) - '@eslint-community/regexpp': 4.10.0 - '@eslint/config-array': 0.16.0 + '@eslint-community/eslint-utils': 4.4.0(eslint@9.8.0) + '@eslint-community/regexpp': 4.11.0 + '@eslint/config-array': 0.17.1 '@eslint/eslintrc': 3.1.0 - '@eslint/js': 9.5.0 + '@eslint/js': 9.8.0 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.3.0 '@nodelib/fs.walk': 1.2.8 @@ -2627,9 +2503,9 @@ snapshots: cross-spawn: 7.0.3 debug: 4.3.4 escape-string-regexp: 4.0.0 - eslint-scope: 8.0.1 + eslint-scope: 8.0.2 eslint-visitor-keys: 4.0.0 - espree: 10.0.1 + espree: 10.1.0 esquery: 1.5.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 @@ -2651,10 +2527,10 @@ snapshots: transitivePeerDependencies: - supports-color - espree@10.0.1: + espree@10.1.0: dependencies: - acorn: 8.11.3 - acorn-jsx: 5.3.2(acorn@8.11.3) + acorn: 8.12.1 + acorn-jsx: 5.3.2(acorn@8.12.1) eslint-visitor-keys: 4.0.0 esprima@4.0.1: {} @@ -2721,6 +2597,10 @@ snapshots: dependencies: flat-cache: 4.0.1 + filelist@1.0.4: + dependencies: + minimatch: 5.1.6 + fill-range@7.0.1: dependencies: to-regex-range: 5.0.1 @@ -2870,7 +2750,7 @@ snapshots: '@babel/parser': 7.23.9 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 - semver: 7.6.2 + semver: 7.6.3 transitivePeerDependencies: - supports-color @@ -2882,7 +2762,7 @@ snapshots: istanbul-lib-source-maps@4.0.1: dependencies: - debug: 4.3.5 + debug: 4.3.6 istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: @@ -2893,6 +2773,13 @@ snapshots: html-escaper: 2.0.2 istanbul-lib-report: 3.0.1 + jake@10.9.2: + dependencies: + async: 3.2.5 + chalk: 4.1.2 + filelist: 1.0.4 + minimatch: 3.1.2 + jest-changed-files@29.7.0: dependencies: execa: 5.1.1 @@ -2905,7 +2792,7 @@ snapshots: '@jest/expect': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.14.5 + '@types/node': 22.0.2 chalk: 4.1.2 co: 4.6.0 dedent: 1.5.1 @@ -2925,16 +2812,16 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@20.14.5): + jest-cli@29.7.0(@types/node@22.0.2): dependencies: '@jest/core': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.14.5) + create-jest: 29.7.0(@types/node@22.0.2) exit: 0.1.2 import-local: 3.1.0 - jest-config: 29.7.0(@types/node@20.14.5) + jest-config: 29.7.0(@types/node@22.0.2) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -2944,7 +2831,7 @@ snapshots: - supports-color - ts-node - jest-config@29.7.0(@types/node@20.14.5): + jest-config@29.7.0(@types/node@22.0.2): dependencies: '@babel/core': 7.23.9 '@jest/test-sequencer': 29.7.0 @@ -2969,7 +2856,7 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 20.14.5 + '@types/node': 22.0.2 transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -2998,7 +2885,7 @@ snapshots: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.14.5 + '@types/node': 22.0.2 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -3008,7 +2895,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.9 - '@types/node': 20.14.5 + '@types/node': 22.0.2 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -3047,7 +2934,7 @@ snapshots: jest-mock@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 20.14.5 + '@types/node': 22.0.2 jest-util: 29.7.0 jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): @@ -3082,7 +2969,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.14.5 + '@types/node': 22.0.2 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -3110,7 +2997,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.14.5 + '@types/node': 22.0.2 chalk: 4.1.2 cjs-module-lexer: 1.2.3 collect-v8-coverage: 1.0.2 @@ -3156,7 +3043,7 @@ snapshots: jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 20.14.5 + '@types/node': 22.0.2 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -3175,7 +3062,7 @@ snapshots: dependencies: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.14.5 + '@types/node': 22.0.2 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -3184,17 +3071,17 @@ snapshots: jest-worker@29.7.0: dependencies: - '@types/node': 20.14.5 + '@types/node': 22.0.2 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@20.14.5): + jest@29.7.0(@types/node@22.0.2): dependencies: '@jest/core': 29.7.0 '@jest/types': 29.6.3 import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@20.14.5) + jest-cli: 29.7.0(@types/node@22.0.2) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -3259,7 +3146,7 @@ snapshots: make-dir@4.0.0: dependencies: - semver: 7.6.2 + semver: 7.6.3 make-error@1.3.6: {} @@ -3287,7 +3174,11 @@ snapshots: dependencies: brace-expansion: 1.1.11 - minimatch@9.0.4: + minimatch@5.1.6: + dependencies: + brace-expansion: 2.0.1 + + minimatch@9.0.5: dependencies: brace-expansion: 2.0.1 @@ -3377,7 +3268,7 @@ snapshots: dependencies: fast-diff: 1.3.0 - prettier@3.3.2: {} + prettier@3.3.3: {} pretty-format@29.7.0: dependencies: @@ -3426,6 +3317,8 @@ snapshots: semver@7.6.2: {} + semver@7.6.3: {} + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -3486,10 +3379,10 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - synckit@0.8.8: + synckit@0.9.1: dependencies: '@pkgr/core': 0.1.1 - tslib: 2.6.2 + tslib: 2.6.3 test-exclude@6.0.0: dependencies: @@ -3507,21 +3400,22 @@ snapshots: dependencies: is-number: 7.0.0 - ts-api-utils@1.3.0(typescript@5.4.5): + ts-api-utils@1.3.0(typescript@5.5.4): dependencies: - typescript: 5.4.5 + typescript: 5.5.4 - ts-jest@29.1.5(@babel/core@7.23.9)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(jest@29.7.0(@types/node@20.14.5))(typescript@5.4.5): + ts-jest@29.2.4(@babel/core@7.23.9)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.23.9))(jest@29.7.0(@types/node@22.0.2))(typescript@5.5.4): dependencies: bs-logger: 0.2.6 + ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@20.14.5) + jest: 29.7.0(@types/node@22.0.2) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 - semver: 7.6.2 - typescript: 5.4.5 + semver: 7.6.3 + typescript: 5.5.4 yargs-parser: 21.1.1 optionalDependencies: '@babel/core': 7.23.9 @@ -3529,7 +3423,7 @@ snapshots: '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.23.9) - tslib@2.6.2: {} + tslib@2.6.3: {} type-check@0.4.0: dependencies: @@ -3539,20 +3433,20 @@ snapshots: type-fest@0.21.3: {} - typescript-eslint@7.13.0(eslint@9.5.0)(typescript@5.4.5): + typescript-eslint@8.0.0(eslint@9.8.0)(typescript@5.5.4): dependencies: - '@typescript-eslint/eslint-plugin': 7.13.0(@typescript-eslint/parser@7.13.0(eslint@9.5.0)(typescript@5.4.5))(eslint@9.5.0)(typescript@5.4.5) - '@typescript-eslint/parser': 7.13.0(eslint@9.5.0)(typescript@5.4.5) - '@typescript-eslint/utils': 7.13.0(eslint@9.5.0)(typescript@5.4.5) - eslint: 9.5.0 + '@typescript-eslint/eslint-plugin': 8.0.0(@typescript-eslint/parser@8.0.0(eslint@9.8.0)(typescript@5.5.4))(eslint@9.8.0)(typescript@5.5.4) + '@typescript-eslint/parser': 8.0.0(eslint@9.8.0)(typescript@5.5.4) + '@typescript-eslint/utils': 8.0.0(eslint@9.8.0)(typescript@5.5.4) optionalDependencies: - typescript: 5.4.5 + typescript: 5.5.4 transitivePeerDependencies: + - eslint - supports-color - typescript@5.4.5: {} + typescript@5.5.4: {} - undici-types@5.26.5: {} + undici-types@6.11.1: {} update-browserslist-db@1.0.13(browserslist@4.22.3): dependencies: diff --git a/api_tests/src/community.spec.ts b/api_tests/src/community.spec.ts index d172f7045..d8aa6cad6 100644 --- a/api_tests/src/community.spec.ts +++ b/api_tests/src/community.spec.ts @@ -1,5 +1,6 @@ jest.setTimeout(120000); +import { AddModToCommunity } from "lemmy-js-client/dist/types/AddModToCommunity"; import { CommunityView } from "lemmy-js-client/dist/types/CommunityView"; import { alpha, @@ -9,6 +10,7 @@ import { resolveCommunity, createCommunity, deleteCommunity, + delay, removeCommunity, getCommunity, followCommunity, @@ -533,3 +535,41 @@ test("Content in local-only community doesn't federate", async () => { Error("couldnt_find_object"), ); }); + +test("Remote mods can edit communities", async () => { + let communityRes = await createCommunity(alpha); + + let betaCommunity = await resolveCommunity( + beta, + communityRes.community_view.community.actor_id, + ); + if (!betaCommunity.community) { + throw "Missing beta community"; + } + let betaOnAlpha = await resolvePerson(alpha, "lemmy_beta@lemmy-beta:8551"); + + let form: AddModToCommunity = { + community_id: communityRes.community_view.community.id, + person_id: betaOnAlpha.person?.person.id as number, + added: true, + }; + alpha.addModToCommunity(form); + + let form2: EditCommunity = { + community_id: betaCommunity.community?.community.id as number, + description: "Example description", + }; + + await editCommunity(beta, form2); + // give alpha time to get and process the edit + await delay(1000); + + let alphaCommunity = await getCommunity( + alpha, + communityRes.community_view.community.id, + ); + + await expect(alphaCommunity.community_view.community.description).toBe( + "Example description", + ); +}); diff --git a/api_tests/src/image.spec.ts b/api_tests/src/image.spec.ts index fe9470d18..ed96451a2 100644 --- a/api_tests/src/image.spec.ts +++ b/api_tests/src/image.spec.ts @@ -33,7 +33,6 @@ import { sampleImage, sampleSite, } from "./shared"; -const downloadFileSync = require("download-file-sync"); beforeAll(setupLogins); @@ -57,7 +56,8 @@ test("Upload image and delete it", async () => { expect(upload.delete_url).toBeDefined(); // ensure that image download is working. theres probably a better way to do this - const content = downloadFileSync(upload.url); + const response = await fetch(upload.url ?? ""); + const content = await response.text(); expect(content.length).toBeGreaterThan(0); // Ensure that it comes back with the list_media endpoint @@ -92,7 +92,8 @@ test("Upload image and delete it", async () => { expect(delete_).toBe(true); // ensure that image is deleted - const content2 = downloadFileSync(upload.url); + const response2 = await fetch(upload.url ?? ""); + const content2 = await response2.text(); expect(content2).toBe(""); // Ensure that it shows the image is deleted @@ -120,7 +121,8 @@ test("Purge user, uploaded image removed", async () => { expect(upload.delete_url).toBeDefined(); // ensure that image download is working. theres probably a better way to do this - const content = downloadFileSync(upload.url); + const response = await fetch(upload.url ?? ""); + const content = await response.text(); expect(content.length).toBeGreaterThan(0); // purge user @@ -132,7 +134,8 @@ test("Purge user, uploaded image removed", async () => { expect(delete_.success).toBe(true); // ensure that image is deleted - const content2 = downloadFileSync(upload.url); + const response2 = await fetch(upload.url ?? ""); + const content2 = await response2.text(); expect(content2).toBe(""); }); @@ -150,7 +153,8 @@ test("Purge post, linked image removed", async () => { expect(upload.delete_url).toBeDefined(); // ensure that image download is working. theres probably a better way to do this - const content = downloadFileSync(upload.url); + const response = await fetch(upload.url ?? ""); + const content = await response.text(); expect(content.length).toBeGreaterThan(0); let community = await resolveBetaCommunity(user); @@ -170,7 +174,8 @@ test("Purge post, linked image removed", async () => { expect(delete_.success).toBe(true); // ensure that image is deleted - const content2 = downloadFileSync(upload.url); + const response2 = await fetch(upload.url ?? ""); + const content2 = await response2.text(); expect(content2).toBe(""); }); diff --git a/api_tests/src/shared.ts b/api_tests/src/shared.ts index 2ae3d9e21..3ca37dac4 100644 --- a/api_tests/src/shared.ts +++ b/api_tests/src/shared.ts @@ -197,7 +197,7 @@ export async function setupLogins() { // (because last_successful_id is set to current id when federation to an instance is first started) // only needed the first time so do in this try await delay(10_000); - } catch (_) { + } catch { console.log("Communities already exist"); } } @@ -899,7 +899,6 @@ export async function deleteAllImages(api: LemmyHttp) { const imagesRes = await api.listAllMedia({ limit: imageFetchLimit, }); - imagesRes.images; Promise.all( imagesRes.images .map(image => { diff --git a/crates/api/Cargo.toml b/crates/api/Cargo.toml index b98b15d62..87879f6cd 100644 --- a/crates/api/Cargo.toml +++ b/crates/api/Cargo.toml @@ -35,11 +35,12 @@ chrono = { workspace = true } url = { workspace = true } hound = "3.5.1" sitemap-rs = "0.2.1" -totp-rs = { version = "5.5.1", features = ["gen_secret", "otpauth"] } -actix-web-httpauth = "0.8.1" +totp-rs = { version = "5.6.0", features = ["gen_secret", "otpauth"] } +actix-web-httpauth = "0.8.2" [dev-dependencies] serial_test = { workspace = true } tokio = { workspace = true } elementtree = "1.2.3" pretty_assertions = { workspace = true } +lemmy_api_crud = { workspace = true } diff --git a/crates/api/src/local_user/verify_email.rs b/crates/api/src/local_user/verify_email.rs index 5f38ffc12..5b895ec7e 100644 --- a/crates/api/src/local_user/verify_email.rs +++ b/crates/api/src/local_user/verify_email.rs @@ -5,12 +5,9 @@ use lemmy_api_common::{ utils::send_new_applicant_email_to_admins, SuccessResponse, }; -use lemmy_db_schema::{ - source::{ - email_verification::EmailVerification, - local_user::{LocalUser, LocalUserUpdateForm}, - }, - RegistrationMode, +use lemmy_db_schema::source::{ + email_verification::EmailVerification, + local_user::{LocalUser, LocalUserUpdateForm}, }; use lemmy_db_views::structs::{LocalUserView, SiteView}; use lemmy_utils::error::{LemmyErrorType, LemmyResult}; @@ -41,9 +38,7 @@ pub async fn verify_email( EmailVerification::delete_old_tokens_for_local_user(&mut context.pool(), local_user_id).await?; // send out notification about registration application to admins if enabled - if site_view.local_site.registration_mode == RegistrationMode::RequireApplication - && site_view.local_site.application_email_admins - { + if site_view.local_site.application_email_admins { let local_user = LocalUserView::read(&mut context.pool(), local_user_id) .await? .ok_or(LemmyErrorType::CouldntFindPerson)?; diff --git a/crates/api/src/post/get_link_metadata.rs b/crates/api/src/post/get_link_metadata.rs index 0669408aa..e469b51c7 100644 --- a/crates/api/src/post/get_link_metadata.rs +++ b/crates/api/src/post/get_link_metadata.rs @@ -4,6 +4,7 @@ use lemmy_api_common::{ post::{GetSiteMetadata, GetSiteMetadataResponse}, request::fetch_link_metadata, }; +use lemmy_db_views::structs::LocalUserView; use lemmy_utils::{ error::{LemmyErrorExt, LemmyResult}, LemmyErrorType, @@ -14,6 +15,8 @@ use url::Url; pub async fn get_link_metadata( data: Query, context: Data, + // Require an account for this API + _local_user_view: LocalUserView, ) -> LemmyResult> { let url = Url::parse(&data.url).with_lemmy_type(LemmyErrorType::InvalidUrl)?; let metadata = fetch_link_metadata(&url, &context).await?; diff --git a/crates/api/src/site/registration_applications/approve.rs b/crates/api/src/site/registration_applications/approve.rs index 823af54c4..dcde78117 100644 --- a/crates/api/src/site/registration_applications/approve.rs +++ b/crates/api/src/site/registration_applications/approve.rs @@ -1,4 +1,5 @@ -use actix_web::web::{Data, Json}; +use activitypub_federation::config::Data; +use actix_web::web::Json; use lemmy_api_common::{ context::LemmyContext, site::{ApproveRegistrationApplication, RegistrationApplicationResponse}, @@ -10,10 +11,13 @@ use lemmy_db_schema::{ registration_application::{RegistrationApplication, RegistrationApplicationUpdateForm}, }, traits::Crud, - utils::diesel_string_update, + utils::{diesel_string_update, get_conn}, }; use lemmy_db_views::structs::{LocalUserView, RegistrationApplicationView}; -use lemmy_utils::{error::LemmyResult, LemmyErrorType}; +use lemmy_utils::{ + error::{LemmyError, LemmyResult}, + LemmyErrorType, +}; pub async fn approve_registration_application( data: Json, @@ -25,34 +29,46 @@ pub async fn approve_registration_application( // Only let admins do this is_admin(&local_user_view)?; - // Update the registration with reason, admin_id - let deny_reason = diesel_string_update(data.deny_reason.as_deref()); - let app_form = RegistrationApplicationUpdateForm { - admin_id: Some(Some(local_user_view.person.id)), - deny_reason, - }; + let pool = &mut context.pool(); + let conn = &mut get_conn(pool).await?; + let tx_data = data.clone(); + let approved_user_id = conn + .build_transaction() + .run(|conn| { + Box::pin(async move { + // Update the registration with reason, admin_id + let deny_reason = diesel_string_update(tx_data.deny_reason.as_deref()); + let app_form = RegistrationApplicationUpdateForm { + admin_id: Some(Some(local_user_view.person.id)), + deny_reason, + }; - let registration_application = - RegistrationApplication::update(&mut context.pool(), app_id, &app_form).await?; + let registration_application = + RegistrationApplication::update(&mut conn.into(), app_id, &app_form).await?; - // Update the local_user row - let local_user_form = LocalUserUpdateForm { - accepted_application: Some(data.approve), - ..Default::default() - }; + // Update the local_user row + let local_user_form = LocalUserUpdateForm { + accepted_application: Some(tx_data.approve), + ..Default::default() + }; - let approved_user_id = registration_application.local_user_id; - LocalUser::update(&mut context.pool(), approved_user_id, &local_user_form).await?; + let approved_user_id = registration_application.local_user_id; + LocalUser::update(&mut conn.into(), approved_user_id, &local_user_form).await?; + + Ok::<_, LemmyError>(approved_user_id) + }) as _ + }) + .await?; if data.approve { 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() { + // Email sending may fail, but this won't revert the application approval send_application_approved_email(&approved_local_user_view, context.settings()).await?; } - } + }; // Read the view let registration_application = RegistrationApplicationView::read(&mut context.pool(), app_id) diff --git a/crates/api/src/site/registration_applications/list.rs b/crates/api/src/site/registration_applications/list.rs index df86b11d5..877e83796 100644 --- a/crates/api/src/site/registration_applications/list.rs +++ b/crates/api/src/site/registration_applications/list.rs @@ -1,4 +1,5 @@ -use actix_web::web::{Data, Json, Query}; +use activitypub_federation::config::Data; +use actix_web::web::{Json, Query}; use lemmy_api_common::{ context::LemmyContext, site::{ListRegistrationApplications, ListRegistrationApplicationsResponse}, diff --git a/crates/api/src/site/registration_applications/mod.rs b/crates/api/src/site/registration_applications/mod.rs index e904f597d..c9a63cdef 100644 --- a/crates/api/src/site/registration_applications/mod.rs +++ b/crates/api/src/site/registration_applications/mod.rs @@ -1,4 +1,6 @@ pub mod approve; pub mod get; pub mod list; +#[cfg(test)] +mod tests; pub mod unread_count; diff --git a/crates/api/src/site/registration_applications/tests.rs b/crates/api/src/site/registration_applications/tests.rs new file mode 100644 index 000000000..062fa550f --- /dev/null +++ b/crates/api/src/site/registration_applications/tests.rs @@ -0,0 +1,428 @@ +use crate::site::registration_applications::{ + approve::approve_registration_application, + list::list_registration_applications, + unread_count::get_unread_registration_application_count, +}; +use activitypub_federation::config::Data; +use actix_web::web::{Json, Query}; +use lemmy_api_common::{ + context::LemmyContext, + site::{ + ApproveRegistrationApplication, + EditSite, + GetUnreadRegistrationApplicationCountResponse, + ListRegistrationApplicationsResponse, + }, +}; +use lemmy_api_crud::site::update::update_site; +use lemmy_db_schema::{ + newtypes::InstanceId, + source::{ + instance::Instance, + local_site::{LocalSite, LocalSiteInsertForm}, + local_site_rate_limit::{LocalSiteRateLimit, LocalSiteRateLimitInsertForm}, + local_user::{LocalUser, LocalUserInsertForm, LocalUserUpdateForm}, + person::{Person, PersonInsertForm}, + registration_application::{RegistrationApplication, RegistrationApplicationInsertForm}, + site::{Site, SiteInsertForm}, + }, + traits::Crud, + utils::DbPool, + RegistrationMode, +}; +use lemmy_db_views::structs::LocalUserView; +use lemmy_utils::{error::LemmyResult, LemmyErrorType, CACHE_DURATION_API}; +use serial_test::serial; + +#[allow(clippy::unwrap_used)] +async fn create_test_site(context: &Data) -> LemmyResult<(Instance, LocalUserView)> { + let pool = &mut context.pool(); + + let inserted_instance = Instance::read_or_create(pool, "my_domain.tld".to_string()) + .await + .expect("Create test instance"); + + let admin_person = Person::create( + pool, + &PersonInsertForm::test_form(inserted_instance.id, "admin"), + ) + .await?; + LocalUser::create( + pool, + &LocalUserInsertForm::test_form_admin(admin_person.id), + vec![], + ) + .await?; + + let admin_local_user_view = LocalUserView::read_person(pool, admin_person.id) + .await? + .unwrap(); + + let site_form = SiteInsertForm::builder() + .name("test site".to_string()) + .instance_id(inserted_instance.id) + .build(); + let site = Site::create(pool, &site_form).await.unwrap(); + + // Create a local site, since this is necessary for determining if email verification is + // required + let local_site_form = LocalSiteInsertForm::builder() + .site_id(site.id) + .require_email_verification(Some(true)) + .application_question(Some(".".to_string())) + .registration_mode(Some(RegistrationMode::RequireApplication)) + .site_setup(Some(true)) + .build(); + let local_site = LocalSite::create(pool, &local_site_form).await.unwrap(); + + // Required to have a working local SiteView when updating the site to change email verification + // requirement or registration mode + let rate_limit_form = LocalSiteRateLimitInsertForm::builder() + .local_site_id(local_site.id) + .build(); + LocalSiteRateLimit::create(pool, &rate_limit_form) + .await + .unwrap(); + + Ok((inserted_instance, admin_local_user_view)) +} + +async fn signup( + pool: &mut DbPool<'_>, + instance_id: InstanceId, + name: &str, + email: Option<&str>, +) -> LemmyResult<(LocalUser, RegistrationApplication)> { + let person_insert_form = PersonInsertForm::test_form(instance_id, name); + let person = Person::create(pool, &person_insert_form).await?; + + let local_user_insert_form = match email { + Some(email) => LocalUserInsertForm { + email: Some(email.to_string()), + email_verified: Some(false), + ..LocalUserInsertForm::test_form(person.id) + }, + None => LocalUserInsertForm::test_form(person.id), + }; + + let local_user = LocalUser::create(pool, &local_user_insert_form, vec![]).await?; + + let application_insert_form = RegistrationApplicationInsertForm { + local_user_id: local_user.id, + answer: "x".to_string(), + }; + let application = RegistrationApplication::create(pool, &application_insert_form).await?; + + Ok((local_user, application)) +} + +#[allow(clippy::unwrap_used)] +async fn get_application_statuses( + context: &Data, + admin: LocalUserView, +) -> LemmyResult<( + Json, + Json, + Json, +)> { + let application_count = + get_unread_registration_application_count(context.reset_request_count(), admin.clone()).await?; + + let unread_applications = list_registration_applications( + Query::from_query("unread_only=true").unwrap(), + context.reset_request_count(), + admin.clone(), + ) + .await?; + + let all_applications = list_registration_applications( + Query::from_query("unread_only=false").unwrap(), + context.reset_request_count(), + admin, + ) + .await?; + + Ok((application_count, unread_applications, all_applications)) +} + +#[allow(clippy::indexing_slicing)] +#[allow(clippy::unwrap_used)] +#[tokio::test] +#[serial] +async fn test_application_approval() -> LemmyResult<()> { + let context = LemmyContext::init_test_context().await; + let pool = &mut context.pool(); + + let (instance, admin_local_user_view) = create_test_site(&context).await?; + + // Non-unread counts unfortunately are duplicated due to different types (i64 vs usize) + let mut expected_total_applications = 0; + let mut expected_unread_applications = 0u8; + + let (local_user_with_email, app_with_email) = + signup(pool, instance.id, "user_w_email", Some("lemmy@localhost")).await?; + + let (application_count, unread_applications, all_applications) = + get_application_statuses(&context, admin_local_user_view.clone()).await?; + + // When email verification is required and the email is not verified the application should not + // be visible to admins + assert_eq!( + application_count.registration_applications, + i64::from(expected_unread_applications), + ); + assert_eq!( + unread_applications.registration_applications.len(), + usize::from(expected_unread_applications), + ); + assert_eq!( + all_applications.registration_applications.len(), + expected_total_applications, + ); + + LocalUser::update( + pool, + local_user_with_email.id, + &LocalUserUpdateForm { + email_verified: Some(true), + ..Default::default() + }, + ) + .await?; + + expected_total_applications += 1; + expected_unread_applications += 1; + + let (application_count, unread_applications, all_applications) = + get_application_statuses(&context, admin_local_user_view.clone()).await?; + + // When email verification is required and the email is verified the application should be + // visible to admins + assert_eq!( + application_count.registration_applications, + i64::from(expected_unread_applications), + ); + assert_eq!( + unread_applications.registration_applications.len(), + usize::from(expected_unread_applications), + ); + assert!( + !unread_applications.registration_applications[0] + .creator_local_user + .accepted_application + ); + assert_eq!( + all_applications.registration_applications.len(), + expected_total_applications, + ); + + let approval = approve_registration_application( + Json(ApproveRegistrationApplication { + id: app_with_email.id, + approve: true, + deny_reason: None, + }), + context.reset_request_count(), + admin_local_user_view.clone(), + ) + .await; + // Approval should be processed up until email sending is attempted + assert!(approval.is_err_and(|e| e.error_type == LemmyErrorType::NoEmailSetup)); + + expected_unread_applications -= 1; + + let (application_count, unread_applications, all_applications) = + get_application_statuses(&context, admin_local_user_view.clone()).await?; + + // When the application is approved it should only be returned for unread queries + assert_eq!( + application_count.registration_applications, + i64::from(expected_unread_applications), + ); + assert_eq!( + unread_applications.registration_applications.len(), + usize::from(expected_unread_applications), + ); + assert_eq!( + all_applications.registration_applications.len(), + expected_total_applications, + ); + assert!( + all_applications.registration_applications[0] + .creator_local_user + .accepted_application + ); + + let (_local_user, app_with_email_2) = signup( + pool, + instance.id, + "user_w_email_2", + Some("lemmy2@localhost"), + ) + .await?; + let (application_count, unread_applications, all_applications) = + get_application_statuses(&context, admin_local_user_view.clone()).await?; + + // Email not verified, so application still not visible + assert_eq!( + application_count.registration_applications, + i64::from(expected_unread_applications), + ); + assert_eq!( + unread_applications.registration_applications.len(), + usize::from(expected_unread_applications), + ); + assert_eq!( + all_applications.registration_applications.len(), + expected_total_applications, + ); + + update_site( + Json(EditSite { + require_email_verification: Some(false), + ..Default::default() + }), + context.reset_request_count(), + admin_local_user_view.clone(), + ) + .await?; + + // TODO: There is probably a better way to ensure cache invalidation + tokio::time::sleep(CACHE_DURATION_API).await; + + expected_total_applications += 1; + expected_unread_applications += 1; + + let (application_count, unread_applications, all_applications) = + get_application_statuses(&context, admin_local_user_view.clone()).await?; + + // After disabling email verification the application should now be visible + assert_eq!( + application_count.registration_applications, + i64::from(expected_unread_applications), + ); + assert_eq!( + unread_applications.registration_applications.len(), + usize::from(expected_unread_applications), + ); + assert_eq!( + all_applications.registration_applications.len(), + expected_total_applications, + ); + + approve_registration_application( + Json(ApproveRegistrationApplication { + id: app_with_email_2.id, + approve: false, + deny_reason: None, + }), + context.reset_request_count(), + admin_local_user_view.clone(), + ) + .await?; + + expected_unread_applications -= 1; + + let (application_count, unread_applications, all_applications) = + get_application_statuses(&context, admin_local_user_view.clone()).await?; + + // Denied applications should not be marked as unread + assert_eq!( + application_count.registration_applications, + i64::from(expected_unread_applications), + ); + assert_eq!( + unread_applications.registration_applications.len(), + usize::from(expected_unread_applications), + ); + assert_eq!( + all_applications.registration_applications.len(), + expected_total_applications, + ); + + signup(pool, instance.id, "user_wo_email", None).await?; + + expected_total_applications += 1; + expected_unread_applications += 1; + + let (application_count, unread_applications, all_applications) = + get_application_statuses(&context, admin_local_user_view.clone()).await?; + + // New user without email should immediately be visible + assert_eq!( + application_count.registration_applications, + i64::from(expected_unread_applications), + ); + assert_eq!( + unread_applications.registration_applications.len(), + usize::from(expected_unread_applications), + ); + assert_eq!( + all_applications.registration_applications.len(), + expected_total_applications, + ); + + signup(pool, instance.id, "user_w_email_3", None).await?; + + expected_total_applications += 1; + expected_unread_applications += 1; + + let (application_count, unread_applications, all_applications) = + get_application_statuses(&context, admin_local_user_view.clone()).await?; + + // New user with email should immediately be visible + assert_eq!( + application_count.registration_applications, + i64::from(expected_unread_applications), + ); + assert_eq!( + unread_applications.registration_applications.len(), + usize::from(expected_unread_applications), + ); + assert_eq!( + all_applications.registration_applications.len(), + expected_total_applications, + ); + + update_site( + Json(EditSite { + registration_mode: Some(RegistrationMode::Open), + ..Default::default() + }), + context.reset_request_count(), + admin_local_user_view.clone(), + ) + .await?; + + // TODO: There is probably a better way to ensure cache invalidation + tokio::time::sleep(CACHE_DURATION_API).await; + + let (application_count, unread_applications, all_applications) = + get_application_statuses(&context, admin_local_user_view.clone()).await?; + + // TODO: At this time applications do not get approved when switching to open registration, so the + // numbers will not change. See https://github.com/LemmyNet/lemmy/issues/4969 + // expected_application_count = 0; + // expected_unread_applications_len = 0; + + // When applications are not required all previous applications should become approved but still + // visible + assert_eq!( + application_count.registration_applications, + i64::from(expected_unread_applications), + ); + assert_eq!( + unread_applications.registration_applications.len(), + usize::from(expected_unread_applications), + ); + assert_eq!( + all_applications.registration_applications.len(), + expected_total_applications, + ); + + LocalSite::delete(pool).await?; + // Instance deletion cascades cleanup of all created persons + Instance::delete(pool, instance.id).await?; + + Ok(()) +} diff --git a/crates/api/src/site/registration_applications/unread_count.rs b/crates/api/src/site/registration_applications/unread_count.rs index a12ecb1d3..5cc391ed0 100644 --- a/crates/api/src/site/registration_applications/unread_count.rs +++ b/crates/api/src/site/registration_applications/unread_count.rs @@ -1,4 +1,5 @@ -use actix_web::web::{Data, Json}; +use activitypub_federation::config::Data; +use actix_web::web::Json; use lemmy_api_common::{ context::LemmyContext, site::GetUnreadRegistrationApplicationCountResponse, diff --git a/crates/api_common/Cargo.toml b/crates/api_common/Cargo.toml index 25bc02893..4eabfe5f9 100644 --- a/crates/api_common/Cargo.toml +++ b/crates/api_common/Cargo.toml @@ -34,7 +34,6 @@ full = [ "reqwest", "actix-web", "futures", - "once_cell", "jsonwebtoken", "mime", ] @@ -61,7 +60,6 @@ reqwest = { workspace = true, optional = true } ts-rs = { workspace = true, optional = true } moka.workspace = true anyhow.workspace = true -once_cell = { workspace = true, optional = true } actix-web = { workspace = true, optional = true } enum-map = { workspace = true } urlencoding = { workspace = true } diff --git a/crates/api_common/src/build_response.rs b/crates/api_common/src/build_response.rs index 200284b00..8f140f2fe 100644 --- a/crates/api_common/src/build_response.rs +++ b/crates/api_common/src/build_response.rs @@ -100,15 +100,20 @@ pub async fn send_local_notifs( person: &Person, do_send_email: bool, context: &LemmyContext, + local_user_view: Option<&LocalUserView>, ) -> LemmyResult> { let mut recipient_ids = Vec::new(); let inbox_link = format!("{}/inbox", context.settings().get_protocol_and_hostname()); // let person = my_local_user.person; // Read the comment view to get extra info - let comment_view = CommentView::read(&mut context.pool(), comment_id, None) - .await? - .ok_or(LemmyErrorType::CouldntFindComment)?; + let comment_view = CommentView::read( + &mut context.pool(), + comment_id, + local_user_view.map(|view| &view.local_user), + ) + .await? + .ok_or(LemmyErrorType::CouldntFindComment)?; let comment = comment_view.comment; let post = comment_view.post; let community = comment_view.community; diff --git a/crates/api_common/src/request.rs b/crates/api_common/src/request.rs index ddbb3dd0c..de6ba4f39 100644 --- a/crates/api_common/src/request.rs +++ b/crates/api_common/src/request.rs @@ -8,6 +8,7 @@ use crate::{ use activitypub_federation::config::Data; use chrono::{DateTime, Utc}; use encoding_rs::{Encoding, UTF_8}; +use futures::StreamExt; use lemmy_db_schema::{ newtypes::DbUrl, source::{ @@ -23,7 +24,12 @@ use lemmy_utils::{ VERSION, }; use mime::Mime; -use reqwest::{header::CONTENT_TYPE, Client, ClientBuilder}; +use reqwest::{ + header::{CONTENT_TYPE, RANGE}, + Client, + ClientBuilder, + Response, +}; use reqwest_middleware::ClientWithMiddleware; use serde::{Deserialize, Serialize}; use tracing::info; @@ -44,7 +50,17 @@ pub fn client_builder(settings: &Settings) -> ClientBuilder { #[tracing::instrument(skip_all)] 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?; + // We only fetch the first 64kB of data in order to not waste bandwidth especially for large + // binary files + let bytes_to_fetch = 64 * 1024; + let response = context + .client() + .get(url.as_str()) + // we only need the first chunk of data. Note that we do not check for Accept-Range so the + // server may ignore this and still respond with the full response + .header(RANGE, format!("bytes=0-{}", bytes_to_fetch - 1)) /* -1 because inclusive */ + .send() + .await?; let content_type: Option = response .headers() @@ -52,19 +68,57 @@ pub async fn fetch_link_metadata(url: &Url, context: &LemmyContext) -> LemmyResu .and_then(|h| h.to_str().ok()) .and_then(|h| h.parse().ok()); - // Can't use .text() here, because it only checks the content header, not the actual bytes - // https://github.com/LemmyNet/lemmy/issues/1964 - let html_bytes = response.bytes().await.map_err(LemmyError::from)?.to_vec(); + let opengraph_data = { + // if the content type is not text/html, we don't need to parse it + let is_html = content_type + .as_ref() + .map(|c| { + (c.type_() == mime::TEXT && c.subtype() == mime::HTML) + || + // application/xhtml+xml is a subset of HTML + (c.type_() == mime::APPLICATION && c.subtype() == "xhtml") + }) + .unwrap_or(false); + if !is_html { + Default::default() + } else { + // Can't use .text() here, because it only checks the content header, not the actual bytes + // https://github.com/LemmyNet/lemmy/issues/1964 + // So we want to do deep inspection of the actually returned bytes but need to be careful not + // spend too much time parsing binary data as HTML - let opengraph_data = extract_opengraph_data(&html_bytes, url) - .map_err(|e| info!("{e}")) - .unwrap_or_default(); + // only take first bytes regardless of how many bytes the server returns + let html_bytes = collect_bytes_until_limit(response, bytes_to_fetch).await?; + extract_opengraph_data(&html_bytes, url) + .map_err(|e| info!("{e}")) + .unwrap_or_default() + } + }; Ok(LinkMetadata { opengraph_data, content_type: content_type.map(|c| c.to_string()), }) } +async fn collect_bytes_until_limit( + response: Response, + requested_bytes: usize, +) -> Result, LemmyError> { + let mut stream = response.bytes_stream(); + let mut bytes = Vec::with_capacity(requested_bytes); + while let Some(chunk) = stream.next().await { + let chunk = chunk.map_err(LemmyError::from)?; + // we may go over the requested size here but the important part is we don't keep aggregating + // more chunks than needed + bytes.extend_from_slice(&chunk); + if bytes.len() >= requested_bytes { + bytes.truncate(requested_bytes); + break; + } + } + Ok(bytes) +} + /// Generates and saves a post thumbnail and metadata. /// /// Takes a callback to generate a send activity task, so that post can be federated with metadata. diff --git a/crates/api_common/src/send_activity.rs b/crates/api_common/src/send_activity.rs index a8b75d4b5..02518ca33 100644 --- a/crates/api_common/src/send_activity.rs +++ b/crates/api_common/src/send_activity.rs @@ -13,7 +13,7 @@ use lemmy_db_schema::{ }; use lemmy_db_views::structs::PrivateMessageView; use lemmy_utils::error::LemmyResult; -use once_cell::sync::{Lazy, OnceCell}; +use std::sync::{LazyLock, OnceLock}; use tokio::{ sync::{ mpsc, @@ -28,7 +28,7 @@ type MatchOutgoingActivitiesBoxed = Box fn(SendActivityData, &'a Data) -> BoxFuture<'a, LemmyResult<()>>>; /// This static is necessary so that the api_common crates don't need to depend on lemmy_apub -pub static MATCH_OUTGOING_ACTIVITIES: OnceCell = OnceCell::new(); +pub static MATCH_OUTGOING_ACTIVITIES: OnceLock = OnceLock::new(); #[derive(Debug)] pub enum SendActivityData { @@ -101,7 +101,7 @@ pub enum SendActivityData { // TODO: instead of static, move this into LemmyContext. make sure that stopping the process with // ctrl+c still works. -static ACTIVITY_CHANNEL: Lazy = Lazy::new(|| { +static ACTIVITY_CHANNEL: LazyLock = LazyLock::new(|| { let (sender, receiver) = mpsc::unbounded_channel(); let weak_sender = sender.downgrade(); ActivityChannel { diff --git a/crates/api_common/src/utils.rs b/crates/api_common/src/utils.rs index 97b12cc5b..0b8e56273 100644 --- a/crates/api_common/src/utils.rs +++ b/crates/api_common/src/utils.rs @@ -53,10 +53,9 @@ use lemmy_utils::{ CACHE_DURATION_FEDERATION, }; use moka::future::Cache; -use once_cell::sync::Lazy; use regex::{escape, Regex, RegexSet}; use rosetta_i18n::{Language, LanguageId}; -use std::collections::HashSet; +use std::{collections::HashSet, sync::LazyLock}; use tracing::warn; use url::{ParseError, Url}; use urlencoding::encode; @@ -546,7 +545,7 @@ pub fn local_site_opt_to_sensitive(local_site: &Option) -> bool { } pub async fn get_url_blocklist(context: &LemmyContext) -> LemmyResult { - static URL_BLOCKLIST: Lazy> = Lazy::new(|| { + static URL_BLOCKLIST: LazyLock> = LazyLock::new(|| { Cache::builder() .max_capacity(1) .time_to_live(CACHE_DURATION_FEDERATION) diff --git a/crates/api_crud/Cargo.toml b/crates/api_crud/Cargo.toml index af50c5648..6055f9ef0 100644 --- a/crates/api_crud/Cargo.toml +++ b/crates/api_crud/Cargo.toml @@ -26,7 +26,6 @@ url = { workspace = true } futures.workspace = true uuid = { workspace = true } moka.workspace = true -once_cell.workspace = true anyhow.workspace = true webmention = "0.5.0" accept-language = "3.1.0" diff --git a/crates/api_crud/src/comment/create.rs b/crates/api_crud/src/comment/create.rs index b7c65740c..49de9d5de 100644 --- a/crates/api_crud/src/comment/create.rs +++ b/crates/api_crud/src/comment/create.rs @@ -134,6 +134,7 @@ pub async fn create_comment( &local_user_view.person, true, &context, + Some(&local_user_view), ) .await?; diff --git a/crates/api_crud/src/comment/delete.rs b/crates/api_crud/src/comment/delete.rs index 29706d365..8c81608c8 100644 --- a/crates/api_crud/src/comment/delete.rs +++ b/crates/api_crud/src/comment/delete.rs @@ -59,8 +59,15 @@ pub async fn delete_comment( .await .with_lemmy_type(LemmyErrorType::CouldntUpdateComment)?; - let recipient_ids = - send_local_notifs(vec![], comment_id, &local_user_view.person, false, &context).await?; + let recipient_ids = send_local_notifs( + vec![], + comment_id, + &local_user_view.person, + false, + &context, + Some(&local_user_view), + ) + .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 f810c8275..ec4923e93 100644 --- a/crates/api_crud/src/comment/remove.rs +++ b/crates/api_crud/src/comment/remove.rs @@ -81,8 +81,15 @@ pub async fn remove_comment( }; ModRemoveComment::create(&mut context.pool(), &form).await?; - let recipient_ids = - send_local_notifs(vec![], comment_id, &local_user_view.person, false, &context).await?; + let recipient_ids = send_local_notifs( + vec![], + comment_id, + &local_user_view.person, + false, + &context, + Some(&local_user_view), + ) + .await?; let updated_comment_id = updated_comment.id; ActivityChannel::submit_activity( diff --git a/crates/api_crud/src/comment/update.rs b/crates/api_crud/src/comment/update.rs index 32bd08240..ed9460825 100644 --- a/crates/api_crud/src/comment/update.rs +++ b/crates/api_crud/src/comment/update.rs @@ -91,6 +91,7 @@ pub async fn update_comment( &local_user_view.person, false, &context, + Some(&local_user_view), ) .await?; diff --git a/crates/api_crud/src/post/create.rs b/crates/api_crud/src/post/create.rs index 0f6abc2aa..a0f0b7525 100644 --- a/crates/api_crud/src/post/create.rs +++ b/crates/api_crud/src/post/create.rs @@ -35,11 +35,11 @@ use lemmy_utils::{ utils::{ slurs::check_slurs, validation::{ - check_url_scheme, is_url_blocked, is_valid_alt_text_field, is_valid_body_field, is_valid_post_title, + is_valid_url, }, }, }; @@ -69,11 +69,11 @@ pub async fn create_post( if let Some(url) = &url { is_url_blocked(url, &url_blocklist)?; - check_url_scheme(url)?; + is_valid_url(url)?; } if let Some(custom_thumbnail) = &custom_thumbnail { - check_url_scheme(custom_thumbnail)?; + is_valid_url(custom_thumbnail)?; } if let Some(alt_text) = &data.alt_text { diff --git a/crates/api_crud/src/post/update.rs b/crates/api_crud/src/post/update.rs index cd4b2d41b..835398596 100644 --- a/crates/api_crud/src/post/update.rs +++ b/crates/api_crud/src/post/update.rs @@ -28,11 +28,11 @@ use lemmy_utils::{ utils::{ slurs::check_slurs, validation::{ - check_url_scheme, is_url_blocked, is_valid_alt_text_field, is_valid_body_field, is_valid_post_title, + is_valid_url, }, }, }; @@ -77,11 +77,11 @@ pub async fn update_post( if let Some(Some(url)) = &url { is_url_blocked(url, &url_blocklist)?; - check_url_scheme(url)?; + is_valid_url(url)?; } if let Some(Some(custom_thumbnail)) = &custom_thumbnail { - check_url_scheme(custom_thumbnail)?; + is_valid_url(custom_thumbnail)?; } let post_id = data.post_id; diff --git a/crates/api_crud/src/site/create.rs b/crates/api_crud/src/site/create.rs index 6b1909966..9dcd1595a 100644 --- a/crates/api_crud/src/site/create.rs +++ b/crates/api_crud/src/site/create.rs @@ -1,6 +1,6 @@ use crate::site::{application_question_check, site_default_post_listing_type_check}; -use activitypub_federation::http_signatures::generate_actor_keypair; -use actix_web::web::{Data, Json}; +use activitypub_federation::{config::Data, http_signatures::generate_actor_keypair}; +use actix_web::web::Json; use lemmy_api_common::{ context::LemmyContext, site::{CreateSite, SiteResponse}, diff --git a/crates/api_crud/src/site/read.rs b/crates/api_crud/src/site/read.rs index e8065c08b..c633bebde 100644 --- a/crates/api_crud/src/site/read.rs +++ b/crates/api_crud/src/site/read.rs @@ -24,14 +24,14 @@ use lemmy_utils::{ VERSION, }; use moka::future::Cache; -use once_cell::sync::Lazy; +use std::sync::LazyLock; #[tracing::instrument(skip(context))] pub async fn get_site( local_user_view: Option, context: Data, ) -> LemmyResult> { - static CACHE: Lazy> = Lazy::new(|| { + static CACHE: LazyLock> = LazyLock::new(|| { Cache::builder() .max_capacity(1) .time_to_live(CACHE_DURATION_API) diff --git a/crates/apub/Cargo.toml b/crates/apub/Cargo.toml index 8f245d076..660489a68 100644 --- a/crates/apub/Cargo.toml +++ b/crates/apub/Cargo.toml @@ -40,7 +40,6 @@ uuid = { workspace = true } async-trait = { workspace = true } anyhow = { workspace = true } reqwest = { workspace = true } -once_cell = { workspace = true } moka.workspace = true serde_with.workspace = true html2md = "0.2.14" diff --git a/crates/apub/src/activities/block/mod.rs b/crates/apub/src/activities/block/mod.rs index ced50e2de..d42b62369 100644 --- a/crates/apub/src/activities/block/mod.rs +++ b/crates/apub/src/activities/block/mod.rs @@ -38,7 +38,6 @@ pub enum SiteOrCommunity { Site(ApubSite), Community(ApubCommunity), } - #[derive(Deserialize)] #[serde(untagged)] pub enum InstanceOrGroup { @@ -74,12 +73,18 @@ impl Object for SiteOrCommunity { }) } - async fn delete(self, _data: &Data) -> LemmyResult<()> { - unimplemented!() + async fn delete(self, data: &Data) -> LemmyResult<()> { + match self { + SiteOrCommunity::Site(i) => i.delete(data).await, + SiteOrCommunity::Community(c) => c.delete(data).await, + } } - async fn into_json(self, _data: &Data) -> LemmyResult { - unimplemented!() + async fn into_json(self, data: &Data) -> LemmyResult { + Ok(match self { + SiteOrCommunity::Site(i) => InstanceOrGroup::Instance(i.into_json(data).await?), + SiteOrCommunity::Community(c) => InstanceOrGroup::Group(c.into_json(data).await?), + }) } #[tracing::instrument(skip_all)] diff --git a/crates/apub/src/activities/create_or_update/comment.rs b/crates/apub/src/activities/create_or_update/comment.rs index 2406d2eb3..89be8d49e 100644 --- a/crates/apub/src/activities/create_or_update/comment.rs +++ b/crates/apub/src/activities/create_or_update/comment.rs @@ -179,7 +179,7 @@ impl ActivityHandler for CreateOrUpdateNote { // 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.id, &actor, do_send_email, context).await?; + send_local_notifs(mentions, comment.id, &actor, do_send_email, context, None).await?; Ok(()) } } diff --git a/crates/apub/src/activities/deletion/delete.rs b/crates/apub/src/activities/deletion/delete.rs index cecc051b4..d203aacf2 100644 --- a/crates/apub/src/activities/deletion/delete.rs +++ b/crates/apub/src/activities/deletion/delete.rs @@ -175,8 +175,9 @@ pub(in crate::activities) async fn receive_remove_action( ) .await?; } - DeletableObjects::PrivateMessage(_) => unimplemented!(), - DeletableObjects::Person { .. } => unimplemented!(), + // TODO these need to be implemented yet, for now, return errors + DeletableObjects::PrivateMessage(_) => Err(LemmyErrorType::CouldntFindPrivateMessage)?, + DeletableObjects::Person(_) => Err(LemmyErrorType::CouldntFindPerson)?, } Ok(()) } diff --git a/crates/apub/src/activities/deletion/undo_delete.rs b/crates/apub/src/activities/deletion/undo_delete.rs index 4f0fad670..b50580852 100644 --- a/crates/apub/src/activities/deletion/undo_delete.rs +++ b/crates/apub/src/activities/deletion/undo_delete.rs @@ -155,8 +155,9 @@ impl UndoDelete { ) .await?; } - DeletableObjects::PrivateMessage(_) => unimplemented!(), - DeletableObjects::Person { .. } => unimplemented!(), + // TODO these need to be implemented yet, for now, return errors + DeletableObjects::PrivateMessage(_) => Err(LemmyErrorType::CouldntFindPrivateMessage)?, + DeletableObjects::Person(_) => Err(LemmyErrorType::CouldntFindPerson)?, } Ok(()) } diff --git a/crates/apub/src/activity_lists.rs b/crates/apub/src/activity_lists.rs index 3aeb7e45e..2d1fac449 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::LemmyResult; +use lemmy_utils::{error::LemmyResult, LemmyErrorType}; use serde::{Deserialize, Serialize}; use url::Url; @@ -117,7 +117,7 @@ impl InCommunity for AnnouncableActivities { CollectionRemove(a) => a.community(context).await, LockPost(a) => a.community(context).await, UndoLockPost(a) => a.community(context).await, - Page(_) => unimplemented!(), + Page(_) => Err(LemmyErrorType::CouldntFindPost.into()), } } } diff --git a/crates/apub/src/fetcher/post_or_comment.rs b/crates/apub/src/fetcher/post_or_comment.rs index 083369b9d..e352e1257 100644 --- a/crates/apub/src/fetcher/post_or_comment.rs +++ b/crates/apub/src/fetcher/post_or_comment.rs @@ -61,8 +61,11 @@ impl Object for PostOrComment { } } - async fn into_json(self, _data: &Data) -> LemmyResult { - unimplemented!() + async fn into_json(self, data: &Data) -> LemmyResult { + Ok(match self { + PostOrComment::Post(p) => PageOrNote::Page(Box::new(p.into_json(data).await?)), + PostOrComment::Comment(c) => PageOrNote::Note(c.into_json(data).await?), + }) } #[tracing::instrument(skip_all)] diff --git a/crates/apub/src/fetcher/search.rs b/crates/apub/src/fetcher/search.rs index 8c533ba88..76c284820 100644 --- a/crates/apub/src/fetcher/search.rs +++ b/crates/apub/src/fetcher/search.rs @@ -118,8 +118,17 @@ impl Object for SearchableObjects { } } - async fn into_json(self, _data: &Data) -> LemmyResult { - unimplemented!() + async fn into_json(self, data: &Data) -> LemmyResult { + Ok(match self { + SearchableObjects::Post(p) => SearchableKinds::Page(Box::new(p.into_json(data).await?)), + SearchableObjects::Comment(c) => SearchableKinds::Note(c.into_json(data).await?), + SearchableObjects::PersonOrCommunity(pc) => { + SearchableKinds::PersonOrGroup(Box::new(match *pc { + UserOrCommunity::User(p) => PersonOrGroup::Person(p.into_json(data).await?), + UserOrCommunity::Community(c) => PersonOrGroup::Group(c.into_json(data).await?), + })) + } + }) } #[tracing::instrument(skip_all)] 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 30b5fd568..c6a1bb17e 100644 --- a/crates/apub/src/fetcher/site_or_community_or_user.rs +++ b/crates/apub/src/fetcher/site_or_community_or_user.rs @@ -1,6 +1,6 @@ use crate::{ fetcher::user_or_community::{PersonOrGroup, UserOrCommunity}, - objects::instance::ApubSite, + objects::{community::ApubCommunity, instance::ApubSite, person::ApubPerson}, protocol::objects::instance::Instance, }; use activitypub_federation::{ @@ -41,11 +41,14 @@ impl Object for SiteOrCommunityOrUser { } #[tracing::instrument(skip_all)] - async fn read_from_id( - _object_id: Url, - _data: &Data, - ) -> LemmyResult> { - unimplemented!(); + async fn read_from_id(object_id: Url, data: &Data) -> LemmyResult> { + let site = ApubSite::read_from_id(object_id.clone(), data).await?; + Ok(match site { + Some(o) => Some(SiteOrCommunityOrUser::Site(o)), + None => UserOrCommunity::read_from_id(object_id, data) + .await? + .map(SiteOrCommunityOrUser::UserOrCommunity), + }) } #[tracing::instrument(skip_all)] @@ -56,8 +59,13 @@ impl Object for SiteOrCommunityOrUser { } } - async fn into_json(self, _data: &Data) -> LemmyResult { - unimplemented!() + async fn into_json(self, data: &Data) -> LemmyResult { + Ok(match self { + SiteOrCommunityOrUser::Site(p) => SiteOrPersonOrGroup::Instance(p.into_json(data).await?), + SiteOrCommunityOrUser::UserOrCommunity(p) => { + SiteOrPersonOrGroup::PersonOrGroup(p.into_json(data).await?) + } + }) } #[tracing::instrument(skip_all)] @@ -75,8 +83,18 @@ impl Object for SiteOrCommunityOrUser { } #[tracing::instrument(skip_all)] - async fn from_json(_apub: Self::Kind, _data: &Data) -> LemmyResult { - unimplemented!(); + async fn from_json(apub: Self::Kind, data: &Data) -> LemmyResult { + Ok(match apub { + SiteOrPersonOrGroup::Instance(a) => { + SiteOrCommunityOrUser::Site(ApubSite::from_json(a, data).await?) + } + SiteOrPersonOrGroup::PersonOrGroup(a) => SiteOrCommunityOrUser::UserOrCommunity(match a { + PersonOrGroup::Person(p) => UserOrCommunity::User(ApubPerson::from_json(p, data).await?), + PersonOrGroup::Group(g) => { + UserOrCommunity::Community(ApubCommunity::from_json(g, data).await?) + } + }), + }) } } @@ -103,6 +121,9 @@ impl Actor for SiteOrCommunityOrUser { } fn inbox(&self) -> Url { - unimplemented!() + match self { + SiteOrCommunityOrUser::Site(u) => u.inbox(), + SiteOrCommunityOrUser::UserOrCommunity(c) => c.inbox(), + } } } diff --git a/crates/apub/src/fetcher/user_or_community.rs b/crates/apub/src/fetcher/user_or_community.rs index d29cbb6b0..129af8803 100644 --- a/crates/apub/src/fetcher/user_or_community.rs +++ b/crates/apub/src/fetcher/user_or_community.rs @@ -65,8 +65,11 @@ impl Object for UserOrCommunity { } } - async fn into_json(self, _data: &Data) -> LemmyResult { - unimplemented!() + async fn into_json(self, data: &Data) -> LemmyResult { + Ok(match self { + UserOrCommunity::User(p) => PersonOrGroup::Person(p.into_json(data).await?), + UserOrCommunity::Community(p) => PersonOrGroup::Group(p.into_json(data).await?), + }) } #[tracing::instrument(skip_all)] @@ -115,7 +118,10 @@ impl Actor for UserOrCommunity { } fn inbox(&self) -> Url { - unimplemented!() + match self { + UserOrCommunity::User(p) => p.inbox(), + UserOrCommunity::Community(p) => p.inbox(), + } } } diff --git a/crates/apub/src/lib.rs b/crates/apub/src/lib.rs index c8960b008..c8506da52 100644 --- a/crates/apub/src/lib.rs +++ b/crates/apub/src/lib.rs @@ -14,9 +14,8 @@ use lemmy_utils::{ CACHE_DURATION_FEDERATION, }; use moka::future::Cache; -use once_cell::sync::Lazy; use serde_json::Value; -use std::sync::Arc; +use std::sync::{Arc, LazyLock}; use url::Url; pub mod activities; @@ -36,7 +35,7 @@ pub const FEDERATION_HTTP_FETCH_LIMIT: u32 = 100; /// 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 /// theoretically also be moved. -pub static FEDERATION_CONTEXT: Lazy = Lazy::new(|| { +pub static FEDERATION_CONTEXT: LazyLock = LazyLock::new(|| { Value::Array(vec![ Value::String("https://join-lemmy.org/context.json".to_string()), Value::String("https://www.w3.org/ns/activitystreams".to_string()), @@ -129,7 +128,7 @@ pub(crate) async fn local_site_data_cached( // 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(|| { + static CACHE: LazyLock>> = LazyLock::new(|| { Cache::builder() .max_capacity(1) .time_to_live(CACHE_DURATION_FEDERATION) diff --git a/crates/apub/src/objects/instance.rs b/crates/apub/src/objects/instance.rs index 6f0a7328d..c67a223e0 100644 --- a/crates/apub/src/objects/instance.rs +++ b/crates/apub/src/objects/instance.rs @@ -88,7 +88,7 @@ impl Object for ApubSite { } async fn delete(self, _data: &Data) -> LemmyResult<()> { - unimplemented!() + Err(LemmyErrorType::CantDeleteSite.into()) } #[tracing::instrument(skip_all)] diff --git a/crates/apub/src/objects/post.rs b/crates/apub/src/objects/post.rs index 7e4254840..44e842413 100644 --- a/crates/apub/src/objects/post.rs +++ b/crates/apub/src/objects/post.rs @@ -41,7 +41,11 @@ use lemmy_db_views_actor::structs::CommunityModeratorView; use lemmy_utils::{ error::{LemmyError, LemmyErrorType, LemmyResult}, spawn_try_task, - utils::{markdown::markdown_to_html, slurs::check_slurs_opt, validation::check_url_scheme}, + utils::{ + markdown::markdown_to_html, + slurs::check_slurs_opt, + validation::{is_url_blocked, is_valid_url}, + }, }; use std::ops::Deref; use stringreader::StringReader; @@ -180,8 +184,15 @@ impl Object for ApubPost { let creator = page.creator()?.dereference(context).await?; let community = page.community(context).await?; if community.posting_restricted_to_mods { - CommunityModeratorView::is_community_moderator(&mut context.pool(), community.id, creator.id) - .await?; + let is_mod = CommunityModeratorView::is_community_moderator( + &mut context.pool(), + community.id, + creator.id, + ) + .await?; + if !is_mod { + Err(LemmyErrorType::OnlyModsCanPostInCommunity)? + } } let mut name = page .name @@ -220,14 +231,16 @@ impl Object for ApubPost { None }; + let url_blocklist = get_url_blocklist(context).await?; + if let Some(url) = &url { - check_url_scheme(url)?; + is_url_blocked(url, &url_blocklist)?; + is_valid_url(url)?; } let alt_text = first_attachment.cloned().and_then(Attachment::alt_text); let slur_regex = &local_site_opt_to_slur_regex(&local_site); - let url_blocklist = get_url_blocklist(context).await?; let body = read_from_string_or_source_opt(&page.content, &page.media_type, &page.source); let body = process_markdown_opt(&body, slur_regex, &url_blocklist, context).await?; diff --git a/crates/apub/src/objects/private_message.rs b/crates/apub/src/objects/private_message.rs index 35f2fe418..fc9697391 100644 --- a/crates/apub/src/objects/private_message.rs +++ b/crates/apub/src/objects/private_message.rs @@ -73,7 +73,7 @@ impl Object for ApubPrivateMessage { async fn delete(self, _context: &Data) -> LemmyResult<()> { // do nothing, because pm can't be fetched over http - unimplemented!() + Err(LemmyErrorType::CouldntFindPrivateMessage.into()) } #[tracing::instrument(skip_all)] diff --git a/crates/apub/src/protocol/objects/group.rs b/crates/apub/src/protocol/objects/group.rs index a95fff262..8f138e001 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, verify_is_remote_object}, + objects::{community::ApubCommunity, read_from_string_or_source_opt}, protocol::{ objects::{Endpoints, LanguageTag}, ImageObject, @@ -80,7 +80,6 @@ impl Group { ) -> 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); diff --git a/crates/apub/src/protocol/objects/page.rs b/crates/apub/src/protocol/objects/page.rs index 6075b14a1..9c37c88c3 100644 --- a/crates/apub/src/protocol/objects/page.rs +++ b/crates/apub/src/protocol/objects/page.rs @@ -193,10 +193,12 @@ impl ActivityHandler for Page { type DataType = LemmyContext; type Error = LemmyError; fn id(&self) -> &Url { - unimplemented!() + self.id.inner() } + fn actor(&self) -> &Url { - unimplemented!() + debug_assert!(false); + self.id.inner() } async fn verify(&self, data: &Data) -> LemmyResult<()> { ApubPost::verify(self, self.id.inner(), data).await diff --git a/crates/db_schema/Cargo.toml b/crates/db_schema/Cargo.toml index dbcd0482c..bf9e4182f 100644 --- a/crates/db_schema/Cargo.toml +++ b/crates/db_schema/Cargo.toml @@ -27,7 +27,6 @@ full = [ "lemmy_utils", "activitypub_federation", "regex", - "once_cell", "serde_json", "diesel_ltree", "diesel-async", @@ -64,7 +63,6 @@ diesel-async = { workspace = true, features = [ "deadpool", ], optional = true } regex = { workspace = true, optional = true } -once_cell = { workspace = true, optional = true } diesel_ltree = { workspace = true, optional = true } typed-builder = { workspace = true } async-trait = { workspace = true } diff --git a/crates/db_schema/src/impls/comment.rs b/crates/db_schema/src/impls/comment.rs index aa7b418fe..977bc9083 100644 --- a/crates/db_schema/src/impls/comment.rs +++ b/crates/db_schema/src/impls/comment.rs @@ -117,7 +117,7 @@ impl Crud for Comment { type UpdateForm = CommentUpdateForm; type IdType = CommentId; - /// This is unimplemented, use [[Comment::create]] + /// Use [[Comment::create]] async fn create(pool: &mut DbPool<'_>, comment_form: &Self::InsertForm) -> Result { debug_assert!(false); Comment::create(pool, comment_form, None).await diff --git a/crates/db_schema/src/impls/local_site.rs b/crates/db_schema/src/impls/local_site.rs index 602dfe1f4..926814c48 100644 --- a/crates/db_schema/src/impls/local_site.rs +++ b/crates/db_schema/src/impls/local_site.rs @@ -7,7 +7,7 @@ use diesel::{dsl::insert_into, result::Error}; use diesel_async::RunQueryDsl; use lemmy_utils::{error::LemmyResult, CACHE_DURATION_API}; use moka::future::Cache; -use once_cell::sync::Lazy; +use std::sync::LazyLock; impl LocalSite { pub async fn create(pool: &mut DbPool<'_>, form: &LocalSiteInsertForm) -> Result { @@ -18,7 +18,7 @@ impl LocalSite { .await } pub async fn read(pool: &mut DbPool<'_>) -> LemmyResult { - static CACHE: Lazy> = Lazy::new(|| { + static CACHE: LazyLock> = LazyLock::new(|| { Cache::builder() .max_capacity(1) .time_to_live(CACHE_DURATION_API) diff --git a/crates/db_schema/src/impls/local_user.rs b/crates/db_schema/src/impls/local_user.rs index 32e8d50b7..acff6af2a 100644 --- a/crates/db_schema/src/impls/local_user.rs +++ b/crates/db_schema/src/impls/local_user.rs @@ -115,11 +115,11 @@ impl LocalUser { let conn = &mut get_conn(pool).await?; // Make sure: - // - The deny reason exists + // - An admin has interacted with the application // - The app is older than a week // - The accepted_application is false let old_denied_registrations = registration_application::table - .filter(registration_application::deny_reason.is_not_null()) + .filter(registration_application::admin_id.is_not_null()) .filter(registration_application::published.lt(now() - 1.week())) .select(registration_application::local_user_id); diff --git a/crates/db_schema/src/impls/person.rs b/crates/db_schema/src/impls/person.rs index 89c108f8c..f2909218c 100644 --- a/crates/db_schema/src/impls/person.rs +++ b/crates/db_schema/src/impls/person.rs @@ -191,9 +191,12 @@ impl Followable for PersonFollower { .get_result::(conn) .await } + + /// Currently no user following async fn follow_accepted(_: &mut DbPool<'_>, _: CommunityId, _: PersonId) -> Result { - unimplemented!() + Err(Error::NotFound) } + async fn unfollow(pool: &mut DbPool<'_>, form: &PersonFollowerForm) -> Result { let conn = &mut get_conn(pool).await?; diesel::delete(person_follower::table.find((form.follower_id, form.person_id))) diff --git a/crates/db_schema/src/impls/private_message_report.rs b/crates/db_schema/src/impls/private_message_report.rs index b5d8fd039..0d5876659 100644 --- a/crates/db_schema/src/impls/private_message_report.rs +++ b/crates/db_schema/src/impls/private_message_report.rs @@ -52,7 +52,7 @@ impl Reportable for PrivateMessageReport { _pm_id_: PrivateMessageId, _by_resolver_id: PersonId, ) -> Result { - unimplemented!() + Err(Error::NotFound) } async fn unresolve( diff --git a/crates/db_schema/src/impls/site.rs b/crates/db_schema/src/impls/site.rs index a371f9e07..9dbd2401d 100644 --- a/crates/db_schema/src/impls/site.rs +++ b/crates/db_schema/src/impls/site.rs @@ -20,7 +20,7 @@ impl Crud for Site { /// Use SiteView::read_local, or Site::read_from_apub_id instead async fn read(_pool: &mut DbPool<'_>, _site_id: SiteId) -> Result, Error> { - unimplemented!() + Err(Error::NotFound) } async fn create(pool: &mut DbPool<'_>, form: &Self::InsertForm) -> Result { diff --git a/crates/db_schema/src/schema.rs b/crates/db_schema/src/schema.rs index 206b3d842..8f5a63559 100644 --- a/crates/db_schema/src/schema.rs +++ b/crates/db_schema/src/schema.rs @@ -711,7 +711,7 @@ diesel::table! { id -> Int4, #[max_length = 200] name -> Varchar, - #[max_length = 512] + #[max_length = 2000] url -> Nullable, body -> Nullable, creator_id -> Int4, diff --git a/crates/db_schema/src/utils.rs b/crates/db_schema/src/utils.rs index 6c02d241c..8f60b20f1 100644 --- a/crates/db_schema/src/utils.rs +++ b/crates/db_schema/src/utils.rs @@ -32,7 +32,6 @@ use lemmy_utils::{ settings::SETTINGS, utils::validation::clean_url_params, }; -use once_cell::sync::Lazy; use regex::Regex; use rustls::{ client::danger::{ @@ -49,7 +48,7 @@ use rustls::{ }; use std::{ ops::{Deref, DerefMut}, - sync::Arc, + sync::{Arc, LazyLock}, time::Duration, }; use tracing::error; @@ -478,7 +477,7 @@ pub fn post_to_comment_sort_type(sort: SortType) -> CommentSortType { } } -static EMAIL_REGEX: Lazy = Lazy::new(|| { +static EMAIL_REGEX: LazyLock = LazyLock::new(|| { Regex::new(r"^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$") .expect("compile email regex") }); diff --git a/crates/federate/Cargo.toml b/crates/federate/Cargo.toml index b8b438901..6b76dbf97 100644 --- a/crates/federate/Cargo.toml +++ b/crates/federate/Cargo.toml @@ -27,7 +27,6 @@ futures.workspace = true chrono.workspace = true diesel = { workspace = true, features = ["postgres", "chrono", "serde_json"] } diesel-async = { workspace = true, features = ["deadpool", "postgres"] } -once_cell.workspace = true reqwest.workspace = true serde_json.workspace = true tokio = { workspace = true, features = ["full"] } @@ -43,4 +42,4 @@ actix-web.workspace = true tracing-test = "0.2.5" uuid.workspace = true test-context = "0.3.0" -mockall = "0.12.1" +mockall = "0.13.0" diff --git a/crates/federate/src/inboxes.rs b/crates/federate/src/inboxes.rs index 9869e5270..cda4da39b 100644 --- a/crates/federate/src/inboxes.rs +++ b/crates/federate/src/inboxes.rs @@ -8,9 +8,11 @@ use lemmy_db_schema::{ utils::{ActualDbPool, DbPool}, }; use lemmy_db_views_actor::structs::CommunityFollowerView; -use once_cell::sync::Lazy; use reqwest::Url; -use std::collections::{HashMap, HashSet}; +use std::{ + collections::{HashMap, HashSet}, + sync::LazyLock, +}; /// interval with which new additions to community_followers are queried. /// @@ -21,7 +23,7 @@ use std::collections::{HashMap, HashSet}; /// currently fairly high because of the current structure of storing inboxes for every person, not /// having a separate list of shared_inboxes, and the architecture of having every instance queue be /// fully separate. (see https://github.com/LemmyNet/lemmy/issues/3958) -static FOLLOW_ADDITIONS_RECHECK_DELAY: Lazy = Lazy::new(|| { +static FOLLOW_ADDITIONS_RECHECK_DELAY: LazyLock = LazyLock::new(|| { if *LEMMY_TEST_FAST_FEDERATION { chrono::TimeDelta::try_seconds(1).expect("TimeDelta out of bounds") } else { @@ -31,8 +33,8 @@ static FOLLOW_ADDITIONS_RECHECK_DELAY: Lazy = Lazy::new(|| { /// The same as FOLLOW_ADDITIONS_RECHECK_DELAY, but triggering when the last person on an instance /// unfollows a specific remote community. This is expected to happen pretty rarely and updating it /// in a timely manner is not too important. -static FOLLOW_REMOVALS_RECHECK_DELAY: Lazy = - Lazy::new(|| chrono::TimeDelta::try_hours(1).expect("TimeDelta out of bounds")); +static FOLLOW_REMOVALS_RECHECK_DELAY: LazyLock = + LazyLock::new(|| chrono::TimeDelta::try_hours(1).expect("TimeDelta out of bounds")); #[async_trait] pub trait DataSource: Send + Sync { diff --git a/crates/federate/src/util.rs b/crates/federate/src/util.rs index afbe957a5..e10a01c30 100644 --- a/crates/federate/src/util.rs +++ b/crates/federate/src/util.rs @@ -18,10 +18,15 @@ use lemmy_db_schema::{ utils::{get_conn, DbPool}, }; use moka::future::Cache; -use once_cell::sync::Lazy; use reqwest::Url; use serde_json::Value; -use std::{fmt::Debug, future::Future, pin::Pin, sync::Arc, time::Duration}; +use std::{ + fmt::Debug, + future::Future, + pin::Pin, + sync::{Arc, LazyLock}, + time::Duration, +}; use tokio::{task::JoinHandle, time::sleep}; use tokio_util::sync::CancellationToken; @@ -29,7 +34,7 @@ use tokio_util::sync::CancellationToken; /// Should only be used for federation tests since it significantly increases CPU and DB load of the /// federation queue. This is intentionally a separate flag from other flags like debug_assertions, /// since this is a invasive change we only need rarely. -pub(crate) static LEMMY_TEST_FAST_FEDERATION: Lazy = Lazy::new(|| { +pub(crate) static LEMMY_TEST_FAST_FEDERATION: LazyLock = LazyLock::new(|| { std::env::var("LEMMY_TEST_FAST_FEDERATION") .map(|s| !s.is_empty()) .unwrap_or(false) @@ -49,7 +54,7 @@ pub(crate) static LEMMY_TEST_FAST_FEDERATION: Lazy = Lazy::new(|| { /// If the delay is too short, the workers (one per federated instance) will wake up too /// often and consume a lot of CPU. If the delay is long, then activities on low-traffic instances /// will on average take delay/2 seconds to federate. -pub(crate) static WORK_FINISHED_RECHECK_DELAY: Lazy = Lazy::new(|| { +pub(crate) static WORK_FINISHED_RECHECK_DELAY: LazyLock = LazyLock::new(|| { if *LEMMY_TEST_FAST_FEDERATION { Duration::from_millis(100) } else { @@ -61,7 +66,7 @@ pub(crate) static WORK_FINISHED_RECHECK_DELAY: Lazy = Lazy::new(|| { /// /// This cache is common to all the instance workers and prevents there from being more than one /// call per N seconds between each DB query to find max(activity_id). -pub(crate) static CACHE_DURATION_LATEST_ID: Lazy = Lazy::new(|| { +pub(crate) static CACHE_DURATION_LATEST_ID: LazyLock = LazyLock::new(|| { if *LEMMY_TEST_FAST_FEDERATION { // in test mode, we use the same cache duration as the recheck delay so when recheck happens // data is fresh, accelerating the time the tests take. @@ -132,8 +137,8 @@ pub(crate) async fn get_actor_cached( actor_type: ActorType, actor_apub_id: &Url, ) -> Result> { - static CACHE: Lazy>> = - Lazy::new(|| Cache::builder().max_capacity(10000).build()); + static CACHE: LazyLock>> = + LazyLock::new(|| Cache::builder().max_capacity(10000).build()); CACHE .try_get_with(actor_apub_id.clone(), async { let url = actor_apub_id.clone().into(); @@ -172,8 +177,8 @@ pub(crate) async fn get_activity_cached( pool: &mut DbPool<'_>, activity_id: ActivityId, ) -> Result { - static ACTIVITIES: Lazy> = - Lazy::new(|| Cache::builder().max_capacity(10000).build()); + static ACTIVITIES: LazyLock> = + LazyLock::new(|| Cache::builder().max_capacity(10000).build()); ACTIVITIES .try_get_with(activity_id, async { let row = SentActivity::read(pool, activity_id) @@ -195,7 +200,7 @@ 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(|| { + static CACHE: LazyLock> = LazyLock::new(|| { Cache::builder() .time_to_live(*CACHE_DURATION_LATEST_ID) .build() diff --git a/crates/routes/Cargo.toml b/crates/routes/Cargo.toml index 0d18e4f1f..a614ba42d 100644 --- a/crates/routes/Cargo.toml +++ b/crates/routes/Cargo.toml @@ -30,7 +30,6 @@ reqwest = { workspace = true, features = ["stream"] } reqwest-middleware = { workspace = true } serde = { workspace = true } url = { workspace = true } -once_cell = { workspace = true } tracing = { workspace = true } tokio = { workspace = true } urlencoding = { workspace = true } diff --git a/crates/routes/src/feeds.rs b/crates/routes/src/feeds.rs index f08f28c4a..f7e7d4059 100644 --- a/crates/routes/src/feeds.rs +++ b/crates/routes/src/feeds.rs @@ -25,7 +25,6 @@ use lemmy_utils::{ error::{LemmyError, LemmyErrorType, LemmyResult}, utils::markdown::{markdown_to_html, sanitize_html}, }; -use once_cell::sync::Lazy; use rss::{ extension::{dublincore::DublinCoreExtension, ExtensionBuilder, ExtensionMap}, Channel, @@ -34,7 +33,7 @@ use rss::{ Item, }; use serde::Deserialize; -use std::{collections::BTreeMap, str::FromStr}; +use std::{collections::BTreeMap, str::FromStr, sync::LazyLock}; const RSS_FETCH_LIMIT: i64 = 20; @@ -80,7 +79,7 @@ pub fn config(cfg: &mut web::ServiceConfig) { ); } -static RSS_NAMESPACE: Lazy> = Lazy::new(|| { +static RSS_NAMESPACE: LazyLock> = LazyLock::new(|| { let mut h = BTreeMap::new(); h.insert( "dc".to_string(), diff --git a/crates/utils/Cargo.toml b/crates/utils/Cargo.toml index 1b71b577a..e94fce9d6 100644 --- a/crates/utils/Cargo.toml +++ b/crates/utils/Cargo.toml @@ -39,7 +39,6 @@ full = [ "dep:urlencoding", "dep:doku", "dep:url", - "dep:once_cell", "dep:smart-default", "dep:enum-map", "dep:futures", @@ -58,7 +57,6 @@ tracing-error = { workspace = true, optional = true } itertools = { workspace = true, optional = true } serde = { workspace = true } serde_json = { workspace = true, optional = true } -once_cell = { workspace = true, optional = true } url = { workspace = true, optional = true } actix-web = { workspace = true, optional = true } anyhow = { workspace = true, optional = true } @@ -81,7 +79,7 @@ lettre = { version = "0.11.7", default-features = false, features = [ "tokio1-rustls-tls", "smtp-transport", ], optional = true } -markdown-it = { version = "0.6.0", optional = true } +markdown-it = { version = "0.6.1", optional = true } ts-rs = { workspace = true, optional = true } enum-map = { workspace = true, optional = true } cfg-if = "1" diff --git a/crates/utils/src/error.rs b/crates/utils/src/error.rs index 896539057..860dad6fd 100644 --- a/crates/utils/src/error.rs +++ b/crates/utils/src/error.rs @@ -179,6 +179,8 @@ pub enum LemmyErrorType { UrlWithoutDomain, InboxTimeout, Unknown(String), + CantDeleteSite, + UrlLengthOverflow, } cfg_if! { diff --git a/crates/utils/src/rate_limit/rate_limiter.rs b/crates/utils/src/rate_limit/rate_limiter.rs index 35c95366d..a3c6f6a27 100644 --- a/crates/utils/src/rate_limit/rate_limiter.rs +++ b/crates/utils/src/rate_limit/rate_limiter.rs @@ -1,15 +1,15 @@ use enum_map::EnumMap; -use once_cell::sync::Lazy; use std::{ collections::HashMap, hash::Hash, net::{IpAddr, Ipv4Addr, Ipv6Addr}, + sync::LazyLock, time::Instant, }; use strum::{AsRefStr, Display}; use tracing::debug; -static START_TIME: Lazy = Lazy::new(Instant::now); +static START_TIME: LazyLock = LazyLock::new(Instant::now); /// Smaller than `std::time::Instant` because it uses a smaller integer for seconds and doesn't /// store nanoseconds diff --git a/crates/utils/src/settings/mod.rs b/crates/utils/src/settings/mod.rs index 6efa3fdd3..aba1a4fb1 100644 --- a/crates/utils/src/settings/mod.rs +++ b/crates/utils/src/settings/mod.rs @@ -1,9 +1,8 @@ use crate::{error::LemmyResult, location_info}; use anyhow::{anyhow, Context}; use deser_hjson::from_str; -use once_cell::sync::Lazy; use regex::Regex; -use std::{env, fs, io::Error}; +use std::{env, fs, io::Error, sync::LazyLock}; use urlencoding::encode; pub mod structs; @@ -12,7 +11,7 @@ use structs::{DatabaseConnection, PictrsConfig, PictrsImageMode, Settings}; static DEFAULT_CONFIG_FILE: &str = "config/config.hjson"; -pub static SETTINGS: Lazy = Lazy::new(|| { +pub static SETTINGS: LazyLock = LazyLock::new(|| { if env::var("LEMMY_INITIALIZE_WITH_DEFAULT_SETTINGS").is_ok() { println!( "LEMMY_INITIALIZE_WITH_DEFAULT_SETTINGS was set, any configuration file has been ignored." @@ -24,7 +23,7 @@ pub static SETTINGS: Lazy = Lazy::new(|| { } }); -static WEBFINGER_REGEX: Lazy = Lazy::new(|| { +static WEBFINGER_REGEX: LazyLock = LazyLock::new(|| { Regex::new(&format!( "^acct:([a-zA-Z0-9_]{{3,}})@{}$", SETTINGS.hostname diff --git a/crates/utils/src/utils/markdown/mod.rs b/crates/utils/src/utils/markdown/mod.rs index 87e2cb3a2..7ed553e06 100644 --- a/crates/utils/src/utils/markdown/mod.rs +++ b/crates/utils/src/utils/markdown/mod.rs @@ -1,14 +1,14 @@ use crate::{error::LemmyResult, settings::SETTINGS, LemmyErrorType}; use markdown_it::{plugins::cmark::inline::image::Image, MarkdownIt}; -use once_cell::sync::Lazy; use regex::RegexSet; +use std::sync::LazyLock; use url::Url; use urlencoding::encode; mod link_rule; mod spoiler_rule; -static MARKDOWN_PARSER: Lazy = Lazy::new(|| { +static MARKDOWN_PARSER: LazyLock = LazyLock::new(|| { let mut parser = MarkdownIt::new(); markdown_it::plugins::cmark::add(&mut parser); markdown_it::plugins::extra::add(&mut parser); diff --git a/crates/utils/src/utils/markdown/spoiler_rule.rs b/crates/utils/src/utils/markdown/spoiler_rule.rs index 3f12807fd..caced310a 100644 --- a/crates/utils/src/utils/markdown/spoiler_rule.rs +++ b/crates/utils/src/utils/markdown/spoiler_rule.rs @@ -34,8 +34,8 @@ use markdown_it::{ NodeValue, Renderer, }; -use once_cell::sync::Lazy; use regex::Regex; +use std::sync::LazyLock; #[derive(Debug)] struct SpoilerBlock { @@ -46,8 +46,8 @@ const SPOILER_PREFIX: &str = "::: spoiler "; const SPOILER_SUFFIX: &str = ":::"; const SPOILER_SUFFIX_NEWLINE: &str = ":::\n"; -static SPOILER_REGEX: Lazy = - Lazy::new(|| Regex::new(r"^::: spoiler .*$").expect("compile spoiler markdown regex.")); +static SPOILER_REGEX: LazyLock = + LazyLock::new(|| Regex::new(r"^::: spoiler .*$").expect("compile spoiler markdown regex.")); impl NodeValue for SpoilerBlock { // Formats any node marked as a 'SpoilerBlock' into HTML. diff --git a/crates/utils/src/utils/mention.rs b/crates/utils/src/utils/mention.rs index 7e5e5f27c..c7cc2043f 100644 --- a/crates/utils/src/utils/mention.rs +++ b/crates/utils/src/utils/mention.rs @@ -1,8 +1,8 @@ use itertools::Itertools; -use once_cell::sync::Lazy; use regex::Regex; +use std::sync::LazyLock; -static MENTIONS_REGEX: Lazy = Lazy::new(|| { +static MENTIONS_REGEX: LazyLock = LazyLock::new(|| { Regex::new(r"@(?P[\w.]+)@(?P[a-zA-Z0-9._:-]+)").expect("compile regex") }); // TODO nothing is done with community / group webfingers yet, so just ignore those for now diff --git a/crates/utils/src/utils/validation.rs b/crates/utils/src/utils/validation.rs index 8891411a5..0a59e2fea 100644 --- a/crates/utils/src/utils/validation.rs +++ b/crates/utils/src/utils/validation.rs @@ -1,16 +1,16 @@ use crate::error::{LemmyErrorExt, LemmyErrorType, LemmyResult}; use itertools::Itertools; -use once_cell::sync::Lazy; use regex::{Regex, RegexBuilder, RegexSet}; +use std::sync::LazyLock; use url::{ParseError, Url}; // From here: https://github.com/vector-im/element-android/blob/develop/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixPatterns.kt#L35 -static VALID_MATRIX_ID_REGEX: Lazy = Lazy::new(|| { +static VALID_MATRIX_ID_REGEX: LazyLock = LazyLock::new(|| { Regex::new(r"^@[A-Za-z0-9\x21-\x39\x3B-\x7F]+:[A-Za-z0-9.-]+(:[0-9]{2,5})?$") .expect("compile regex") }); // taken from https://en.wikipedia.org/wiki/UTM_parameters -static CLEAN_URL_PARAMS_REGEX: Lazy = Lazy::new(|| { +static CLEAN_URL_PARAMS_REGEX: LazyLock = LazyLock::new(|| { Regex::new( r"^(utm_source|utm_medium|utm_campaign|utm_term|utm_content|gclid|gclsrc|dclid|fbclid)=", ) @@ -21,6 +21,7 @@ const ALLOWED_POST_URL_SCHEMES: [&str; 3] = ["http", "https", "magnet"]; const BODY_MAX_LENGTH: usize = 10000; const POST_BODY_MAX_LENGTH: usize = 50000; const BIO_MAX_LENGTH: usize = 300; +const URL_MAX_LENGTH: usize = 2000; const ALT_TEXT_MAX_LENGTH: usize = 1500; const SITE_NAME_MAX_LENGTH: usize = 20; const SITE_NAME_MIN_LENGTH: usize = 1; @@ -87,12 +88,12 @@ fn has_newline(name: &str) -> bool { } pub fn is_valid_actor_name(name: &str, actor_name_max_length: usize) -> LemmyResult<()> { - static VALID_ACTOR_NAME_REGEX_EN: Lazy = - Lazy::new(|| Regex::new(r"^[a-zA-Z0-9_]{3,}$").expect("compile regex")); - static VALID_ACTOR_NAME_REGEX_AR: Lazy = - Lazy::new(|| Regex::new(r"^[\p{Arabic}0-9_]{3,}$").expect("compile regex")); - static VALID_ACTOR_NAME_REGEX_RU: Lazy = - Lazy::new(|| Regex::new(r"^[\p{Cyrillic}0-9_]{3,}$").expect("compile regex")); + static VALID_ACTOR_NAME_REGEX_EN: LazyLock = + LazyLock::new(|| Regex::new(r"^[a-zA-Z0-9_]{3,}$").expect("compile regex")); + static VALID_ACTOR_NAME_REGEX_AR: LazyLock = + LazyLock::new(|| Regex::new(r"^[\p{Arabic}0-9_]{3,}$").expect("compile regex")); + static VALID_ACTOR_NAME_REGEX_RU: LazyLock = + LazyLock::new(|| Regex::new(r"^[\p{Cyrillic}0-9_]{3,}$").expect("compile regex")); let check = name.chars().count() <= actor_name_max_length && !has_newline(name); @@ -284,11 +285,17 @@ pub fn check_site_visibility_valid( } } -pub fn check_url_scheme(url: &Url) -> LemmyResult<()> { +pub fn is_valid_url(url: &Url) -> LemmyResult<()> { if !ALLOWED_POST_URL_SCHEMES.contains(&url.scheme()) { Err(LemmyErrorType::InvalidUrlScheme)? } + max_length_check( + url.as_str(), + URL_MAX_LENGTH, + LemmyErrorType::UrlLengthOverflow, + )?; + Ok(()) } @@ -349,7 +356,6 @@ mod tests { utils::validation::{ build_and_check_regex, check_site_visibility_valid, - check_url_scheme, check_urls_are_valid, clean_url_params, is_url_blocked, @@ -358,11 +364,13 @@ mod tests { is_valid_display_name, is_valid_matrix_id, is_valid_post_title, + is_valid_url, site_description_length_check, site_name_length_check, BIO_MAX_LENGTH, SITE_DESCRIPTION_MAX_LENGTH, SITE_NAME_MAX_LENGTH, + URL_MAX_LENGTH, }, }; use pretty_assertions::assert_eq; @@ -580,15 +588,27 @@ mod tests { } #[test] - fn test_check_url_scheme() -> LemmyResult<()> { - assert!(check_url_scheme(&Url::parse("http://example.com")?).is_ok()); - assert!(check_url_scheme(&Url::parse("https://example.com")?).is_ok()); - assert!(check_url_scheme(&Url::parse("https://example.com")?).is_ok()); - assert!(check_url_scheme(&Url::parse("ftp://example.com")?).is_err()); - assert!(check_url_scheme(&Url::parse("javascript:void")?).is_err()); + fn test_check_url_valid() -> LemmyResult<()> { + assert!(is_valid_url(&Url::parse("http://example.com")?).is_ok()); + assert!(is_valid_url(&Url::parse("https://example.com")?).is_ok()); + assert!(is_valid_url(&Url::parse("https://example.com")?).is_ok()); + assert!(is_valid_url(&Url::parse("ftp://example.com")?) + .is_err_and(|e| e.error_type.eq(&LemmyErrorType::InvalidUrlScheme))); + assert!(is_valid_url(&Url::parse("javascript:void")?) + .is_err_and(|e| e.error_type.eq(&LemmyErrorType::InvalidUrlScheme))); let magnet_link="magnet:?xt=urn:btih:4b390af3891e323778959d5abfff4b726510f14c&dn=Ravel%20Complete%20Piano%20Sheet%20Music%20-%20Public%20Domain&tr=udp%3A%2F%2Fopen.tracker.cl%3A1337%2Fannounce"; - assert!(check_url_scheme(&Url::parse(magnet_link)?).is_ok()); + assert!(is_valid_url(&Url::parse(magnet_link)?).is_ok()); + + // Also make sure the length overflow hits an error + let mut long_str = "http://example.com/test=".to_string(); + for _ in 1..URL_MAX_LENGTH { + long_str.push('X'); + } + let long_url = Url::parse(&long_str)?; + assert!( + is_valid_url(&long_url).is_err_and(|e| e.error_type.eq(&LemmyErrorType::UrlLengthOverflow)) + ); Ok(()) } diff --git a/crates/utils/translations b/crates/utils/translations index ee2cffac8..bc9b53057 160000 --- a/crates/utils/translations +++ b/crates/utils/translations @@ -1 +1 @@ -Subproject commit ee2cffac809ad466644f061ad79ac577b6c2e4fd +Subproject commit bc9b5305769900c5a59d8f139f110e004085f92b diff --git a/docker/Dockerfile b/docker/Dockerfile index 5125e3c3c..156d30dcc 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,11 +1,11 @@ -# syntax=docker/dockerfile:1.8 -ARG RUST_VERSION=1.78 +# syntax=docker/dockerfile:1.9 +ARG RUST_VERSION=1.80 ARG CARGO_BUILD_FEATURES=default ARG RUST_RELEASE_MODE=debug ARG AMD_BUILDER_IMAGE=rust:${RUST_VERSION} # Repo: https://github.com/raskyld/lemmy-cross-toolchains -ARG ARM_BUILDER_IMAGE="ghcr.io/raskyld/aarch64-lemmy-linux-gnu:v0.3.0" +ARG ARM_BUILDER_IMAGE="ghcr.io/raskyld/aarch64-lemmy-linux-gnu:v0.4.0" ARG AMD_RUNNER_IMAGE=debian:bookworm-slim ARG ARM_RUNNER_IMAGE=debian:bookworm-slim diff --git a/docker/federation/docker-compose.yml b/docker/federation/docker-compose.yml index 2befc78c5..090ad71a8 100644 --- a/docker/federation/docker-compose.yml +++ b/docker/federation/docker-compose.yml @@ -20,7 +20,7 @@ x-lemmy-default: &lemmy-default restart: always x-postgres-default: &postgres-default - image: pgautoupgrade/pgautoupgrade:16-alpine + image: pgautoupgrade/pgautoupgrade:15-alpine environment: - POSTGRES_USER=lemmy - POSTGRES_PASSWORD=password diff --git a/migrations/2024-08-03-155932_increase_post_url_max_length/down.sql b/migrations/2024-08-03-155932_increase_post_url_max_length/down.sql new file mode 100644 index 000000000..d25918578 --- /dev/null +++ b/migrations/2024-08-03-155932_increase_post_url_max_length/down.sql @@ -0,0 +1,3 @@ +ALTER TABLE post + ALTER COLUMN url TYPE varchar(512); + diff --git a/migrations/2024-08-03-155932_increase_post_url_max_length/up.sql b/migrations/2024-08-03-155932_increase_post_url_max_length/up.sql new file mode 100644 index 000000000..7c6818d22 --- /dev/null +++ b/migrations/2024-08-03-155932_increase_post_url_max_length/up.sql @@ -0,0 +1,5 @@ +-- Change the post url max limit to 2000 +-- From here: https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers#417184 +ALTER TABLE post + ALTER COLUMN url TYPE varchar(2000); + diff --git a/renovate.json b/renovate.json index 1911d651b..8d57f0aa8 100644 --- a/renovate.json +++ b/renovate.json @@ -1,5 +1,6 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": ["config:recommended"], - "schedule": ["before 4am on the first day of the month"] + "schedule": ["before 4am on the first day of the month"], + "automerge": true }