mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-11-28 20:31:24 +00:00
Merge branch 'main' into image-mode-changes
This commit is contained in:
commit
85499722c2
227 changed files with 5501 additions and 2979 deletions
|
@ -133,22 +133,11 @@ steps:
|
||||||
DATABASE_URL: postgres://lemmy:password@database:5432/lemmy
|
DATABASE_URL: postgres://lemmy:password@database:5432/lemmy
|
||||||
commands:
|
commands:
|
||||||
- <<: *install_diesel_cli
|
- <<: *install_diesel_cli
|
||||||
|
- cp crates/db_schema/src/schema.rs tmp.schema
|
||||||
- diesel migration run
|
- diesel migration run
|
||||||
- diesel print-schema --config-file=diesel.toml > tmp.schema
|
|
||||||
- diff tmp.schema crates/db_schema/src/schema.rs
|
- diff tmp.schema crates/db_schema/src/schema.rs
|
||||||
when: *slow_check_paths
|
when: *slow_check_paths
|
||||||
|
|
||||||
check_db_perf_tool:
|
|
||||||
image: *rust_image
|
|
||||||
environment:
|
|
||||||
LEMMY_DATABASE_URL: postgres://lemmy:password@database:5432/lemmy
|
|
||||||
RUST_BACKTRACE: "1"
|
|
||||||
CARGO_HOME: .cargo_home
|
|
||||||
commands:
|
|
||||||
# same as scripts/db_perf.sh but without creating a new database server
|
|
||||||
- cargo run --package lemmy_db_perf -- --posts 10 --read-post-pages 1
|
|
||||||
when: *slow_check_paths
|
|
||||||
|
|
||||||
cargo_clippy:
|
cargo_clippy:
|
||||||
image: *rust_image
|
image: *rust_image
|
||||||
environment:
|
environment:
|
||||||
|
@ -221,6 +210,17 @@ steps:
|
||||||
- diff before.sqldump after.sqldump
|
- diff before.sqldump after.sqldump
|
||||||
when: *slow_check_paths
|
when: *slow_check_paths
|
||||||
|
|
||||||
|
check_db_perf_tool:
|
||||||
|
image: *rust_image
|
||||||
|
environment:
|
||||||
|
LEMMY_DATABASE_URL: postgres://lemmy:password@database:5432/lemmy
|
||||||
|
RUST_BACKTRACE: "1"
|
||||||
|
CARGO_HOME: .cargo_home
|
||||||
|
commands:
|
||||||
|
# same as scripts/db_perf.sh but without creating a new database server
|
||||||
|
- cargo run --package lemmy_db_perf -- --posts 10 --read-post-pages 1
|
||||||
|
when: *slow_check_paths
|
||||||
|
|
||||||
run_federation_tests:
|
run_federation_tests:
|
||||||
image: node:22-bookworm-slim
|
image: node:22-bookworm-slim
|
||||||
environment:
|
environment:
|
||||||
|
@ -290,14 +290,14 @@ steps:
|
||||||
when:
|
when:
|
||||||
- event: tag
|
- event: tag
|
||||||
|
|
||||||
notify_on_failure:
|
notify_on_build:
|
||||||
image: alpine:3
|
image: alpine:3
|
||||||
commands:
|
commands:
|
||||||
- apk add curl
|
- apk add curl
|
||||||
- "curl -d'Lemmy CI build failed: ${CI_PIPELINE_URL}' ntfy.sh/lemmy_drone_ci"
|
- "curl -d'Lemmy CI build ${CI_PIPELINE_STATUS}: ${CI_PIPELINE_URL}' ntfy.sh/lemmy_drone_ci"
|
||||||
when:
|
when:
|
||||||
- event: [pull_request, tag]
|
- event: [pull_request, tag]
|
||||||
status: failure
|
status: [failure, success]
|
||||||
|
|
||||||
notify_on_tag_deploy:
|
notify_on_tag_deploy:
|
||||||
image: alpine:3
|
image: alpine:3
|
||||||
|
|
314
Cargo.lock
generated
314
Cargo.lock
generated
|
@ -137,7 +137,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb"
|
checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -272,7 +272,7 @@ dependencies = [
|
||||||
"actix-router",
|
"actix-router",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -435,9 +435,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.89"
|
version = "1.0.93"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6"
|
checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
]
|
]
|
||||||
|
@ -484,13 +484,13 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-trait"
|
name = "async-trait"
|
||||||
version = "0.1.82"
|
version = "0.1.83"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1"
|
checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -635,7 +635,7 @@ dependencies = [
|
||||||
"regex",
|
"regex",
|
||||||
"rustc-hash 1.1.0",
|
"rustc-hash 1.1.0",
|
||||||
"shlex",
|
"shlex",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
"which",
|
"which",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -833,9 +833,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.19"
|
version = "4.5.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7be5744db7978a28d9df86a214130d106a89ce49644cbc4e3f0c22c3fba30615"
|
checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
|
@ -843,9 +843,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.19"
|
version = "4.5.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a5fbc17d3ef8278f55b282b2a2e75ae6f6c7d4bb70ed3d0382375104bfafdb4b"
|
checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
|
@ -862,7 +862,7 @@ dependencies = [
|
||||||
"heck 0.5.0",
|
"heck 0.5.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1096,7 +1096,7 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"strsim 0.11.1",
|
"strsim 0.11.1",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1118,20 +1118,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling_core 0.20.10",
|
"darling_core 0.20.10",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "deadpool"
|
|
||||||
version = "0.9.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "421fe0f90f2ab22016f32a9881be5134fdd71c65298917084b0c7477cbc3856e"
|
|
||||||
dependencies = [
|
|
||||||
"async-trait",
|
|
||||||
"deadpool-runtime",
|
|
||||||
"num_cpus",
|
|
||||||
"retain_mut",
|
|
||||||
"tokio",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1194,7 +1181,7 @@ checksum = "2cdc8d50f426189eef89dac62fabfa0abb27d5cc008f25bf4156a0203325becc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1215,7 +1202,7 @@ dependencies = [
|
||||||
"darling 0.20.10",
|
"darling 0.20.10",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1225,7 +1212,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4abae7035bf79b9877b779505d8cf3749285b80c43941eda66604841889451dc"
|
checksum = "4abae7035bf79b9877b779505d8cf3749285b80c43941eda66604841889451dc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_builder_core",
|
"derive_builder_core",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1238,7 +1225,7 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1252,9 +1239,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "diesel"
|
name = "diesel"
|
||||||
version = "2.1.6"
|
version = "2.2.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ff236accb9a5069572099f0b350a92e9560e8e63a9b8d546162f4a5e03026bb2"
|
checksum = "158fe8e2e68695bd615d7e4f3227c0727b151330d3e253b525086c348d055d5e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
|
@ -1268,12 +1255,12 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "diesel-async"
|
name = "diesel-async"
|
||||||
version = "0.4.1"
|
version = "0.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "acada1517534c92d3f382217b485db8a8638f111b0e3f2a2a8e26165050f77be"
|
checksum = "4c5c6ec8d5c7b8444d19a47161797cbe361e0fb1ee40c6a8124ec915b64a4125"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"deadpool 0.9.5",
|
"deadpool",
|
||||||
"diesel",
|
"diesel",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"scoped-futures",
|
"scoped-futures",
|
||||||
|
@ -1281,6 +1268,15 @@ dependencies = [
|
||||||
"tokio-postgres",
|
"tokio-postgres",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "diesel-bind-if-some"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1ed8ce9db476124d2eaf4c9db45dc6581b8e8c4c4d47d5e0f39de1fb55dfb2a7"
|
||||||
|
dependencies = [
|
||||||
|
"diesel",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "diesel-derive-enum"
|
name = "diesel-derive-enum"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
|
@ -1290,7 +1286,7 @@ dependencies = [
|
||||||
"heck 0.4.1",
|
"heck 0.4.1",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1301,19 +1297,20 @@ checksum = "d5adf688c584fe33726ce0e2898f608a2a92578ac94a4a92fcecf73214fe0716"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "diesel_derives"
|
name = "diesel_derives"
|
||||||
version = "2.1.4"
|
version = "2.2.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "14701062d6bed917b5c7103bdffaee1e4609279e240488ad24e7bd979ca6866c"
|
checksum = "e7f2c3de51e2ba6bf2a648285696137aaf0f5f487bcbea93972fe8a364e131a4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"diesel_table_macro_syntax",
|
"diesel_table_macro_syntax",
|
||||||
|
"dsl_auto_type",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1328,9 +1325,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "diesel_migrations"
|
name = "diesel_migrations"
|
||||||
version = "2.1.0"
|
version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6036b3f0120c5961381b570ee20a02432d7e2d27ea60de9578799cf9156914ac"
|
checksum = "8a73ce704bad4231f001bff3314d91dce4aba0770cee8b233991859abc15c1f6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"diesel",
|
"diesel",
|
||||||
"migrations_internals",
|
"migrations_internals",
|
||||||
|
@ -1339,11 +1336,11 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "diesel_table_macro_syntax"
|
name = "diesel_table_macro_syntax"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fc5557efc453706fed5e4fa85006fe9817c224c3f480a34c7e5959fd700921c5"
|
checksum = "209c735641a413bc68c4923a9d6ad4bcb3ca306b794edaa7eb0b3228a99ffb25"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1381,7 +1378,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1420,6 +1417,20 @@ version = "1.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
|
checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dsl_auto_type"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c5d9abe6314103864cc2d8901b7ae224e0ab1a103a0a416661b4097b0779b607"
|
||||||
|
dependencies = [
|
||||||
|
"darling 0.20.10",
|
||||||
|
"either",
|
||||||
|
"heck 0.5.0",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.87",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dunce"
|
name = "dunce"
|
||||||
version = "1.0.5"
|
version = "1.0.5"
|
||||||
|
@ -1465,9 +1476,9 @@ checksum = "e079f19b08ca6239f47f8ba8509c11cf3ea30095831f7fed61441475edd8c449"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "encoding_rs"
|
name = "encoding_rs"
|
||||||
version = "0.8.34"
|
version = "0.8.35"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59"
|
checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
@ -1495,7 +1506,7 @@ checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1693,7 +1704,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1905,7 +1916,7 @@ dependencies = [
|
||||||
"markup5ever 0.12.1",
|
"markup5ever 0.12.1",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2069,7 +2080,7 @@ dependencies = [
|
||||||
"http 1.1.0",
|
"http 1.1.0",
|
||||||
"hyper 1.4.1",
|
"hyper 1.4.1",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"rustls 0.23.14",
|
"rustls 0.23.16",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-rustls 0.26.0",
|
"tokio-rustls 0.26.0",
|
||||||
|
@ -2114,7 +2125,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8215279f83f9b829403812f845aa2d0dd5966332aa2fd0334a375256f3dd0322"
|
checksum = "8215279f83f9b829403812f845aa2d0dd5966332aa2fd0334a375256f3dd0322"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2255,7 +2266,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2276,24 +2287,23 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "0.5.0"
|
version = "1.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
|
checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-bidi",
|
"idna_adapter",
|
||||||
"unicode-normalization",
|
"smallvec",
|
||||||
|
"utf8_iter",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna_adapter"
|
||||||
version = "1.0.2"
|
version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bd69211b9b519e98303c015e21a007e293db403b6c85b9b124e133d25e242cdd"
|
checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"icu_normalizer",
|
"icu_normalizer",
|
||||||
"icu_properties",
|
"icu_properties",
|
||||||
"smallvec",
|
|
||||||
"utf8_iter",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2609,10 +2619,11 @@ dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"bcrypt",
|
"bcrypt",
|
||||||
"chrono",
|
"chrono",
|
||||||
"deadpool 0.12.1",
|
"deadpool",
|
||||||
"derive-new",
|
"derive-new",
|
||||||
"diesel",
|
"diesel",
|
||||||
"diesel-async",
|
"diesel-async",
|
||||||
|
"diesel-bind-if-some",
|
||||||
"diesel-derive-enum",
|
"diesel-derive-enum",
|
||||||
"diesel-derive-newtype",
|
"diesel-derive-newtype",
|
||||||
"diesel_ltree",
|
"diesel_ltree",
|
||||||
|
@ -2623,7 +2634,7 @@ dependencies = [
|
||||||
"moka",
|
"moka",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"regex",
|
"regex",
|
||||||
"rustls 0.23.14",
|
"rustls 0.23.16",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_with",
|
"serde_with",
|
||||||
|
@ -2634,6 +2645,7 @@ dependencies = [
|
||||||
"tokio-postgres-rustls",
|
"tokio-postgres-rustls",
|
||||||
"tracing",
|
"tracing",
|
||||||
"ts-rs",
|
"ts-rs",
|
||||||
|
"tuplex",
|
||||||
"url",
|
"url",
|
||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
@ -2774,7 +2786,7 @@ dependencies = [
|
||||||
"reqwest 0.12.8",
|
"reqwest 0.12.8",
|
||||||
"reqwest-middleware",
|
"reqwest-middleware",
|
||||||
"reqwest-tracing",
|
"reqwest-tracing",
|
||||||
"rustls 0.23.14",
|
"rustls 0.23.16",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serial_test",
|
"serial_test",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
@ -2825,9 +2837,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lettre"
|
name = "lettre"
|
||||||
version = "0.11.9"
|
version = "0.11.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "69f204773bab09b150320ea1c83db41dc6ee606a4bc36dc1f43005fe7b58ce06"
|
checksum = "0161e452348e399deb685ba05e55ee116cae9410f4f51fe42d597361444521d9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
|
@ -2838,12 +2850,12 @@ dependencies = [
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"httpdate",
|
"httpdate",
|
||||||
"idna 1.0.2",
|
"idna 1.0.3",
|
||||||
"mime",
|
"mime",
|
||||||
"nom",
|
"nom",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"quoted_printable",
|
"quoted_printable",
|
||||||
"rustls 0.23.14",
|
"rustls 0.23.16",
|
||||||
"rustls-pemfile 2.1.3",
|
"rustls-pemfile 2.1.3",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
"socket2",
|
"socket2",
|
||||||
|
@ -3110,9 +3122,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "migrations_internals"
|
name = "migrations_internals"
|
||||||
version = "2.1.0"
|
version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0f23f71580015254b020e856feac3df5878c2c7a8812297edd6c0a485ac9dada"
|
checksum = "fd01039851e82f8799046eabbb354056283fb265c8ec0996af940f4e85a380ff"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"toml",
|
"toml",
|
||||||
|
@ -3120,9 +3132,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "migrations_macros"
|
name = "migrations_macros"
|
||||||
version = "2.1.0"
|
version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cce3325ac70e67bbab5bd837a31cae01f1a6db64e0e744a33cb03a543469ef08"
|
checksum = "ffb161cc72176cb37aa47f1fc520d3ef02263d67d661f44f05d05a079e1237fd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"migrations_internals",
|
"migrations_internals",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
@ -3202,7 +3214,7 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3514,7 +3526,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3684,7 +3696,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba"
|
checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3785,6 +3797,16 @@ dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quick-xml"
|
||||||
|
version = "0.37.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f22f29bdff3987b4d8632ef95fd6424ec7e4e0a57e2f4fc63e489e75357f6a03"
|
||||||
|
dependencies = [
|
||||||
|
"encoding_rs",
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quinn"
|
name = "quinn"
|
||||||
version = "0.11.5"
|
version = "0.11.5"
|
||||||
|
@ -3796,7 +3818,7 @@ dependencies = [
|
||||||
"quinn-proto",
|
"quinn-proto",
|
||||||
"quinn-udp",
|
"quinn-udp",
|
||||||
"rustc-hash 2.0.0",
|
"rustc-hash 2.0.0",
|
||||||
"rustls 0.23.14",
|
"rustls 0.23.16",
|
||||||
"socket2",
|
"socket2",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
@ -3813,7 +3835,7 @@ dependencies = [
|
||||||
"rand",
|
"rand",
|
||||||
"ring",
|
"ring",
|
||||||
"rustc-hash 2.0.0",
|
"rustc-hash 2.0.0",
|
||||||
"rustls 0.23.14",
|
"rustls 0.23.16",
|
||||||
"slab",
|
"slab",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tinyvec",
|
"tinyvec",
|
||||||
|
@ -3895,7 +3917,7 @@ checksum = "a25d631e41bfb5fdcde1d4e2215f62f7f0afa3ff11e26563765bd6ea1d229aeb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3909,9 +3931,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.11.0"
|
version = "1.11.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8"
|
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
|
@ -4024,7 +4046,7 @@ dependencies = [
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"quinn",
|
"quinn",
|
||||||
"rustls 0.23.14",
|
"rustls 0.23.16",
|
||||||
"rustls-pemfile 2.1.3",
|
"rustls-pemfile 2.1.3",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -4075,12 +4097,6 @@ dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "retain_mut"
|
|
||||||
version = "0.1.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4389f1d5789befaf6029ebd9f7dac4af7f7e3d61b69d4f30e2ac02b57e7712b0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rgb"
|
name = "rgb"
|
||||||
version = "0.8.50"
|
version = "0.8.50"
|
||||||
|
@ -4147,14 +4163,14 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rss"
|
name = "rss"
|
||||||
version = "2.0.9"
|
version = "2.0.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "27e92048f840d98c6d6dd870af9101610ea9ff413f11f1bcebf4f4c31d96d957"
|
checksum = "554a62b3dd5450fcbb0435b3db809f9dd3c6e9f5726172408f7ad3b57ed59057"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atom_syndication",
|
"atom_syndication",
|
||||||
"derive_builder",
|
"derive_builder",
|
||||||
"never",
|
"never",
|
||||||
"quick-xml 0.36.1",
|
"quick-xml 0.37.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -4211,9 +4227,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls"
|
name = "rustls"
|
||||||
version = "0.23.14"
|
version = "0.23.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "415d9944693cb90382053259f89fbb077ea730ad7273047ec63b19bc9b160ba8"
|
checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aws-lc-rs",
|
"aws-lc-rs",
|
||||||
"log",
|
"log",
|
||||||
|
@ -4246,9 +4262,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-pki-types"
|
name = "rustls-pki-types"
|
||||||
version = "1.9.0"
|
version = "1.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55"
|
checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-webpki"
|
name = "rustls-webpki"
|
||||||
|
@ -4353,29 +4369,29 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.210"
|
version = "1.0.215"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
|
checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.210"
|
version = "1.0.215"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
|
checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.128"
|
version = "1.0.132"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
|
checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.5.0",
|
"indexmap 2.5.0",
|
||||||
"itoa",
|
"itoa",
|
||||||
|
@ -4432,14 +4448,14 @@ dependencies = [
|
||||||
"darling 0.20.10",
|
"darling 0.20.10",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serial_test"
|
name = "serial_test"
|
||||||
version = "3.1.1"
|
version = "3.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4b4b487fe2acf240a021cf57c6b2b4903b1e78ca0ecd862a71b71d2a51fed77d"
|
checksum = "1b258109f244e1d6891bf1053a55d63a5cd4f8f4c30cf9a1280989f80e7a1fa9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures",
|
"futures",
|
||||||
"log",
|
"log",
|
||||||
|
@ -4451,13 +4467,13 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serial_test_derive"
|
name = "serial_test_derive"
|
||||||
version = "3.1.1"
|
version = "3.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "82fe9db325bcef1fbcde82e078a5cc4efdf787e96b3b9cf45b50b529f2083d67"
|
checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -4542,9 +4558,9 @@ checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sitemap-rs"
|
name = "sitemap-rs"
|
||||||
version = "0.2.1"
|
version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "88cc73a9aac975541c9054e74ceae8d8ee85edc89a322404c275c1d100fffa51"
|
checksum = "3c4c6ab96128064ba085256d34e205153555b3803094d76e24d406c76f85a2c9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"xml-builder",
|
"xml-builder",
|
||||||
|
@ -4573,7 +4589,7 @@ checksum = "0eb01866308440fc64d6c44d9e86c5cc17adfe33c4d6eed55da9145044d0ffc1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -4701,7 +4717,7 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"rustversion",
|
"rustversion",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -4723,9 +4739,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.77"
|
version = "2.0.87"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
|
checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -4755,7 +4771,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -4851,7 +4867,7 @@ checksum = "78ea17a2dc368aeca6f554343ced1b1e31f76d63683fa8016e5844bd7a5144a1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -4871,7 +4887,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -4948,9 +4964,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.40.0"
|
version = "1.41.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998"
|
checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
@ -4972,7 +4988,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -5008,7 +5024,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "04fb792ccd6bbcd4bba408eb8a292f70fc4a3589e5d793626f45190e6454b6ab"
|
checksum = "04fb792ccd6bbcd4bba408eb8a292f70fc4a3589e5d793626f45190e6454b6ab"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ring",
|
"ring",
|
||||||
"rustls 0.23.14",
|
"rustls 0.23.16",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-postgres",
|
"tokio-postgres",
|
||||||
"tokio-rustls 0.26.0",
|
"tokio-rustls 0.26.0",
|
||||||
|
@ -5031,7 +5047,7 @@ version = "0.26.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4"
|
checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustls 0.23.14",
|
"rustls 0.23.16",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
@ -5051,9 +5067,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.7.8"
|
version = "0.8.19"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257"
|
checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_spanned",
|
"serde_spanned",
|
||||||
|
@ -5072,9 +5088,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_edit"
|
name = "toml_edit"
|
||||||
version = "0.19.15"
|
version = "0.22.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
|
checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.5.0",
|
"indexmap 2.5.0",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -5159,7 +5175,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -5232,7 +5248,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "04659ddb06c87d233c566112c1c9c5b9e98256d9af50ec3bc9c8327f873a7568"
|
checksum = "04659ddb06c87d233c566112c1c9c5b9e98256d9af50ec3bc9c8327f873a7568"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -5268,10 +5284,16 @@ checksum = "0ea0b99e8ec44abd6f94a18f28f7934437809dd062820797c52401298116f70e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
"termcolor",
|
"termcolor",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tuplex"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "676ac81d5454c4dcf37955d34fa8626ede3490f744b86ca14a7b90168d2a08aa"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typenum"
|
name = "typenum"
|
||||||
version = "1.17.0"
|
version = "1.17.0"
|
||||||
|
@ -5331,12 +5353,12 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "2.5.2"
|
version = "2.5.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c"
|
checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"form_urlencoded",
|
"form_urlencoded",
|
||||||
"idna 0.5.0",
|
"idna 1.0.3",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
@ -5379,9 +5401,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.10.0"
|
version = "1.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314"
|
checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -5458,7 +5480,7 @@ dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -5492,7 +5514,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
"wasm-bindgen-backend",
|
"wasm-bindgen-backend",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
@ -5812,9 +5834,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
version = "0.5.40"
|
version = "0.6.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876"
|
checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
@ -5923,7 +5945,7 @@ checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
"synstructure",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -5945,7 +5967,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -5965,7 +5987,7 @@ checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
"synstructure",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -5986,7 +6008,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -6008,7 +6030,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.77",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
46
Cargo.toml
46
Cargo.toml
|
@ -78,6 +78,9 @@ uninlined_format_args = "allow"
|
||||||
unused_self = "deny"
|
unused_self = "deny"
|
||||||
unwrap_used = "deny"
|
unwrap_used = "deny"
|
||||||
unimplemented = "deny"
|
unimplemented = "deny"
|
||||||
|
unused_async = "deny"
|
||||||
|
map_err_ignore = "deny"
|
||||||
|
expect_used = "deny"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
lemmy_api = { version = "=0.19.6-beta.7", path = "./crates/api" }
|
lemmy_api = { version = "=0.19.6-beta.7", path = "./crates/api" }
|
||||||
|
@ -94,10 +97,10 @@ lemmy_federate = { version = "=0.19.6-beta.7", path = "./crates/federate" }
|
||||||
activitypub_federation = { version = "0.6.0-alpha2", default-features = false, features = [
|
activitypub_federation = { version = "0.6.0-alpha2", default-features = false, features = [
|
||||||
"actix-web",
|
"actix-web",
|
||||||
] }
|
] }
|
||||||
diesel = "2.1.6"
|
diesel = "2.2.4"
|
||||||
diesel_migrations = "2.1.0"
|
diesel_migrations = "2.2.0"
|
||||||
diesel-async = "0.4.1"
|
diesel-async = "0.5.1"
|
||||||
serde = { version = "1.0.204", features = ["derive"] }
|
serde = { version = "1.0.215", features = ["derive"] }
|
||||||
serde_with = "3.9.0"
|
serde_with = "3.9.0"
|
||||||
actix-web = { version = "4.9.0", default-features = false, features = [
|
actix-web = { version = "4.9.0", default-features = false, features = [
|
||||||
"macros",
|
"macros",
|
||||||
|
@ -110,7 +113,7 @@ actix-web = { version = "4.9.0", default-features = false, features = [
|
||||||
tracing = "0.1.40"
|
tracing = "0.1.40"
|
||||||
tracing-actix-web = { version = "0.7.10", default-features = false }
|
tracing-actix-web = { version = "0.7.10", default-features = false }
|
||||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
||||||
url = { version = "2.5.2", features = ["serde"] }
|
url = { version = "2.5.3", features = ["serde"] }
|
||||||
reqwest = { version = "0.12.7", default-features = false, features = [
|
reqwest = { version = "0.12.7", default-features = false, features = [
|
||||||
"json",
|
"json",
|
||||||
"blocking",
|
"blocking",
|
||||||
|
@ -122,24 +125,27 @@ reqwest-tracing = "0.5.3"
|
||||||
clokwerk = "0.4.0"
|
clokwerk = "0.4.0"
|
||||||
doku = { version = "0.21.1", features = ["url-2"] }
|
doku = { version = "0.21.1", features = ["url-2"] }
|
||||||
bcrypt = "0.15.1"
|
bcrypt = "0.15.1"
|
||||||
chrono = { version = "0.4.38", features = ["serde"], default-features = false }
|
chrono = { version = "0.4.38", features = [
|
||||||
serde_json = { version = "1.0.121", features = ["preserve_order"] }
|
"serde",
|
||||||
|
"now",
|
||||||
|
], default-features = false }
|
||||||
|
serde_json = { version = "1.0.132", features = ["preserve_order"] }
|
||||||
base64 = "0.22.1"
|
base64 = "0.22.1"
|
||||||
uuid = { version = "1.10.0", features = ["serde", "v4"] }
|
uuid = { version = "1.11.0", features = ["serde", "v4"] }
|
||||||
async-trait = "0.1.81"
|
async-trait = "0.1.83"
|
||||||
captcha = "0.0.9"
|
captcha = "0.0.9"
|
||||||
anyhow = { version = "1.0.86", features = [
|
anyhow = { version = "1.0.93", features = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
] } # backtrace is on by default on nightly, but not stable rust
|
] } # backtrace is on by default on nightly, but not stable rust
|
||||||
diesel_ltree = "0.3.1"
|
diesel_ltree = "0.3.1"
|
||||||
serial_test = "3.1.1"
|
serial_test = "3.2.0"
|
||||||
tokio = { version = "1.39.2", features = ["full"] }
|
tokio = { version = "1.41.1", features = ["full"] }
|
||||||
regex = "1.10.5"
|
regex = "1.11.1"
|
||||||
diesel-derive-newtype = "2.1.2"
|
diesel-derive-newtype = "2.1.2"
|
||||||
diesel-derive-enum = { version = "2.1.0", features = ["postgres"] }
|
diesel-derive-enum = { version = "2.1.0", features = ["postgres"] }
|
||||||
strum = { version = "0.26.3", features = ["derive"] }
|
strum = { version = "0.26.3", features = ["derive"] }
|
||||||
itertools = "0.13.0"
|
itertools = "0.13.0"
|
||||||
futures = "0.3.30"
|
futures = "0.3.31"
|
||||||
http = "1.1"
|
http = "1.1"
|
||||||
rosetta-i18n = "0.1.3"
|
rosetta-i18n = "0.1.3"
|
||||||
ts-rs = { version = "10.0.0", features = [
|
ts-rs = { version = "10.0.0", features = [
|
||||||
|
@ -148,17 +154,19 @@ ts-rs = { version = "10.0.0", features = [
|
||||||
"no-serde-warnings",
|
"no-serde-warnings",
|
||||||
"url-impl",
|
"url-impl",
|
||||||
] }
|
] }
|
||||||
rustls = { version = "0.23.12", features = ["ring"] }
|
rustls = { version = "0.23.16", features = ["ring"] }
|
||||||
futures-util = "0.3.30"
|
futures-util = "0.3.31"
|
||||||
tokio-postgres = "0.7.11"
|
tokio-postgres = "0.7.12"
|
||||||
tokio-postgres-rustls = "0.12.0"
|
tokio-postgres-rustls = "0.12.0"
|
||||||
urlencoding = "2.1.3"
|
urlencoding = "2.1.3"
|
||||||
enum-map = "2.7"
|
enum-map = "2.7"
|
||||||
moka = { version = "0.12.8", features = ["future"] }
|
moka = { version = "0.12.8", features = ["future"] }
|
||||||
i-love-jesus = { version = "0.1.0" }
|
i-love-jesus = { version = "0.1.0" }
|
||||||
clap = { version = "4.5.13", features = ["derive", "env"] }
|
clap = { version = "4.5.21", features = ["derive", "env"] }
|
||||||
pretty_assertions = "1.4.0"
|
pretty_assertions = "1.4.1"
|
||||||
derive-new = "0.7.0"
|
derive-new = "0.7.0"
|
||||||
|
diesel-bind-if-some = "0.1.0"
|
||||||
|
tuplex = "0.1.2"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
lemmy_api = { workspace = true }
|
lemmy_api = { workspace = true }
|
||||||
|
|
|
@ -10,27 +10,28 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "tsc --noEmit && eslint --report-unused-disable-directives && prettier --check 'src/**/*.ts'",
|
"lint": "tsc --noEmit && eslint --report-unused-disable-directives && prettier --check 'src/**/*.ts'",
|
||||||
"fix": "prettier --write src && eslint --fix src",
|
"fix": "prettier --write src && eslint --fix src",
|
||||||
"api-test": "jest -i follow.spec.ts && jest -i image.spec.ts && jest -i user.spec.ts && jest -i private_message.spec.ts && jest -i community.spec.ts && jest -i post.spec.ts && jest -i comment.spec.ts ",
|
"api-test": "jest -i follow.spec.ts && jest -i image.spec.ts && jest -i user.spec.ts && jest -i private_message.spec.ts && jest -i community.spec.ts && jest -i private_community.spec.ts && jest -i post.spec.ts && jest -i comment.spec.ts ",
|
||||||
"api-test-follow": "jest -i follow.spec.ts",
|
"api-test-follow": "jest -i follow.spec.ts",
|
||||||
"api-test-comment": "jest -i comment.spec.ts",
|
"api-test-comment": "jest -i comment.spec.ts",
|
||||||
"api-test-post": "jest -i post.spec.ts",
|
"api-test-post": "jest -i post.spec.ts",
|
||||||
"api-test-user": "jest -i user.spec.ts",
|
"api-test-user": "jest -i user.spec.ts",
|
||||||
"api-test-community": "jest -i community.spec.ts",
|
"api-test-community": "jest -i community.spec.ts",
|
||||||
|
"api-test-private-community": "jest -i private_community.spec.ts",
|
||||||
"api-test-private-message": "jest -i private_message.spec.ts",
|
"api-test-private-message": "jest -i private_message.spec.ts",
|
||||||
"api-test-image": "jest -i image.spec.ts"
|
"api-test-image": "jest -i image.spec.ts"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^29.5.12",
|
"@types/jest": "^29.5.12",
|
||||||
"@types/node": "^22.3.0",
|
"@types/node": "^22.9.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.1.0",
|
"@typescript-eslint/eslint-plugin": "^8.13.0",
|
||||||
"@typescript-eslint/parser": "^8.1.0",
|
"@typescript-eslint/parser": "^8.13.0",
|
||||||
"eslint": "^9.9.0",
|
"eslint": "^9.14.0",
|
||||||
"eslint-plugin-prettier": "^5.1.3",
|
"eslint-plugin-prettier": "^5.1.3",
|
||||||
"jest": "^29.5.0",
|
"jest": "^29.5.0",
|
||||||
"lemmy-js-client": "0.20.0-alpha.11",
|
"lemmy-js-client": "0.20.0-alpha.18",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.2.5",
|
||||||
"ts-jest": "^29.1.0",
|
"ts-jest": "^29.1.0",
|
||||||
"typescript": "^5.5.4",
|
"typescript": "^5.5.4",
|
||||||
"typescript-eslint": "^8.1.0"
|
"typescript-eslint": "^8.13.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,38 +12,38 @@ importers:
|
||||||
specifier: ^29.5.12
|
specifier: ^29.5.12
|
||||||
version: 29.5.14
|
version: 29.5.14
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^22.3.0
|
specifier: ^22.9.0
|
||||||
version: 22.8.6
|
version: 22.9.0
|
||||||
'@typescript-eslint/eslint-plugin':
|
'@typescript-eslint/eslint-plugin':
|
||||||
specifier: ^8.1.0
|
specifier: ^8.13.0
|
||||||
version: 8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.6.3))(eslint@9.13.0)(typescript@5.6.3)
|
version: 8.13.0(@typescript-eslint/parser@8.13.0(eslint@9.14.0)(typescript@5.6.3))(eslint@9.14.0)(typescript@5.6.3)
|
||||||
'@typescript-eslint/parser':
|
'@typescript-eslint/parser':
|
||||||
specifier: ^8.1.0
|
specifier: ^8.13.0
|
||||||
version: 8.12.2(eslint@9.13.0)(typescript@5.6.3)
|
version: 8.13.0(eslint@9.14.0)(typescript@5.6.3)
|
||||||
eslint:
|
eslint:
|
||||||
specifier: ^9.9.0
|
specifier: ^9.14.0
|
||||||
version: 9.13.0
|
version: 9.14.0
|
||||||
eslint-plugin-prettier:
|
eslint-plugin-prettier:
|
||||||
specifier: ^5.1.3
|
specifier: ^5.1.3
|
||||||
version: 5.2.1(eslint@9.13.0)(prettier@3.3.3)
|
version: 5.2.1(eslint@9.14.0)(prettier@3.3.3)
|
||||||
jest:
|
jest:
|
||||||
specifier: ^29.5.0
|
specifier: ^29.5.0
|
||||||
version: 29.7.0(@types/node@22.8.6)
|
version: 29.7.0(@types/node@22.9.0)
|
||||||
lemmy-js-client:
|
lemmy-js-client:
|
||||||
specifier: 0.20.0-alpha.11
|
specifier: 0.20.0-alpha.18
|
||||||
version: 0.20.0-alpha.11
|
version: 0.20.0-alpha.18
|
||||||
prettier:
|
prettier:
|
||||||
specifier: ^3.2.5
|
specifier: ^3.2.5
|
||||||
version: 3.3.3
|
version: 3.3.3
|
||||||
ts-jest:
|
ts-jest:
|
||||||
specifier: ^29.1.0
|
specifier: ^29.1.0
|
||||||
version: 29.2.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@22.8.6))(typescript@5.6.3)
|
version: 29.2.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@22.9.0))(typescript@5.6.3)
|
||||||
typescript:
|
typescript:
|
||||||
specifier: ^5.5.4
|
specifier: ^5.5.4
|
||||||
version: 5.6.3
|
version: 5.6.3
|
||||||
typescript-eslint:
|
typescript-eslint:
|
||||||
specifier: ^8.1.0
|
specifier: ^8.13.0
|
||||||
version: 8.12.2(eslint@9.13.0)(typescript@5.6.3)
|
version: 8.13.0(eslint@9.14.0)(typescript@5.6.3)
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
|
@ -240,8 +240,8 @@ packages:
|
||||||
resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==}
|
resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
|
|
||||||
'@eslint/js@9.13.0':
|
'@eslint/js@9.14.0':
|
||||||
resolution: {integrity: sha512-IFLyoY4d72Z5y/6o/BazFBezupzI/taV8sGumxTAVw3lXG9A6md1Dc34T9s1FoD/an9pJH8RHbAxsaEbBed9lA==}
|
resolution: {integrity: sha512-pFoEtFWCPyDOl+C6Ift+wC7Ro89otjigCf5vcuWqWgqNSQbRrpjSvdeE6ofLz4dHmyxD5f7gIdGT4+p36L6Twg==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
|
|
||||||
'@eslint/object-schema@2.1.4':
|
'@eslint/object-schema@2.1.4':
|
||||||
|
@ -268,6 +268,10 @@ packages:
|
||||||
resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==}
|
resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==}
|
||||||
engines: {node: '>=18.18'}
|
engines: {node: '>=18.18'}
|
||||||
|
|
||||||
|
'@humanwhocodes/retry@0.4.1':
|
||||||
|
resolution: {integrity: sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==}
|
||||||
|
engines: {node: '>=18.18'}
|
||||||
|
|
||||||
'@istanbuljs/load-nyc-config@1.1.0':
|
'@istanbuljs/load-nyc-config@1.1.0':
|
||||||
resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==}
|
resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
@ -418,8 +422,8 @@ packages:
|
||||||
'@types/json-schema@7.0.15':
|
'@types/json-schema@7.0.15':
|
||||||
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
||||||
|
|
||||||
'@types/node@22.8.6':
|
'@types/node@22.9.0':
|
||||||
resolution: {integrity: sha512-tosuJYKrIqjQIlVCM4PEGxOmyg3FCPa/fViuJChnGeEIhjA46oy8FMVoF9su1/v8PNs2a8Q0iFNyOx0uOF91nw==}
|
resolution: {integrity: sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==}
|
||||||
|
|
||||||
'@types/stack-utils@2.0.3':
|
'@types/stack-utils@2.0.3':
|
||||||
resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==}
|
resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==}
|
||||||
|
@ -430,8 +434,8 @@ packages:
|
||||||
'@types/yargs@17.0.32':
|
'@types/yargs@17.0.32':
|
||||||
resolution: {integrity: sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==}
|
resolution: {integrity: sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==}
|
||||||
|
|
||||||
'@typescript-eslint/eslint-plugin@8.12.2':
|
'@typescript-eslint/eslint-plugin@8.13.0':
|
||||||
resolution: {integrity: sha512-gQxbxM8mcxBwaEmWdtLCIGLfixBMHhQjBqR8sVWNTPpcj45WlYL2IObS/DNMLH1DBP0n8qz+aiiLTGfopPEebw==}
|
resolution: {integrity: sha512-nQtBLiZYMUPkclSeC3id+x4uVd1SGtHuElTxL++SfP47jR0zfkZBJHc+gL4qPsgTuypz0k8Y2GheaDYn6Gy3rg==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0
|
'@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0
|
||||||
|
@ -441,8 +445,8 @@ packages:
|
||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@typescript-eslint/parser@8.12.2':
|
'@typescript-eslint/parser@8.13.0':
|
||||||
resolution: {integrity: sha512-MrvlXNfGPLH3Z+r7Tk+Z5moZAc0dzdVjTgUgwsdGweH7lydysQsnSww3nAmsq8blFuRD5VRlAr9YdEFw3e6PBw==}
|
resolution: {integrity: sha512-w0xp+xGg8u/nONcGw1UXAr6cjCPU1w0XVyBs6Zqaj5eLmxkKQAByTdV/uGgNN5tVvN/kKpoQlP2cL7R+ajZZIQ==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: ^8.57.0 || ^9.0.0
|
eslint: ^8.57.0 || ^9.0.0
|
||||||
|
@ -451,12 +455,12 @@ packages:
|
||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@typescript-eslint/scope-manager@8.12.2':
|
'@typescript-eslint/scope-manager@8.13.0':
|
||||||
resolution: {integrity: sha512-gPLpLtrj9aMHOvxJkSbDBmbRuYdtiEbnvO25bCMza3DhMjTQw0u7Y1M+YR5JPbMsXXnSPuCf5hfq0nEkQDL/JQ==}
|
resolution: {integrity: sha512-XsGWww0odcUT0gJoBZ1DeulY1+jkaHUciUq4jKNv4cpInbvvrtDoyBH9rE/n2V29wQJPk8iCH1wipra9BhmiMA==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
|
|
||||||
'@typescript-eslint/type-utils@8.12.2':
|
'@typescript-eslint/type-utils@8.13.0':
|
||||||
resolution: {integrity: sha512-bwuU4TAogPI+1q/IJSKuD4shBLc/d2vGcRT588q+jzayQyjVK2X6v/fbR4InY2U2sgf8MEvVCqEWUzYzgBNcGQ==}
|
resolution: {integrity: sha512-Rqnn6xXTR316fP4D2pohZenJnp+NwQ1mo7/JM+J1LWZENSLkJI8ID8QNtlvFeb0HnFSK94D6q0cnMX6SbE5/vA==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
typescript: '*'
|
typescript: '*'
|
||||||
|
@ -464,12 +468,12 @@ packages:
|
||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@typescript-eslint/types@8.12.2':
|
'@typescript-eslint/types@8.13.0':
|
||||||
resolution: {integrity: sha512-VwDwMF1SZ7wPBUZwmMdnDJ6sIFk4K4s+ALKLP6aIQsISkPv8jhiw65sAK6SuWODN/ix+m+HgbYDkH+zLjrzvOA==}
|
resolution: {integrity: sha512-4cyFErJetFLckcThRUFdReWJjVsPCqyBlJTi6IDEpc1GWCIIZRFxVppjWLIMcQhNGhdWJJRYFHpHoDWvMlDzng==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
|
|
||||||
'@typescript-eslint/typescript-estree@8.12.2':
|
'@typescript-eslint/typescript-estree@8.13.0':
|
||||||
resolution: {integrity: sha512-mME5MDwGe30Pq9zKPvyduyU86PH7aixwqYR2grTglAdB+AN8xXQ1vFGpYaUSJ5o5P/5znsSBeNcs5g5/2aQwow==}
|
resolution: {integrity: sha512-v7SCIGmVsRK2Cy/LTLGN22uea6SaUIlpBcO/gnMGT/7zPtxp90bphcGf4fyrCQl3ZtiBKqVTG32hb668oIYy1g==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
typescript: '*'
|
typescript: '*'
|
||||||
|
@ -477,14 +481,14 @@ packages:
|
||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@typescript-eslint/utils@8.12.2':
|
'@typescript-eslint/utils@8.13.0':
|
||||||
resolution: {integrity: sha512-UTTuDIX3fkfAz6iSVa5rTuSfWIYZ6ATtEocQ/umkRSyC9O919lbZ8dcH7mysshrCdrAM03skJOEYaBugxN+M6A==}
|
resolution: {integrity: sha512-A1EeYOND6Uv250nybnLZapeXpYMl8tkzYUxqmoKAWnI4sei3ihf2XdZVd+vVOmHGcp3t+P7yRrNsyyiXTvShFQ==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: ^8.57.0 || ^9.0.0
|
eslint: ^8.57.0 || ^9.0.0
|
||||||
|
|
||||||
'@typescript-eslint/visitor-keys@8.12.2':
|
'@typescript-eslint/visitor-keys@8.13.0':
|
||||||
resolution: {integrity: sha512-PChz8UaKQAVNHghsHcPyx1OMHoFRUEA7rJSK/mDhdq85bk+PLsUHUBqTQTFt18VJZbmxBovM65fezlheQRsSDA==}
|
resolution: {integrity: sha512-7N/+lztJqH4Mrf0lb10R/CbI1EaAMMGyF5y0oJvFoAhafwgiRA7TXyd8TFn8FC8k5y2dTsYogg238qavRGNnlw==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
|
|
||||||
acorn-jsx@5.3.2:
|
acorn-jsx@5.3.2:
|
||||||
|
@ -649,6 +653,10 @@ packages:
|
||||||
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
|
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
|
|
||||||
|
cross-spawn@7.0.5:
|
||||||
|
resolution: {integrity: sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==}
|
||||||
|
engines: {node: '>= 8'}
|
||||||
|
|
||||||
debug@4.3.7:
|
debug@4.3.7:
|
||||||
resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==}
|
resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==}
|
||||||
engines: {node: '>=6.0'}
|
engines: {node: '>=6.0'}
|
||||||
|
@ -737,8 +745,8 @@ packages:
|
||||||
resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==}
|
resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
|
|
||||||
eslint@9.13.0:
|
eslint@9.14.0:
|
||||||
resolution: {integrity: sha512-EYZK6SX6zjFHST/HRytOdA/zE72Cq/bfw45LSyuwrdvcclb/gqV8RRQxywOBEWO2+WDpva6UZa4CcDeJKzUCFA==}
|
resolution: {integrity: sha512-c2FHsVBr87lnUtjP4Yhvk4yEhKrQavGafRA/Se1ouse8PfbfC/Qh9Mxa00yWsZRlqeUB9raXip0aiiUZkgnr9g==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -1159,8 +1167,8 @@ packages:
|
||||||
resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
|
resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
lemmy-js-client@0.20.0-alpha.11:
|
lemmy-js-client@0.20.0-alpha.18:
|
||||||
resolution: {integrity: sha512-iRSG4xHMjPDIreQqVIoJ5JrMY71uk07G0Zbgyf068xKbib22J3+i1x/XgCTs6tiHlqTnw1Ig/KRq7p7qJoA4uw==}
|
resolution: {integrity: sha512-oZy8DboTWfUar4mPWpi7SYrOEjTBJxkvd1e6QaVwoA5UhqQV1WhxEYbzrpi/gXnEokaVQ0i5sjtL/Y2PHMO3MQ==}
|
||||||
|
|
||||||
leven@3.1.0:
|
leven@3.1.0:
|
||||||
resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==}
|
resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==}
|
||||||
|
@ -1533,8 +1541,8 @@ packages:
|
||||||
resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
|
resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
typescript-eslint@8.12.2:
|
typescript-eslint@8.13.0:
|
||||||
resolution: {integrity: sha512-UbuVUWSrHVR03q9CWx+JDHeO6B/Hr9p4U5lRH++5tq/EbFq1faYZe50ZSBePptgfIKLEti0aPQ3hFgnPVcd8ZQ==}
|
resolution: {integrity: sha512-vIMpDRJrQd70au2G8w34mPps0ezFSPMEX4pXkTzUkrNbRX+36ais2ksGWN0esZL+ZMaFJEneOBHzCgSqle7DHw==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
typescript: '*'
|
typescript: '*'
|
||||||
|
@ -1808,9 +1816,9 @@ snapshots:
|
||||||
|
|
||||||
'@bcoe/v8-coverage@0.2.3': {}
|
'@bcoe/v8-coverage@0.2.3': {}
|
||||||
|
|
||||||
'@eslint-community/eslint-utils@4.4.1(eslint@9.13.0)':
|
'@eslint-community/eslint-utils@4.4.1(eslint@9.14.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint: 9.13.0
|
eslint: 9.14.0
|
||||||
eslint-visitor-keys: 3.4.3
|
eslint-visitor-keys: 3.4.3
|
||||||
|
|
||||||
'@eslint-community/regexpp@4.12.1': {}
|
'@eslint-community/regexpp@4.12.1': {}
|
||||||
|
@ -1839,7 +1847,7 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@eslint/js@9.13.0': {}
|
'@eslint/js@9.14.0': {}
|
||||||
|
|
||||||
'@eslint/object-schema@2.1.4': {}
|
'@eslint/object-schema@2.1.4': {}
|
||||||
|
|
||||||
|
@ -1858,6 +1866,8 @@ snapshots:
|
||||||
|
|
||||||
'@humanwhocodes/retry@0.3.1': {}
|
'@humanwhocodes/retry@0.3.1': {}
|
||||||
|
|
||||||
|
'@humanwhocodes/retry@0.4.1': {}
|
||||||
|
|
||||||
'@istanbuljs/load-nyc-config@1.1.0':
|
'@istanbuljs/load-nyc-config@1.1.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
camelcase: 5.3.1
|
camelcase: 5.3.1
|
||||||
|
@ -1871,7 +1881,7 @@ snapshots:
|
||||||
'@jest/console@29.7.0':
|
'@jest/console@29.7.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jest/types': 29.6.3
|
'@jest/types': 29.6.3
|
||||||
'@types/node': 22.8.6
|
'@types/node': 22.9.0
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
jest-message-util: 29.7.0
|
jest-message-util: 29.7.0
|
||||||
jest-util: 29.7.0
|
jest-util: 29.7.0
|
||||||
|
@ -1884,14 +1894,14 @@ snapshots:
|
||||||
'@jest/test-result': 29.7.0
|
'@jest/test-result': 29.7.0
|
||||||
'@jest/transform': 29.7.0
|
'@jest/transform': 29.7.0
|
||||||
'@jest/types': 29.6.3
|
'@jest/types': 29.6.3
|
||||||
'@types/node': 22.8.6
|
'@types/node': 22.9.0
|
||||||
ansi-escapes: 4.3.2
|
ansi-escapes: 4.3.2
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
ci-info: 3.9.0
|
ci-info: 3.9.0
|
||||||
exit: 0.1.2
|
exit: 0.1.2
|
||||||
graceful-fs: 4.2.11
|
graceful-fs: 4.2.11
|
||||||
jest-changed-files: 29.7.0
|
jest-changed-files: 29.7.0
|
||||||
jest-config: 29.7.0(@types/node@22.8.6)
|
jest-config: 29.7.0(@types/node@22.9.0)
|
||||||
jest-haste-map: 29.7.0
|
jest-haste-map: 29.7.0
|
||||||
jest-message-util: 29.7.0
|
jest-message-util: 29.7.0
|
||||||
jest-regex-util: 29.6.3
|
jest-regex-util: 29.6.3
|
||||||
|
@ -1916,7 +1926,7 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jest/fake-timers': 29.7.0
|
'@jest/fake-timers': 29.7.0
|
||||||
'@jest/types': 29.6.3
|
'@jest/types': 29.6.3
|
||||||
'@types/node': 22.8.6
|
'@types/node': 22.9.0
|
||||||
jest-mock: 29.7.0
|
jest-mock: 29.7.0
|
||||||
|
|
||||||
'@jest/expect-utils@29.7.0':
|
'@jest/expect-utils@29.7.0':
|
||||||
|
@ -1934,7 +1944,7 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jest/types': 29.6.3
|
'@jest/types': 29.6.3
|
||||||
'@sinonjs/fake-timers': 10.3.0
|
'@sinonjs/fake-timers': 10.3.0
|
||||||
'@types/node': 22.8.6
|
'@types/node': 22.9.0
|
||||||
jest-message-util: 29.7.0
|
jest-message-util: 29.7.0
|
||||||
jest-mock: 29.7.0
|
jest-mock: 29.7.0
|
||||||
jest-util: 29.7.0
|
jest-util: 29.7.0
|
||||||
|
@ -1956,7 +1966,7 @@ snapshots:
|
||||||
'@jest/transform': 29.7.0
|
'@jest/transform': 29.7.0
|
||||||
'@jest/types': 29.6.3
|
'@jest/types': 29.6.3
|
||||||
'@jridgewell/trace-mapping': 0.3.22
|
'@jridgewell/trace-mapping': 0.3.22
|
||||||
'@types/node': 22.8.6
|
'@types/node': 22.9.0
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
collect-v8-coverage: 1.0.2
|
collect-v8-coverage: 1.0.2
|
||||||
exit: 0.1.2
|
exit: 0.1.2
|
||||||
|
@ -2026,7 +2036,7 @@ snapshots:
|
||||||
'@jest/schemas': 29.6.3
|
'@jest/schemas': 29.6.3
|
||||||
'@types/istanbul-lib-coverage': 2.0.6
|
'@types/istanbul-lib-coverage': 2.0.6
|
||||||
'@types/istanbul-reports': 3.0.4
|
'@types/istanbul-reports': 3.0.4
|
||||||
'@types/node': 22.8.6
|
'@types/node': 22.9.0
|
||||||
'@types/yargs': 17.0.32
|
'@types/yargs': 17.0.32
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
|
|
||||||
|
@ -2096,7 +2106,7 @@ snapshots:
|
||||||
|
|
||||||
'@types/graceful-fs@4.1.9':
|
'@types/graceful-fs@4.1.9':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 22.8.6
|
'@types/node': 22.9.0
|
||||||
|
|
||||||
'@types/istanbul-lib-coverage@2.0.6': {}
|
'@types/istanbul-lib-coverage@2.0.6': {}
|
||||||
|
|
||||||
|
@ -2115,7 +2125,7 @@ snapshots:
|
||||||
|
|
||||||
'@types/json-schema@7.0.15': {}
|
'@types/json-schema@7.0.15': {}
|
||||||
|
|
||||||
'@types/node@22.8.6':
|
'@types/node@22.9.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 6.19.8
|
undici-types: 6.19.8
|
||||||
|
|
||||||
|
@ -2127,15 +2137,15 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/yargs-parser': 21.0.3
|
'@types/yargs-parser': 21.0.3
|
||||||
|
|
||||||
'@typescript-eslint/eslint-plugin@8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.6.3))(eslint@9.13.0)(typescript@5.6.3)':
|
'@typescript-eslint/eslint-plugin@8.13.0(@typescript-eslint/parser@8.13.0(eslint@9.14.0)(typescript@5.6.3))(eslint@9.14.0)(typescript@5.6.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@eslint-community/regexpp': 4.12.1
|
'@eslint-community/regexpp': 4.12.1
|
||||||
'@typescript-eslint/parser': 8.12.2(eslint@9.13.0)(typescript@5.6.3)
|
'@typescript-eslint/parser': 8.13.0(eslint@9.14.0)(typescript@5.6.3)
|
||||||
'@typescript-eslint/scope-manager': 8.12.2
|
'@typescript-eslint/scope-manager': 8.13.0
|
||||||
'@typescript-eslint/type-utils': 8.12.2(eslint@9.13.0)(typescript@5.6.3)
|
'@typescript-eslint/type-utils': 8.13.0(eslint@9.14.0)(typescript@5.6.3)
|
||||||
'@typescript-eslint/utils': 8.12.2(eslint@9.13.0)(typescript@5.6.3)
|
'@typescript-eslint/utils': 8.13.0(eslint@9.14.0)(typescript@5.6.3)
|
||||||
'@typescript-eslint/visitor-keys': 8.12.2
|
'@typescript-eslint/visitor-keys': 8.13.0
|
||||||
eslint: 9.13.0
|
eslint: 9.14.0
|
||||||
graphemer: 1.4.0
|
graphemer: 1.4.0
|
||||||
ignore: 5.3.2
|
ignore: 5.3.2
|
||||||
natural-compare: 1.4.0
|
natural-compare: 1.4.0
|
||||||
|
@ -2145,28 +2155,28 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.6.3)':
|
'@typescript-eslint/parser@8.13.0(eslint@9.14.0)(typescript@5.6.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/scope-manager': 8.12.2
|
'@typescript-eslint/scope-manager': 8.13.0
|
||||||
'@typescript-eslint/types': 8.12.2
|
'@typescript-eslint/types': 8.13.0
|
||||||
'@typescript-eslint/typescript-estree': 8.12.2(typescript@5.6.3)
|
'@typescript-eslint/typescript-estree': 8.13.0(typescript@5.6.3)
|
||||||
'@typescript-eslint/visitor-keys': 8.12.2
|
'@typescript-eslint/visitor-keys': 8.13.0
|
||||||
debug: 4.3.7
|
debug: 4.3.7
|
||||||
eslint: 9.13.0
|
eslint: 9.14.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
typescript: 5.6.3
|
typescript: 5.6.3
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@typescript-eslint/scope-manager@8.12.2':
|
'@typescript-eslint/scope-manager@8.13.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/types': 8.12.2
|
'@typescript-eslint/types': 8.13.0
|
||||||
'@typescript-eslint/visitor-keys': 8.12.2
|
'@typescript-eslint/visitor-keys': 8.13.0
|
||||||
|
|
||||||
'@typescript-eslint/type-utils@8.12.2(eslint@9.13.0)(typescript@5.6.3)':
|
'@typescript-eslint/type-utils@8.13.0(eslint@9.14.0)(typescript@5.6.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/typescript-estree': 8.12.2(typescript@5.6.3)
|
'@typescript-eslint/typescript-estree': 8.13.0(typescript@5.6.3)
|
||||||
'@typescript-eslint/utils': 8.12.2(eslint@9.13.0)(typescript@5.6.3)
|
'@typescript-eslint/utils': 8.13.0(eslint@9.14.0)(typescript@5.6.3)
|
||||||
debug: 4.3.7
|
debug: 4.3.7
|
||||||
ts-api-utils: 1.4.0(typescript@5.6.3)
|
ts-api-utils: 1.4.0(typescript@5.6.3)
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
|
@ -2175,12 +2185,12 @@ snapshots:
|
||||||
- eslint
|
- eslint
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@typescript-eslint/types@8.12.2': {}
|
'@typescript-eslint/types@8.13.0': {}
|
||||||
|
|
||||||
'@typescript-eslint/typescript-estree@8.12.2(typescript@5.6.3)':
|
'@typescript-eslint/typescript-estree@8.13.0(typescript@5.6.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/types': 8.12.2
|
'@typescript-eslint/types': 8.13.0
|
||||||
'@typescript-eslint/visitor-keys': 8.12.2
|
'@typescript-eslint/visitor-keys': 8.13.0
|
||||||
debug: 4.3.7
|
debug: 4.3.7
|
||||||
fast-glob: 3.3.2
|
fast-glob: 3.3.2
|
||||||
is-glob: 4.0.3
|
is-glob: 4.0.3
|
||||||
|
@ -2192,20 +2202,20 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@typescript-eslint/utils@8.12.2(eslint@9.13.0)(typescript@5.6.3)':
|
'@typescript-eslint/utils@8.13.0(eslint@9.14.0)(typescript@5.6.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@eslint-community/eslint-utils': 4.4.1(eslint@9.13.0)
|
'@eslint-community/eslint-utils': 4.4.1(eslint@9.14.0)
|
||||||
'@typescript-eslint/scope-manager': 8.12.2
|
'@typescript-eslint/scope-manager': 8.13.0
|
||||||
'@typescript-eslint/types': 8.12.2
|
'@typescript-eslint/types': 8.13.0
|
||||||
'@typescript-eslint/typescript-estree': 8.12.2(typescript@5.6.3)
|
'@typescript-eslint/typescript-estree': 8.13.0(typescript@5.6.3)
|
||||||
eslint: 9.13.0
|
eslint: 9.14.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
- typescript
|
- typescript
|
||||||
|
|
||||||
'@typescript-eslint/visitor-keys@8.12.2':
|
'@typescript-eslint/visitor-keys@8.13.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/types': 8.12.2
|
'@typescript-eslint/types': 8.13.0
|
||||||
eslint-visitor-keys: 3.4.3
|
eslint-visitor-keys: 3.4.3
|
||||||
|
|
||||||
acorn-jsx@5.3.2(acorn@8.14.0):
|
acorn-jsx@5.3.2(acorn@8.14.0):
|
||||||
|
@ -2373,13 +2383,13 @@ snapshots:
|
||||||
|
|
||||||
convert-source-map@2.0.0: {}
|
convert-source-map@2.0.0: {}
|
||||||
|
|
||||||
create-jest@29.7.0(@types/node@22.8.6):
|
create-jest@29.7.0(@types/node@22.9.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jest/types': 29.6.3
|
'@jest/types': 29.6.3
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
exit: 0.1.2
|
exit: 0.1.2
|
||||||
graceful-fs: 4.2.11
|
graceful-fs: 4.2.11
|
||||||
jest-config: 29.7.0(@types/node@22.8.6)
|
jest-config: 29.7.0(@types/node@22.9.0)
|
||||||
jest-util: 29.7.0
|
jest-util: 29.7.0
|
||||||
prompts: 2.4.2
|
prompts: 2.4.2
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
|
@ -2394,6 +2404,12 @@ snapshots:
|
||||||
shebang-command: 2.0.0
|
shebang-command: 2.0.0
|
||||||
which: 2.0.2
|
which: 2.0.2
|
||||||
|
|
||||||
|
cross-spawn@7.0.5:
|
||||||
|
dependencies:
|
||||||
|
path-key: 3.1.1
|
||||||
|
shebang-command: 2.0.0
|
||||||
|
which: 2.0.2
|
||||||
|
|
||||||
debug@4.3.7:
|
debug@4.3.7:
|
||||||
dependencies:
|
dependencies:
|
||||||
ms: 2.1.3
|
ms: 2.1.3
|
||||||
|
@ -2428,9 +2444,9 @@ snapshots:
|
||||||
|
|
||||||
escape-string-regexp@4.0.0: {}
|
escape-string-regexp@4.0.0: {}
|
||||||
|
|
||||||
eslint-plugin-prettier@5.2.1(eslint@9.13.0)(prettier@3.3.3):
|
eslint-plugin-prettier@5.2.1(eslint@9.14.0)(prettier@3.3.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint: 9.13.0
|
eslint: 9.14.0
|
||||||
prettier: 3.3.3
|
prettier: 3.3.3
|
||||||
prettier-linter-helpers: 1.0.0
|
prettier-linter-helpers: 1.0.0
|
||||||
synckit: 0.9.1
|
synckit: 0.9.1
|
||||||
|
@ -2444,23 +2460,23 @@ snapshots:
|
||||||
|
|
||||||
eslint-visitor-keys@4.2.0: {}
|
eslint-visitor-keys@4.2.0: {}
|
||||||
|
|
||||||
eslint@9.13.0:
|
eslint@9.14.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@eslint-community/eslint-utils': 4.4.1(eslint@9.13.0)
|
'@eslint-community/eslint-utils': 4.4.1(eslint@9.14.0)
|
||||||
'@eslint-community/regexpp': 4.12.1
|
'@eslint-community/regexpp': 4.12.1
|
||||||
'@eslint/config-array': 0.18.0
|
'@eslint/config-array': 0.18.0
|
||||||
'@eslint/core': 0.7.0
|
'@eslint/core': 0.7.0
|
||||||
'@eslint/eslintrc': 3.1.0
|
'@eslint/eslintrc': 3.1.0
|
||||||
'@eslint/js': 9.13.0
|
'@eslint/js': 9.14.0
|
||||||
'@eslint/plugin-kit': 0.2.2
|
'@eslint/plugin-kit': 0.2.2
|
||||||
'@humanfs/node': 0.16.6
|
'@humanfs/node': 0.16.6
|
||||||
'@humanwhocodes/module-importer': 1.0.1
|
'@humanwhocodes/module-importer': 1.0.1
|
||||||
'@humanwhocodes/retry': 0.3.1
|
'@humanwhocodes/retry': 0.4.1
|
||||||
'@types/estree': 1.0.6
|
'@types/estree': 1.0.6
|
||||||
'@types/json-schema': 7.0.15
|
'@types/json-schema': 7.0.15
|
||||||
ajv: 6.12.6
|
ajv: 6.12.6
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
cross-spawn: 7.0.3
|
cross-spawn: 7.0.5
|
||||||
debug: 4.3.7
|
debug: 4.3.7
|
||||||
escape-string-regexp: 4.0.0
|
escape-string-regexp: 4.0.0
|
||||||
eslint-scope: 8.2.0
|
eslint-scope: 8.2.0
|
||||||
|
@ -2736,7 +2752,7 @@ snapshots:
|
||||||
'@jest/expect': 29.7.0
|
'@jest/expect': 29.7.0
|
||||||
'@jest/test-result': 29.7.0
|
'@jest/test-result': 29.7.0
|
||||||
'@jest/types': 29.6.3
|
'@jest/types': 29.6.3
|
||||||
'@types/node': 22.8.6
|
'@types/node': 22.9.0
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
co: 4.6.0
|
co: 4.6.0
|
||||||
dedent: 1.5.1
|
dedent: 1.5.1
|
||||||
|
@ -2756,16 +2772,16 @@ snapshots:
|
||||||
- babel-plugin-macros
|
- babel-plugin-macros
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
jest-cli@29.7.0(@types/node@22.8.6):
|
jest-cli@29.7.0(@types/node@22.9.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jest/core': 29.7.0
|
'@jest/core': 29.7.0
|
||||||
'@jest/test-result': 29.7.0
|
'@jest/test-result': 29.7.0
|
||||||
'@jest/types': 29.6.3
|
'@jest/types': 29.6.3
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
create-jest: 29.7.0(@types/node@22.8.6)
|
create-jest: 29.7.0(@types/node@22.9.0)
|
||||||
exit: 0.1.2
|
exit: 0.1.2
|
||||||
import-local: 3.1.0
|
import-local: 3.1.0
|
||||||
jest-config: 29.7.0(@types/node@22.8.6)
|
jest-config: 29.7.0(@types/node@22.9.0)
|
||||||
jest-util: 29.7.0
|
jest-util: 29.7.0
|
||||||
jest-validate: 29.7.0
|
jest-validate: 29.7.0
|
||||||
yargs: 17.7.2
|
yargs: 17.7.2
|
||||||
|
@ -2775,7 +2791,7 @@ snapshots:
|
||||||
- supports-color
|
- supports-color
|
||||||
- ts-node
|
- ts-node
|
||||||
|
|
||||||
jest-config@29.7.0(@types/node@22.8.6):
|
jest-config@29.7.0(@types/node@22.9.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.23.9
|
'@babel/core': 7.23.9
|
||||||
'@jest/test-sequencer': 29.7.0
|
'@jest/test-sequencer': 29.7.0
|
||||||
|
@ -2800,7 +2816,7 @@ snapshots:
|
||||||
slash: 3.0.0
|
slash: 3.0.0
|
||||||
strip-json-comments: 3.1.1
|
strip-json-comments: 3.1.1
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@types/node': 22.8.6
|
'@types/node': 22.9.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- babel-plugin-macros
|
- babel-plugin-macros
|
||||||
- supports-color
|
- supports-color
|
||||||
|
@ -2829,7 +2845,7 @@ snapshots:
|
||||||
'@jest/environment': 29.7.0
|
'@jest/environment': 29.7.0
|
||||||
'@jest/fake-timers': 29.7.0
|
'@jest/fake-timers': 29.7.0
|
||||||
'@jest/types': 29.6.3
|
'@jest/types': 29.6.3
|
||||||
'@types/node': 22.8.6
|
'@types/node': 22.9.0
|
||||||
jest-mock: 29.7.0
|
jest-mock: 29.7.0
|
||||||
jest-util: 29.7.0
|
jest-util: 29.7.0
|
||||||
|
|
||||||
|
@ -2839,7 +2855,7 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jest/types': 29.6.3
|
'@jest/types': 29.6.3
|
||||||
'@types/graceful-fs': 4.1.9
|
'@types/graceful-fs': 4.1.9
|
||||||
'@types/node': 22.8.6
|
'@types/node': 22.9.0
|
||||||
anymatch: 3.1.3
|
anymatch: 3.1.3
|
||||||
fb-watchman: 2.0.2
|
fb-watchman: 2.0.2
|
||||||
graceful-fs: 4.2.11
|
graceful-fs: 4.2.11
|
||||||
|
@ -2878,7 +2894,7 @@ snapshots:
|
||||||
jest-mock@29.7.0:
|
jest-mock@29.7.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jest/types': 29.6.3
|
'@jest/types': 29.6.3
|
||||||
'@types/node': 22.8.6
|
'@types/node': 22.9.0
|
||||||
jest-util: 29.7.0
|
jest-util: 29.7.0
|
||||||
|
|
||||||
jest-pnp-resolver@1.2.3(jest-resolve@29.7.0):
|
jest-pnp-resolver@1.2.3(jest-resolve@29.7.0):
|
||||||
|
@ -2913,7 +2929,7 @@ snapshots:
|
||||||
'@jest/test-result': 29.7.0
|
'@jest/test-result': 29.7.0
|
||||||
'@jest/transform': 29.7.0
|
'@jest/transform': 29.7.0
|
||||||
'@jest/types': 29.6.3
|
'@jest/types': 29.6.3
|
||||||
'@types/node': 22.8.6
|
'@types/node': 22.9.0
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
emittery: 0.13.1
|
emittery: 0.13.1
|
||||||
graceful-fs: 4.2.11
|
graceful-fs: 4.2.11
|
||||||
|
@ -2941,7 +2957,7 @@ snapshots:
|
||||||
'@jest/test-result': 29.7.0
|
'@jest/test-result': 29.7.0
|
||||||
'@jest/transform': 29.7.0
|
'@jest/transform': 29.7.0
|
||||||
'@jest/types': 29.6.3
|
'@jest/types': 29.6.3
|
||||||
'@types/node': 22.8.6
|
'@types/node': 22.9.0
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
cjs-module-lexer: 1.2.3
|
cjs-module-lexer: 1.2.3
|
||||||
collect-v8-coverage: 1.0.2
|
collect-v8-coverage: 1.0.2
|
||||||
|
@ -2987,7 +3003,7 @@ snapshots:
|
||||||
jest-util@29.7.0:
|
jest-util@29.7.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jest/types': 29.6.3
|
'@jest/types': 29.6.3
|
||||||
'@types/node': 22.8.6
|
'@types/node': 22.9.0
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
ci-info: 3.9.0
|
ci-info: 3.9.0
|
||||||
graceful-fs: 4.2.11
|
graceful-fs: 4.2.11
|
||||||
|
@ -3006,7 +3022,7 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jest/test-result': 29.7.0
|
'@jest/test-result': 29.7.0
|
||||||
'@jest/types': 29.6.3
|
'@jest/types': 29.6.3
|
||||||
'@types/node': 22.8.6
|
'@types/node': 22.9.0
|
||||||
ansi-escapes: 4.3.2
|
ansi-escapes: 4.3.2
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
emittery: 0.13.1
|
emittery: 0.13.1
|
||||||
|
@ -3015,17 +3031,17 @@ snapshots:
|
||||||
|
|
||||||
jest-worker@29.7.0:
|
jest-worker@29.7.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 22.8.6
|
'@types/node': 22.9.0
|
||||||
jest-util: 29.7.0
|
jest-util: 29.7.0
|
||||||
merge-stream: 2.0.0
|
merge-stream: 2.0.0
|
||||||
supports-color: 8.1.1
|
supports-color: 8.1.1
|
||||||
|
|
||||||
jest@29.7.0(@types/node@22.8.6):
|
jest@29.7.0(@types/node@22.9.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jest/core': 29.7.0
|
'@jest/core': 29.7.0
|
||||||
'@jest/types': 29.6.3
|
'@jest/types': 29.6.3
|
||||||
import-local: 3.1.0
|
import-local: 3.1.0
|
||||||
jest-cli: 29.7.0(@types/node@22.8.6)
|
jest-cli: 29.7.0(@types/node@22.9.0)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@types/node'
|
- '@types/node'
|
||||||
- babel-plugin-macros
|
- babel-plugin-macros
|
||||||
|
@ -3061,7 +3077,7 @@ snapshots:
|
||||||
|
|
||||||
kleur@3.0.3: {}
|
kleur@3.0.3: {}
|
||||||
|
|
||||||
lemmy-js-client@0.20.0-alpha.11: {}
|
lemmy-js-client@0.20.0-alpha.18: {}
|
||||||
|
|
||||||
leven@3.1.0: {}
|
leven@3.1.0: {}
|
||||||
|
|
||||||
|
@ -3342,12 +3358,12 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
typescript: 5.6.3
|
typescript: 5.6.3
|
||||||
|
|
||||||
ts-jest@29.2.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@22.8.6))(typescript@5.6.3):
|
ts-jest@29.2.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@22.9.0))(typescript@5.6.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
bs-logger: 0.2.6
|
bs-logger: 0.2.6
|
||||||
ejs: 3.1.10
|
ejs: 3.1.10
|
||||||
fast-json-stable-stringify: 2.1.0
|
fast-json-stable-stringify: 2.1.0
|
||||||
jest: 29.7.0(@types/node@22.8.6)
|
jest: 29.7.0(@types/node@22.9.0)
|
||||||
jest-util: 29.7.0
|
jest-util: 29.7.0
|
||||||
json5: 2.2.3
|
json5: 2.2.3
|
||||||
lodash.memoize: 4.1.2
|
lodash.memoize: 4.1.2
|
||||||
|
@ -3371,11 +3387,11 @@ snapshots:
|
||||||
|
|
||||||
type-fest@0.21.3: {}
|
type-fest@0.21.3: {}
|
||||||
|
|
||||||
typescript-eslint@8.12.2(eslint@9.13.0)(typescript@5.6.3):
|
typescript-eslint@8.13.0(eslint@9.14.0)(typescript@5.6.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/eslint-plugin': 8.12.2(@typescript-eslint/parser@8.12.2(eslint@9.13.0)(typescript@5.6.3))(eslint@9.13.0)(typescript@5.6.3)
|
'@typescript-eslint/eslint-plugin': 8.13.0(@typescript-eslint/parser@8.13.0(eslint@9.14.0)(typescript@5.6.3))(eslint@9.14.0)(typescript@5.6.3)
|
||||||
'@typescript-eslint/parser': 8.12.2(eslint@9.13.0)(typescript@5.6.3)
|
'@typescript-eslint/parser': 8.13.0(eslint@9.14.0)(typescript@5.6.3)
|
||||||
'@typescript-eslint/utils': 8.12.2(eslint@9.13.0)(typescript@5.6.3)
|
'@typescript-eslint/utils': 8.13.0(eslint@9.14.0)(typescript@5.6.3)
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
typescript: 5.6.3
|
typescript: 5.6.3
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
|
|
214
api_tests/src/private_community.spec.ts
Normal file
214
api_tests/src/private_community.spec.ts
Normal file
|
@ -0,0 +1,214 @@
|
||||||
|
jest.setTimeout(120000);
|
||||||
|
|
||||||
|
import { FollowCommunity } from "lemmy-js-client";
|
||||||
|
import {
|
||||||
|
alpha,
|
||||||
|
setupLogins,
|
||||||
|
createCommunity,
|
||||||
|
unfollows,
|
||||||
|
registerUser,
|
||||||
|
listCommunityPendingFollows,
|
||||||
|
getCommunity,
|
||||||
|
getCommunityPendingFollowsCount,
|
||||||
|
approveCommunityPendingFollow,
|
||||||
|
randomString,
|
||||||
|
createPost,
|
||||||
|
createComment,
|
||||||
|
beta,
|
||||||
|
resolveCommunity,
|
||||||
|
betaUrl,
|
||||||
|
resolvePost,
|
||||||
|
resolveComment,
|
||||||
|
likeComment,
|
||||||
|
waitUntil,
|
||||||
|
} from "./shared";
|
||||||
|
|
||||||
|
beforeAll(setupLogins);
|
||||||
|
afterAll(unfollows);
|
||||||
|
|
||||||
|
test("Follow a private community", async () => {
|
||||||
|
// create private community
|
||||||
|
const community = await createCommunity(alpha, randomString(10), "Private");
|
||||||
|
expect(community.community_view.community.visibility).toBe("Private");
|
||||||
|
const alphaCommunityId = community.community_view.community.id;
|
||||||
|
|
||||||
|
// No pending follows yet
|
||||||
|
const pendingFollows0 = await listCommunityPendingFollows(alpha);
|
||||||
|
expect(pendingFollows0.items.length).toBe(0);
|
||||||
|
const pendingFollowsCount0 = await getCommunityPendingFollowsCount(
|
||||||
|
alpha,
|
||||||
|
alphaCommunityId,
|
||||||
|
);
|
||||||
|
expect(pendingFollowsCount0.count).toBe(0);
|
||||||
|
|
||||||
|
// follow as new user
|
||||||
|
const user = await registerUser(beta, betaUrl);
|
||||||
|
const betaCommunity = (
|
||||||
|
await resolveCommunity(user, community.community_view.community.actor_id)
|
||||||
|
).community;
|
||||||
|
expect(betaCommunity).toBeDefined();
|
||||||
|
const betaCommunityId = betaCommunity!.community.id;
|
||||||
|
const follow_form: FollowCommunity = {
|
||||||
|
community_id: betaCommunityId,
|
||||||
|
follow: true,
|
||||||
|
};
|
||||||
|
await user.followCommunity(follow_form);
|
||||||
|
|
||||||
|
// Follow listed as pending
|
||||||
|
const follow1 = await getCommunity(user, betaCommunityId);
|
||||||
|
expect(follow1.community_view.subscribed).toBe("ApprovalRequired");
|
||||||
|
|
||||||
|
// Wait for follow to federate, shown as pending
|
||||||
|
let pendingFollows1 = await waitUntil(
|
||||||
|
() => listCommunityPendingFollows(alpha),
|
||||||
|
f => f.items.length == 1,
|
||||||
|
);
|
||||||
|
expect(pendingFollows1.items[0].is_new_instance).toBe(true);
|
||||||
|
const pendingFollowsCount1 = await getCommunityPendingFollowsCount(
|
||||||
|
alpha,
|
||||||
|
alphaCommunityId,
|
||||||
|
);
|
||||||
|
expect(pendingFollowsCount1.count).toBe(1);
|
||||||
|
|
||||||
|
// user still sees approval required at this point
|
||||||
|
const betaCommunity2 = await getCommunity(user, betaCommunityId);
|
||||||
|
expect(betaCommunity2.community_view.subscribed).toBe("ApprovalRequired");
|
||||||
|
|
||||||
|
// Approve the follow
|
||||||
|
const approve = await approveCommunityPendingFollow(
|
||||||
|
alpha,
|
||||||
|
alphaCommunityId,
|
||||||
|
pendingFollows1.items[0].person.id,
|
||||||
|
);
|
||||||
|
expect(approve.success).toBe(true);
|
||||||
|
|
||||||
|
// Follow is confirmed
|
||||||
|
await waitUntil(
|
||||||
|
() => getCommunity(user, betaCommunityId),
|
||||||
|
c => c.community_view.subscribed == "Subscribed",
|
||||||
|
);
|
||||||
|
const pendingFollows2 = await listCommunityPendingFollows(alpha);
|
||||||
|
expect(pendingFollows2.items.length).toBe(0);
|
||||||
|
const pendingFollowsCount2 = await getCommunityPendingFollowsCount(
|
||||||
|
alpha,
|
||||||
|
alphaCommunityId,
|
||||||
|
);
|
||||||
|
expect(pendingFollowsCount2.count).toBe(0);
|
||||||
|
|
||||||
|
// follow with another user from that instance, is_new_instance should be false now
|
||||||
|
const user2 = await registerUser(beta, betaUrl);
|
||||||
|
await user2.followCommunity(follow_form);
|
||||||
|
let pendingFollows3 = await waitUntil(
|
||||||
|
() => listCommunityPendingFollows(alpha),
|
||||||
|
f => f.items.length == 1,
|
||||||
|
);
|
||||||
|
expect(pendingFollows3.items[0].is_new_instance).toBe(false);
|
||||||
|
|
||||||
|
// cleanup pending follow
|
||||||
|
const approve2 = await approveCommunityPendingFollow(
|
||||||
|
alpha,
|
||||||
|
alphaCommunityId,
|
||||||
|
pendingFollows3.items[0].person.id,
|
||||||
|
);
|
||||||
|
expect(approve2.success).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Only followers can view and interact with private community content", async () => {
|
||||||
|
// create private community
|
||||||
|
const community = await createCommunity(alpha, randomString(10), "Private");
|
||||||
|
expect(community.community_view.community.visibility).toBe("Private");
|
||||||
|
const alphaCommunityId = community.community_view.community.id;
|
||||||
|
|
||||||
|
// create post and comment
|
||||||
|
const post0 = await createPost(alpha, alphaCommunityId);
|
||||||
|
const post_id = post0.post_view.post.id;
|
||||||
|
expect(post_id).toBeDefined();
|
||||||
|
const comment = await createComment(alpha, post_id);
|
||||||
|
const comment_id = comment.comment_view.comment.id;
|
||||||
|
expect(comment_id).toBeDefined();
|
||||||
|
|
||||||
|
// user is not following the community and cannot view nor create posts
|
||||||
|
const user = await registerUser(beta, betaUrl);
|
||||||
|
const betaCommunity = (
|
||||||
|
await resolveCommunity(user, community.community_view.community.actor_id)
|
||||||
|
).community!.community;
|
||||||
|
await expect(resolvePost(user, post0.post_view.post)).rejects.toStrictEqual(
|
||||||
|
Error("not_found"),
|
||||||
|
);
|
||||||
|
await expect(
|
||||||
|
resolveComment(user, comment.comment_view.comment),
|
||||||
|
).rejects.toStrictEqual(Error("not_found"));
|
||||||
|
await expect(createPost(user, betaCommunity.id)).rejects.toStrictEqual(
|
||||||
|
Error("not_found"),
|
||||||
|
);
|
||||||
|
|
||||||
|
// follow the community and approve
|
||||||
|
const follow_form: FollowCommunity = {
|
||||||
|
community_id: betaCommunity.id,
|
||||||
|
follow: true,
|
||||||
|
};
|
||||||
|
await user.followCommunity(follow_form);
|
||||||
|
const pendingFollows1 = await waitUntil(
|
||||||
|
() => listCommunityPendingFollows(alpha),
|
||||||
|
f => f.items.length == 1,
|
||||||
|
);
|
||||||
|
const approve = await approveCommunityPendingFollow(
|
||||||
|
alpha,
|
||||||
|
alphaCommunityId,
|
||||||
|
pendingFollows1.items[0].person.id,
|
||||||
|
);
|
||||||
|
expect(approve.success).toBe(true);
|
||||||
|
|
||||||
|
// now user can fetch posts and comments in community (using signed fetch), and create posts
|
||||||
|
await waitUntil(
|
||||||
|
() => resolvePost(user, post0.post_view.post),
|
||||||
|
p => p?.post?.post.id != undefined,
|
||||||
|
);
|
||||||
|
const resolvedComment = (
|
||||||
|
await resolveComment(user, comment.comment_view.comment)
|
||||||
|
).comment;
|
||||||
|
expect(resolvedComment?.comment.id).toBeDefined();
|
||||||
|
|
||||||
|
const post1 = await createPost(user, betaCommunity.id);
|
||||||
|
expect(post1.post_view).toBeDefined();
|
||||||
|
const like = await likeComment(user, 1, resolvedComment!.comment);
|
||||||
|
expect(like.comment_view.my_vote).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Reject follower", async () => {
|
||||||
|
// create private community
|
||||||
|
const community = await createCommunity(alpha, randomString(10), "Private");
|
||||||
|
expect(community.community_view.community.visibility).toBe("Private");
|
||||||
|
const alphaCommunityId = community.community_view.community.id;
|
||||||
|
|
||||||
|
// user is not following the community and cannot view nor create posts
|
||||||
|
const user = await registerUser(beta, betaUrl);
|
||||||
|
const betaCommunity1 = (
|
||||||
|
await resolveCommunity(user, community.community_view.community.actor_id)
|
||||||
|
).community!.community;
|
||||||
|
|
||||||
|
// follow the community and reject
|
||||||
|
const follow_form: FollowCommunity = {
|
||||||
|
community_id: betaCommunity1.id,
|
||||||
|
follow: true,
|
||||||
|
};
|
||||||
|
const follow = await user.followCommunity(follow_form);
|
||||||
|
expect(follow.community_view.subscribed).toBe("ApprovalRequired");
|
||||||
|
|
||||||
|
const pendingFollows1 = await waitUntil(
|
||||||
|
() => listCommunityPendingFollows(alpha),
|
||||||
|
f => f.items.length == 1,
|
||||||
|
);
|
||||||
|
const approve = await approveCommunityPendingFollow(
|
||||||
|
alpha,
|
||||||
|
alphaCommunityId,
|
||||||
|
pendingFollows1.items[0].person.id,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
expect(approve.success).toBe(true);
|
||||||
|
|
||||||
|
await waitUntil(
|
||||||
|
() => getCommunity(user, betaCommunity1.id),
|
||||||
|
c => c.community_view.subscribed == "NotSubscribed",
|
||||||
|
);
|
||||||
|
});
|
|
@ -1,17 +1,23 @@
|
||||||
import {
|
import {
|
||||||
|
ApproveCommunityPendingFollower,
|
||||||
BlockCommunity,
|
BlockCommunity,
|
||||||
BlockCommunityResponse,
|
BlockCommunityResponse,
|
||||||
BlockInstance,
|
BlockInstance,
|
||||||
BlockInstanceResponse,
|
BlockInstanceResponse,
|
||||||
CommunityId,
|
CommunityId,
|
||||||
|
CommunityVisibility,
|
||||||
CreatePrivateMessageReport,
|
CreatePrivateMessageReport,
|
||||||
DeleteImage,
|
DeleteImage,
|
||||||
EditCommunity,
|
EditCommunity,
|
||||||
|
GetCommunityPendingFollowsCountResponse,
|
||||||
GetReplies,
|
GetReplies,
|
||||||
GetRepliesResponse,
|
GetRepliesResponse,
|
||||||
GetUnreadCountResponse,
|
GetUnreadCountResponse,
|
||||||
InstanceId,
|
InstanceId,
|
||||||
LemmyHttp,
|
LemmyHttp,
|
||||||
|
ListCommunityPendingFollows,
|
||||||
|
ListCommunityPendingFollowsResponse,
|
||||||
|
PersonId,
|
||||||
PostView,
|
PostView,
|
||||||
PrivateMessageReportResponse,
|
PrivateMessageReportResponse,
|
||||||
SuccessResponse,
|
SuccessResponse,
|
||||||
|
@ -198,7 +204,7 @@ export async function setupLogins() {
|
||||||
// only needed the first time so do in this try
|
// only needed the first time so do in this try
|
||||||
await delay(10_000);
|
await delay(10_000);
|
||||||
} catch {
|
} catch {
|
||||||
console.log("Communities already exist");
|
//console.log("Communities already exist");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -554,12 +560,14 @@ export async function likeComment(
|
||||||
export async function createCommunity(
|
export async function createCommunity(
|
||||||
api: LemmyHttp,
|
api: LemmyHttp,
|
||||||
name_: string = randomString(10),
|
name_: string = randomString(10),
|
||||||
|
visibility: CommunityVisibility = "Public",
|
||||||
): Promise<CommunityResponse> {
|
): Promise<CommunityResponse> {
|
||||||
let description = "a sample description";
|
let description = "a sample description";
|
||||||
let form: CreateCommunity = {
|
let form: CreateCommunity = {
|
||||||
name: name_,
|
name: name_,
|
||||||
title: name_,
|
title: name_,
|
||||||
description,
|
description,
|
||||||
|
visibility,
|
||||||
};
|
};
|
||||||
return api.createCommunity(form);
|
return api.createCommunity(form);
|
||||||
}
|
}
|
||||||
|
@ -688,7 +696,6 @@ export async function saveUserSettingsBio(
|
||||||
let form: SaveUserSettings = {
|
let form: SaveUserSettings = {
|
||||||
show_nsfw: true,
|
show_nsfw: true,
|
||||||
blur_nsfw: false,
|
blur_nsfw: false,
|
||||||
auto_expand: true,
|
|
||||||
theme: "darkly",
|
theme: "darkly",
|
||||||
default_post_sort_type: "Active",
|
default_post_sort_type: "Active",
|
||||||
default_listing_type: "All",
|
default_listing_type: "All",
|
||||||
|
@ -709,7 +716,6 @@ export async function saveUserSettingsFederated(
|
||||||
let form: SaveUserSettings = {
|
let form: SaveUserSettings = {
|
||||||
show_nsfw: false,
|
show_nsfw: false,
|
||||||
blur_nsfw: true,
|
blur_nsfw: true,
|
||||||
auto_expand: false,
|
|
||||||
default_post_sort_type: "Hot",
|
default_post_sort_type: "Hot",
|
||||||
default_listing_type: "All",
|
default_listing_type: "All",
|
||||||
interface_language: "",
|
interface_language: "",
|
||||||
|
@ -872,6 +878,39 @@ export function blockCommunity(
|
||||||
return api.blockCommunity(form);
|
return api.blockCommunity(form);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function listCommunityPendingFollows(
|
||||||
|
api: LemmyHttp,
|
||||||
|
): Promise<ListCommunityPendingFollowsResponse> {
|
||||||
|
let form: ListCommunityPendingFollows = {
|
||||||
|
pending_only: true,
|
||||||
|
all_communities: false,
|
||||||
|
page: 1,
|
||||||
|
limit: 50,
|
||||||
|
};
|
||||||
|
return api.listCommunityPendingFollows(form);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCommunityPendingFollowsCount(
|
||||||
|
api: LemmyHttp,
|
||||||
|
community_id: CommunityId,
|
||||||
|
): Promise<GetCommunityPendingFollowsCountResponse> {
|
||||||
|
return api.getCommunityPendingFollowsCount(community_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function approveCommunityPendingFollow(
|
||||||
|
api: LemmyHttp,
|
||||||
|
community_id: CommunityId,
|
||||||
|
follower_id: PersonId,
|
||||||
|
approve: boolean = true,
|
||||||
|
): Promise<SuccessResponse> {
|
||||||
|
let form: ApproveCommunityPendingFollower = {
|
||||||
|
community_id,
|
||||||
|
follower_id,
|
||||||
|
approve,
|
||||||
|
};
|
||||||
|
return api.approveCommunityPendingFollow(form);
|
||||||
|
}
|
||||||
|
|
||||||
export function delay(millis = 500) {
|
export function delay(millis = 500) {
|
||||||
return new Promise(resolve => setTimeout(resolve, millis));
|
return new Promise(resolve => setTimeout(resolve, millis));
|
||||||
}
|
}
|
||||||
|
@ -948,7 +987,7 @@ export function getCommentParentId(comment: Comment): number | undefined {
|
||||||
if (split.length > 1) {
|
if (split.length > 1) {
|
||||||
return Number(split[split.length - 2]);
|
return Number(split[split.length - 2]);
|
||||||
} else {
|
} else {
|
||||||
console.log(`Failed to extract comment parent id from ${comment.path}`);
|
console.error(`Failed to extract comment parent id from ${comment.path}`);
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -962,8 +1001,12 @@ export async function waitUntil<T>(
|
||||||
let retry = 0;
|
let retry = 0;
|
||||||
let result;
|
let result;
|
||||||
while (retry++ < retries) {
|
while (retry++ < retries) {
|
||||||
result = await fetcher();
|
try {
|
||||||
if (checker(result)) return result;
|
result = await fetcher();
|
||||||
|
if (checker(result)) return result;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
await delay(
|
await delay(
|
||||||
delaySeconds[Math.min(retry - 1, delaySeconds.length - 1)] * 1000,
|
delaySeconds[Math.min(retry - 1, delaySeconds.length - 1)] * 1000,
|
||||||
);
|
);
|
||||||
|
|
|
@ -71,7 +71,7 @@
|
||||||
# Timeout for uploading images to pictrs (in seconds)
|
# Timeout for uploading images to pictrs (in seconds)
|
||||||
upload_timeout: 30
|
upload_timeout: 30
|
||||||
# Resize post thumbnails to this maximum width/height.
|
# Resize post thumbnails to this maximum width/height.
|
||||||
max_thumbnail_size: 256
|
max_thumbnail_size: 512
|
||||||
}
|
}
|
||||||
# Email sending configuration. All options except login/password are mandatory
|
# Email sending configuration. All options except login/password are mandatory
|
||||||
email: {
|
email: {
|
||||||
|
@ -117,5 +117,5 @@
|
||||||
}
|
}
|
||||||
# Sets a response Access-Control-Allow-Origin CORS header
|
# Sets a response Access-Control-Allow-Origin CORS header
|
||||||
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
|
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
|
||||||
cors_origin: "*"
|
cors_origin: "lemmy.tld"
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ tracing = { workspace = true }
|
||||||
chrono = { workspace = true }
|
chrono = { workspace = true }
|
||||||
url = { workspace = true }
|
url = { workspace = true }
|
||||||
hound = "3.5.1"
|
hound = "3.5.1"
|
||||||
sitemap-rs = "0.2.1"
|
sitemap-rs = "0.2.2"
|
||||||
totp-rs = { version = "5.6.0", features = ["gen_secret", "otpauth"] }
|
totp-rs = { version = "5.6.0", features = ["gen_secret", "otpauth"] }
|
||||||
actix-web-httpauth = "0.8.2"
|
actix-web-httpauth = "0.8.2"
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ pub async fn distinguish_comment(
|
||||||
|
|
||||||
check_community_user_action(
|
check_community_user_action(
|
||||||
&local_user_view.person,
|
&local_user_view.person,
|
||||||
orig_comment.community.id,
|
&orig_comment.community,
|
||||||
&mut context.pool(),
|
&mut context.pool(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -39,7 +39,7 @@ pub async fn distinguish_comment(
|
||||||
// Verify that only a mod or admin can distinguish a comment
|
// Verify that only a mod or admin can distinguish a comment
|
||||||
check_community_mod_action(
|
check_community_mod_action(
|
||||||
&local_user_view.person,
|
&local_user_view.person,
|
||||||
orig_comment.community.id,
|
&orig_comment.community,
|
||||||
false,
|
false,
|
||||||
&mut context.pool(),
|
&mut context.pool(),
|
||||||
)
|
)
|
||||||
|
|
|
@ -50,7 +50,7 @@ pub async fn like_comment(
|
||||||
|
|
||||||
check_community_user_action(
|
check_community_user_action(
|
||||||
&local_user_view.person,
|
&local_user_view.person,
|
||||||
orig_comment.community.id,
|
&orig_comment.community,
|
||||||
&mut context.pool(),
|
&mut context.pool(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -92,8 +92,7 @@ pub async fn like_comment(
|
||||||
score: data.score,
|
score: data.score,
|
||||||
},
|
},
|
||||||
&context,
|
&context,
|
||||||
)
|
)?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(Json(
|
Ok(Json(
|
||||||
build_comment_response(
|
build_comment_response(
|
||||||
|
|
|
@ -44,7 +44,7 @@ pub async fn create_comment_report(
|
||||||
|
|
||||||
check_community_user_action(
|
check_community_user_action(
|
||||||
&local_user_view.person,
|
&local_user_view.person,
|
||||||
comment_view.community.id,
|
&comment_view.community,
|
||||||
&mut context.pool(),
|
&mut context.pool(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -85,8 +85,7 @@ pub async fn create_comment_report(
|
||||||
reason: data.reason.clone(),
|
reason: data.reason.clone(),
|
||||||
},
|
},
|
||||||
&context,
|
&context,
|
||||||
)
|
)?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(Json(CommentReportResponse {
|
Ok(Json(CommentReportResponse {
|
||||||
comment_report_view,
|
comment_report_view,
|
||||||
|
|
|
@ -22,7 +22,7 @@ pub async fn resolve_comment_report(
|
||||||
let person_id = local_user_view.person.id;
|
let person_id = local_user_view.person.id;
|
||||||
check_community_mod_action(
|
check_community_mod_action(
|
||||||
&local_user_view.person,
|
&local_user_view.person,
|
||||||
report.community.id,
|
&report.community,
|
||||||
true,
|
true,
|
||||||
&mut context.pool(),
|
&mut context.pool(),
|
||||||
)
|
)
|
||||||
|
|
|
@ -24,12 +24,11 @@ pub async fn add_mod_to_community(
|
||||||
context: Data<LemmyContext>,
|
context: Data<LemmyContext>,
|
||||||
local_user_view: LocalUserView,
|
local_user_view: LocalUserView,
|
||||||
) -> LemmyResult<Json<AddModToCommunityResponse>> {
|
) -> LemmyResult<Json<AddModToCommunityResponse>> {
|
||||||
let community_id = data.community_id;
|
let community = Community::read(&mut context.pool(), data.community_id).await?;
|
||||||
|
|
||||||
// Verify that only mods or admins can add mod
|
// Verify that only mods or admins can add mod
|
||||||
check_community_mod_action(
|
check_community_mod_action(
|
||||||
&local_user_view.person,
|
&local_user_view.person,
|
||||||
community_id,
|
&community,
|
||||||
false,
|
false,
|
||||||
&mut context.pool(),
|
&mut context.pool(),
|
||||||
)
|
)
|
||||||
|
@ -39,15 +38,13 @@ pub async fn add_mod_to_community(
|
||||||
if !data.added {
|
if !data.added {
|
||||||
LocalUser::is_higher_mod_or_admin_check(
|
LocalUser::is_higher_mod_or_admin_check(
|
||||||
&mut context.pool(),
|
&mut context.pool(),
|
||||||
community_id,
|
community.id,
|
||||||
local_user_view.person.id,
|
local_user_view.person.id,
|
||||||
vec![data.person_id],
|
vec![data.person_id],
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let community = Community::read(&mut context.pool(), community_id).await?;
|
|
||||||
|
|
||||||
// If user is admin and community is remote, explicitly check that he is a
|
// If user is admin and community is remote, explicitly check that he is a
|
||||||
// moderator. This is necessary because otherwise the action would be rejected
|
// moderator. This is necessary because otherwise the action would be rejected
|
||||||
// by the community's home instance.
|
// by the community's home instance.
|
||||||
|
@ -98,8 +95,7 @@ pub async fn add_mod_to_community(
|
||||||
added: data.added,
|
added: data.added,
|
||||||
},
|
},
|
||||||
&context,
|
&context,
|
||||||
)
|
)?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(Json(AddModToCommunityResponse { moderators }))
|
Ok(Json(AddModToCommunityResponse { moderators }))
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ use lemmy_api_common::{
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::{
|
source::{
|
||||||
community::{
|
community::{
|
||||||
|
Community,
|
||||||
CommunityFollower,
|
CommunityFollower,
|
||||||
CommunityFollowerForm,
|
CommunityFollowerForm,
|
||||||
CommunityPersonBan,
|
CommunityPersonBan,
|
||||||
|
@ -38,11 +39,12 @@ pub async fn ban_from_community(
|
||||||
) -> LemmyResult<Json<BanFromCommunityResponse>> {
|
) -> LemmyResult<Json<BanFromCommunityResponse>> {
|
||||||
let banned_person_id = data.person_id;
|
let banned_person_id = data.person_id;
|
||||||
let expires = check_expire_time(data.expires)?;
|
let expires = check_expire_time(data.expires)?;
|
||||||
|
let community = Community::read(&mut context.pool(), data.community_id).await?;
|
||||||
|
|
||||||
// Verify that only mods or admins can ban
|
// Verify that only mods or admins can ban
|
||||||
check_community_mod_action(
|
check_community_mod_action(
|
||||||
&local_user_view.person,
|
&local_user_view.person,
|
||||||
data.community_id,
|
&community,
|
||||||
false,
|
false,
|
||||||
&mut context.pool(),
|
&mut context.pool(),
|
||||||
)
|
)
|
||||||
|
@ -72,12 +74,7 @@ pub async fn ban_from_community(
|
||||||
.with_lemmy_type(LemmyErrorType::CommunityUserAlreadyBanned)?;
|
.with_lemmy_type(LemmyErrorType::CommunityUserAlreadyBanned)?;
|
||||||
|
|
||||||
// Also unsubscribe them from the community, if they are subscribed
|
// Also unsubscribe them from the community, if they are subscribed
|
||||||
let community_follower_form = CommunityFollowerForm {
|
let community_follower_form = CommunityFollowerForm::new(data.community_id, banned_person_id);
|
||||||
community_id: data.community_id,
|
|
||||||
person_id: banned_person_id,
|
|
||||||
pending: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
CommunityFollower::unfollow(&mut context.pool(), &community_follower_form)
|
CommunityFollower::unfollow(&mut context.pool(), &community_follower_form)
|
||||||
.await
|
.await
|
||||||
.ok();
|
.ok();
|
||||||
|
@ -123,8 +120,7 @@ pub async fn ban_from_community(
|
||||||
data: data.0.clone(),
|
data: data.0.clone(),
|
||||||
},
|
},
|
||||||
&context,
|
&context,
|
||||||
)
|
)?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(Json(BanFromCommunityResponse {
|
Ok(Json(BanFromCommunityResponse {
|
||||||
person_view,
|
person_view,
|
||||||
|
|
|
@ -35,12 +35,7 @@ pub async fn block_community(
|
||||||
.with_lemmy_type(LemmyErrorType::CommunityBlockAlreadyExists)?;
|
.with_lemmy_type(LemmyErrorType::CommunityBlockAlreadyExists)?;
|
||||||
|
|
||||||
// Also, unfollow the community, and send a federated unfollow
|
// Also, unfollow the community, and send a federated unfollow
|
||||||
let community_follower_form = CommunityFollowerForm {
|
let community_follower_form = CommunityFollowerForm::new(data.community_id, person_id);
|
||||||
community_id: data.community_id,
|
|
||||||
person_id,
|
|
||||||
pending: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
CommunityFollower::unfollow(&mut context.pool(), &community_follower_form)
|
CommunityFollower::unfollow(&mut context.pool(), &community_follower_form)
|
||||||
.await
|
.await
|
||||||
.ok();
|
.ok();
|
||||||
|
@ -65,8 +60,7 @@ pub async fn block_community(
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
&context,
|
&context,
|
||||||
)
|
)?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(Json(BlockCommunityResponse {
|
Ok(Json(BlockCommunityResponse {
|
||||||
blocked: data.block,
|
blocked: data.block,
|
||||||
|
|
|
@ -4,17 +4,18 @@ use lemmy_api_common::{
|
||||||
community::{CommunityResponse, FollowCommunity},
|
community::{CommunityResponse, FollowCommunity},
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
send_activity::{ActivityChannel, SendActivityData},
|
send_activity::{ActivityChannel, SendActivityData},
|
||||||
utils::check_community_user_action,
|
utils::{check_community_deleted_removed, check_user_valid},
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::{
|
source::{
|
||||||
actor_language::CommunityLanguage,
|
actor_language::CommunityLanguage,
|
||||||
community::{Community, CommunityFollower, CommunityFollowerForm},
|
community::{Community, CommunityFollower, CommunityFollowerForm, CommunityFollowerState},
|
||||||
},
|
},
|
||||||
traits::{Crud, Followable},
|
traits::{Crud, Followable},
|
||||||
|
CommunityVisibility,
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::LocalUserView;
|
use lemmy_db_views::structs::LocalUserView;
|
||||||
use lemmy_db_views_actor::structs::CommunityView;
|
use lemmy_db_views_actor::structs::{CommunityPersonBanView, CommunityView};
|
||||||
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult};
|
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult};
|
||||||
|
|
||||||
#[tracing::instrument(skip(context))]
|
#[tracing::instrument(skip(context))]
|
||||||
|
@ -23,40 +24,52 @@ pub async fn follow_community(
|
||||||
context: Data<LemmyContext>,
|
context: Data<LemmyContext>,
|
||||||
local_user_view: LocalUserView,
|
local_user_view: LocalUserView,
|
||||||
) -> LemmyResult<Json<CommunityResponse>> {
|
) -> LemmyResult<Json<CommunityResponse>> {
|
||||||
|
check_user_valid(&local_user_view.person)?;
|
||||||
let community = Community::read(&mut context.pool(), data.community_id).await?;
|
let community = Community::read(&mut context.pool(), data.community_id).await?;
|
||||||
let mut community_follower_form = CommunityFollowerForm {
|
let form = CommunityFollowerForm::new(community.id, local_user_view.person.id);
|
||||||
community_id: community.id,
|
|
||||||
person_id: local_user_view.person.id,
|
|
||||||
pending: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
if data.follow {
|
if data.follow {
|
||||||
|
// Only run these checks for local community, in case of remote community the local
|
||||||
|
// state may be outdated. Can't use check_community_user_action() here as it only allows
|
||||||
|
// actions from existing followers for private community (so following would be impossible).
|
||||||
if community.local {
|
if community.local {
|
||||||
check_community_user_action(&local_user_view.person, community.id, &mut context.pool())
|
check_community_deleted_removed(&community)?;
|
||||||
|
CommunityPersonBanView::check(&mut context.pool(), local_user_view.person.id, community.id)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
CommunityFollower::follow(&mut context.pool(), &community_follower_form)
|
|
||||||
.await
|
|
||||||
.with_lemmy_type(LemmyErrorType::CommunityFollowerAlreadyExists)?;
|
|
||||||
} else {
|
|
||||||
// Mark as pending, the actual federation activity is sent via `SendActivity` handler
|
|
||||||
community_follower_form.pending = true;
|
|
||||||
CommunityFollower::follow(&mut context.pool(), &community_follower_form)
|
|
||||||
.await
|
|
||||||
.with_lemmy_type(LemmyErrorType::CommunityFollowerAlreadyExists)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let state = if community.local {
|
||||||
|
// Local follow is accepted immediately
|
||||||
|
Some(CommunityFollowerState::Accepted)
|
||||||
|
} else if community.visibility == CommunityVisibility::Private {
|
||||||
|
// Private communities require manual approval
|
||||||
|
Some(CommunityFollowerState::ApprovalRequired)
|
||||||
|
} else {
|
||||||
|
// remote follow needs to be federated first
|
||||||
|
Some(CommunityFollowerState::Pending)
|
||||||
|
};
|
||||||
|
|
||||||
|
let form = CommunityFollowerForm {
|
||||||
|
state,
|
||||||
|
..CommunityFollowerForm::new(community.id, local_user_view.person.id)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Write to db
|
||||||
|
CommunityFollower::follow(&mut context.pool(), &form)
|
||||||
|
.await
|
||||||
|
.with_lemmy_type(LemmyErrorType::CommunityFollowerAlreadyExists)?;
|
||||||
} else {
|
} else {
|
||||||
CommunityFollower::unfollow(&mut context.pool(), &community_follower_form)
|
CommunityFollower::unfollow(&mut context.pool(), &form)
|
||||||
.await
|
.await
|
||||||
.with_lemmy_type(LemmyErrorType::CommunityFollowerAlreadyExists)?;
|
.with_lemmy_type(LemmyErrorType::CommunityFollowerAlreadyExists)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Send the federated follow
|
||||||
if !community.local {
|
if !community.local {
|
||||||
ActivityChannel::submit_activity(
|
ActivityChannel::submit_activity(
|
||||||
SendActivityData::FollowCommunity(community, local_user_view.person.clone(), data.follow),
|
SendActivityData::FollowCommunity(community, local_user_view.person.clone(), data.follow),
|
||||||
&context,
|
&context,
|
||||||
)
|
)?;
|
||||||
.await?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let community_id = data.community_id;
|
let community_id = data.community_id;
|
||||||
|
|
|
@ -48,8 +48,7 @@ pub async fn hide_community(
|
||||||
ActivityChannel::submit_activity(
|
ActivityChannel::submit_activity(
|
||||||
SendActivityData::UpdateCommunity(local_user_view.person.clone(), community),
|
SendActivityData::UpdateCommunity(local_user_view.person.clone(), community),
|
||||||
&context,
|
&context,
|
||||||
)
|
)?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(Json(SuccessResponse::default()))
|
Ok(Json(SuccessResponse::default()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,5 +3,6 @@ pub mod ban;
|
||||||
pub mod block;
|
pub mod block;
|
||||||
pub mod follow;
|
pub mod follow;
|
||||||
pub mod hide;
|
pub mod hide;
|
||||||
|
pub mod pending_follows;
|
||||||
pub mod random;
|
pub mod random;
|
||||||
pub mod transfer;
|
pub mod transfer;
|
||||||
|
|
46
crates/api/src/community/pending_follows/approve.rs
Normal file
46
crates/api/src/community/pending_follows/approve.rs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
use activitypub_federation::config::Data;
|
||||||
|
use actix_web::web::Json;
|
||||||
|
use lemmy_api_common::{
|
||||||
|
community::ApproveCommunityPendingFollower,
|
||||||
|
context::LemmyContext,
|
||||||
|
send_activity::{ActivityChannel, SendActivityData},
|
||||||
|
utils::is_mod_or_admin,
|
||||||
|
SuccessResponse,
|
||||||
|
};
|
||||||
|
use lemmy_db_schema::{
|
||||||
|
source::community::{CommunityFollower, CommunityFollowerForm},
|
||||||
|
traits::Followable,
|
||||||
|
};
|
||||||
|
use lemmy_db_views::structs::LocalUserView;
|
||||||
|
use lemmy_utils::error::LemmyResult;
|
||||||
|
|
||||||
|
pub async fn post_pending_follows_approve(
|
||||||
|
data: Json<ApproveCommunityPendingFollower>,
|
||||||
|
context: Data<LemmyContext>,
|
||||||
|
local_user_view: LocalUserView,
|
||||||
|
) -> LemmyResult<Json<SuccessResponse>> {
|
||||||
|
is_mod_or_admin(
|
||||||
|
&mut context.pool(),
|
||||||
|
&local_user_view.person,
|
||||||
|
data.community_id,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let activity_data = if data.approve {
|
||||||
|
CommunityFollower::approve(
|
||||||
|
&mut context.pool(),
|
||||||
|
data.community_id,
|
||||||
|
data.follower_id,
|
||||||
|
local_user_view.person.id,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
SendActivityData::AcceptFollower(data.community_id, data.follower_id)
|
||||||
|
} else {
|
||||||
|
let form = CommunityFollowerForm::new(data.community_id, data.follower_id);
|
||||||
|
CommunityFollower::unfollow(&mut context.pool(), &form).await?;
|
||||||
|
SendActivityData::RejectFollower(data.community_id, data.follower_id)
|
||||||
|
};
|
||||||
|
ActivityChannel::submit_activity(activity_data, &context)?;
|
||||||
|
|
||||||
|
Ok(Json(SuccessResponse::default()))
|
||||||
|
}
|
25
crates/api/src/community/pending_follows/count.rs
Normal file
25
crates/api/src/community/pending_follows/count.rs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
use actix_web::web::{Data, Json, Query};
|
||||||
|
use lemmy_api_common::{
|
||||||
|
community::{GetCommunityPendingFollowsCount, GetCommunityPendingFollowsCountResponse},
|
||||||
|
context::LemmyContext,
|
||||||
|
utils::is_mod_or_admin,
|
||||||
|
};
|
||||||
|
use lemmy_db_views::structs::LocalUserView;
|
||||||
|
use lemmy_db_views_actor::structs::CommunityFollowerView;
|
||||||
|
use lemmy_utils::error::LemmyResult;
|
||||||
|
|
||||||
|
pub async fn get_pending_follows_count(
|
||||||
|
data: Query<GetCommunityPendingFollowsCount>,
|
||||||
|
context: Data<LemmyContext>,
|
||||||
|
local_user_view: LocalUserView,
|
||||||
|
) -> LemmyResult<Json<GetCommunityPendingFollowsCountResponse>> {
|
||||||
|
is_mod_or_admin(
|
||||||
|
&mut context.pool(),
|
||||||
|
&local_user_view.person,
|
||||||
|
data.community_id,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
let count =
|
||||||
|
CommunityFollowerView::count_approval_required(&mut context.pool(), data.community_id).await?;
|
||||||
|
Ok(Json(GetCommunityPendingFollowsCountResponse { count }))
|
||||||
|
}
|
29
crates/api/src/community/pending_follows/list.rs
Normal file
29
crates/api/src/community/pending_follows/list.rs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
use actix_web::web::{Data, Json, Query};
|
||||||
|
use lemmy_api_common::{
|
||||||
|
community::{ListCommunityPendingFollows, ListCommunityPendingFollowsResponse},
|
||||||
|
context::LemmyContext,
|
||||||
|
utils::check_community_mod_of_any_or_admin_action,
|
||||||
|
};
|
||||||
|
use lemmy_db_views::structs::LocalUserView;
|
||||||
|
use lemmy_db_views_actor::structs::CommunityFollowerView;
|
||||||
|
use lemmy_utils::error::LemmyResult;
|
||||||
|
|
||||||
|
pub async fn get_pending_follows_list(
|
||||||
|
data: Query<ListCommunityPendingFollows>,
|
||||||
|
context: Data<LemmyContext>,
|
||||||
|
local_user_view: LocalUserView,
|
||||||
|
) -> LemmyResult<Json<ListCommunityPendingFollowsResponse>> {
|
||||||
|
check_community_mod_of_any_or_admin_action(&local_user_view, &mut context.pool()).await?;
|
||||||
|
let all_communities =
|
||||||
|
data.all_communities.unwrap_or_default() && local_user_view.local_user.admin;
|
||||||
|
let items = CommunityFollowerView::list_approval_required(
|
||||||
|
&mut context.pool(),
|
||||||
|
local_user_view.person.id,
|
||||||
|
all_communities,
|
||||||
|
data.pending_only.unwrap_or_default(),
|
||||||
|
data.page,
|
||||||
|
data.limit,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(Json(ListCommunityPendingFollowsResponse { items }))
|
||||||
|
}
|
3
crates/api/src/community/pending_follows/mod.rs
Normal file
3
crates/api/src/community/pending_follows/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
pub mod approve;
|
||||||
|
pub mod count;
|
||||||
|
pub mod list;
|
|
@ -7,7 +7,7 @@ use lemmy_api_common::{
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::{
|
source::{
|
||||||
community::{CommunityModerator, CommunityModeratorForm},
|
community::{Community, CommunityModerator, CommunityModeratorForm},
|
||||||
moderator::{ModTransferCommunity, ModTransferCommunityForm},
|
moderator::{ModTransferCommunity, ModTransferCommunityForm},
|
||||||
},
|
},
|
||||||
traits::{Crud, Joinable},
|
traits::{Crud, Joinable},
|
||||||
|
@ -27,11 +27,11 @@ pub async fn transfer_community(
|
||||||
context: Data<LemmyContext>,
|
context: Data<LemmyContext>,
|
||||||
local_user_view: LocalUserView,
|
local_user_view: LocalUserView,
|
||||||
) -> LemmyResult<Json<GetCommunityResponse>> {
|
) -> LemmyResult<Json<GetCommunityResponse>> {
|
||||||
let community_id = data.community_id;
|
let community = Community::read(&mut context.pool(), data.community_id).await?;
|
||||||
let mut community_mods =
|
let mut community_mods =
|
||||||
CommunityModeratorView::for_community(&mut context.pool(), community_id).await?;
|
CommunityModeratorView::for_community(&mut context.pool(), community.id).await?;
|
||||||
|
|
||||||
check_community_user_action(&local_user_view.person, community_id, &mut context.pool()).await?;
|
check_community_user_action(&local_user_view.person, &community, &mut context.pool()).await?;
|
||||||
|
|
||||||
// Make sure transferrer is either the top community mod, or an admin
|
// Make sure transferrer is either the top community mod, or an admin
|
||||||
if !(is_top_mod(&local_user_view, &community_mods).is_ok() || is_admin(&local_user_view).is_ok())
|
if !(is_top_mod(&local_user_view, &community_mods).is_ok() || is_admin(&local_user_view).is_ok())
|
||||||
|
|
|
@ -145,7 +145,7 @@ fn build_totp_2fa(hostname: &str, username: &str, secret: &str) -> LemmyResult<T
|
||||||
let sec = Secret::Raw(secret.as_bytes().to_vec());
|
let sec = Secret::Raw(secret.as_bytes().to_vec());
|
||||||
let sec_bytes = sec
|
let sec_bytes = sec
|
||||||
.to_bytes()
|
.to_bytes()
|
||||||
.map_err(|_| LemmyErrorType::CouldntParseTotpSecret)?;
|
.with_lemmy_type(LemmyErrorType::CouldntParseTotpSecret)?;
|
||||||
|
|
||||||
TOTP::new(
|
TOTP::new(
|
||||||
totp_rs::Algorithm::SHA1,
|
totp_rs::Algorithm::SHA1,
|
||||||
|
@ -197,11 +197,7 @@ pub(crate) async fn ban_nonlocal_user_from_local_communities(
|
||||||
.ok();
|
.ok();
|
||||||
|
|
||||||
// Also unsubscribe them from the community, if they are subscribed
|
// Also unsubscribe them from the community, if they are subscribed
|
||||||
let community_follower_form = CommunityFollowerForm {
|
let community_follower_form = CommunityFollowerForm::new(community_id, target.id);
|
||||||
community_id,
|
|
||||||
person_id: target.id,
|
|
||||||
pending: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
CommunityFollower::unfollow(&mut context.pool(), &community_follower_form)
|
CommunityFollower::unfollow(&mut context.pool(), &community_follower_form)
|
||||||
.await
|
.await
|
||||||
|
@ -242,8 +238,7 @@ pub(crate) async fn ban_nonlocal_user_from_local_communities(
|
||||||
data: ban_from_community,
|
data: ban_from_community,
|
||||||
},
|
},
|
||||||
context,
|
context,
|
||||||
)
|
)?;
|
||||||
.await?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ pub async fn add_admin(
|
||||||
// Make sure that the person_id added is local
|
// Make sure that the person_id added is local
|
||||||
let added_local_user = LocalUserView::read_person(&mut context.pool(), data.person_id)
|
let added_local_user = LocalUserView::read_person(&mut context.pool(), data.person_id)
|
||||||
.await
|
.await
|
||||||
.map_err(|_| LemmyErrorType::ObjectNotLocal)?;
|
.with_lemmy_type(LemmyErrorType::ObjectNotLocal)?;
|
||||||
|
|
||||||
LocalUser::update(
|
LocalUser::update(
|
||||||
&mut context.pool(),
|
&mut context.pool(),
|
||||||
|
|
|
@ -111,8 +111,7 @@ pub async fn ban_from_site(
|
||||||
expires: data.expires,
|
expires: data.expires,
|
||||||
},
|
},
|
||||||
&context,
|
&context,
|
||||||
)
|
)?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(Json(BanPersonResponse {
|
Ok(Json(BanPersonResponse {
|
||||||
person_view,
|
person_view,
|
||||||
|
|
|
@ -10,7 +10,7 @@ use lemmy_db_schema::source::{
|
||||||
login_token::LoginToken,
|
login_token::LoginToken,
|
||||||
password_reset_request::PasswordResetRequest,
|
password_reset_request::PasswordResetRequest,
|
||||||
};
|
};
|
||||||
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult};
|
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
|
||||||
|
|
||||||
#[tracing::instrument(skip(context))]
|
#[tracing::instrument(skip(context))]
|
||||||
pub async fn change_password_after_reset(
|
pub async fn change_password_after_reset(
|
||||||
|
@ -32,9 +32,7 @@ pub async fn change_password_after_reset(
|
||||||
|
|
||||||
// Update the user with the new password
|
// Update the user with the new password
|
||||||
let password = data.password.clone();
|
let password = data.password.clone();
|
||||||
LocalUser::update_password(&mut context.pool(), local_user_id, &password)
|
LocalUser::update_password(&mut context.pool(), local_user_id, &password).await?;
|
||||||
.await
|
|
||||||
.with_lemmy_type(LemmyErrorType::CouldntUpdateUser)?;
|
|
||||||
|
|
||||||
LoginToken::invalidate_all(&mut context.pool(), local_user_id).await?;
|
LoginToken::invalidate_all(&mut context.pool(), local_user_id).await?;
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ use captcha::{gen, Difficulty};
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
person::{CaptchaResponse, GetCaptchaResponse},
|
person::{CaptchaResponse, GetCaptchaResponse},
|
||||||
|
LemmyErrorType,
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::source::{
|
use lemmy_db_schema::source::{
|
||||||
captcha_answer::{CaptchaAnswer, CaptchaAnswerForm},
|
captcha_answer::{CaptchaAnswer, CaptchaAnswerForm},
|
||||||
|
@ -37,7 +38,9 @@ pub async fn get_captcha(context: Data<LemmyContext>) -> LemmyResult<HttpRespons
|
||||||
|
|
||||||
let answer = captcha.chars_as_string();
|
let answer = captcha.chars_as_string();
|
||||||
|
|
||||||
let png = captcha.as_base64().expect("failed to generate captcha");
|
let png = captcha
|
||||||
|
.as_base64()
|
||||||
|
.ok_or(LemmyErrorType::CouldntCreateImageCaptcha)?;
|
||||||
|
|
||||||
let wav = captcha_as_wav_base64(&captcha)?;
|
let wav = captcha_as_wav_base64(&captcha)?;
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ use lemmy_api_common::{
|
||||||
SuccessResponse,
|
SuccessResponse,
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::{LocalUserView, SiteView};
|
use lemmy_db_views::structs::{LocalUserView, SiteView};
|
||||||
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
|
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult};
|
||||||
|
|
||||||
#[tracing::instrument(skip(context))]
|
#[tracing::instrument(skip(context))]
|
||||||
pub async fn reset_password(
|
pub async fn reset_password(
|
||||||
|
@ -17,7 +17,7 @@ pub async fn reset_password(
|
||||||
let email = data.email.to_lowercase();
|
let email = data.email.to_lowercase();
|
||||||
let local_user_view = LocalUserView::find_by_email(&mut context.pool(), &email)
|
let local_user_view = LocalUserView::find_by_email(&mut context.pool(), &email)
|
||||||
.await
|
.await
|
||||||
.map_err(|_| LemmyErrorType::IncorrectLogin)?;
|
.with_lemmy_type(LemmyErrorType::IncorrectLogin)?;
|
||||||
|
|
||||||
let site_view = SiteView::read_local(&mut context.pool()).await?;
|
let site_view = SiteView::read_local(&mut context.pool()).await?;
|
||||||
check_email_verified(&local_user_view, &site_view)?;
|
check_email_verified(&local_user_view, &site_view)?;
|
||||||
|
|
|
@ -141,7 +141,9 @@ pub async fn save_user_settings(
|
||||||
post_listing_mode: data.post_listing_mode,
|
post_listing_mode: data.post_listing_mode,
|
||||||
enable_keyboard_navigation: data.enable_keyboard_navigation,
|
enable_keyboard_navigation: data.enable_keyboard_navigation,
|
||||||
enable_animated_images: data.enable_animated_images,
|
enable_animated_images: data.enable_animated_images,
|
||||||
|
enable_private_messages: data.enable_private_messages,
|
||||||
collapse_bot_comments: data.collapse_bot_comments,
|
collapse_bot_comments: data.collapse_bot_comments,
|
||||||
|
auto_mark_fetched_posts_as_read: data.auto_mark_fetched_posts_as_read,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ use lemmy_api_common::{
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::{
|
source::{
|
||||||
|
community::Community,
|
||||||
moderator::{ModFeaturePost, ModFeaturePostForm},
|
moderator::{ModFeaturePost, ModFeaturePostForm},
|
||||||
post::{Post, PostUpdateForm},
|
post::{Post, PostUpdateForm},
|
||||||
},
|
},
|
||||||
|
@ -27,9 +28,10 @@ pub async fn feature_post(
|
||||||
let post_id = data.post_id;
|
let post_id = data.post_id;
|
||||||
let orig_post = Post::read(&mut context.pool(), post_id).await?;
|
let orig_post = Post::read(&mut context.pool(), post_id).await?;
|
||||||
|
|
||||||
|
let community = Community::read(&mut context.pool(), orig_post.community_id).await?;
|
||||||
check_community_mod_action(
|
check_community_mod_action(
|
||||||
&local_user_view.person,
|
&local_user_view.person,
|
||||||
orig_post.community_id,
|
&community,
|
||||||
false,
|
false,
|
||||||
&mut context.pool(),
|
&mut context.pool(),
|
||||||
)
|
)
|
||||||
|
@ -67,8 +69,7 @@ pub async fn feature_post(
|
||||||
ActivityChannel::submit_activity(
|
ActivityChannel::submit_activity(
|
||||||
SendActivityData::FeaturePost(post, local_user_view.person.clone(), data.featured),
|
SendActivityData::FeaturePost(post, local_user_view.person.clone(), data.featured),
|
||||||
&context,
|
&context,
|
||||||
)
|
)?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
build_post_response(&context, orig_post.community_id, local_user_view, post_id).await
|
build_post_response(&context, orig_post.community_id, local_user_view, post_id).await
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,34 +1,39 @@
|
||||||
use actix_web::web::{Data, Json};
|
use actix_web::web::{Data, Json};
|
||||||
use lemmy_api_common::{context::LemmyContext, post::HidePost, SuccessResponse};
|
use lemmy_api_common::{
|
||||||
|
context::LemmyContext,
|
||||||
|
post::{HidePost, PostResponse},
|
||||||
|
};
|
||||||
use lemmy_db_schema::source::post::PostHide;
|
use lemmy_db_schema::source::post::PostHide;
|
||||||
use lemmy_db_views::structs::LocalUserView;
|
use lemmy_db_views::structs::{LocalUserView, PostView};
|
||||||
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult, MAX_API_PARAM_ELEMENTS};
|
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult};
|
||||||
use std::collections::HashSet;
|
|
||||||
|
|
||||||
#[tracing::instrument(skip(context))]
|
#[tracing::instrument(skip(context))]
|
||||||
pub async fn hide_post(
|
pub async fn hide_post(
|
||||||
data: Json<HidePost>,
|
data: Json<HidePost>,
|
||||||
context: Data<LemmyContext>,
|
context: Data<LemmyContext>,
|
||||||
local_user_view: LocalUserView,
|
local_user_view: LocalUserView,
|
||||||
) -> LemmyResult<Json<SuccessResponse>> {
|
) -> LemmyResult<Json<PostResponse>> {
|
||||||
let post_ids = HashSet::from_iter(data.post_ids.clone());
|
|
||||||
|
|
||||||
if post_ids.len() > MAX_API_PARAM_ELEMENTS {
|
|
||||||
Err(LemmyErrorType::TooManyItems)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let person_id = local_user_view.person.id;
|
let person_id = local_user_view.person.id;
|
||||||
|
let post_id = data.post_id;
|
||||||
|
|
||||||
// Mark the post as hidden / unhidden
|
// Mark the post as hidden / unhidden
|
||||||
if data.hide {
|
if data.hide {
|
||||||
PostHide::hide(&mut context.pool(), post_ids, person_id)
|
PostHide::hide(&mut context.pool(), post_id, person_id)
|
||||||
.await
|
.await
|
||||||
.with_lemmy_type(LemmyErrorType::CouldntHidePost)?;
|
.with_lemmy_type(LemmyErrorType::CouldntHidePost)?;
|
||||||
} else {
|
} else {
|
||||||
PostHide::unhide(&mut context.pool(), post_ids, person_id)
|
PostHide::unhide(&mut context.pool(), post_id, person_id)
|
||||||
.await
|
.await
|
||||||
.with_lemmy_type(LemmyErrorType::CouldntHidePost)?;
|
.with_lemmy_type(LemmyErrorType::CouldntHidePost)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Json(SuccessResponse::default()))
|
let post_view = PostView::read(
|
||||||
|
&mut context.pool(),
|
||||||
|
post_id,
|
||||||
|
Some(&local_user_view.local_user),
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(Json(PostResponse { post_view }))
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,23 +5,16 @@ use lemmy_api_common::{
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
post::{CreatePostLike, PostResponse},
|
post::{CreatePostLike, PostResponse},
|
||||||
send_activity::{ActivityChannel, SendActivityData},
|
send_activity::{ActivityChannel, SendActivityData},
|
||||||
utils::{
|
utils::{check_bot_account, check_community_user_action, check_local_vote_mode, VoteItem},
|
||||||
check_bot_account,
|
|
||||||
check_community_user_action,
|
|
||||||
check_local_vote_mode,
|
|
||||||
mark_post_as_read,
|
|
||||||
VoteItem,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::{
|
source::{
|
||||||
community::Community,
|
|
||||||
local_site::LocalSite,
|
local_site::LocalSite,
|
||||||
post::{Post, PostLike, PostLikeForm},
|
post::{PostLike, PostLikeForm, PostRead, PostReadForm},
|
||||||
},
|
},
|
||||||
traits::{Crud, Likeable},
|
traits::Likeable,
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::LocalUserView;
|
use lemmy_db_views::structs::{LocalUserView, PostView};
|
||||||
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult};
|
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
@ -45,20 +38,16 @@ pub async fn like_post(
|
||||||
check_bot_account(&local_user_view.person)?;
|
check_bot_account(&local_user_view.person)?;
|
||||||
|
|
||||||
// Check for a community ban
|
// Check for a community ban
|
||||||
let post = Post::read(&mut context.pool(), post_id).await?;
|
let post = PostView::read(&mut context.pool(), post_id, None, false).await?;
|
||||||
|
|
||||||
check_community_user_action(
|
check_community_user_action(
|
||||||
&local_user_view.person,
|
&local_user_view.person,
|
||||||
post.community_id,
|
&post.community,
|
||||||
&mut context.pool(),
|
&mut context.pool(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let like_form = PostLikeForm {
|
let like_form = PostLikeForm::new(data.post_id, local_user_view.person.id, data.score);
|
||||||
post_id: data.post_id,
|
|
||||||
person_id: local_user_view.person.id,
|
|
||||||
score: data.score,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Remove any likes first
|
// Remove any likes first
|
||||||
let person_id = local_user_view.person.id;
|
let person_id = local_user_view.person.id;
|
||||||
|
@ -73,20 +62,19 @@ pub async fn like_post(
|
||||||
.with_lemmy_type(LemmyErrorType::CouldntLikePost)?;
|
.with_lemmy_type(LemmyErrorType::CouldntLikePost)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
mark_post_as_read(person_id, post_id, &mut context.pool()).await?;
|
// Mark Post Read
|
||||||
|
let read_form = PostReadForm::new(post_id, person_id);
|
||||||
let community = Community::read(&mut context.pool(), post.community_id).await?;
|
PostRead::mark_as_read(&mut context.pool(), &read_form).await?;
|
||||||
|
|
||||||
ActivityChannel::submit_activity(
|
ActivityChannel::submit_activity(
|
||||||
SendActivityData::LikePostOrComment {
|
SendActivityData::LikePostOrComment {
|
||||||
object_id: post.ap_id,
|
object_id: post.post.ap_id,
|
||||||
actor: local_user_view.person.clone(),
|
actor: local_user_view.person.clone(),
|
||||||
community,
|
community: post.community.clone(),
|
||||||
score: data.score,
|
score: data.score,
|
||||||
},
|
},
|
||||||
&context,
|
&context,
|
||||||
)
|
)?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
build_post_response(context.deref(), post.community_id, local_user_view, post_id).await
|
build_post_response(context.deref(), post.community.id, local_user_view, post_id).await
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ use lemmy_db_schema::{
|
||||||
},
|
},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::LocalUserView;
|
use lemmy_db_views::structs::{LocalUserView, PostView};
|
||||||
use lemmy_utils::error::LemmyResult;
|
use lemmy_utils::error::LemmyResult;
|
||||||
|
|
||||||
#[tracing::instrument(skip(context))]
|
#[tracing::instrument(skip(context))]
|
||||||
|
@ -24,11 +24,11 @@ pub async fn lock_post(
|
||||||
local_user_view: LocalUserView,
|
local_user_view: LocalUserView,
|
||||||
) -> LemmyResult<Json<PostResponse>> {
|
) -> LemmyResult<Json<PostResponse>> {
|
||||||
let post_id = data.post_id;
|
let post_id = data.post_id;
|
||||||
let orig_post = Post::read(&mut context.pool(), post_id).await?;
|
let orig_post = PostView::read(&mut context.pool(), post_id, None, false).await?;
|
||||||
|
|
||||||
check_community_mod_action(
|
check_community_mod_action(
|
||||||
&local_user_view.person,
|
&local_user_view.person,
|
||||||
orig_post.community_id,
|
&orig_post.community,
|
||||||
false,
|
false,
|
||||||
&mut context.pool(),
|
&mut context.pool(),
|
||||||
)
|
)
|
||||||
|
@ -58,8 +58,7 @@ pub async fn lock_post(
|
||||||
ActivityChannel::submit_activity(
|
ActivityChannel::submit_activity(
|
||||||
SendActivityData::LockPost(post, local_user_view.person.clone(), data.locked),
|
SendActivityData::LockPost(post, local_user_view.person.clone(), data.locked),
|
||||||
&context,
|
&context,
|
||||||
)
|
)?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
build_post_response(&context, orig_post.community_id, local_user_view, post_id).await
|
build_post_response(&context, orig_post.community.id, local_user_view, post_id).await
|
||||||
}
|
}
|
||||||
|
|
24
crates/api/src/post/mark_many_read.rs
Normal file
24
crates/api/src/post/mark_many_read.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
use actix_web::web::{Data, Json};
|
||||||
|
use lemmy_api_common::{context::LemmyContext, post::MarkManyPostsAsRead, SuccessResponse};
|
||||||
|
use lemmy_db_schema::source::post::PostRead;
|
||||||
|
use lemmy_db_views::structs::LocalUserView;
|
||||||
|
use lemmy_utils::error::{LemmyErrorType, LemmyResult, MAX_API_PARAM_ELEMENTS};
|
||||||
|
|
||||||
|
#[tracing::instrument(skip(context))]
|
||||||
|
pub async fn mark_posts_as_read(
|
||||||
|
data: Json<MarkManyPostsAsRead>,
|
||||||
|
context: Data<LemmyContext>,
|
||||||
|
local_user_view: LocalUserView,
|
||||||
|
) -> LemmyResult<Json<SuccessResponse>> {
|
||||||
|
let post_ids = &data.post_ids;
|
||||||
|
if post_ids.len() > MAX_API_PARAM_ELEMENTS {
|
||||||
|
Err(LemmyErrorType::TooManyItems)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let person_id = local_user_view.person.id;
|
||||||
|
|
||||||
|
// Mark the posts as read
|
||||||
|
PostRead::mark_many_as_read(&mut context.pool(), post_ids, person_id).await?;
|
||||||
|
|
||||||
|
Ok(Json(SuccessResponse::default()))
|
||||||
|
}
|
|
@ -1,34 +1,35 @@
|
||||||
use actix_web::web::{Data, Json};
|
use actix_web::web::{Data, Json};
|
||||||
use lemmy_api_common::{context::LemmyContext, post::MarkPostAsRead, SuccessResponse};
|
use lemmy_api_common::{
|
||||||
use lemmy_db_schema::source::post::PostRead;
|
context::LemmyContext,
|
||||||
use lemmy_db_views::structs::LocalUserView;
|
post::{MarkPostAsRead, PostResponse},
|
||||||
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult, MAX_API_PARAM_ELEMENTS};
|
};
|
||||||
use std::collections::HashSet;
|
use lemmy_db_schema::source::post::{PostRead, PostReadForm};
|
||||||
|
use lemmy_db_views::structs::{LocalUserView, PostView};
|
||||||
|
use lemmy_utils::error::LemmyResult;
|
||||||
|
|
||||||
#[tracing::instrument(skip(context))]
|
#[tracing::instrument(skip(context))]
|
||||||
pub async fn mark_post_as_read(
|
pub async fn mark_post_as_read(
|
||||||
data: Json<MarkPostAsRead>,
|
data: Json<MarkPostAsRead>,
|
||||||
context: Data<LemmyContext>,
|
context: Data<LemmyContext>,
|
||||||
local_user_view: LocalUserView,
|
local_user_view: LocalUserView,
|
||||||
) -> LemmyResult<Json<SuccessResponse>> {
|
) -> LemmyResult<Json<PostResponse>> {
|
||||||
let post_ids = HashSet::from_iter(data.post_ids.clone());
|
|
||||||
|
|
||||||
if post_ids.len() > MAX_API_PARAM_ELEMENTS {
|
|
||||||
Err(LemmyErrorType::TooManyItems)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let person_id = local_user_view.person.id;
|
let person_id = local_user_view.person.id;
|
||||||
|
let post_id = data.post_id;
|
||||||
|
|
||||||
// Mark the post as read / unread
|
// Mark the post as read / unread
|
||||||
|
let form = PostReadForm::new(post_id, person_id);
|
||||||
if data.read {
|
if data.read {
|
||||||
PostRead::mark_as_read(&mut context.pool(), post_ids, person_id)
|
PostRead::mark_as_read(&mut context.pool(), &form).await?;
|
||||||
.await
|
|
||||||
.with_lemmy_type(LemmyErrorType::CouldntMarkPostAsRead)?;
|
|
||||||
} else {
|
} else {
|
||||||
PostRead::mark_as_unread(&mut context.pool(), post_ids, person_id)
|
PostRead::mark_as_unread(&mut context.pool(), &form).await?;
|
||||||
.await
|
|
||||||
.with_lemmy_type(LemmyErrorType::CouldntMarkPostAsRead)?;
|
|
||||||
}
|
}
|
||||||
|
let post_view = PostView::read(
|
||||||
|
&mut context.pool(),
|
||||||
|
post_id,
|
||||||
|
Some(&local_user_view.local_user),
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
Ok(Json(SuccessResponse::default()))
|
Ok(Json(PostResponse { post_view }))
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,5 +4,6 @@ pub mod hide;
|
||||||
pub mod like;
|
pub mod like;
|
||||||
pub mod list_post_likes;
|
pub mod list_post_likes;
|
||||||
pub mod lock;
|
pub mod lock;
|
||||||
|
pub mod mark_many_read;
|
||||||
pub mod mark_read;
|
pub mod mark_read;
|
||||||
pub mod save;
|
pub mod save;
|
||||||
|
|
|
@ -2,10 +2,9 @@ use actix_web::web::{Data, Json};
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
post::{PostResponse, SavePost},
|
post::{PostResponse, SavePost},
|
||||||
utils::mark_post_as_read,
|
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::post::{PostSaved, PostSavedForm},
|
source::post::{PostRead, PostReadForm, PostSaved, PostSavedForm},
|
||||||
traits::Saveable,
|
traits::Saveable,
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::{LocalUserView, PostView};
|
use lemmy_db_views::structs::{LocalUserView, PostView};
|
||||||
|
@ -17,10 +16,7 @@ pub async fn save_post(
|
||||||
context: Data<LemmyContext>,
|
context: Data<LemmyContext>,
|
||||||
local_user_view: LocalUserView,
|
local_user_view: LocalUserView,
|
||||||
) -> LemmyResult<Json<PostResponse>> {
|
) -> LemmyResult<Json<PostResponse>> {
|
||||||
let post_saved_form = PostSavedForm {
|
let post_saved_form = PostSavedForm::new(data.post_id, local_user_view.person.id);
|
||||||
post_id: data.post_id,
|
|
||||||
person_id: local_user_view.person.id,
|
|
||||||
};
|
|
||||||
|
|
||||||
if data.save {
|
if data.save {
|
||||||
PostSaved::save(&mut context.pool(), &post_saved_form)
|
PostSaved::save(&mut context.pool(), &post_saved_form)
|
||||||
|
@ -42,7 +38,8 @@ pub async fn save_post(
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
mark_post_as_read(person_id, post_id, &mut context.pool()).await?;
|
let read_form = PostReadForm::new(post_id, person_id);
|
||||||
|
PostRead::mark_as_read(&mut context.pool(), &read_form).await?;
|
||||||
|
|
||||||
Ok(Json(PostResponse { post_view }))
|
Ok(Json(PostResponse { post_view }))
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ pub async fn create_post_report(
|
||||||
|
|
||||||
check_community_user_action(
|
check_community_user_action(
|
||||||
&local_user_view.person,
|
&local_user_view.person,
|
||||||
post_view.community.id,
|
&post_view.community,
|
||||||
&mut context.pool(),
|
&mut context.pool(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -80,8 +80,7 @@ pub async fn create_post_report(
|
||||||
reason: data.reason.clone(),
|
reason: data.reason.clone(),
|
||||||
},
|
},
|
||||||
&context,
|
&context,
|
||||||
)
|
)?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(Json(PostReportResponse { post_report_view }))
|
Ok(Json(PostReportResponse { post_report_view }))
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ pub async fn resolve_post_report(
|
||||||
let person_id = local_user_view.person.id;
|
let person_id = local_user_view.person.id;
|
||||||
check_community_mod_action(
|
check_community_mod_action(
|
||||||
&local_user_view.person,
|
&local_user_view.person,
|
||||||
report.community.id,
|
&report.community,
|
||||||
true,
|
true,
|
||||||
&mut context.pool(),
|
&mut context.pool(),
|
||||||
)
|
)
|
||||||
|
|
|
@ -67,8 +67,7 @@ pub async fn purge_comment(
|
||||||
reason: data.reason.clone(),
|
reason: data.reason.clone(),
|
||||||
},
|
},
|
||||||
&context,
|
&context,
|
||||||
)
|
)?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(Json(SuccessResponse::default()))
|
Ok(Json(SuccessResponse::default()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,8 +75,7 @@ pub async fn purge_community(
|
||||||
removed: true,
|
removed: true,
|
||||||
},
|
},
|
||||||
&context,
|
&context,
|
||||||
)
|
)?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(Json(SuccessResponse::default()))
|
Ok(Json(SuccessResponse::default()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,8 +80,7 @@ pub async fn purge_person(
|
||||||
expires: None,
|
expires: None,
|
||||||
},
|
},
|
||||||
&context,
|
&context,
|
||||||
)
|
)?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(Json(SuccessResponse::default()))
|
Ok(Json(SuccessResponse::default()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,8 +66,7 @@ pub async fn purge_post(
|
||||||
removed: true,
|
removed: true,
|
||||||
},
|
},
|
||||||
&context,
|
&context,
|
||||||
)
|
)?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(Json(SuccessResponse::default()))
|
Ok(Json(SuccessResponse::default()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,7 @@ use lemmy_utils::error::LemmyResult;
|
||||||
use sitemap_rs::{url::Url, url_set::UrlSet};
|
use sitemap_rs::{url::Url, url_set::UrlSet};
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
async fn generate_urlset(
|
fn generate_urlset(posts: Vec<(DbUrl, chrono::DateTime<chrono::Utc>)>) -> LemmyResult<UrlSet> {
|
||||||
posts: Vec<(DbUrl, chrono::DateTime<chrono::Utc>)>,
|
|
||||||
) -> LemmyResult<UrlSet> {
|
|
||||||
let urls = posts
|
let urls = posts
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map_while(|(url, date_time)| {
|
.map_while(|(url, date_time)| {
|
||||||
|
@ -31,7 +29,7 @@ pub async fn get_sitemap(context: Data<LemmyContext>) -> LemmyResult<HttpRespons
|
||||||
info!("Loaded latest {} posts", posts.len());
|
info!("Loaded latest {} posts", posts.len());
|
||||||
|
|
||||||
let mut buf = Vec::<u8>::new();
|
let mut buf = Vec::<u8>::new();
|
||||||
generate_urlset(posts).await?.write(&mut buf)?;
|
generate_urlset(posts)?.write(&mut buf)?;
|
||||||
|
|
||||||
Ok(
|
Ok(
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok()
|
||||||
|
@ -74,7 +72,7 @@ pub(crate) mod tests {
|
||||||
];
|
];
|
||||||
|
|
||||||
let mut buf = Vec::<u8>::new();
|
let mut buf = Vec::<u8>::new();
|
||||||
generate_urlset(posts).await?.write(&mut buf)?;
|
generate_urlset(posts)?.write(&mut buf)?;
|
||||||
let root = Element::from_reader(buf.as_slice())?;
|
let root = Element::from_reader(buf.as_slice())?;
|
||||||
|
|
||||||
assert_eq!(root.tag().name(), "urlset");
|
assert_eq!(root.tag().name(), "urlset");
|
||||||
|
|
|
@ -67,7 +67,7 @@ mime = { version = "0.3.17", optional = true }
|
||||||
webpage = { version = "2.0", default-features = false, features = [
|
webpage = { version = "2.0", default-features = false, features = [
|
||||||
"serde",
|
"serde",
|
||||||
], optional = true }
|
], optional = true }
|
||||||
encoding_rs = { version = "0.8.34", optional = true }
|
encoding_rs = { version = "0.8.35", optional = true }
|
||||||
jsonwebtoken = { version = "9.3.0", optional = true }
|
jsonwebtoken = { version = "9.3.0", optional = true }
|
||||||
# necessary for wasmt compilation
|
# necessary for wasmt compilation
|
||||||
getrandom = { version = "0.2.15", features = ["js"] }
|
getrandom = { version = "0.2.15", features = ["js"] }
|
||||||
|
|
|
@ -92,7 +92,7 @@ mod tests {
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[serial]
|
#[serial]
|
||||||
async fn test_should_not_validate_user_token_after_password_change() -> LemmyResult<()> {
|
async fn test_should_not_validate_user_token_after_password_change() -> LemmyResult<()> {
|
||||||
let pool_ = build_db_pool_for_tests().await;
|
let pool_ = build_db_pool_for_tests();
|
||||||
let pool = &mut (&pool_).into();
|
let pool = &mut (&pool_).into();
|
||||||
let secret = Secret::init(pool).await?;
|
let secret = Secret::init(pool).await?;
|
||||||
let context = LemmyContext::create(
|
let context = LemmyContext::create(
|
||||||
|
|
|
@ -8,6 +8,7 @@ use lemmy_db_views_actor::structs::{
|
||||||
CommunityModeratorView,
|
CommunityModeratorView,
|
||||||
CommunitySortType,
|
CommunitySortType,
|
||||||
CommunityView,
|
CommunityView,
|
||||||
|
PendingFollow,
|
||||||
PersonView,
|
PersonView,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -274,3 +275,50 @@ pub struct GetRandomCommunity {
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
#[cfg_attr(feature = "full", ts(optional))]
|
||||||
pub type_: Option<ListingType>,
|
pub type_: Option<ListingType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[skip_serializing_none]
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
#[cfg_attr(feature = "full", derive(TS))]
|
||||||
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
|
pub struct ListCommunityPendingFollows {
|
||||||
|
/// Only shows the unapproved applications
|
||||||
|
#[cfg_attr(feature = "full", ts(optional))]
|
||||||
|
pub pending_only: Option<bool>,
|
||||||
|
// Only for admins, show pending follows for communities which you dont moderate
|
||||||
|
#[cfg_attr(feature = "full", ts(optional))]
|
||||||
|
pub all_communities: Option<bool>,
|
||||||
|
#[cfg_attr(feature = "full", ts(optional))]
|
||||||
|
pub page: Option<i64>,
|
||||||
|
#[cfg_attr(feature = "full", ts(optional))]
|
||||||
|
pub limit: Option<i64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
#[cfg_attr(feature = "full", derive(TS))]
|
||||||
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
|
pub struct GetCommunityPendingFollowsCount {
|
||||||
|
pub community_id: CommunityId,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
#[cfg_attr(feature = "full", derive(TS))]
|
||||||
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
|
pub struct GetCommunityPendingFollowsCountResponse {
|
||||||
|
pub count: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
#[cfg_attr(feature = "full", derive(TS))]
|
||||||
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
|
pub struct ListCommunityPendingFollowsResponse {
|
||||||
|
pub items: Vec<PendingFollow>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
#[cfg_attr(feature = "full", derive(TS))]
|
||||||
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
|
pub struct ApproveCommunityPendingFollower {
|
||||||
|
pub community_id: CommunityId,
|
||||||
|
pub follower_id: PersonId,
|
||||||
|
pub approve: bool,
|
||||||
|
}
|
||||||
|
|
|
@ -55,9 +55,10 @@ impl LemmyContext {
|
||||||
/// Initialize a context for use in tests which blocks federation network calls.
|
/// Initialize a context for use in tests which blocks federation network calls.
|
||||||
///
|
///
|
||||||
/// Do not use this in production code.
|
/// Do not use this in production code.
|
||||||
|
#[allow(clippy::expect_used)]
|
||||||
pub async fn init_test_federation_config() -> FederationConfig<LemmyContext> {
|
pub async fn init_test_federation_config() -> FederationConfig<LemmyContext> {
|
||||||
// call this to run migrations
|
// call this to run migrations
|
||||||
let pool = build_db_pool_for_tests().await;
|
let pool = build_db_pool_for_tests();
|
||||||
|
|
||||||
let client = client_builder(&SETTINGS).build().expect("build client");
|
let client = client_builder(&SETTINGS).build().expect("build client");
|
||||||
|
|
||||||
|
|
|
@ -163,6 +163,9 @@ pub struct SaveUserSettings {
|
||||||
/// should be paused
|
/// should be paused
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
#[cfg_attr(feature = "full", ts(optional))]
|
||||||
pub enable_animated_images: Option<bool>,
|
pub enable_animated_images: Option<bool>,
|
||||||
|
/// Whether a user can send / receive private messages
|
||||||
|
#[cfg_attr(feature = "full", ts(optional))]
|
||||||
|
pub enable_private_messages: Option<bool>,
|
||||||
/// Whether to auto-collapse bot comments.
|
/// Whether to auto-collapse bot comments.
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
#[cfg_attr(feature = "full", ts(optional))]
|
||||||
pub collapse_bot_comments: Option<bool>,
|
pub collapse_bot_comments: Option<bool>,
|
||||||
|
@ -175,6 +178,9 @@ pub struct SaveUserSettings {
|
||||||
pub show_downvotes: Option<bool>,
|
pub show_downvotes: Option<bool>,
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
#[cfg_attr(feature = "full", ts(optional))]
|
||||||
pub show_upvote_percentage: Option<bool>,
|
pub show_upvote_percentage: Option<bool>,
|
||||||
|
/// Whether to automatically mark fetched posts as read.
|
||||||
|
#[cfg_attr(feature = "full", ts(optional))]
|
||||||
|
pub auto_mark_fetched_posts_as_read: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
|
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
|
||||||
|
|
|
@ -108,6 +108,9 @@ pub struct GetPosts {
|
||||||
/// If true, then show the nsfw posts (even if your user setting is to hide them)
|
/// If true, then show the nsfw posts (even if your user setting is to hide them)
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
#[cfg_attr(feature = "full", ts(optional))]
|
||||||
pub show_nsfw: Option<bool>,
|
pub show_nsfw: Option<bool>,
|
||||||
|
/// Whether to automatically mark fetched posts as read.
|
||||||
|
#[cfg_attr(feature = "full", ts(optional))]
|
||||||
|
pub mark_as_read: Option<bool>,
|
||||||
#[cfg_attr(feature = "full", ts(optional))]
|
#[cfg_attr(feature = "full", ts(optional))]
|
||||||
/// If true, then only show posts with no comments
|
/// If true, then only show posts with no comments
|
||||||
pub no_comments_only: Option<bool>,
|
pub no_comments_only: Option<bool>,
|
||||||
|
@ -193,17 +196,26 @@ pub struct RemovePost {
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
/// Mark a post as read.
|
/// Mark a post as read.
|
||||||
pub struct MarkPostAsRead {
|
pub struct MarkPostAsRead {
|
||||||
pub post_ids: Vec<PostId>,
|
pub post_id: PostId,
|
||||||
pub read: bool,
|
pub read: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[skip_serializing_none]
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
|
||||||
|
#[cfg_attr(feature = "full", derive(TS))]
|
||||||
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
|
/// Mark several posts as read.
|
||||||
|
pub struct MarkManyPostsAsRead {
|
||||||
|
pub post_ids: Vec<PostId>,
|
||||||
|
}
|
||||||
|
|
||||||
#[skip_serializing_none]
|
#[skip_serializing_none]
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
|
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
|
||||||
#[cfg_attr(feature = "full", derive(TS))]
|
#[cfg_attr(feature = "full", derive(TS))]
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
/// Hide a post from list views
|
/// Hide a post from list views
|
||||||
pub struct HidePost {
|
pub struct HidePost {
|
||||||
pub post_ids: Vec<PostId>,
|
pub post_id: PostId,
|
||||||
pub hide: bool,
|
pub hide: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ use lemmy_db_schema::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
error::{LemmyError, LemmyErrorType, LemmyResult},
|
error::{LemmyError, LemmyErrorExt, LemmyErrorType, LemmyResult},
|
||||||
settings::structs::{PictrsImageMode, Settings},
|
settings::structs::{PictrsImageMode, Settings},
|
||||||
REQWEST_TIMEOUT,
|
REQWEST_TIMEOUT,
|
||||||
VERSION,
|
VERSION,
|
||||||
|
@ -61,7 +61,8 @@ pub async fn fetch_link_metadata(url: &Url, context: &LemmyContext) -> LemmyResu
|
||||||
// server may ignore this and still respond with the full response
|
// server may ignore this and still respond with the full response
|
||||||
.header(RANGE, format!("bytes=0-{}", bytes_to_fetch - 1)) /* -1 because inclusive */
|
.header(RANGE, format!("bytes=0-{}", bytes_to_fetch - 1)) /* -1 because inclusive */
|
||||||
.send()
|
.send()
|
||||||
.await?;
|
.await?
|
||||||
|
.error_for_status()?;
|
||||||
|
|
||||||
let content_type: Option<Mime> = response
|
let content_type: Option<Mime> = response
|
||||||
.headers()
|
.headers()
|
||||||
|
@ -175,7 +176,7 @@ pub async fn generate_post_link_metadata(
|
||||||
};
|
};
|
||||||
let updated_post = Post::update(&mut context.pool(), post.id, &form).await?;
|
let updated_post = Post::update(&mut context.pool(), post.id, &form).await?;
|
||||||
if let Some(send_activity) = send_activity(updated_post) {
|
if let Some(send_activity) = send_activity(updated_post) {
|
||||||
ActivityChannel::submit_activity(send_activity, &context).await?;
|
ActivityChannel::submit_activity(send_activity, &context)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -308,7 +309,8 @@ pub async fn purge_image_from_pictrs(image_url: &Url, context: &LemmyContext) ->
|
||||||
.timeout(REQWEST_TIMEOUT)
|
.timeout(REQWEST_TIMEOUT)
|
||||||
.header("x-api-token", pictrs_api_key)
|
.header("x-api-token", pictrs_api_key)
|
||||||
.send()
|
.send()
|
||||||
.await?;
|
.await?
|
||||||
|
.error_for_status()?;
|
||||||
|
|
||||||
let response: PictrsPurgeResponse = response.json().await.map_err(LemmyError::from)?;
|
let response: PictrsPurgeResponse = response.json().await.map_err(LemmyError::from)?;
|
||||||
|
|
||||||
|
@ -333,8 +335,8 @@ pub async fn delete_image_from_pictrs(
|
||||||
.delete(&url)
|
.delete(&url)
|
||||||
.timeout(REQWEST_TIMEOUT)
|
.timeout(REQWEST_TIMEOUT)
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await?
|
||||||
.map_err(LemmyError::from)?;
|
.error_for_status()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,6 +368,7 @@ async fn generate_pictrs_thumbnail(image_url: &Url, context: &LemmyContext) -> L
|
||||||
.timeout(REQWEST_TIMEOUT)
|
.timeout(REQWEST_TIMEOUT)
|
||||||
.send()
|
.send()
|
||||||
.await?
|
.await?
|
||||||
|
.error_for_status()?
|
||||||
.json::<PictrsResponse>()
|
.json::<PictrsResponse>()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
@ -406,16 +409,14 @@ pub async fn fetch_pictrs_proxied_image_details(
|
||||||
// Pictrs needs you to fetch the proxied image before you can fetch the details
|
// Pictrs needs you to fetch the proxied image before you can fetch the details
|
||||||
let proxy_url = format!("{pictrs_url}image/original?proxy={encoded_image_url}");
|
let proxy_url = format!("{pictrs_url}image/original?proxy={encoded_image_url}");
|
||||||
|
|
||||||
let res = context
|
context
|
||||||
.client()
|
.client()
|
||||||
.get(&proxy_url)
|
.get(&proxy_url)
|
||||||
.timeout(REQWEST_TIMEOUT)
|
.timeout(REQWEST_TIMEOUT)
|
||||||
.send()
|
.send()
|
||||||
.await?
|
.await?
|
||||||
.status();
|
.error_for_status()
|
||||||
if !res.is_success() {
|
.with_lemmy_type(LemmyErrorType::NotAnImageType)?;
|
||||||
Err(LemmyErrorType::NotAnImageType)?
|
|
||||||
}
|
|
||||||
|
|
||||||
let details_url = format!("{pictrs_url}image/details/original?proxy={encoded_image_url}");
|
let details_url = format!("{pictrs_url}image/details/original?proxy={encoded_image_url}");
|
||||||
|
|
||||||
|
@ -425,6 +426,7 @@ pub async fn fetch_pictrs_proxied_image_details(
|
||||||
.timeout(REQWEST_TIMEOUT)
|
.timeout(REQWEST_TIMEOUT)
|
||||||
.send()
|
.send()
|
||||||
.await?
|
.await?
|
||||||
|
.error_for_status()?
|
||||||
.json()
|
.json()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
@ -521,7 +523,7 @@ mod tests {
|
||||||
|
|
||||||
// root relative url
|
// root relative url
|
||||||
let html_bytes = b"<!DOCTYPE html><html><head><meta property='og:image' content='/image.jpg'></head><body></body></html>";
|
let html_bytes = b"<!DOCTYPE html><html><head><meta property='og:image' content='/image.jpg'></head><body></body></html>";
|
||||||
let metadata = extract_opengraph_data(html_bytes, &url).expect("Unable to parse metadata");
|
let metadata = extract_opengraph_data(html_bytes, &url)?;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
metadata.image,
|
metadata.image,
|
||||||
Some(Url::parse("https://example.com/image.jpg")?.into())
|
Some(Url::parse("https://example.com/image.jpg")?.into())
|
||||||
|
@ -529,7 +531,7 @@ mod tests {
|
||||||
|
|
||||||
// base relative url
|
// base relative url
|
||||||
let html_bytes = b"<!DOCTYPE html><html><head><meta property='og:image' content='image.jpg'></head><body></body></html>";
|
let html_bytes = b"<!DOCTYPE html><html><head><meta property='og:image' content='image.jpg'></head><body></body></html>";
|
||||||
let metadata = extract_opengraph_data(html_bytes, &url).expect("Unable to parse metadata");
|
let metadata = extract_opengraph_data(html_bytes, &url)?;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
metadata.image,
|
metadata.image,
|
||||||
Some(Url::parse("https://example.com/one/image.jpg")?.into())
|
Some(Url::parse("https://example.com/one/image.jpg")?.into())
|
||||||
|
@ -537,7 +539,7 @@ mod tests {
|
||||||
|
|
||||||
// absolute url
|
// absolute url
|
||||||
let html_bytes = b"<!DOCTYPE html><html><head><meta property='og:image' content='https://cdn.host.com/image.jpg'></head><body></body></html>";
|
let html_bytes = b"<!DOCTYPE html><html><head><meta property='og:image' content='https://cdn.host.com/image.jpg'></head><body></body></html>";
|
||||||
let metadata = extract_opengraph_data(html_bytes, &url).expect("Unable to parse metadata");
|
let metadata = extract_opengraph_data(html_bytes, &url)?;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
metadata.image,
|
metadata.image,
|
||||||
Some(Url::parse("https://cdn.host.com/image.jpg")?.into())
|
Some(Url::parse("https://cdn.host.com/image.jpg")?.into())
|
||||||
|
@ -545,7 +547,7 @@ mod tests {
|
||||||
|
|
||||||
// protocol relative url
|
// protocol relative url
|
||||||
let html_bytes = b"<!DOCTYPE html><html><head><meta property='og:image' content='//example.com/image.jpg'></head><body></body></html>";
|
let html_bytes = b"<!DOCTYPE html><html><head><meta property='og:image' content='//example.com/image.jpg'></head><body></body></html>";
|
||||||
let metadata = extract_opengraph_data(html_bytes, &url).expect("Unable to parse metadata");
|
let metadata = extract_opengraph_data(html_bytes, &url)?;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
metadata.image,
|
metadata.image,
|
||||||
Some(Url::parse("https://example.com/image.jpg")?.into())
|
Some(Url::parse("https://example.com/image.jpg")?.into())
|
||||||
|
|
|
@ -59,6 +59,8 @@ pub enum SendActivityData {
|
||||||
score: i16,
|
score: i16,
|
||||||
},
|
},
|
||||||
FollowCommunity(Community, Person, bool),
|
FollowCommunity(Community, Person, bool),
|
||||||
|
AcceptFollower(CommunityId, PersonId),
|
||||||
|
RejectFollower(CommunityId, PersonId),
|
||||||
UpdateCommunity(Person, Community),
|
UpdateCommunity(Person, Community),
|
||||||
DeleteCommunity(Person, Community, bool),
|
DeleteCommunity(Person, Community, bool),
|
||||||
RemoveCommunity {
|
RemoveCommunity {
|
||||||
|
@ -123,10 +125,7 @@ impl ActivityChannel {
|
||||||
lock.recv().await
|
lock.recv().await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn submit_activity(
|
pub fn submit_activity(data: SendActivityData, _context: &Data<LemmyContext>) -> LemmyResult<()> {
|
||||||
data: SendActivityData,
|
|
||||||
_context: &Data<LemmyContext>,
|
|
||||||
) -> LemmyResult<()> {
|
|
||||||
// could do `ACTIVITY_CHANNEL.keepalive_sender.lock()` instead and get rid of weak_sender,
|
// could do `ACTIVITY_CHANNEL.keepalive_sender.lock()` instead and get rid of weak_sender,
|
||||||
// not sure which way is more efficient
|
// not sure which way is more efficient
|
||||||
if let Some(sender) = ACTIVITY_CHANNEL.weak_sender.upgrade() {
|
if let Some(sender) = ACTIVITY_CHANNEL.weak_sender.upgrade() {
|
||||||
|
|
|
@ -514,6 +514,7 @@ pub struct ReadableFederationState {
|
||||||
next_retry: Option<DateTime<Utc>>,
|
next_retry: Option<DateTime<Utc>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::expect_used)]
|
||||||
impl From<FederationQueueState> for ReadableFederationState {
|
impl From<FederationQueueState> for ReadableFederationState {
|
||||||
fn from(internal_state: FederationQueueState) -> Self {
|
fn from(internal_state: FederationQueueState) -> Self {
|
||||||
ReadableFederationState {
|
ReadableFederationState {
|
||||||
|
|
|
@ -28,7 +28,7 @@ use lemmy_db_schema::{
|
||||||
password_reset_request::PasswordResetRequest,
|
password_reset_request::PasswordResetRequest,
|
||||||
person::{Person, PersonUpdateForm},
|
person::{Person, PersonUpdateForm},
|
||||||
person_block::PersonBlock,
|
person_block::PersonBlock,
|
||||||
post::{Post, PostLike, PostRead},
|
post::{Post, PostLike},
|
||||||
registration_application::RegistrationApplication,
|
registration_application::RegistrationApplication,
|
||||||
site::Site,
|
site::Site,
|
||||||
},
|
},
|
||||||
|
@ -42,6 +42,7 @@ use lemmy_db_views::{
|
||||||
structs::{LocalImageView, LocalUserView, SiteView},
|
structs::{LocalImageView, LocalUserView, SiteView},
|
||||||
};
|
};
|
||||||
use lemmy_db_views_actor::structs::{
|
use lemmy_db_views_actor::structs::{
|
||||||
|
CommunityFollowerView,
|
||||||
CommunityModeratorView,
|
CommunityModeratorView,
|
||||||
CommunityPersonBanView,
|
CommunityPersonBanView,
|
||||||
CommunityView,
|
CommunityView,
|
||||||
|
@ -64,7 +65,7 @@ use lemmy_utils::{
|
||||||
use moka::future::Cache;
|
use moka::future::Cache;
|
||||||
use regex::{escape, Regex, RegexSet};
|
use regex::{escape, Regex, RegexSet};
|
||||||
use rosetta_i18n::{Language, LanguageId};
|
use rosetta_i18n::{Language, LanguageId};
|
||||||
use std::{collections::HashSet, sync::LazyLock};
|
use std::sync::LazyLock;
|
||||||
use tracing::warn;
|
use tracing::warn;
|
||||||
use url::{ParseError, Url};
|
use url::{ParseError, Url};
|
||||||
use urlencoding::encode;
|
use urlencoding::encode;
|
||||||
|
@ -140,19 +141,6 @@ pub fn is_top_mod(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Marks a post as read for a given person.
|
|
||||||
#[tracing::instrument(skip_all)]
|
|
||||||
pub async fn mark_post_as_read(
|
|
||||||
person_id: PersonId,
|
|
||||||
post_id: PostId,
|
|
||||||
pool: &mut DbPool<'_>,
|
|
||||||
) -> LemmyResult<()> {
|
|
||||||
PostRead::mark_as_read(pool, HashSet::from([post_id]), person_id)
|
|
||||||
.await
|
|
||||||
.with_lemmy_type(LemmyErrorType::CouldntMarkPostAsRead)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Updates the read comment count for a post. Usually done when reading or creating a new comment.
|
/// Updates the read comment count for a post. Usually done when reading or creating a new comment.
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub async fn update_read_comments(
|
pub async fn update_read_comments(
|
||||||
|
@ -165,7 +153,6 @@ pub async fn update_read_comments(
|
||||||
person_id,
|
person_id,
|
||||||
post_id,
|
post_id,
|
||||||
read_comments,
|
read_comments,
|
||||||
..PersonPostAggregatesForm::default()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
PersonPostAggregates::upsert(pool, &person_post_agg_form).await?;
|
PersonPostAggregates::upsert(pool, &person_post_agg_form).await?;
|
||||||
|
@ -232,20 +219,17 @@ pub async fn check_registration_application(
|
||||||
/// the user isn't banned.
|
/// the user isn't banned.
|
||||||
pub async fn check_community_user_action(
|
pub async fn check_community_user_action(
|
||||||
person: &Person,
|
person: &Person,
|
||||||
community_id: CommunityId,
|
community: &Community,
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
) -> LemmyResult<()> {
|
) -> LemmyResult<()> {
|
||||||
check_user_valid(person)?;
|
check_user_valid(person)?;
|
||||||
check_community_deleted_removed(community_id, pool).await?;
|
check_community_deleted_removed(community)?;
|
||||||
CommunityPersonBanView::check(pool, person.id, community_id).await?;
|
CommunityPersonBanView::check(pool, person.id, community.id).await?;
|
||||||
|
CommunityFollowerView::check_private_community_action(pool, person.id, community).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn check_community_deleted_removed(
|
pub fn check_community_deleted_removed(community: &Community) -> LemmyResult<()> {
|
||||||
community_id: CommunityId,
|
|
||||||
pool: &mut DbPool<'_>,
|
|
||||||
) -> LemmyResult<()> {
|
|
||||||
let community = Community::read(pool, community_id).await?;
|
|
||||||
if community.deleted || community.removed {
|
if community.deleted || community.removed {
|
||||||
Err(LemmyErrorType::Deleted)?
|
Err(LemmyErrorType::Deleted)?
|
||||||
}
|
}
|
||||||
|
@ -258,16 +242,16 @@ async fn check_community_deleted_removed(
|
||||||
/// removed/deleted.
|
/// removed/deleted.
|
||||||
pub async fn check_community_mod_action(
|
pub async fn check_community_mod_action(
|
||||||
person: &Person,
|
person: &Person,
|
||||||
community_id: CommunityId,
|
community: &Community,
|
||||||
allow_deleted: bool,
|
allow_deleted: bool,
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
) -> LemmyResult<()> {
|
) -> LemmyResult<()> {
|
||||||
is_mod_or_admin(pool, person, community_id).await?;
|
is_mod_or_admin(pool, person, community.id).await?;
|
||||||
CommunityPersonBanView::check(pool, person.id, community_id).await?;
|
CommunityPersonBanView::check(pool, person.id, community.id).await?;
|
||||||
|
|
||||||
// it must be possible to restore deleted community
|
// it must be possible to restore deleted community
|
||||||
if !allow_deleted {
|
if !allow_deleted {
|
||||||
check_community_deleted_removed(community_id, pool).await?;
|
check_community_deleted_removed(community)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -357,6 +341,16 @@ pub fn check_private_instance(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If private messages are disabled, dont allow them to be sent / received
|
||||||
|
#[tracing::instrument(skip_all)]
|
||||||
|
pub fn check_private_messages_enabled(local_user_view: &LocalUserView) -> Result<(), LemmyError> {
|
||||||
|
if !local_user_view.local_user.enable_private_messages {
|
||||||
|
Err(LemmyErrorType::CouldntCreatePrivateMessage)?
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub async fn build_federated_instances(
|
pub async fn build_federated_instances(
|
||||||
local_site: &LocalSite,
|
local_site: &LocalSite,
|
||||||
|
@ -448,7 +442,11 @@ pub async fn send_password_reset_email(
|
||||||
// Generate a random token
|
// Generate a random token
|
||||||
let token = uuid::Uuid::new_v4().to_string();
|
let token = uuid::Uuid::new_v4().to_string();
|
||||||
|
|
||||||
let email = &user.local_user.email.clone().expect("email");
|
let email = &user
|
||||||
|
.local_user
|
||||||
|
.email
|
||||||
|
.clone()
|
||||||
|
.ok_or(LemmyErrorType::EmailRequired)?;
|
||||||
let lang = get_interface_language(user);
|
let lang = get_interface_language(user);
|
||||||
let subject = &lang.password_reset_subject(&user.person.name);
|
let subject = &lang.password_reset_subject(&user.person.name);
|
||||||
let protocol_and_hostname = settings.get_protocol_and_hostname();
|
let protocol_and_hostname = settings.get_protocol_and_hostname();
|
||||||
|
@ -498,6 +496,7 @@ pub fn get_interface_language_from_settings(user: &LocalUserView) -> Lang {
|
||||||
lang_str_to_lang(&user.local_user.interface_language)
|
lang_str_to_lang(&user.local_user.interface_language)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::expect_used)]
|
||||||
fn lang_str_to_lang(lang: &str) -> Lang {
|
fn lang_str_to_lang(lang: &str) -> Lang {
|
||||||
let lang_id = LanguageId::new(lang);
|
let lang_id = LanguageId::new(lang);
|
||||||
Lang::from_language_id(&lang_id).unwrap_or_else(|| {
|
Lang::from_language_id(&lang_id).unwrap_or_else(|| {
|
||||||
|
@ -524,11 +523,11 @@ pub fn local_site_rate_limit_to_rate_limit_config(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn local_site_to_slur_regex(local_site: &LocalSite) -> Option<Regex> {
|
pub fn local_site_to_slur_regex(local_site: &LocalSite) -> Option<LemmyResult<Regex>> {
|
||||||
build_slur_regex(local_site.slur_filter_regex.as_deref())
|
build_slur_regex(local_site.slur_filter_regex.as_deref())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn local_site_opt_to_slur_regex(local_site: &Option<LocalSite>) -> Option<Regex> {
|
pub fn local_site_opt_to_slur_regex(local_site: &Option<LocalSite>) -> Option<LemmyResult<Regex>> {
|
||||||
local_site
|
local_site
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(local_site_to_slur_regex)
|
.map(local_site_to_slur_regex)
|
||||||
|
@ -563,7 +562,11 @@ pub async fn send_application_approved_email(
|
||||||
user: &LocalUserView,
|
user: &LocalUserView,
|
||||||
settings: &Settings,
|
settings: &Settings,
|
||||||
) -> LemmyResult<()> {
|
) -> LemmyResult<()> {
|
||||||
let email = &user.local_user.email.clone().expect("email");
|
let email = &user
|
||||||
|
.local_user
|
||||||
|
.email
|
||||||
|
.clone()
|
||||||
|
.ok_or(LemmyErrorType::EmailRequired)?;
|
||||||
let lang = get_interface_language(user);
|
let lang = get_interface_language(user);
|
||||||
let subject = lang.registration_approved_subject(&user.person.actor_id);
|
let subject = lang.registration_approved_subject(&user.person.actor_id);
|
||||||
let body = lang.registration_approved_body(&settings.hostname);
|
let body = lang.registration_approved_body(&settings.hostname);
|
||||||
|
@ -585,7 +588,11 @@ pub async fn send_new_applicant_email_to_admins(
|
||||||
);
|
);
|
||||||
|
|
||||||
for admin in &admins {
|
for admin in &admins {
|
||||||
let email = &admin.local_user.email.clone().expect("email");
|
let email = &admin
|
||||||
|
.local_user
|
||||||
|
.email
|
||||||
|
.clone()
|
||||||
|
.ok_or(LemmyErrorType::EmailRequired)?;
|
||||||
let lang = get_interface_language_from_settings(admin);
|
let lang = get_interface_language_from_settings(admin);
|
||||||
let subject = lang.new_application_subject(&settings.hostname, applicant_username);
|
let subject = lang.new_application_subject(&settings.hostname, applicant_username);
|
||||||
let body = lang.new_application_body(applications_link);
|
let body = lang.new_application_body(applications_link);
|
||||||
|
@ -607,11 +614,13 @@ pub async fn send_new_report_email_to_admins(
|
||||||
let reports_link = &format!("{}/reports", settings.get_protocol_and_hostname(),);
|
let reports_link = &format!("{}/reports", settings.get_protocol_and_hostname(),);
|
||||||
|
|
||||||
for admin in &admins {
|
for admin in &admins {
|
||||||
let email = &admin.local_user.email.clone().expect("email");
|
if let Some(email) = &admin.local_user.email {
|
||||||
let lang = get_interface_language_from_settings(admin);
|
let lang = get_interface_language_from_settings(admin);
|
||||||
let subject = lang.new_report_subject(&settings.hostname, reported_username, reporter_username);
|
let subject =
|
||||||
let body = lang.new_report_body(reports_link);
|
lang.new_report_subject(&settings.hostname, reported_username, reporter_username);
|
||||||
send_email(&subject, email, &admin.person.name, &body, settings).await?;
|
let body = lang.new_report_body(reports_link);
|
||||||
|
send_email(&subject, email, &admin.person.name, &body, settings).await?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1036,7 +1045,7 @@ pub fn check_conflicting_like_filters(
|
||||||
|
|
||||||
pub async fn process_markdown(
|
pub async fn process_markdown(
|
||||||
text: &str,
|
text: &str,
|
||||||
slur_regex: &Option<Regex>,
|
slur_regex: &Option<LemmyResult<Regex>>,
|
||||||
url_blocklist: &RegexSet,
|
url_blocklist: &RegexSet,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
) -> LemmyResult<String> {
|
) -> LemmyResult<String> {
|
||||||
|
@ -1068,7 +1077,7 @@ pub async fn process_markdown(
|
||||||
|
|
||||||
pub async fn process_markdown_opt(
|
pub async fn process_markdown_opt(
|
||||||
text: &Option<String>,
|
text: &Option<String>,
|
||||||
slur_regex: &Option<Regex>,
|
slur_regex: &Option<LemmyResult<Regex>>,
|
||||||
url_blocklist: &RegexSet,
|
url_blocklist: &RegexSet,
|
||||||
context: &LemmyContext,
|
context: &LemmyContext,
|
||||||
) -> LemmyResult<Option<String>> {
|
) -> LemmyResult<Option<String>> {
|
||||||
|
|
|
@ -16,9 +16,8 @@ use lemmy_api_common::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
impls::actor_language::default_post_language,
|
impls::actor_language::validate_post_language,
|
||||||
source::{
|
source::{
|
||||||
actor_language::CommunityLanguage,
|
|
||||||
comment::{Comment, CommentInsertForm, CommentLike, CommentLikeForm},
|
comment::{Comment, CommentInsertForm, CommentLike, CommentLikeForm},
|
||||||
comment_reply::{CommentReply, CommentReplyUpdateForm},
|
comment_reply::{CommentReply, CommentReplyUpdateForm},
|
||||||
local_site::LocalSite,
|
local_site::LocalSite,
|
||||||
|
@ -61,7 +60,12 @@ pub async fn create_comment(
|
||||||
let post = post_view.post;
|
let post = post_view.post;
|
||||||
let community_id = post_view.community.id;
|
let community_id = post_view.community.id;
|
||||||
|
|
||||||
check_community_user_action(&local_user_view.person, community_id, &mut context.pool()).await?;
|
check_community_user_action(
|
||||||
|
&local_user_view.person,
|
||||||
|
&post_view.community,
|
||||||
|
&mut context.pool(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
check_post_deleted_or_removed(&post)?;
|
check_post_deleted_or_removed(&post)?;
|
||||||
|
|
||||||
// Check if post is locked, no new comments
|
// Check if post is locked, no new comments
|
||||||
|
@ -88,21 +92,13 @@ pub async fn create_comment(
|
||||||
check_comment_depth(parent)?;
|
check_comment_depth(parent)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// attempt to set default language if none was provided
|
let language_id = validate_post_language(
|
||||||
let language_id = match data.language_id {
|
&mut context.pool(),
|
||||||
Some(lid) => lid,
|
data.language_id,
|
||||||
None => {
|
community_id,
|
||||||
default_post_language(
|
local_user_view.local_user.id,
|
||||||
&mut context.pool(),
|
)
|
||||||
community_id,
|
.await?;
|
||||||
local_user_view.local_user.id,
|
|
||||||
)
|
|
||||||
.await?
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
CommunityLanguage::is_allowed_community_language(&mut context.pool(), language_id, community_id)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let comment_form = CommentInsertForm {
|
let comment_form = CommentInsertForm {
|
||||||
language_id: Some(language_id),
|
language_id: Some(language_id),
|
||||||
|
@ -143,8 +139,7 @@ pub async fn create_comment(
|
||||||
ActivityChannel::submit_activity(
|
ActivityChannel::submit_activity(
|
||||||
SendActivityData::CreateComment(inserted_comment.clone()),
|
SendActivityData::CreateComment(inserted_comment.clone()),
|
||||||
&context,
|
&context,
|
||||||
)
|
)?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
// Update the read comments, so your own new comment doesn't appear as a +1 unread
|
// Update the read comments, so your own new comment doesn't appear as a +1 unread
|
||||||
update_read_comments(
|
update_read_comments(
|
||||||
|
|
|
@ -35,7 +35,7 @@ pub async fn delete_comment(
|
||||||
|
|
||||||
check_community_user_action(
|
check_community_user_action(
|
||||||
&local_user_view.person,
|
&local_user_view.person,
|
||||||
orig_comment.community.id,
|
&orig_comment.community,
|
||||||
&mut context.pool(),
|
&mut context.pool(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -76,8 +76,7 @@ pub async fn delete_comment(
|
||||||
orig_comment.community,
|
orig_comment.community,
|
||||||
),
|
),
|
||||||
&context,
|
&context,
|
||||||
)
|
)?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(Json(
|
Ok(Json(
|
||||||
build_comment_response(
|
build_comment_response(
|
||||||
|
|
|
@ -35,7 +35,7 @@ pub async fn remove_comment(
|
||||||
|
|
||||||
check_community_mod_action(
|
check_community_mod_action(
|
||||||
&local_user_view.person,
|
&local_user_view.person,
|
||||||
orig_comment.community.id,
|
&orig_comment.community,
|
||||||
false,
|
false,
|
||||||
&mut context.pool(),
|
&mut context.pool(),
|
||||||
)
|
)
|
||||||
|
@ -99,8 +99,7 @@ pub async fn remove_comment(
|
||||||
reason: data.reason.clone(),
|
reason: data.reason.clone(),
|
||||||
},
|
},
|
||||||
&context,
|
&context,
|
||||||
)
|
)?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(Json(
|
Ok(Json(
|
||||||
build_comment_response(
|
build_comment_response(
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use activitypub_federation::config::Data;
|
use activitypub_federation::config::Data;
|
||||||
use actix_web::web::Json;
|
use actix_web::web::Json;
|
||||||
|
use chrono::Utc;
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
build_response::{build_comment_response, send_local_notifs},
|
build_response::{build_comment_response, send_local_notifs},
|
||||||
comment::{CommentResponse, EditComment},
|
comment::{CommentResponse, EditComment},
|
||||||
|
@ -13,13 +14,12 @@ use lemmy_api_common::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
|
impls::actor_language::validate_post_language,
|
||||||
source::{
|
source::{
|
||||||
actor_language::CommunityLanguage,
|
|
||||||
comment::{Comment, CommentUpdateForm},
|
comment::{Comment, CommentUpdateForm},
|
||||||
local_site::LocalSite,
|
local_site::LocalSite,
|
||||||
},
|
},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
utils::naive_now,
|
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::{CommentView, LocalUserView};
|
use lemmy_db_views::structs::{CommentView, LocalUserView};
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
|
@ -45,7 +45,7 @@ pub async fn update_comment(
|
||||||
|
|
||||||
check_community_user_action(
|
check_community_user_action(
|
||||||
&local_user_view.person,
|
&local_user_view.person,
|
||||||
orig_comment.community.id,
|
&orig_comment.community,
|
||||||
&mut context.pool(),
|
&mut context.pool(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -55,14 +55,13 @@ pub async fn update_comment(
|
||||||
Err(LemmyErrorType::NoCommentEditAllowed)?
|
Err(LemmyErrorType::NoCommentEditAllowed)?
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(language_id) = data.language_id {
|
let language_id = validate_post_language(
|
||||||
CommunityLanguage::is_allowed_community_language(
|
&mut context.pool(),
|
||||||
&mut context.pool(),
|
data.language_id,
|
||||||
language_id,
|
orig_comment.community.id,
|
||||||
orig_comment.community.id,
|
local_user_view.local_user.id,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
|
||||||
|
|
||||||
let slur_regex = local_site_to_slur_regex(&local_site);
|
let slur_regex = local_site_to_slur_regex(&local_site);
|
||||||
let url_blocklist = get_url_blocklist(&context).await?;
|
let url_blocklist = get_url_blocklist(&context).await?;
|
||||||
|
@ -74,8 +73,8 @@ pub async fn update_comment(
|
||||||
let comment_id = data.comment_id;
|
let comment_id = data.comment_id;
|
||||||
let form = CommentUpdateForm {
|
let form = CommentUpdateForm {
|
||||||
content,
|
content,
|
||||||
language_id: data.language_id,
|
language_id: Some(language_id),
|
||||||
updated: Some(Some(naive_now())),
|
updated: Some(Some(Utc::now())),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let updated_comment = Comment::update(&mut context.pool(), comment_id, &form)
|
let updated_comment = Comment::update(&mut context.pool(), comment_id, &form)
|
||||||
|
@ -98,8 +97,7 @@ pub async fn update_comment(
|
||||||
ActivityChannel::submit_activity(
|
ActivityChannel::submit_activity(
|
||||||
SendActivityData::UpdateComment(updated_comment.clone()),
|
SendActivityData::UpdateComment(updated_comment.clone()),
|
||||||
&context,
|
&context,
|
||||||
)
|
)?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(Json(
|
Ok(Json(
|
||||||
build_comment_response(
|
build_comment_response(
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use super::check_community_visibility_allowed;
|
||||||
use activitypub_federation::{config::Data, http_signatures::generate_actor_keypair};
|
use activitypub_federation::{config::Data, http_signatures::generate_actor_keypair};
|
||||||
use actix_web::web::Json;
|
use actix_web::web::Json;
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
|
@ -23,6 +24,7 @@ use lemmy_db_schema::{
|
||||||
Community,
|
Community,
|
||||||
CommunityFollower,
|
CommunityFollower,
|
||||||
CommunityFollowerForm,
|
CommunityFollowerForm,
|
||||||
|
CommunityFollowerState,
|
||||||
CommunityInsertForm,
|
CommunityInsertForm,
|
||||||
CommunityModerator,
|
CommunityModerator,
|
||||||
CommunityModeratorForm,
|
CommunityModeratorForm,
|
||||||
|
@ -82,6 +84,12 @@ pub async fn create_community(
|
||||||
|
|
||||||
is_valid_actor_name(&data.name, local_site.actor_name_max_length as usize)?;
|
is_valid_actor_name(&data.name, local_site.actor_name_max_length as usize)?;
|
||||||
|
|
||||||
|
if let Some(desc) = &data.description {
|
||||||
|
is_valid_body_field(desc, false)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
check_community_visibility_allowed(data.visibility, &local_user_view)?;
|
||||||
|
|
||||||
// Double check for duplicate community actor_ids
|
// Double check for duplicate community actor_ids
|
||||||
let community_actor_id = generate_local_apub_endpoint(
|
let community_actor_id = generate_local_apub_endpoint(
|
||||||
EndpointType::Community,
|
EndpointType::Community,
|
||||||
|
@ -135,7 +143,8 @@ pub async fn create_community(
|
||||||
let community_follower_form = CommunityFollowerForm {
|
let community_follower_form = CommunityFollowerForm {
|
||||||
community_id: inserted_community.id,
|
community_id: inserted_community.id,
|
||||||
person_id: local_user_view.person.id,
|
person_id: local_user_view.person.id,
|
||||||
pending: false,
|
state: Some(CommunityFollowerState::Accepted),
|
||||||
|
approver_id: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
CommunityFollower::follow(&mut context.pool(), &community_follower_form)
|
CommunityFollower::follow(&mut context.pool(), &community_follower_form)
|
||||||
|
|
|
@ -22,13 +22,13 @@ pub async fn delete_community(
|
||||||
local_user_view: LocalUserView,
|
local_user_view: LocalUserView,
|
||||||
) -> LemmyResult<Json<CommunityResponse>> {
|
) -> LemmyResult<Json<CommunityResponse>> {
|
||||||
// Fetch the community mods
|
// Fetch the community mods
|
||||||
let community_id = data.community_id;
|
|
||||||
let community_mods =
|
let community_mods =
|
||||||
CommunityModeratorView::for_community(&mut context.pool(), community_id).await?;
|
CommunityModeratorView::for_community(&mut context.pool(), data.community_id).await?;
|
||||||
|
|
||||||
|
let community = Community::read(&mut context.pool(), data.community_id).await?;
|
||||||
check_community_mod_action(
|
check_community_mod_action(
|
||||||
&local_user_view.person,
|
&local_user_view.person,
|
||||||
community_id,
|
&community,
|
||||||
true,
|
true,
|
||||||
&mut context.pool(),
|
&mut context.pool(),
|
||||||
)
|
)
|
||||||
|
@ -54,8 +54,7 @@ pub async fn delete_community(
|
||||||
ActivityChannel::submit_activity(
|
ActivityChannel::submit_activity(
|
||||||
SendActivityData::DeleteCommunity(local_user_view.person.clone(), community, data.deleted),
|
SendActivityData::DeleteCommunity(local_user_view.person.clone(), community, data.deleted),
|
||||||
&context,
|
&context,
|
||||||
)
|
)?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
build_community_response(&context, local_user_view, community_id).await
|
build_community_response(&context, local_user_view, community_id).await
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,22 @@
|
||||||
|
use lemmy_api_common::utils::is_admin;
|
||||||
|
use lemmy_db_schema::CommunityVisibility;
|
||||||
|
use lemmy_db_views::structs::LocalUserView;
|
||||||
|
use lemmy_utils::error::LemmyResult;
|
||||||
|
|
||||||
pub mod create;
|
pub mod create;
|
||||||
pub mod delete;
|
pub mod delete;
|
||||||
pub mod list;
|
pub mod list;
|
||||||
pub mod remove;
|
pub mod remove;
|
||||||
pub mod update;
|
pub mod update;
|
||||||
|
|
||||||
|
/// For now only admins can make communities private, in order to prevent abuse.
|
||||||
|
/// Need to implement admin approval for new communities to get rid of this.
|
||||||
|
fn check_community_visibility_allowed(
|
||||||
|
visibility: Option<CommunityVisibility>,
|
||||||
|
local_user_view: &LocalUserView,
|
||||||
|
) -> LemmyResult<()> {
|
||||||
|
if visibility == Some(lemmy_db_schema::CommunityVisibility::Private) {
|
||||||
|
is_admin(local_user_view)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
@ -23,9 +23,10 @@ pub async fn remove_community(
|
||||||
context: Data<LemmyContext>,
|
context: Data<LemmyContext>,
|
||||||
local_user_view: LocalUserView,
|
local_user_view: LocalUserView,
|
||||||
) -> LemmyResult<Json<CommunityResponse>> {
|
) -> LemmyResult<Json<CommunityResponse>> {
|
||||||
|
let community = Community::read(&mut context.pool(), data.community_id).await?;
|
||||||
check_community_mod_action(
|
check_community_mod_action(
|
||||||
&local_user_view.person,
|
&local_user_view.person,
|
||||||
data.community_id,
|
&community,
|
||||||
true,
|
true,
|
||||||
&mut context.pool(),
|
&mut context.pool(),
|
||||||
)
|
)
|
||||||
|
@ -65,8 +66,7 @@ pub async fn remove_community(
|
||||||
removed: data.removed,
|
removed: data.removed,
|
||||||
},
|
},
|
||||||
&context,
|
&context,
|
||||||
)
|
)?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
build_community_response(&context, local_user_view, community_id).await
|
build_community_response(&context, local_user_view, community_id).await
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
use super::check_community_visibility_allowed;
|
||||||
use activitypub_federation::config::Data;
|
use activitypub_federation::config::Data;
|
||||||
use actix_web::web::Json;
|
use actix_web::web::Json;
|
||||||
|
use chrono::Utc;
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
build_response::build_community_response,
|
build_response::build_community_response,
|
||||||
community::{CommunityResponse, EditCommunity},
|
community::{CommunityResponse, EditCommunity},
|
||||||
|
@ -21,7 +23,7 @@ use lemmy_db_schema::{
|
||||||
local_site::LocalSite,
|
local_site::LocalSite,
|
||||||
},
|
},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
utils::{diesel_string_update, diesel_url_update, naive_now},
|
utils::{diesel_string_update, diesel_url_update},
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::LocalUserView;
|
use lemmy_db_views::structs::LocalUserView;
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
|
@ -51,6 +53,7 @@ pub async fn update_community(
|
||||||
is_valid_body_field(sidebar, false)?;
|
is_valid_body_field(sidebar, false)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
check_community_visibility_allowed(data.visibility, &local_user_view)?;
|
||||||
let description = diesel_string_update(data.description.as_deref());
|
let description = diesel_string_update(data.description.as_deref());
|
||||||
|
|
||||||
let old_community = Community::read(&mut context.pool(), data.community_id).await?;
|
let old_community = Community::read(&mut context.pool(), data.community_id).await?;
|
||||||
|
@ -66,7 +69,7 @@ pub async fn update_community(
|
||||||
// Verify its a mod (only mods can edit it)
|
// Verify its a mod (only mods can edit it)
|
||||||
check_community_mod_action(
|
check_community_mod_action(
|
||||||
&local_user_view.person,
|
&local_user_view.person,
|
||||||
data.community_id,
|
&old_community,
|
||||||
false,
|
false,
|
||||||
&mut context.pool(),
|
&mut context.pool(),
|
||||||
)
|
)
|
||||||
|
@ -93,7 +96,7 @@ pub async fn update_community(
|
||||||
nsfw: data.nsfw,
|
nsfw: data.nsfw,
|
||||||
posting_restricted_to_mods: data.posting_restricted_to_mods,
|
posting_restricted_to_mods: data.posting_restricted_to_mods,
|
||||||
visibility: data.visibility,
|
visibility: data.visibility,
|
||||||
updated: Some(Some(naive_now())),
|
updated: Some(Some(Utc::now())),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -105,8 +108,7 @@ pub async fn update_community(
|
||||||
ActivityChannel::submit_activity(
|
ActivityChannel::submit_activity(
|
||||||
SendActivityData::UpdateCommunity(local_user_view.person.clone(), community),
|
SendActivityData::UpdateCommunity(local_user_view.person.clone(), community),
|
||||||
&context,
|
&context,
|
||||||
)
|
)?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
build_community_response(&context, local_user_view, community_id).await
|
build_community_response(&context, local_user_view, community_id).await
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
use activitypub_federation::config::Data;
|
use activitypub_federation::config::Data;
|
||||||
use actix_web::web::Json;
|
use actix_web::web::Json;
|
||||||
|
use chrono::Utc;
|
||||||
use lemmy_api_common::{context::LemmyContext, oauth_provider::EditOAuthProvider, utils::is_admin};
|
use lemmy_api_common::{context::LemmyContext, oauth_provider::EditOAuthProvider, utils::is_admin};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::oauth_provider::{OAuthProvider, OAuthProviderUpdateForm},
|
source::oauth_provider::{OAuthProvider, OAuthProviderUpdateForm},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
utils::{diesel_required_string_update, diesel_required_url_update, naive_now},
|
utils::{diesel_required_string_update, diesel_required_url_update},
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::LocalUserView;
|
use lemmy_db_views::structs::LocalUserView;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::LemmyError;
|
||||||
|
@ -32,7 +33,7 @@ pub async fn update_oauth_provider(
|
||||||
auto_verify_email: data.auto_verify_email,
|
auto_verify_email: data.auto_verify_email,
|
||||||
account_linking_enabled: data.account_linking_enabled,
|
account_linking_enabled: data.account_linking_enabled,
|
||||||
enabled: data.enabled,
|
enabled: data.enabled,
|
||||||
updated: Some(Some(naive_now())),
|
updated: Some(Some(Utc::now())),
|
||||||
};
|
};
|
||||||
|
|
||||||
let update_result =
|
let update_result =
|
||||||
|
|
|
@ -12,17 +12,15 @@ use lemmy_api_common::{
|
||||||
get_url_blocklist,
|
get_url_blocklist,
|
||||||
honeypot_check,
|
honeypot_check,
|
||||||
local_site_to_slur_regex,
|
local_site_to_slur_regex,
|
||||||
mark_post_as_read,
|
|
||||||
process_markdown_opt,
|
process_markdown_opt,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
impls::actor_language::default_post_language,
|
impls::actor_language::validate_post_language,
|
||||||
source::{
|
source::{
|
||||||
actor_language::CommunityLanguage,
|
|
||||||
community::Community,
|
community::Community,
|
||||||
local_site::LocalSite,
|
local_site::LocalSite,
|
||||||
post::{Post, PostInsertForm, PostLike, PostLikeForm},
|
post::{Post, PostInsertForm, PostLike, PostLikeForm, PostRead, PostReadForm},
|
||||||
},
|
},
|
||||||
traits::{Crud, Likeable},
|
traits::{Crud, Likeable},
|
||||||
utils::diesel_url_create,
|
utils::diesel_url_create,
|
||||||
|
@ -85,15 +83,9 @@ pub async fn create_post(
|
||||||
is_valid_body_field(body, true)?;
|
is_valid_body_field(body, true)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
check_community_user_action(
|
let community = Community::read(&mut context.pool(), data.community_id).await?;
|
||||||
&local_user_view.person,
|
check_community_user_action(&local_user_view.person, &community, &mut context.pool()).await?;
|
||||||
data.community_id,
|
|
||||||
&mut context.pool(),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let community_id = data.community_id;
|
|
||||||
let community = Community::read(&mut context.pool(), community_id).await?;
|
|
||||||
if community.posting_restricted_to_mods {
|
if community.posting_restricted_to_mods {
|
||||||
let community_id = data.community_id;
|
let community_id = data.community_id;
|
||||||
CommunityModeratorView::check_is_community_moderator(
|
CommunityModeratorView::check_is_community_moderator(
|
||||||
|
@ -104,23 +96,13 @@ pub async fn create_post(
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// attempt to set default language if none was provided
|
let language_id = validate_post_language(
|
||||||
let language_id = match data.language_id {
|
&mut context.pool(),
|
||||||
Some(lid) => lid,
|
data.language_id,
|
||||||
None => {
|
data.community_id,
|
||||||
default_post_language(
|
local_user_view.local_user.id,
|
||||||
&mut context.pool(),
|
)
|
||||||
community_id,
|
.await?;
|
||||||
local_user_view.local_user.id,
|
|
||||||
)
|
|
||||||
.await?
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Only need to check if language is allowed in case user set it explicitly. When using default
|
|
||||||
// language, it already only returns allowed languages.
|
|
||||||
CommunityLanguage::is_allowed_community_language(&mut context.pool(), language_id, community_id)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let scheduled_publish_time =
|
let scheduled_publish_time =
|
||||||
convert_published_time(data.scheduled_publish_time, &local_user_view, &context).await?;
|
convert_published_time(data.scheduled_publish_time, &local_user_view, &context).await?;
|
||||||
|
@ -142,6 +124,7 @@ pub async fn create_post(
|
||||||
.await
|
.await
|
||||||
.with_lemmy_type(LemmyErrorType::CouldntCreatePost)?;
|
.with_lemmy_type(LemmyErrorType::CouldntCreatePost)?;
|
||||||
|
|
||||||
|
let community_id = community.id;
|
||||||
let federate_post = if scheduled_publish_time.is_none() {
|
let federate_post = if scheduled_publish_time.is_none() {
|
||||||
send_webmention(inserted_post.clone(), community);
|
send_webmention(inserted_post.clone(), community);
|
||||||
|post| Some(SendActivityData::CreatePost(post))
|
|post| Some(SendActivityData::CreatePost(post))
|
||||||
|
@ -159,17 +142,14 @@ pub async fn create_post(
|
||||||
// They like their own post by default
|
// They like their own post by default
|
||||||
let person_id = local_user_view.person.id;
|
let person_id = local_user_view.person.id;
|
||||||
let post_id = inserted_post.id;
|
let post_id = inserted_post.id;
|
||||||
let like_form = PostLikeForm {
|
let like_form = PostLikeForm::new(post_id, person_id, 1);
|
||||||
post_id,
|
|
||||||
person_id,
|
|
||||||
score: 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
PostLike::like(&mut context.pool(), &like_form)
|
PostLike::like(&mut context.pool(), &like_form)
|
||||||
.await
|
.await
|
||||||
.with_lemmy_type(LemmyErrorType::CouldntLikePost)?;
|
.with_lemmy_type(LemmyErrorType::CouldntLikePost)?;
|
||||||
|
|
||||||
mark_post_as_read(person_id, post_id, &mut context.pool()).await?;
|
let read_form = PostReadForm::new(post_id, person_id);
|
||||||
|
PostRead::mark_as_read(&mut context.pool(), &read_form).await?;
|
||||||
|
|
||||||
build_post_response(&context, community_id, local_user_view, post_id).await
|
build_post_response(&context, community_id, local_user_view, post_id).await
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,10 @@ use lemmy_api_common::{
|
||||||
utils::check_community_user_action,
|
utils::check_community_user_action,
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::post::{Post, PostUpdateForm},
|
source::{
|
||||||
|
community::Community,
|
||||||
|
post::{Post, PostUpdateForm},
|
||||||
|
},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::LocalUserView;
|
use lemmy_db_views::structs::LocalUserView;
|
||||||
|
@ -28,12 +31,8 @@ pub async fn delete_post(
|
||||||
Err(LemmyErrorType::CouldntUpdatePost)?
|
Err(LemmyErrorType::CouldntUpdatePost)?
|
||||||
}
|
}
|
||||||
|
|
||||||
check_community_user_action(
|
let community = Community::read(&mut context.pool(), orig_post.community_id).await?;
|
||||||
&local_user_view.person,
|
check_community_user_action(&local_user_view.person, &community, &mut context.pool()).await?;
|
||||||
orig_post.community_id,
|
|
||||||
&mut context.pool(),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
// Verify that only the creator can delete
|
// Verify that only the creator can delete
|
||||||
if !Post::is_post_creator(local_user_view.person.id, orig_post.creator_id) {
|
if !Post::is_post_creator(local_user_view.person.id, orig_post.creator_id) {
|
||||||
|
@ -54,8 +53,7 @@ pub async fn delete_post(
|
||||||
ActivityChannel::submit_activity(
|
ActivityChannel::submit_activity(
|
||||||
SendActivityData::DeletePost(post, local_user_view.person.clone(), data.0),
|
SendActivityData::DeletePost(post, local_user_view.person.clone(), data.0),
|
||||||
&context,
|
&context,
|
||||||
)
|
)?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
build_post_response(
|
build_post_response(
|
||||||
&context,
|
&context,
|
||||||
|
|
|
@ -2,10 +2,13 @@ use actix_web::web::{Data, Json, Query};
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
post::{GetPost, GetPostResponse},
|
post::{GetPost, GetPostResponse},
|
||||||
utils::{check_private_instance, is_mod_or_admin_opt, mark_post_as_read, update_read_comments},
|
utils::{check_private_instance, is_mod_or_admin_opt, update_read_comments},
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::{comment::Comment, post::Post},
|
source::{
|
||||||
|
comment::Comment,
|
||||||
|
post::{Post, PostRead, PostReadForm},
|
||||||
|
},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
};
|
};
|
||||||
use lemmy_db_views::{
|
use lemmy_db_views::{
|
||||||
|
@ -62,7 +65,8 @@ pub async fn get_post(
|
||||||
|
|
||||||
let post_id = post_view.post.id;
|
let post_id = post_view.post.id;
|
||||||
if let Some(person_id) = person_id {
|
if let Some(person_id) = person_id {
|
||||||
mark_post_as_read(person_id, post_id, &mut context.pool()).await?;
|
let read_form = PostReadForm::new(post_id, person_id);
|
||||||
|
PostRead::mark_as_read(&mut context.pool(), &read_form).await?;
|
||||||
|
|
||||||
update_read_comments(
|
update_read_comments(
|
||||||
person_id,
|
person_id,
|
||||||
|
|
|
@ -9,6 +9,7 @@ use lemmy_api_common::{
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::{
|
source::{
|
||||||
|
community::Community,
|
||||||
local_user::LocalUser,
|
local_user::LocalUser,
|
||||||
moderator::{ModRemovePost, ModRemovePostForm},
|
moderator::{ModRemovePost, ModRemovePostForm},
|
||||||
post::{Post, PostUpdateForm},
|
post::{Post, PostUpdateForm},
|
||||||
|
@ -26,11 +27,16 @@ pub async fn remove_post(
|
||||||
local_user_view: LocalUserView,
|
local_user_view: LocalUserView,
|
||||||
) -> LemmyResult<Json<PostResponse>> {
|
) -> LemmyResult<Json<PostResponse>> {
|
||||||
let post_id = data.post_id;
|
let post_id = data.post_id;
|
||||||
|
|
||||||
|
// We cannot use PostView to avoid a database read here, as it doesn't return removed items
|
||||||
|
// by default. So we would have to pass in `is_mod_or_admin`, but that is impossible without
|
||||||
|
// knowing which community the post belongs to.
|
||||||
let orig_post = Post::read(&mut context.pool(), post_id).await?;
|
let orig_post = Post::read(&mut context.pool(), post_id).await?;
|
||||||
|
let community = Community::read(&mut context.pool(), orig_post.community_id).await?;
|
||||||
|
|
||||||
check_community_mod_action(
|
check_community_mod_action(
|
||||||
&local_user_view.person,
|
&local_user_view.person,
|
||||||
orig_post.community_id,
|
&community,
|
||||||
false,
|
false,
|
||||||
&mut context.pool(),
|
&mut context.pool(),
|
||||||
)
|
)
|
||||||
|
@ -77,8 +83,7 @@ pub async fn remove_post(
|
||||||
removed: data.removed,
|
removed: data.removed,
|
||||||
},
|
},
|
||||||
&context,
|
&context,
|
||||||
)
|
)?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
build_post_response(&context, orig_post.community_id, local_user_view, post_id).await
|
build_post_response(&context, orig_post.community_id, local_user_view, post_id).await
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use super::{convert_published_time, create::send_webmention};
|
use super::{convert_published_time, create::send_webmention};
|
||||||
use activitypub_federation::config::Data;
|
use activitypub_federation::config::Data;
|
||||||
use actix_web::web::Json;
|
use actix_web::web::Json;
|
||||||
|
use chrono::Utc;
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
build_response::build_post_response,
|
build_response::build_post_response,
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
|
@ -15,16 +16,16 @@ use lemmy_api_common::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
|
impls::actor_language::validate_post_language,
|
||||||
source::{
|
source::{
|
||||||
actor_language::CommunityLanguage,
|
|
||||||
community::Community,
|
community::Community,
|
||||||
local_site::LocalSite,
|
local_site::LocalSite,
|
||||||
post::{Post, PostUpdateForm},
|
post::{Post, PostUpdateForm},
|
||||||
},
|
},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
utils::{diesel_string_update, diesel_url_update, naive_now},
|
utils::{diesel_string_update, diesel_url_update},
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::LocalUserView;
|
use lemmy_db_views::structs::{LocalUserView, PostView};
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
error::{LemmyErrorExt, LemmyErrorType, LemmyResult},
|
error::{LemmyErrorExt, LemmyErrorType, LemmyResult},
|
||||||
utils::{
|
utils::{
|
||||||
|
@ -87,32 +88,31 @@ pub async fn update_post(
|
||||||
}
|
}
|
||||||
|
|
||||||
let post_id = data.post_id;
|
let post_id = data.post_id;
|
||||||
let orig_post = Post::read(&mut context.pool(), post_id).await?;
|
let orig_post = PostView::read(&mut context.pool(), post_id, None, false).await?;
|
||||||
|
|
||||||
check_community_user_action(
|
check_community_user_action(
|
||||||
&local_user_view.person,
|
&local_user_view.person,
|
||||||
orig_post.community_id,
|
&orig_post.community,
|
||||||
&mut context.pool(),
|
&mut context.pool(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// Verify that only the creator can edit
|
// Verify that only the creator can edit
|
||||||
if !Post::is_post_creator(local_user_view.person.id, orig_post.creator_id) {
|
if !Post::is_post_creator(local_user_view.person.id, orig_post.post.creator_id) {
|
||||||
Err(LemmyErrorType::NoPostEditAllowed)?
|
Err(LemmyErrorType::NoPostEditAllowed)?
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(language_id) = data.language_id {
|
let language_id = validate_post_language(
|
||||||
CommunityLanguage::is_allowed_community_language(
|
&mut context.pool(),
|
||||||
&mut context.pool(),
|
data.language_id,
|
||||||
language_id,
|
orig_post.post.community_id,
|
||||||
orig_post.community_id,
|
local_user_view.local_user.id,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
|
||||||
|
|
||||||
// handle changes to scheduled_publish_time
|
// handle changes to scheduled_publish_time
|
||||||
let scheduled_publish_time = match (
|
let scheduled_publish_time = match (
|
||||||
orig_post.scheduled_publish_time,
|
orig_post.post.scheduled_publish_time,
|
||||||
data.scheduled_publish_time,
|
data.scheduled_publish_time,
|
||||||
) {
|
) {
|
||||||
// schedule time can be changed if post is still scheduled (and not published yet)
|
// schedule time can be changed if post is still scheduled (and not published yet)
|
||||||
|
@ -131,8 +131,8 @@ pub async fn update_post(
|
||||||
body,
|
body,
|
||||||
alt_text,
|
alt_text,
|
||||||
nsfw: data.nsfw,
|
nsfw: data.nsfw,
|
||||||
language_id: data.language_id,
|
language_id: Some(language_id),
|
||||||
updated: Some(Some(naive_now())),
|
updated: Some(Some(Utc::now())),
|
||||||
scheduled_publish_time,
|
scheduled_publish_time,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
@ -144,12 +144,12 @@ pub async fn update_post(
|
||||||
|
|
||||||
// send out federation/webmention if necessary
|
// send out federation/webmention if necessary
|
||||||
match (
|
match (
|
||||||
orig_post.scheduled_publish_time,
|
orig_post.post.scheduled_publish_time,
|
||||||
data.scheduled_publish_time,
|
data.scheduled_publish_time,
|
||||||
) {
|
) {
|
||||||
// schedule was removed, send create activity and webmention
|
// schedule was removed, send create activity and webmention
|
||||||
(Some(_), None) => {
|
(Some(_), None) => {
|
||||||
let community = Community::read(&mut context.pool(), orig_post.community_id).await?;
|
let community = Community::read(&mut context.pool(), orig_post.community.id).await?;
|
||||||
send_webmention(updated_post.clone(), community);
|
send_webmention(updated_post.clone(), community);
|
||||||
generate_post_link_metadata(
|
generate_post_link_metadata(
|
||||||
updated_post.clone(),
|
updated_post.clone(),
|
||||||
|
@ -175,7 +175,7 @@ pub async fn update_post(
|
||||||
|
|
||||||
build_post_response(
|
build_post_response(
|
||||||
context.deref(),
|
context.deref(),
|
||||||
orig_post.community_id,
|
orig_post.community.id,
|
||||||
local_user_view,
|
local_user_view,
|
||||||
post_id,
|
post_id,
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,6 +5,7 @@ use lemmy_api_common::{
|
||||||
private_message::{CreatePrivateMessage, PrivateMessageResponse},
|
private_message::{CreatePrivateMessage, PrivateMessageResponse},
|
||||||
send_activity::{ActivityChannel, SendActivityData},
|
send_activity::{ActivityChannel, SendActivityData},
|
||||||
utils::{
|
utils::{
|
||||||
|
check_private_messages_enabled,
|
||||||
get_interface_language,
|
get_interface_language,
|
||||||
get_url_blocklist,
|
get_url_blocklist,
|
||||||
local_site_to_slur_regex,
|
local_site_to_slur_regex,
|
||||||
|
@ -46,6 +47,16 @@ pub async fn create_private_message(
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
check_private_messages_enabled(&local_user_view)?;
|
||||||
|
|
||||||
|
// Don't allow local sends to people who have private messages disabled
|
||||||
|
let recipient_local_user_opt = LocalUserView::read_person(&mut context.pool(), data.recipient_id)
|
||||||
|
.await
|
||||||
|
.ok();
|
||||||
|
if let Some(recipient_local_user) = recipient_local_user_opt {
|
||||||
|
check_private_messages_enabled(&recipient_local_user)?;
|
||||||
|
}
|
||||||
|
|
||||||
let private_message_form = PrivateMessageInsertForm::new(
|
let private_message_form = PrivateMessageInsertForm::new(
|
||||||
local_user_view.person.id,
|
local_user_view.person.id,
|
||||||
data.recipient_id,
|
data.recipient_id,
|
||||||
|
@ -78,8 +89,7 @@ pub async fn create_private_message(
|
||||||
ActivityChannel::submit_activity(
|
ActivityChannel::submit_activity(
|
||||||
SendActivityData::CreatePrivateMessage(view.clone()),
|
SendActivityData::CreatePrivateMessage(view.clone()),
|
||||||
&context,
|
&context,
|
||||||
)
|
)?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(Json(PrivateMessageResponse {
|
Ok(Json(PrivateMessageResponse {
|
||||||
private_message_view: view,
|
private_message_view: view,
|
||||||
|
|
|
@ -42,8 +42,7 @@ pub async fn delete_private_message(
|
||||||
ActivityChannel::submit_activity(
|
ActivityChannel::submit_activity(
|
||||||
SendActivityData::DeletePrivateMessage(local_user_view.person, private_message, data.deleted),
|
SendActivityData::DeletePrivateMessage(local_user_view.person, private_message, data.deleted),
|
||||||
&context,
|
&context,
|
||||||
)
|
)?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
let view = PrivateMessageView::read(&mut context.pool(), private_message_id).await?;
|
let view = PrivateMessageView::read(&mut context.pool(), private_message_id).await?;
|
||||||
Ok(Json(PrivateMessageResponse {
|
Ok(Json(PrivateMessageResponse {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use activitypub_federation::config::Data;
|
use activitypub_federation::config::Data;
|
||||||
use actix_web::web::Json;
|
use actix_web::web::Json;
|
||||||
|
use chrono::Utc;
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
private_message::{EditPrivateMessage, PrivateMessageResponse},
|
private_message::{EditPrivateMessage, PrivateMessageResponse},
|
||||||
|
@ -12,7 +13,6 @@ use lemmy_db_schema::{
|
||||||
private_message::{PrivateMessage, PrivateMessageUpdateForm},
|
private_message::{PrivateMessage, PrivateMessageUpdateForm},
|
||||||
},
|
},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
utils::naive_now,
|
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::{LocalUserView, PrivateMessageView};
|
use lemmy_db_views::structs::{LocalUserView, PrivateMessageView};
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
|
@ -47,7 +47,7 @@ pub async fn update_private_message(
|
||||||
private_message_id,
|
private_message_id,
|
||||||
&PrivateMessageUpdateForm {
|
&PrivateMessageUpdateForm {
|
||||||
content: Some(content),
|
content: Some(content),
|
||||||
updated: Some(Some(naive_now())),
|
updated: Some(Some(Utc::now())),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -59,8 +59,7 @@ pub async fn update_private_message(
|
||||||
ActivityChannel::submit_activity(
|
ActivityChannel::submit_activity(
|
||||||
SendActivityData::UpdatePrivateMessage(view.clone()),
|
SendActivityData::UpdatePrivateMessage(view.clone()),
|
||||||
&context,
|
&context,
|
||||||
)
|
)?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(Json(PrivateMessageResponse {
|
Ok(Json(PrivateMessageResponse {
|
||||||
private_message_view: view,
|
private_message_view: view,
|
||||||
|
|
|
@ -2,6 +2,7 @@ use super::not_zero;
|
||||||
use crate::site::{application_question_check, site_default_post_listing_type_check};
|
use crate::site::{application_question_check, site_default_post_listing_type_check};
|
||||||
use activitypub_federation::{config::Data, http_signatures::generate_actor_keypair};
|
use activitypub_federation::{config::Data, http_signatures::generate_actor_keypair};
|
||||||
use actix_web::web::Json;
|
use actix_web::web::Json;
|
||||||
|
use chrono::Utc;
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
site::{CreateSite, SiteResponse},
|
site::{CreateSite, SiteResponse},
|
||||||
|
@ -23,7 +24,7 @@ use lemmy_db_schema::{
|
||||||
site::{Site, SiteUpdateForm},
|
site::{Site, SiteUpdateForm},
|
||||||
},
|
},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
utils::{diesel_string_update, diesel_url_create, naive_now},
|
utils::{diesel_string_update, diesel_url_create},
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::{LocalUserView, SiteView};
|
use lemmy_db_views::structs::{LocalUserView, SiteView};
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
|
@ -75,7 +76,7 @@ pub async fn create_site(
|
||||||
icon: Some(icon),
|
icon: Some(icon),
|
||||||
banner: Some(banner),
|
banner: Some(banner),
|
||||||
actor_id: Some(actor_id),
|
actor_id: Some(actor_id),
|
||||||
last_refreshed_at: Some(naive_now()),
|
last_refreshed_at: Some(Utc::now()),
|
||||||
inbox_url,
|
inbox_url,
|
||||||
private_key: Some(Some(keypair.private_key)),
|
private_key: Some(Some(keypair.private_key)),
|
||||||
public_key: Some(keypair.public_key),
|
public_key: Some(keypair.public_key),
|
||||||
|
@ -102,7 +103,7 @@ pub async fn create_site(
|
||||||
legal_information: diesel_string_update(data.legal_information.as_deref()),
|
legal_information: diesel_string_update(data.legal_information.as_deref()),
|
||||||
application_email_admins: data.application_email_admins,
|
application_email_admins: data.application_email_admins,
|
||||||
hide_modlog_mod_names: data.hide_modlog_mod_names,
|
hide_modlog_mod_names: data.hide_modlog_mod_names,
|
||||||
updated: Some(Some(naive_now())),
|
updated: Some(Some(Utc::now())),
|
||||||
slur_filter_regex: diesel_string_update(data.slur_filter_regex.as_deref()),
|
slur_filter_regex: diesel_string_update(data.slur_filter_regex.as_deref()),
|
||||||
actor_name_max_length: data.actor_name_max_length,
|
actor_name_max_length: data.actor_name_max_length,
|
||||||
federation_enabled: data.federation_enabled,
|
federation_enabled: data.federation_enabled,
|
||||||
|
@ -161,7 +162,7 @@ fn validate_create_payload(local_site: &LocalSite, create_site: &CreateSite) ->
|
||||||
.slur_filter_regex
|
.slur_filter_regex
|
||||||
.as_deref()
|
.as_deref()
|
||||||
.or(local_site.slur_filter_regex.as_deref()),
|
.or(local_site.slur_filter_regex.as_deref()),
|
||||||
)?;
|
);
|
||||||
|
|
||||||
site_name_length_check(&create_site.name)?;
|
site_name_length_check(&create_site.name)?;
|
||||||
check_slurs(&create_site.name, &slur_regex)?;
|
check_slurs(&create_site.name, &slur_regex)?;
|
||||||
|
|
|
@ -2,6 +2,7 @@ use super::not_zero;
|
||||||
use crate::site::{application_question_check, site_default_post_listing_type_check};
|
use crate::site::{application_question_check, site_default_post_listing_type_check};
|
||||||
use activitypub_federation::config::Data;
|
use activitypub_federation::config::Data;
|
||||||
use actix_web::web::Json;
|
use actix_web::web::Json;
|
||||||
|
use chrono::Utc;
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
request::replace_image,
|
request::replace_image,
|
||||||
|
@ -27,7 +28,7 @@ use lemmy_db_schema::{
|
||||||
site::{Site, SiteUpdateForm},
|
site::{Site, SiteUpdateForm},
|
||||||
},
|
},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
utils::{diesel_string_update, diesel_url_update, naive_now},
|
utils::{diesel_string_update, diesel_url_update},
|
||||||
RegistrationMode,
|
RegistrationMode,
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::{LocalUserView, SiteView};
|
use lemmy_db_views::structs::{LocalUserView, SiteView};
|
||||||
|
@ -88,7 +89,7 @@ pub async fn update_site(
|
||||||
icon,
|
icon,
|
||||||
banner,
|
banner,
|
||||||
content_warning: diesel_string_update(data.content_warning.as_deref()),
|
content_warning: diesel_string_update(data.content_warning.as_deref()),
|
||||||
updated: Some(Some(naive_now())),
|
updated: Some(Some(Utc::now())),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -111,7 +112,7 @@ pub async fn update_site(
|
||||||
legal_information: diesel_string_update(data.legal_information.as_deref()),
|
legal_information: diesel_string_update(data.legal_information.as_deref()),
|
||||||
application_email_admins: data.application_email_admins,
|
application_email_admins: data.application_email_admins,
|
||||||
hide_modlog_mod_names: data.hide_modlog_mod_names,
|
hide_modlog_mod_names: data.hide_modlog_mod_names,
|
||||||
updated: Some(Some(naive_now())),
|
updated: Some(Some(Utc::now())),
|
||||||
slur_filter_regex: diesel_string_update(data.slur_filter_regex.as_deref()),
|
slur_filter_regex: diesel_string_update(data.slur_filter_regex.as_deref()),
|
||||||
actor_name_max_length: data.actor_name_max_length,
|
actor_name_max_length: data.actor_name_max_length,
|
||||||
federation_enabled: data.federation_enabled,
|
federation_enabled: data.federation_enabled,
|
||||||
|
@ -210,7 +211,7 @@ fn validate_update_payload(local_site: &LocalSite, edit_site: &EditSite) -> Lemm
|
||||||
.slur_filter_regex
|
.slur_filter_regex
|
||||||
.as_deref()
|
.as_deref()
|
||||||
.or(local_site.slur_filter_regex.as_deref()),
|
.or(local_site.slur_filter_regex.as_deref()),
|
||||||
)?;
|
);
|
||||||
|
|
||||||
if let Some(name) = &edit_site.name {
|
if let Some(name) = &edit_site.name {
|
||||||
// The name doesn't need to be updated, but if provided it cannot be blanked out...
|
// The name doesn't need to be updated, but if provided it cannot be blanked out...
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use activitypub_federation::config::Data;
|
use activitypub_federation::config::Data;
|
||||||
use actix_web::web::Json;
|
use actix_web::web::Json;
|
||||||
|
use chrono::Utc;
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
tagline::{TaglineResponse, UpdateTagline},
|
tagline::{TaglineResponse, UpdateTagline},
|
||||||
|
@ -11,7 +12,6 @@ use lemmy_db_schema::{
|
||||||
tagline::{Tagline, TaglineUpdateForm},
|
tagline::{Tagline, TaglineUpdateForm},
|
||||||
},
|
},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
utils::naive_now,
|
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::LocalUserView;
|
use lemmy_db_views::structs::LocalUserView;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::LemmyError;
|
||||||
|
@ -33,7 +33,7 @@ pub async fn update_tagline(
|
||||||
|
|
||||||
let tagline_form = TaglineUpdateForm {
|
let tagline_form = TaglineUpdateForm {
|
||||||
content,
|
content,
|
||||||
updated: naive_now(),
|
updated: Utc::now(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let tagline = Tagline::update(&mut context.pool(), data.id, &tagline_form).await?;
|
let tagline = Tagline::update(&mut context.pool(), data.id, &tagline_form).await?;
|
||||||
|
|
|
@ -148,14 +148,15 @@ pub async fn register(
|
||||||
let inserted_local_user = create_local_user(&context, language_tags, &local_user_form).await?;
|
let inserted_local_user = create_local_user(&context, language_tags, &local_user_form).await?;
|
||||||
|
|
||||||
if local_site.site_setup && require_registration_application {
|
if local_site.site_setup && require_registration_application {
|
||||||
// Create the registration application
|
if let Some(answer) = data.answer.clone() {
|
||||||
let form = RegistrationApplicationInsertForm {
|
// Create the registration application
|
||||||
local_user_id: inserted_local_user.id,
|
let form = RegistrationApplicationInsertForm {
|
||||||
// We already made sure answer was not null above
|
local_user_id: inserted_local_user.id,
|
||||||
answer: data.answer.clone().expect("must have an answer"),
|
answer,
|
||||||
};
|
};
|
||||||
|
|
||||||
RegistrationApplication::create(&mut context.pool(), &form).await?;
|
RegistrationApplication::create(&mut context.pool(), &form).await?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Email the admins, only if email verification is not required
|
// Email the admins, only if email verification is not required
|
||||||
|
@ -304,7 +305,7 @@ pub async fn authenticate_with_oauth(
|
||||||
|
|
||||||
OAuthAccount::create(&mut context.pool(), &oauth_account_form)
|
OAuthAccount::create(&mut context.pool(), &oauth_account_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|_| LemmyErrorType::OauthLoginFailed)?;
|
.with_lemmy_type(LemmyErrorType::OauthLoginFailed)?;
|
||||||
|
|
||||||
local_user = user_view.local_user.clone();
|
local_user = user_view.local_user.clone();
|
||||||
} else {
|
} else {
|
||||||
|
@ -365,7 +366,7 @@ pub async fn authenticate_with_oauth(
|
||||||
|
|
||||||
OAuthAccount::create(&mut context.pool(), &oauth_account_form)
|
OAuthAccount::create(&mut context.pool(), &oauth_account_form)
|
||||||
.await
|
.await
|
||||||
.map_err(|_| LemmyErrorType::IncorrectLogin)?;
|
.with_lemmy_type(LemmyErrorType::IncorrectLogin)?;
|
||||||
|
|
||||||
// prevent sign in until application is accepted
|
// prevent sign in until application is accepted
|
||||||
if local_site.site_setup
|
if local_site.site_setup
|
||||||
|
@ -373,17 +374,19 @@ pub async fn authenticate_with_oauth(
|
||||||
&& !local_user.accepted_application
|
&& !local_user.accepted_application
|
||||||
&& !local_user.admin
|
&& !local_user.admin
|
||||||
{
|
{
|
||||||
// Create the registration application
|
if let Some(answer) = data.answer.clone() {
|
||||||
RegistrationApplication::create(
|
// Create the registration application
|
||||||
&mut context.pool(),
|
RegistrationApplication::create(
|
||||||
&RegistrationApplicationInsertForm {
|
&mut context.pool(),
|
||||||
local_user_id: local_user.id,
|
&RegistrationApplicationInsertForm {
|
||||||
answer: data.answer.clone().expect("must have an answer"),
|
local_user_id: local_user.id,
|
||||||
},
|
answer,
|
||||||
)
|
},
|
||||||
.await?;
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
login_response.registration_created = true;
|
login_response.registration_created = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check email is verified when required
|
// Check email is verified when required
|
||||||
|
@ -483,7 +486,7 @@ async fn send_verification_email_if_required(
|
||||||
&local_user
|
&local_user
|
||||||
.email
|
.email
|
||||||
.clone()
|
.clone()
|
||||||
.expect("invalid verification email"),
|
.ok_or(LemmyErrorType::EmailRequired)?,
|
||||||
&mut context.pool(),
|
&mut context.pool(),
|
||||||
context.settings(),
|
context.settings(),
|
||||||
)
|
)
|
||||||
|
@ -524,18 +527,16 @@ async fn oauth_request_access_token(
|
||||||
("client_secret", &oauth_provider.client_secret),
|
("client_secret", &oauth_provider.client_secret),
|
||||||
])
|
])
|
||||||
.send()
|
.send()
|
||||||
.await;
|
.await
|
||||||
|
.with_lemmy_type(LemmyErrorType::OauthLoginFailed)?
|
||||||
let response = response.map_err(|_| LemmyErrorType::OauthLoginFailed)?;
|
.error_for_status()
|
||||||
if !response.status().is_success() {
|
.with_lemmy_type(LemmyErrorType::OauthLoginFailed)?;
|
||||||
Err(LemmyErrorType::OauthLoginFailed)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract the access token
|
// Extract the access token
|
||||||
let token_response = response
|
let token_response = response
|
||||||
.json::<TokenResponse>()
|
.json::<TokenResponse>()
|
||||||
.await
|
.await
|
||||||
.map_err(|_| LemmyErrorType::OauthLoginFailed)?;
|
.with_lemmy_type(LemmyErrorType::OauthLoginFailed)?;
|
||||||
|
|
||||||
Ok(token_response)
|
Ok(token_response)
|
||||||
}
|
}
|
||||||
|
@ -552,18 +553,16 @@ async fn oidc_get_user_info(
|
||||||
.header("Accept", "application/json")
|
.header("Accept", "application/json")
|
||||||
.bearer_auth(access_token)
|
.bearer_auth(access_token)
|
||||||
.send()
|
.send()
|
||||||
.await;
|
.await
|
||||||
|
.with_lemmy_type(LemmyErrorType::OauthLoginFailed)?
|
||||||
let response = response.map_err(|_| LemmyErrorType::OauthLoginFailed)?;
|
.error_for_status()
|
||||||
if !response.status().is_success() {
|
.with_lemmy_type(LemmyErrorType::OauthLoginFailed)?;
|
||||||
Err(LemmyErrorType::OauthLoginFailed)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract the OAUTH user_id claim from the returned user_info
|
// Extract the OAUTH user_id claim from the returned user_info
|
||||||
let user_info = response
|
let user_info = response
|
||||||
.json::<serde_json::Value>()
|
.json::<serde_json::Value>()
|
||||||
.await
|
.await
|
||||||
.map_err(|_| LemmyErrorType::OauthLoginFailed)?;
|
.with_lemmy_type(LemmyErrorType::OauthLoginFailed)?;
|
||||||
|
|
||||||
Ok(user_info)
|
Ok(user_info)
|
||||||
}
|
}
|
||||||
|
@ -571,7 +570,7 @@ async fn oidc_get_user_info(
|
||||||
fn read_user_info(user_info: &serde_json::Value, key: &str) -> LemmyResult<String> {
|
fn read_user_info(user_info: &serde_json::Value, key: &str) -> LemmyResult<String> {
|
||||||
if let Some(value) = user_info.get(key) {
|
if let Some(value) = user_info.get(key) {
|
||||||
let result = serde_json::from_value::<String>(value.clone())
|
let result = serde_json::from_value::<String>(value.clone())
|
||||||
.map_err(|_| LemmyErrorType::OauthLoginFailed)?;
|
.with_lemmy_type(LemmyErrorType::OauthLoginFailed)?;
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
Err(LemmyErrorType::OauthLoginFailed)?
|
Err(LemmyErrorType::OauthLoginFailed)?
|
||||||
|
|
|
@ -45,8 +45,7 @@ pub async fn delete_account(
|
||||||
ActivityChannel::submit_activity(
|
ActivityChannel::submit_activity(
|
||||||
SendActivityData::DeleteUser(local_user_view.person, data.delete_content),
|
SendActivityData::DeleteUser(local_user_view.person, data.delete_content),
|
||||||
&context,
|
&context,
|
||||||
)
|
)?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(Json(SuccessResponse::default()))
|
Ok(Json(SuccessResponse::default()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ reqwest = { workspace = true }
|
||||||
moka.workspace = true
|
moka.workspace = true
|
||||||
serde_with.workspace = true
|
serde_with.workspace = true
|
||||||
html2md = "0.2.14"
|
html2md = "0.2.14"
|
||||||
html2text = "0.12.5"
|
html2text = "0.12.6"
|
||||||
stringreader = "0.1.1"
|
stringreader = "0.1.1"
|
||||||
enum_delegate = "0.2.0"
|
enum_delegate = "0.2.0"
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use super::to_and_audience;
|
||||||
use crate::{
|
use crate::{
|
||||||
activities::{
|
activities::{
|
||||||
block::{generate_cc, SiteOrCommunity},
|
block::{generate_cc, SiteOrCommunity},
|
||||||
|
@ -7,6 +8,7 @@ use crate::{
|
||||||
verify_is_public,
|
verify_is_public,
|
||||||
verify_mod_action,
|
verify_mod_action,
|
||||||
verify_person_in_community,
|
verify_person_in_community,
|
||||||
|
verify_visibility,
|
||||||
},
|
},
|
||||||
activity_lists::AnnouncableActivities,
|
activity_lists::AnnouncableActivities,
|
||||||
insert_received_activity,
|
insert_received_activity,
|
||||||
|
@ -15,7 +17,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use activitypub_federation::{
|
use activitypub_federation::{
|
||||||
config::Data,
|
config::Data,
|
||||||
kinds::{activity::BlockType, public},
|
kinds::activity::BlockType,
|
||||||
protocol::verification::verify_domains_match,
|
protocol::verification::verify_domains_match,
|
||||||
traits::{ActivityHandler, Actor},
|
traits::{ActivityHandler, Actor},
|
||||||
};
|
};
|
||||||
|
@ -52,14 +54,10 @@ impl BlockUser {
|
||||||
expires: Option<DateTime<Utc>>,
|
expires: Option<DateTime<Utc>>,
|
||||||
context: &Data<LemmyContext>,
|
context: &Data<LemmyContext>,
|
||||||
) -> LemmyResult<BlockUser> {
|
) -> LemmyResult<BlockUser> {
|
||||||
let audience = if let SiteOrCommunity::Community(c) = target {
|
let (to, audience) = to_and_audience(target)?;
|
||||||
Some(c.id().into())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
Ok(BlockUser {
|
Ok(BlockUser {
|
||||||
actor: mod_.id().into(),
|
actor: mod_.id().into(),
|
||||||
to: vec![public()],
|
to,
|
||||||
object: user.id().into(),
|
object: user.id().into(),
|
||||||
cc: generate_cc(target, &mut context.pool()).await?,
|
cc: generate_cc(target, &mut context.pool()).await?,
|
||||||
target: target.id(),
|
target: target.id(),
|
||||||
|
@ -125,9 +123,9 @@ impl ActivityHandler for BlockUser {
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
async fn verify(&self, context: &Data<LemmyContext>) -> LemmyResult<()> {
|
async fn verify(&self, context: &Data<LemmyContext>) -> LemmyResult<()> {
|
||||||
verify_is_public(&self.to, &self.cc)?;
|
|
||||||
match self.target.dereference(context).await? {
|
match self.target.dereference(context).await? {
|
||||||
SiteOrCommunity::Site(site) => {
|
SiteOrCommunity::Site(site) => {
|
||||||
|
verify_is_public(&self.to, &self.cc)?;
|
||||||
let domain = self
|
let domain = self
|
||||||
.object
|
.object
|
||||||
.inner()
|
.inner()
|
||||||
|
@ -143,6 +141,7 @@ impl ActivityHandler for BlockUser {
|
||||||
verify_domains_match(&site.id(), self.object.inner())?;
|
verify_domains_match(&site.id(), self.object.inner())?;
|
||||||
}
|
}
|
||||||
SiteOrCommunity::Community(community) => {
|
SiteOrCommunity::Community(community) => {
|
||||||
|
verify_visibility(&self.to, &self.cc, &community)?;
|
||||||
verify_person_in_community(&self.actor, &community, context).await?;
|
verify_person_in_community(&self.actor, &community, context).await?;
|
||||||
verify_mod_action(&self.actor, &community, context).await?;
|
verify_mod_action(&self.actor, &community, context).await?;
|
||||||
}
|
}
|
||||||
|
@ -194,11 +193,7 @@ impl ActivityHandler for BlockUser {
|
||||||
CommunityPersonBan::ban(&mut context.pool(), &community_user_ban_form).await?;
|
CommunityPersonBan::ban(&mut context.pool(), &community_user_ban_form).await?;
|
||||||
|
|
||||||
// Also unsubscribe them from the community, if they are subscribed
|
// Also unsubscribe them from the community, if they are subscribed
|
||||||
let community_follower_form = CommunityFollowerForm {
|
let community_follower_form = CommunityFollowerForm::new(community.id, blocked_person.id);
|
||||||
community_id: community.id,
|
|
||||||
person_id: blocked_person.id,
|
|
||||||
pending: false,
|
|
||||||
};
|
|
||||||
CommunityFollower::unfollow(&mut context.pool(), &community_follower_form)
|
CommunityFollower::unfollow(&mut context.pool(), &community_follower_form)
|
||||||
.await
|
.await
|
||||||
.ok();
|
.ok();
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use super::generate_to;
|
||||||
use crate::{
|
use crate::{
|
||||||
objects::{community::ApubCommunity, instance::ApubSite},
|
objects::{community::ApubCommunity, instance::ApubSite},
|
||||||
protocol::{
|
protocol::{
|
||||||
|
@ -8,6 +9,7 @@ use crate::{
|
||||||
use activitypub_federation::{
|
use activitypub_federation::{
|
||||||
config::Data,
|
config::Data,
|
||||||
fetch::object_id::ObjectId,
|
fetch::object_id::ObjectId,
|
||||||
|
kinds::public,
|
||||||
traits::{Actor, Object},
|
traits::{Actor, Object},
|
||||||
};
|
};
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
|
@ -205,3 +207,13 @@ pub(crate) async fn send_ban_from_community(
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn to_and_audience(
|
||||||
|
target: &SiteOrCommunity,
|
||||||
|
) -> LemmyResult<(Vec<Url>, Option<ObjectId<ApubCommunity>>)> {
|
||||||
|
Ok(if let SiteOrCommunity::Community(c) = target {
|
||||||
|
(vec![generate_to(c)?], Some(c.id().into()))
|
||||||
|
} else {
|
||||||
|
(vec![public()], None)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use super::to_and_audience;
|
||||||
use crate::{
|
use crate::{
|
||||||
activities::{
|
activities::{
|
||||||
block::{generate_cc, SiteOrCommunity},
|
block::{generate_cc, SiteOrCommunity},
|
||||||
|
@ -5,6 +6,7 @@ use crate::{
|
||||||
generate_activity_id,
|
generate_activity_id,
|
||||||
send_lemmy_activity,
|
send_lemmy_activity,
|
||||||
verify_is_public,
|
verify_is_public,
|
||||||
|
verify_visibility,
|
||||||
},
|
},
|
||||||
activity_lists::AnnouncableActivities,
|
activity_lists::AnnouncableActivities,
|
||||||
insert_received_activity,
|
insert_received_activity,
|
||||||
|
@ -13,7 +15,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use activitypub_federation::{
|
use activitypub_federation::{
|
||||||
config::Data,
|
config::Data,
|
||||||
kinds::{activity::UndoType, public},
|
kinds::activity::UndoType,
|
||||||
protocol::verification::verify_domains_match,
|
protocol::verification::verify_domains_match,
|
||||||
traits::{ActivityHandler, Actor},
|
traits::{ActivityHandler, Actor},
|
||||||
};
|
};
|
||||||
|
@ -44,11 +46,7 @@ impl UndoBlockUser {
|
||||||
context: &Data<LemmyContext>,
|
context: &Data<LemmyContext>,
|
||||||
) -> LemmyResult<()> {
|
) -> LemmyResult<()> {
|
||||||
let block = BlockUser::new(target, user, mod_, None, reason, None, context).await?;
|
let block = BlockUser::new(target, user, mod_, None, reason, None, context).await?;
|
||||||
let audience = if let SiteOrCommunity::Community(c) = target {
|
let (to, audience) = to_and_audience(target)?;
|
||||||
Some(c.id().into())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let id = generate_activity_id(
|
let id = generate_activity_id(
|
||||||
UndoType::Undo,
|
UndoType::Undo,
|
||||||
|
@ -56,7 +54,7 @@ impl UndoBlockUser {
|
||||||
)?;
|
)?;
|
||||||
let undo = UndoBlockUser {
|
let undo = UndoBlockUser {
|
||||||
actor: mod_.id().into(),
|
actor: mod_.id().into(),
|
||||||
to: vec![public()],
|
to,
|
||||||
object: block,
|
object: block,
|
||||||
cc: generate_cc(target, &mut context.pool()).await?,
|
cc: generate_cc(target, &mut context.pool()).await?,
|
||||||
kind: UndoType::Undo,
|
kind: UndoType::Undo,
|
||||||
|
@ -94,7 +92,6 @@ impl ActivityHandler for UndoBlockUser {
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
async fn verify(&self, context: &Data<LemmyContext>) -> LemmyResult<()> {
|
async fn verify(&self, context: &Data<LemmyContext>) -> LemmyResult<()> {
|
||||||
verify_is_public(&self.to, &self.cc)?;
|
|
||||||
verify_domains_match(self.actor.inner(), self.object.actor.inner())?;
|
verify_domains_match(self.actor.inner(), self.object.actor.inner())?;
|
||||||
self.object.verify(context).await?;
|
self.object.verify(context).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -108,6 +105,7 @@ impl ActivityHandler for UndoBlockUser {
|
||||||
let blocked_person = self.object.object.dereference(context).await?;
|
let blocked_person = self.object.object.dereference(context).await?;
|
||||||
match self.object.target.dereference(context).await? {
|
match self.object.target.dereference(context).await? {
|
||||||
SiteOrCommunity::Site(_site) => {
|
SiteOrCommunity::Site(_site) => {
|
||||||
|
verify_is_public(&self.to, &self.cc)?;
|
||||||
let blocked_person = Person::update(
|
let blocked_person = Person::update(
|
||||||
&mut context.pool(),
|
&mut context.pool(),
|
||||||
blocked_person.id,
|
blocked_person.id,
|
||||||
|
@ -135,6 +133,7 @@ impl ActivityHandler for UndoBlockUser {
|
||||||
ModBan::create(&mut context.pool(), &form).await?;
|
ModBan::create(&mut context.pool(), &form).await?;
|
||||||
}
|
}
|
||||||
SiteOrCommunity::Community(community) => {
|
SiteOrCommunity::Community(community) => {
|
||||||
|
verify_visibility(&self.to, &self.cc, &community)?;
|
||||||
let community_user_ban_form = CommunityPersonBanForm {
|
let community_user_ban_form = CommunityPersonBanForm {
|
||||||
community_id: community.id,
|
community_id: community.id,
|
||||||
person_id: blocked_person.id,
|
person_id: blocked_person.id,
|
||||||
|
|
|
@ -2,9 +2,10 @@ use crate::{
|
||||||
activities::{
|
activities::{
|
||||||
generate_activity_id,
|
generate_activity_id,
|
||||||
generate_announce_activity_id,
|
generate_announce_activity_id,
|
||||||
|
generate_to,
|
||||||
send_lemmy_activity,
|
send_lemmy_activity,
|
||||||
verify_is_public,
|
|
||||||
verify_person_in_community,
|
verify_person_in_community,
|
||||||
|
verify_visibility,
|
||||||
},
|
},
|
||||||
activity_lists::AnnouncableActivities,
|
activity_lists::AnnouncableActivities,
|
||||||
insert_received_activity,
|
insert_received_activity,
|
||||||
|
@ -18,7 +19,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use activitypub_federation::{
|
use activitypub_federation::{
|
||||||
config::Data,
|
config::Data,
|
||||||
kinds::{activity::AnnounceType, public},
|
kinds::activity::AnnounceType,
|
||||||
traits::{ActivityHandler, Actor},
|
traits::{ActivityHandler, Actor},
|
||||||
};
|
};
|
||||||
use lemmy_api_common::context::LemmyContext;
|
use lemmy_api_common::context::LemmyContext;
|
||||||
|
@ -92,7 +93,7 @@ impl AnnounceActivity {
|
||||||
generate_announce_activity_id(inner_kind, &context.settings().get_protocol_and_hostname())?;
|
generate_announce_activity_id(inner_kind, &context.settings().get_protocol_and_hostname())?;
|
||||||
Ok(AnnounceActivity {
|
Ok(AnnounceActivity {
|
||||||
actor: community.id().into(),
|
actor: community.id().into(),
|
||||||
to: vec![public()],
|
to: vec![generate_to(community)?],
|
||||||
object: IdOrNestedObject::NestedObject(object),
|
object: IdOrNestedObject::NestedObject(object),
|
||||||
cc: community
|
cc: community
|
||||||
.followers_url
|
.followers_url
|
||||||
|
@ -129,7 +130,7 @@ impl AnnounceActivity {
|
||||||
actor: c.actor.clone().into_inner(),
|
actor: c.actor.clone().into_inner(),
|
||||||
other: serde_json::to_value(c.object)?
|
other: serde_json::to_value(c.object)?
|
||||||
.as_object()
|
.as_object()
|
||||||
.expect("is object")
|
.ok_or(FederationError::Unreachable)?
|
||||||
.clone(),
|
.clone(),
|
||||||
};
|
};
|
||||||
let announce_compat = AnnounceActivity::new(announcable_page, community, context)?;
|
let announce_compat = AnnounceActivity::new(announcable_page, community, context)?;
|
||||||
|
@ -154,7 +155,6 @@ impl ActivityHandler for AnnounceActivity {
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
async fn verify(&self, _context: &Data<Self::DataType>) -> LemmyResult<()> {
|
async fn verify(&self, _context: &Data<Self::DataType>) -> LemmyResult<()> {
|
||||||
verify_is_public(&self.to, &self.cc)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,6 +169,7 @@ impl ActivityHandler for AnnounceActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
let community = object.community(context).await?;
|
let community = object.community(context).await?;
|
||||||
|
verify_visibility(&self.to, &self.cc, &community)?;
|
||||||
can_accept_activity_in_community(&Some(community), context).await?;
|
can_accept_activity_in_community(&Some(community), context).await?;
|
||||||
|
|
||||||
// verify here in order to avoid fetching the object twice over http
|
// verify here in order to avoid fetching the object twice over http
|
||||||
|
|
|
@ -2,9 +2,10 @@ use crate::{
|
||||||
activities::{
|
activities::{
|
||||||
community::send_activity_in_community,
|
community::send_activity_in_community,
|
||||||
generate_activity_id,
|
generate_activity_id,
|
||||||
verify_is_public,
|
generate_to,
|
||||||
verify_mod_action,
|
verify_mod_action,
|
||||||
verify_person_in_community,
|
verify_person_in_community,
|
||||||
|
verify_visibility,
|
||||||
},
|
},
|
||||||
activity_lists::AnnouncableActivities,
|
activity_lists::AnnouncableActivities,
|
||||||
insert_received_activity,
|
insert_received_activity,
|
||||||
|
@ -17,7 +18,7 @@ use crate::{
|
||||||
use activitypub_federation::{
|
use activitypub_federation::{
|
||||||
config::Data,
|
config::Data,
|
||||||
fetch::object_id::ObjectId,
|
fetch::object_id::ObjectId,
|
||||||
kinds::{activity::AddType, public},
|
kinds::activity::AddType,
|
||||||
traits::{ActivityHandler, Actor},
|
traits::{ActivityHandler, Actor},
|
||||||
};
|
};
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
|
@ -53,7 +54,7 @@ impl CollectionAdd {
|
||||||
)?;
|
)?;
|
||||||
let add = CollectionAdd {
|
let add = CollectionAdd {
|
||||||
actor: actor.id().into(),
|
actor: actor.id().into(),
|
||||||
to: vec![public()],
|
to: vec![generate_to(community)?],
|
||||||
object: added_mod.id(),
|
object: added_mod.id(),
|
||||||
target: generate_moderators_url(&community.actor_id)?.into(),
|
target: generate_moderators_url(&community.actor_id)?.into(),
|
||||||
cc: vec![community.id()],
|
cc: vec![community.id()],
|
||||||
|
@ -79,7 +80,7 @@ impl CollectionAdd {
|
||||||
)?;
|
)?;
|
||||||
let add = CollectionAdd {
|
let add = CollectionAdd {
|
||||||
actor: actor.id().into(),
|
actor: actor.id().into(),
|
||||||
to: vec![public()],
|
to: vec![generate_to(community)?],
|
||||||
object: featured_post.ap_id.clone().into(),
|
object: featured_post.ap_id.clone().into(),
|
||||||
target: generate_featured_url(&community.actor_id)?.into(),
|
target: generate_featured_url(&community.actor_id)?.into(),
|
||||||
cc: vec![community.id()],
|
cc: vec![community.id()],
|
||||||
|
@ -115,8 +116,8 @@ impl ActivityHandler for CollectionAdd {
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
async fn verify(&self, context: &Data<Self::DataType>) -> LemmyResult<()> {
|
async fn verify(&self, context: &Data<Self::DataType>) -> LemmyResult<()> {
|
||||||
verify_is_public(&self.to, &self.cc)?;
|
|
||||||
let community = self.community(context).await?;
|
let community = self.community(context).await?;
|
||||||
|
verify_visibility(&self.to, &self.cc, &community)?;
|
||||||
verify_person_in_community(&self.actor, &community, context).await?;
|
verify_person_in_community(&self.actor, &community, context).await?;
|
||||||
verify_mod_action(&self.actor, &community, context).await?;
|
verify_mod_action(&self.actor, &community, context).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -2,9 +2,10 @@ use crate::{
|
||||||
activities::{
|
activities::{
|
||||||
community::send_activity_in_community,
|
community::send_activity_in_community,
|
||||||
generate_activity_id,
|
generate_activity_id,
|
||||||
verify_is_public,
|
generate_to,
|
||||||
verify_mod_action,
|
verify_mod_action,
|
||||||
verify_person_in_community,
|
verify_person_in_community,
|
||||||
|
verify_visibility,
|
||||||
},
|
},
|
||||||
activity_lists::AnnouncableActivities,
|
activity_lists::AnnouncableActivities,
|
||||||
insert_received_activity,
|
insert_received_activity,
|
||||||
|
@ -14,7 +15,7 @@ use crate::{
|
||||||
use activitypub_federation::{
|
use activitypub_federation::{
|
||||||
config::Data,
|
config::Data,
|
||||||
fetch::object_id::ObjectId,
|
fetch::object_id::ObjectId,
|
||||||
kinds::{activity::RemoveType, public},
|
kinds::activity::RemoveType,
|
||||||
traits::{ActivityHandler, Actor},
|
traits::{ActivityHandler, Actor},
|
||||||
};
|
};
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
|
@ -48,7 +49,7 @@ impl CollectionRemove {
|
||||||
)?;
|
)?;
|
||||||
let remove = CollectionRemove {
|
let remove = CollectionRemove {
|
||||||
actor: actor.id().into(),
|
actor: actor.id().into(),
|
||||||
to: vec![public()],
|
to: vec![generate_to(community)?],
|
||||||
object: removed_mod.id(),
|
object: removed_mod.id(),
|
||||||
target: generate_moderators_url(&community.actor_id)?.into(),
|
target: generate_moderators_url(&community.actor_id)?.into(),
|
||||||
id: id.clone(),
|
id: id.clone(),
|
||||||
|
@ -74,7 +75,7 @@ impl CollectionRemove {
|
||||||
)?;
|
)?;
|
||||||
let remove = CollectionRemove {
|
let remove = CollectionRemove {
|
||||||
actor: actor.id().into(),
|
actor: actor.id().into(),
|
||||||
to: vec![public()],
|
to: vec![generate_to(community)?],
|
||||||
object: featured_post.ap_id.clone().into(),
|
object: featured_post.ap_id.clone().into(),
|
||||||
target: generate_featured_url(&community.actor_id)?.into(),
|
target: generate_featured_url(&community.actor_id)?.into(),
|
||||||
cc: vec![community.id()],
|
cc: vec![community.id()],
|
||||||
|
@ -110,8 +111,8 @@ impl ActivityHandler for CollectionRemove {
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
async fn verify(&self, context: &Data<Self::DataType>) -> LemmyResult<()> {
|
async fn verify(&self, context: &Data<Self::DataType>) -> LemmyResult<()> {
|
||||||
verify_is_public(&self.to, &self.cc)?;
|
|
||||||
let community = self.community(context).await?;
|
let community = self.community(context).await?;
|
||||||
|
verify_visibility(&self.to, &self.cc, &community)?;
|
||||||
verify_person_in_community(&self.actor, &community, context).await?;
|
verify_person_in_community(&self.actor, &community, context).await?;
|
||||||
verify_mod_action(&self.actor, &community, context).await?;
|
verify_mod_action(&self.actor, &community, context).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -3,9 +3,10 @@ use crate::{
|
||||||
check_community_deleted_or_removed,
|
check_community_deleted_or_removed,
|
||||||
community::send_activity_in_community,
|
community::send_activity_in_community,
|
||||||
generate_activity_id,
|
generate_activity_id,
|
||||||
verify_is_public,
|
generate_to,
|
||||||
verify_mod_action,
|
verify_mod_action,
|
||||||
verify_person_in_community,
|
verify_person_in_community,
|
||||||
|
verify_visibility,
|
||||||
},
|
},
|
||||||
activity_lists::AnnouncableActivities,
|
activity_lists::AnnouncableActivities,
|
||||||
insert_received_activity,
|
insert_received_activity,
|
||||||
|
@ -18,7 +19,7 @@ use crate::{
|
||||||
use activitypub_federation::{
|
use activitypub_federation::{
|
||||||
config::Data,
|
config::Data,
|
||||||
fetch::object_id::ObjectId,
|
fetch::object_id::ObjectId,
|
||||||
kinds::{activity::UndoType, public},
|
kinds::activity::UndoType,
|
||||||
traits::ActivityHandler,
|
traits::ActivityHandler,
|
||||||
};
|
};
|
||||||
use lemmy_api_common::context::LemmyContext;
|
use lemmy_api_common::context::LemmyContext;
|
||||||
|
@ -49,8 +50,8 @@ impl ActivityHandler for LockPage {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn verify(&self, context: &Data<Self::DataType>) -> Result<(), Self::Error> {
|
async fn verify(&self, context: &Data<Self::DataType>) -> Result<(), Self::Error> {
|
||||||
verify_is_public(&self.to, &self.cc)?;
|
|
||||||
let community = self.community(context).await?;
|
let community = self.community(context).await?;
|
||||||
|
verify_visibility(&self.to, &self.cc, &community)?;
|
||||||
verify_person_in_community(&self.actor, &community, context).await?;
|
verify_person_in_community(&self.actor, &community, context).await?;
|
||||||
check_community_deleted_or_removed(&community)?;
|
check_community_deleted_or_removed(&community)?;
|
||||||
verify_mod_action(&self.actor, &community, context).await?;
|
verify_mod_action(&self.actor, &community, context).await?;
|
||||||
|
@ -92,8 +93,8 @@ impl ActivityHandler for UndoLockPage {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn verify(&self, context: &Data<Self::DataType>) -> Result<(), Self::Error> {
|
async fn verify(&self, context: &Data<Self::DataType>) -> Result<(), Self::Error> {
|
||||||
verify_is_public(&self.to, &self.cc)?;
|
|
||||||
let community = self.community(context).await?;
|
let community = self.community(context).await?;
|
||||||
|
verify_visibility(&self.to, &self.cc, &community)?;
|
||||||
verify_person_in_community(&self.actor, &community, context).await?;
|
verify_person_in_community(&self.actor, &community, context).await?;
|
||||||
check_community_deleted_or_removed(&community)?;
|
check_community_deleted_or_removed(&community)?;
|
||||||
verify_mod_action(&self.actor, &community, context).await?;
|
verify_mod_action(&self.actor, &community, context).await?;
|
||||||
|
@ -137,7 +138,7 @@ pub(crate) async fn send_lock_post(
|
||||||
let community_id = community.actor_id.inner().clone();
|
let community_id = community.actor_id.inner().clone();
|
||||||
let lock = LockPage {
|
let lock = LockPage {
|
||||||
actor: actor.actor_id.clone().into(),
|
actor: actor.actor_id.clone().into(),
|
||||||
to: vec![public()],
|
to: vec![generate_to(&community)?],
|
||||||
object: ObjectId::from(post.ap_id),
|
object: ObjectId::from(post.ap_id),
|
||||||
cc: vec![community_id.clone()],
|
cc: vec![community_id.clone()],
|
||||||
kind: LockType::Lock,
|
kind: LockType::Lock,
|
||||||
|
@ -153,7 +154,7 @@ pub(crate) async fn send_lock_post(
|
||||||
)?;
|
)?;
|
||||||
let undo = UndoLockPage {
|
let undo = UndoLockPage {
|
||||||
actor: lock.actor.clone(),
|
actor: lock.actor.clone(),
|
||||||
to: vec![public()],
|
to: vec![generate_to(&community)?],
|
||||||
cc: lock.cc.clone(),
|
cc: lock.cc.clone(),
|
||||||
kind: UndoType::Undo,
|
kind: UndoType::Undo,
|
||||||
id,
|
id,
|
||||||
|
|
|
@ -70,7 +70,8 @@ impl Report {
|
||||||
let object_creator = Person::read(&mut context.pool(), object_creator_id).await?;
|
let object_creator = Person::read(&mut context.pool(), object_creator_id).await?;
|
||||||
let object_creator_site: Option<ApubSite> =
|
let object_creator_site: Option<ApubSite> =
|
||||||
Site::read_from_instance_id(&mut context.pool(), object_creator.instance_id)
|
Site::read_from_instance_id(&mut context.pool(), object_creator.instance_id)
|
||||||
.await?
|
.await
|
||||||
|
.ok()
|
||||||
.map(Into::into);
|
.map(Into::into);
|
||||||
if let Some(inbox) = object_creator_site.map(|s| s.shared_inbox_or_inbox()) {
|
if let Some(inbox) = object_creator_site.map(|s| s.shared_inbox_or_inbox()) {
|
||||||
inboxes.add_inbox(inbox);
|
inboxes.add_inbox(inbox);
|
||||||
|
|
|
@ -2,9 +2,10 @@ use crate::{
|
||||||
activities::{
|
activities::{
|
||||||
community::send_activity_in_community,
|
community::send_activity_in_community,
|
||||||
generate_activity_id,
|
generate_activity_id,
|
||||||
verify_is_public,
|
generate_to,
|
||||||
verify_mod_action,
|
verify_mod_action,
|
||||||
verify_person_in_community,
|
verify_person_in_community,
|
||||||
|
verify_visibility,
|
||||||
},
|
},
|
||||||
activity_lists::AnnouncableActivities,
|
activity_lists::AnnouncableActivities,
|
||||||
insert_received_activity,
|
insert_received_activity,
|
||||||
|
@ -13,9 +14,10 @@ use crate::{
|
||||||
};
|
};
|
||||||
use activitypub_federation::{
|
use activitypub_federation::{
|
||||||
config::Data,
|
config::Data,
|
||||||
kinds::{activity::UpdateType, public},
|
kinds::activity::UpdateType,
|
||||||
traits::{ActivityHandler, Actor, Object},
|
traits::{ActivityHandler, Actor, Object},
|
||||||
};
|
};
|
||||||
|
use chrono::Utc;
|
||||||
use lemmy_api_common::context::LemmyContext;
|
use lemmy_api_common::context::LemmyContext;
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::{
|
source::{
|
||||||
|
@ -24,7 +26,6 @@ use lemmy_db_schema::{
|
||||||
person::Person,
|
person::Person,
|
||||||
},
|
},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
utils::naive_now,
|
|
||||||
};
|
};
|
||||||
use lemmy_utils::error::{LemmyError, LemmyResult};
|
use lemmy_utils::error::{LemmyError, LemmyResult};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
@ -42,7 +43,7 @@ pub(crate) async fn send_update_community(
|
||||||
)?;
|
)?;
|
||||||
let update = UpdateCommunity {
|
let update = UpdateCommunity {
|
||||||
actor: actor.id().into(),
|
actor: actor.id().into(),
|
||||||
to: vec![public()],
|
to: vec![generate_to(&community)?],
|
||||||
object: Box::new(community.clone().into_json(&context).await?),
|
object: Box::new(community.clone().into_json(&context).await?),
|
||||||
cc: vec![community.id()],
|
cc: vec![community.id()],
|
||||||
kind: UpdateType::Update,
|
kind: UpdateType::Update,
|
||||||
|
@ -77,8 +78,8 @@ impl ActivityHandler for UpdateCommunity {
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
async fn verify(&self, context: &Data<Self::DataType>) -> LemmyResult<()> {
|
async fn verify(&self, context: &Data<Self::DataType>) -> LemmyResult<()> {
|
||||||
verify_is_public(&self.to, &self.cc)?;
|
|
||||||
let community = self.community(context).await?;
|
let community = self.community(context).await?;
|
||||||
|
verify_visibility(&self.to, &self.cc, &community)?;
|
||||||
verify_person_in_community(&self.actor, &community, context).await?;
|
verify_person_in_community(&self.actor, &community, context).await?;
|
||||||
verify_mod_action(&self.actor, &community, context).await?;
|
verify_mod_action(&self.actor, &community, context).await?;
|
||||||
ApubCommunity::verify(&self.object, &community.actor_id.clone().into(), context).await?;
|
ApubCommunity::verify(&self.object, &community.actor_id.clone().into(), context).await?;
|
||||||
|
@ -102,7 +103,7 @@ impl ActivityHandler for UpdateCommunity {
|
||||||
nsfw: Some(self.object.sensitive.unwrap_or(false)),
|
nsfw: Some(self.object.sensitive.unwrap_or(false)),
|
||||||
actor_id: Some(self.object.id.into()),
|
actor_id: Some(self.object.id.into()),
|
||||||
public_key: Some(self.object.public_key.public_key_pem),
|
public_key: Some(self.object.public_key.public_key_pem),
|
||||||
last_refreshed_at: Some(naive_now()),
|
last_refreshed_at: Some(Utc::now()),
|
||||||
icon: Some(self.object.icon.map(|i| i.url.into())),
|
icon: Some(self.object.icon.map(|i| i.url.into())),
|
||||||
banner: Some(self.object.image.map(|i| i.url.into())),
|
banner: Some(self.object.image.map(|i| i.url.into())),
|
||||||
followers_url: self.object.followers.map(Into::into),
|
followers_url: self.object.followers.map(Into::into),
|
||||||
|
|
|
@ -3,8 +3,9 @@ use crate::{
|
||||||
check_community_deleted_or_removed,
|
check_community_deleted_or_removed,
|
||||||
community::send_activity_in_community,
|
community::send_activity_in_community,
|
||||||
generate_activity_id,
|
generate_activity_id,
|
||||||
verify_is_public,
|
generate_to,
|
||||||
verify_person_in_community,
|
verify_person_in_community,
|
||||||
|
verify_visibility,
|
||||||
},
|
},
|
||||||
activity_lists::AnnouncableActivities,
|
activity_lists::AnnouncableActivities,
|
||||||
insert_received_activity,
|
insert_received_activity,
|
||||||
|
@ -18,7 +19,6 @@ use crate::{
|
||||||
use activitypub_federation::{
|
use activitypub_federation::{
|
||||||
config::Data,
|
config::Data,
|
||||||
fetch::object_id::ObjectId,
|
fetch::object_id::ObjectId,
|
||||||
kinds::public,
|
|
||||||
protocol::verification::{verify_domains_match, verify_urls_match},
|
protocol::verification::{verify_domains_match, verify_urls_match},
|
||||||
traits::{ActivityHandler, Actor, Object},
|
traits::{ActivityHandler, Actor, Object},
|
||||||
};
|
};
|
||||||
|
@ -70,7 +70,7 @@ impl CreateOrUpdateNote {
|
||||||
|
|
||||||
let create_or_update = CreateOrUpdateNote {
|
let create_or_update = CreateOrUpdateNote {
|
||||||
actor: person.id().into(),
|
actor: person.id().into(),
|
||||||
to: vec![public()],
|
to: vec![generate_to(&community)?],
|
||||||
cc: note.cc.clone(),
|
cc: note.cc.clone(),
|
||||||
tag: note.tag.clone(),
|
tag: note.tag.clone(),
|
||||||
object: note,
|
object: note,
|
||||||
|
@ -118,9 +118,9 @@ impl ActivityHandler for CreateOrUpdateNote {
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
async fn verify(&self, context: &Data<Self::DataType>) -> LemmyResult<()> {
|
async fn verify(&self, context: &Data<Self::DataType>) -> LemmyResult<()> {
|
||||||
verify_is_public(&self.to, &self.cc)?;
|
|
||||||
let post = self.object.get_parents(context).await?.0;
|
let post = self.object.get_parents(context).await?.0;
|
||||||
let community = self.community(context).await?;
|
let community = self.community(context).await?;
|
||||||
|
verify_visibility(&self.to, &self.cc, &community)?;
|
||||||
|
|
||||||
verify_person_in_community(&self.actor, &community, context).await?;
|
verify_person_in_community(&self.actor, &community, context).await?;
|
||||||
verify_domains_match(self.actor.inner(), self.object.id.inner())?;
|
verify_domains_match(self.actor.inner(), self.object.id.inner())?;
|
||||||
|
|
|
@ -3,8 +3,9 @@ use crate::{
|
||||||
check_community_deleted_or_removed,
|
check_community_deleted_or_removed,
|
||||||
community::send_activity_in_community,
|
community::send_activity_in_community,
|
||||||
generate_activity_id,
|
generate_activity_id,
|
||||||
verify_is_public,
|
generate_to,
|
||||||
verify_person_in_community,
|
verify_person_in_community,
|
||||||
|
verify_visibility,
|
||||||
},
|
},
|
||||||
activity_lists::AnnouncableActivities,
|
activity_lists::AnnouncableActivities,
|
||||||
insert_received_activity,
|
insert_received_activity,
|
||||||
|
@ -16,7 +17,6 @@ use crate::{
|
||||||
};
|
};
|
||||||
use activitypub_federation::{
|
use activitypub_federation::{
|
||||||
config::Data,
|
config::Data,
|
||||||
kinds::public,
|
|
||||||
protocol::verification::{verify_domains_match, verify_urls_match},
|
protocol::verification::{verify_domains_match, verify_urls_match},
|
||||||
traits::{ActivityHandler, Actor, Object},
|
traits::{ActivityHandler, Actor, Object},
|
||||||
};
|
};
|
||||||
|
@ -49,7 +49,7 @@ impl CreateOrUpdatePage {
|
||||||
)?;
|
)?;
|
||||||
Ok(CreateOrUpdatePage {
|
Ok(CreateOrUpdatePage {
|
||||||
actor: actor.id().into(),
|
actor: actor.id().into(),
|
||||||
to: vec![public()],
|
to: vec![generate_to(community)?],
|
||||||
object: post.into_json(context).await?,
|
object: post.into_json(context).await?,
|
||||||
cc: vec![community.id()],
|
cc: vec![community.id()],
|
||||||
kind,
|
kind,
|
||||||
|
@ -102,8 +102,8 @@ impl ActivityHandler for CreateOrUpdatePage {
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
async fn verify(&self, context: &Data<LemmyContext>) -> LemmyResult<()> {
|
async fn verify(&self, context: &Data<LemmyContext>) -> LemmyResult<()> {
|
||||||
verify_is_public(&self.to, &self.cc)?;
|
|
||||||
let community = self.community(context).await?;
|
let community = self.community(context).await?;
|
||||||
|
verify_visibility(&self.to, &self.cc, &community)?;
|
||||||
verify_person_in_community(&self.actor, &community, context).await?;
|
verify_person_in_community(&self.actor, &community, context).await?;
|
||||||
check_community_deleted_or_removed(&community)?;
|
check_community_deleted_or_removed(&community)?;
|
||||||
verify_domains_match(self.actor.inner(), self.object.id.inner())?;
|
verify_domains_match(self.actor.inner(), self.object.id.inner())?;
|
||||||
|
@ -118,11 +118,7 @@ impl ActivityHandler for CreateOrUpdatePage {
|
||||||
let post = ApubPost::from_json(self.object, context).await?;
|
let post = ApubPost::from_json(self.object, context).await?;
|
||||||
|
|
||||||
// author likes their own post by default
|
// author likes their own post by default
|
||||||
let like_form = PostLikeForm {
|
let like_form = PostLikeForm::new(post.id, post.creator_id, 1);
|
||||||
post_id: post.id,
|
|
||||||
person_id: post.creator_id,
|
|
||||||
score: 1,
|
|
||||||
};
|
|
||||||
PostLike::like(&mut context.pool(), &like_form).await?;
|
PostLike::like(&mut context.pool(), &like_form).await?;
|
||||||
|
|
||||||
// Calculate initial hot_rank for post
|
// Calculate initial hot_rank for post
|
||||||
|
|
|
@ -84,7 +84,7 @@ impl Delete {
|
||||||
pub(in crate::activities::deletion) fn new(
|
pub(in crate::activities::deletion) fn new(
|
||||||
actor: &ApubPerson,
|
actor: &ApubPerson,
|
||||||
object: DeletableObjects,
|
object: DeletableObjects,
|
||||||
to: Url,
|
to: Vec<Url>,
|
||||||
community: Option<&Community>,
|
community: Option<&Community>,
|
||||||
summary: Option<String>,
|
summary: Option<String>,
|
||||||
context: &Data<LemmyContext>,
|
context: &Data<LemmyContext>,
|
||||||
|
@ -96,7 +96,7 @@ impl Delete {
|
||||||
let cc: Option<Url> = community.map(|c| c.actor_id.clone().into());
|
let cc: Option<Url> = community.map(|c| c.actor_id.clone().into());
|
||||||
Ok(Delete {
|
Ok(Delete {
|
||||||
actor: actor.actor_id.clone().into(),
|
actor: actor.actor_id.clone().into(),
|
||||||
to: vec![to],
|
to,
|
||||||
object: IdOrNestedObject::Id(object.id()),
|
object: IdOrNestedObject::Id(object.id()),
|
||||||
cc: cc.into_iter().collect(),
|
cc: cc.into_iter().collect(),
|
||||||
kind: DeleteType::Delete,
|
kind: DeleteType::Delete,
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
|
use super::{generate_to, verify_is_public};
|
||||||
use crate::{
|
use crate::{
|
||||||
activities::{
|
activities::{
|
||||||
community::send_activity_in_community,
|
community::send_activity_in_community,
|
||||||
send_lemmy_activity,
|
send_lemmy_activity,
|
||||||
verify_is_public,
|
|
||||||
verify_mod_action,
|
verify_mod_action,
|
||||||
verify_person,
|
verify_person,
|
||||||
verify_person_in_community,
|
verify_person_in_community,
|
||||||
|
verify_visibility,
|
||||||
},
|
},
|
||||||
activity_lists::AnnouncableActivities,
|
activity_lists::AnnouncableActivities,
|
||||||
objects::{
|
objects::{
|
||||||
|
@ -59,11 +60,12 @@ pub(crate) async fn send_apub_delete_in_community(
|
||||||
) -> LemmyResult<()> {
|
) -> LemmyResult<()> {
|
||||||
let actor = ApubPerson::from(actor);
|
let actor = ApubPerson::from(actor);
|
||||||
let is_mod_action = reason.is_some();
|
let is_mod_action = reason.is_some();
|
||||||
|
let to = vec![generate_to(&community)?];
|
||||||
let activity = if deleted {
|
let activity = if deleted {
|
||||||
let delete = Delete::new(&actor, object, public(), Some(&community), reason, context)?;
|
let delete = Delete::new(&actor, object, to, Some(&community), reason, context)?;
|
||||||
AnnouncableActivities::Delete(delete)
|
AnnouncableActivities::Delete(delete)
|
||||||
} else {
|
} else {
|
||||||
let undo = UndoDelete::new(&actor, object, public(), Some(&community), reason, context)?;
|
let undo = UndoDelete::new(&actor, object, to, Some(&community), reason, context)?;
|
||||||
AnnouncableActivities::UndoDelete(undo)
|
AnnouncableActivities::UndoDelete(undo)
|
||||||
};
|
};
|
||||||
send_activity_in_community(
|
send_activity_in_community(
|
||||||
|
@ -92,10 +94,10 @@ pub(crate) async fn send_apub_delete_private_message(
|
||||||
let deletable = DeletableObjects::PrivateMessage(pm.into());
|
let deletable = DeletableObjects::PrivateMessage(pm.into());
|
||||||
let inbox = ActivitySendTargets::to_inbox(recipient.shared_inbox_or_inbox());
|
let inbox = ActivitySendTargets::to_inbox(recipient.shared_inbox_or_inbox());
|
||||||
if deleted {
|
if deleted {
|
||||||
let delete: Delete = Delete::new(actor, deletable, recipient.id(), None, None, &context)?;
|
let delete: Delete = Delete::new(actor, deletable, vec![recipient.id()], None, None, &context)?;
|
||||||
send_lemmy_activity(&context, delete, actor, inbox, true).await?;
|
send_lemmy_activity(&context, delete, actor, inbox, true).await?;
|
||||||
} else {
|
} else {
|
||||||
let undo = UndoDelete::new(actor, deletable, recipient.id(), None, None, &context)?;
|
let undo = UndoDelete::new(actor, deletable, vec![recipient.id()], None, None, &context)?;
|
||||||
send_lemmy_activity(&context, undo, actor, inbox, true).await?;
|
send_lemmy_activity(&context, undo, actor, inbox, true).await?;
|
||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -109,7 +111,7 @@ pub async fn send_apub_delete_user(
|
||||||
let person: ApubPerson = person.into();
|
let person: ApubPerson = person.into();
|
||||||
|
|
||||||
let deletable = DeletableObjects::Person(person.clone());
|
let deletable = DeletableObjects::Person(person.clone());
|
||||||
let mut delete: Delete = Delete::new(&person, deletable, public(), None, None, &context)?;
|
let mut delete: Delete = Delete::new(&person, deletable, vec![public()], None, None, &context)?;
|
||||||
delete.remove_data = Some(remove_data);
|
delete.remove_data = Some(remove_data);
|
||||||
|
|
||||||
let inboxes = ActivitySendTargets::to_all_instances();
|
let inboxes = ActivitySendTargets::to_all_instances();
|
||||||
|
@ -170,7 +172,7 @@ pub(in crate::activities) async fn verify_delete_activity(
|
||||||
let object = DeletableObjects::read_from_db(activity.object.id(), context).await?;
|
let object = DeletableObjects::read_from_db(activity.object.id(), context).await?;
|
||||||
match object {
|
match object {
|
||||||
DeletableObjects::Community(community) => {
|
DeletableObjects::Community(community) => {
|
||||||
verify_is_public(&activity.to, &[])?;
|
verify_visibility(&activity.to, &[], &community)?;
|
||||||
if community.local {
|
if community.local {
|
||||||
// can only do this check for local community, in remote case it would try to fetch the
|
// can only do this check for local community, in remote case it would try to fetch the
|
||||||
// deleted community (which fails)
|
// deleted community (which fails)
|
||||||
|
@ -185,22 +187,24 @@ pub(in crate::activities) async fn verify_delete_activity(
|
||||||
verify_urls_match(person.actor_id.inner(), activity.object.id())?;
|
verify_urls_match(person.actor_id.inner(), activity.object.id())?;
|
||||||
}
|
}
|
||||||
DeletableObjects::Post(p) => {
|
DeletableObjects::Post(p) => {
|
||||||
verify_is_public(&activity.to, &[])?;
|
let community = activity.community(context).await?;
|
||||||
|
verify_visibility(&activity.to, &[], &community)?;
|
||||||
verify_delete_post_or_comment(
|
verify_delete_post_or_comment(
|
||||||
&activity.actor,
|
&activity.actor,
|
||||||
&p.ap_id.clone().into(),
|
&p.ap_id.clone().into(),
|
||||||
&activity.community(context).await?,
|
&community,
|
||||||
is_mod_action,
|
is_mod_action,
|
||||||
context,
|
context,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
DeletableObjects::Comment(c) => {
|
DeletableObjects::Comment(c) => {
|
||||||
verify_is_public(&activity.to, &[])?;
|
let community = activity.community(context).await?;
|
||||||
|
verify_visibility(&activity.to, &[], &community)?;
|
||||||
verify_delete_post_or_comment(
|
verify_delete_post_or_comment(
|
||||||
&activity.actor,
|
&activity.actor,
|
||||||
&c.ap_id.clone().into(),
|
&c.ap_id.clone().into(),
|
||||||
&activity.community(context).await?,
|
&community,
|
||||||
is_mod_action,
|
is_mod_action,
|
||||||
context,
|
context,
|
||||||
)
|
)
|
||||||
|
|
|
@ -68,7 +68,7 @@ impl UndoDelete {
|
||||||
pub(in crate::activities::deletion) fn new(
|
pub(in crate::activities::deletion) fn new(
|
||||||
actor: &ApubPerson,
|
actor: &ApubPerson,
|
||||||
object: DeletableObjects,
|
object: DeletableObjects,
|
||||||
to: Url,
|
to: Vec<Url>,
|
||||||
community: Option<&Community>,
|
community: Option<&Community>,
|
||||||
summary: Option<String>,
|
summary: Option<String>,
|
||||||
context: &Data<LemmyContext>,
|
context: &Data<LemmyContext>,
|
||||||
|
@ -82,7 +82,7 @@ impl UndoDelete {
|
||||||
let cc: Option<Url> = community.map(|c| c.actor_id.clone().into());
|
let cc: Option<Url> = community.map(|c| c.actor_id.clone().into());
|
||||||
Ok(UndoDelete {
|
Ok(UndoDelete {
|
||||||
actor: actor.actor_id.clone().into(),
|
actor: actor.actor_id.clone().into(),
|
||||||
to: vec![to],
|
to,
|
||||||
object,
|
object,
|
||||||
cc: cc.into_iter().collect(),
|
cc: cc.into_iter().collect(),
|
||||||
kind: UndoType::Undo,
|
kind: UndoType::Undo,
|
||||||
|
|
|
@ -20,7 +20,7 @@ use lemmy_api_common::context::LemmyContext;
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::{
|
source::{
|
||||||
activity::ActivitySendTargets,
|
activity::ActivitySendTargets,
|
||||||
community::{CommunityFollower, CommunityFollowerForm},
|
community::{CommunityFollower, CommunityFollowerForm, CommunityFollowerState},
|
||||||
person::{PersonFollower, PersonFollowerForm},
|
person::{PersonFollower, PersonFollowerForm},
|
||||||
},
|
},
|
||||||
traits::Followable,
|
traits::Followable,
|
||||||
|
@ -102,21 +102,25 @@ impl ActivityHandler for Follow {
|
||||||
pending: false,
|
pending: false,
|
||||||
};
|
};
|
||||||
PersonFollower::follow(&mut context.pool(), &form).await?;
|
PersonFollower::follow(&mut context.pool(), &form).await?;
|
||||||
|
AcceptFollow::send(self, context).await?;
|
||||||
}
|
}
|
||||||
UserOrCommunity::Community(c) => {
|
UserOrCommunity::Community(c) => {
|
||||||
// Dont allow following local-only community via federation.
|
let state = Some(match c.visibility {
|
||||||
if c.visibility != CommunityVisibility::Public {
|
CommunityVisibility::Public => CommunityFollowerState::Accepted,
|
||||||
return Err(LemmyErrorType::NotFound.into());
|
CommunityVisibility::Private => CommunityFollowerState::ApprovalRequired,
|
||||||
}
|
// Dont allow following local-only community via federation.
|
||||||
|
CommunityVisibility::LocalOnly => return Err(LemmyErrorType::NotFound.into()),
|
||||||
|
});
|
||||||
let form = CommunityFollowerForm {
|
let form = CommunityFollowerForm {
|
||||||
community_id: c.id,
|
state,
|
||||||
person_id: actor.id,
|
..CommunityFollowerForm::new(c.id, actor.id)
|
||||||
pending: false,
|
|
||||||
};
|
};
|
||||||
CommunityFollower::follow(&mut context.pool(), &form).await?;
|
CommunityFollower::follow(&mut context.pool(), &form).await?;
|
||||||
|
if c.visibility == CommunityVisibility::Public {
|
||||||
|
AcceptFollow::send(self, context).await?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
AcceptFollow::send(self, context).await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,26 @@
|
||||||
|
use super::generate_activity_id;
|
||||||
use crate::{
|
use crate::{
|
||||||
objects::{community::ApubCommunity, person::ApubPerson},
|
objects::{community::ApubCommunity, person::ApubPerson},
|
||||||
protocol::activities::following::{follow::Follow, undo_follow::UndoFollow},
|
protocol::activities::following::{
|
||||||
|
accept::AcceptFollow,
|
||||||
|
follow::Follow,
|
||||||
|
reject::RejectFollow,
|
||||||
|
undo_follow::UndoFollow,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use activitypub_federation::config::Data;
|
use activitypub_federation::{config::Data, kinds::activity::FollowType};
|
||||||
use lemmy_api_common::context::LemmyContext;
|
use lemmy_api_common::context::LemmyContext;
|
||||||
use lemmy_db_schema::source::{community::Community, person::Person};
|
use lemmy_db_schema::{
|
||||||
|
newtypes::{CommunityId, PersonId},
|
||||||
|
source::{community::Community, person::Person},
|
||||||
|
traits::Crud,
|
||||||
|
};
|
||||||
use lemmy_utils::error::LemmyResult;
|
use lemmy_utils::error::LemmyResult;
|
||||||
|
|
||||||
pub mod accept;
|
pub(crate) mod accept;
|
||||||
pub mod follow;
|
pub(crate) mod follow;
|
||||||
pub mod undo_follow;
|
pub(crate) mod reject;
|
||||||
|
pub(crate) mod undo_follow;
|
||||||
|
|
||||||
pub async fn send_follow_community(
|
pub async fn send_follow_community(
|
||||||
community: Community,
|
community: Community,
|
||||||
|
@ -25,3 +36,29 @@ pub async fn send_follow_community(
|
||||||
UndoFollow::send(&actor, &community, context).await
|
UndoFollow::send(&actor, &community, context).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn send_accept_or_reject_follow(
|
||||||
|
community_id: CommunityId,
|
||||||
|
person_id: PersonId,
|
||||||
|
accepted: bool,
|
||||||
|
context: &Data<LemmyContext>,
|
||||||
|
) -> LemmyResult<()> {
|
||||||
|
let community = Community::read(&mut context.pool(), community_id).await?;
|
||||||
|
let person = Person::read(&mut context.pool(), person_id).await?;
|
||||||
|
|
||||||
|
let follow = Follow {
|
||||||
|
actor: person.actor_id.into(),
|
||||||
|
to: Some([community.actor_id.clone().into()]),
|
||||||
|
object: community.actor_id.into(),
|
||||||
|
kind: FollowType::Follow,
|
||||||
|
id: generate_activity_id(
|
||||||
|
FollowType::Follow,
|
||||||
|
&context.settings().get_protocol_and_hostname(),
|
||||||
|
)?,
|
||||||
|
};
|
||||||
|
if accepted {
|
||||||
|
AcceptFollow::send(follow, context).await
|
||||||
|
} else {
|
||||||
|
RejectFollow::send(follow, context).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
79
crates/apub/src/activities/following/reject.rs
Normal file
79
crates/apub/src/activities/following/reject.rs
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
use crate::{
|
||||||
|
activities::{generate_activity_id, send_lemmy_activity},
|
||||||
|
insert_received_activity,
|
||||||
|
protocol::activities::following::{follow::Follow, reject::RejectFollow},
|
||||||
|
};
|
||||||
|
use activitypub_federation::{
|
||||||
|
config::Data,
|
||||||
|
kinds::activity::RejectType,
|
||||||
|
protocol::verification::verify_urls_match,
|
||||||
|
traits::{ActivityHandler, Actor},
|
||||||
|
};
|
||||||
|
use lemmy_api_common::context::LemmyContext;
|
||||||
|
use lemmy_db_schema::{
|
||||||
|
source::{
|
||||||
|
activity::ActivitySendTargets,
|
||||||
|
community::{CommunityFollower, CommunityFollowerForm},
|
||||||
|
},
|
||||||
|
traits::Followable,
|
||||||
|
};
|
||||||
|
use lemmy_utils::error::{LemmyError, LemmyResult};
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
impl RejectFollow {
|
||||||
|
#[tracing::instrument(skip_all)]
|
||||||
|
pub async fn send(follow: Follow, context: &Data<LemmyContext>) -> LemmyResult<()> {
|
||||||
|
let user_or_community = follow.object.dereference_local(context).await?;
|
||||||
|
let person = follow.actor.clone().dereference(context).await?;
|
||||||
|
let reject = RejectFollow {
|
||||||
|
actor: user_or_community.id().into(),
|
||||||
|
to: Some([person.id().into()]),
|
||||||
|
object: follow,
|
||||||
|
kind: RejectType::Reject,
|
||||||
|
id: generate_activity_id(
|
||||||
|
RejectType::Reject,
|
||||||
|
&context.settings().get_protocol_and_hostname(),
|
||||||
|
)?,
|
||||||
|
};
|
||||||
|
let inbox = ActivitySendTargets::to_inbox(person.shared_inbox_or_inbox());
|
||||||
|
send_lemmy_activity(context, reject, &user_or_community, inbox, true).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handle rejected follows
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl ActivityHandler for RejectFollow {
|
||||||
|
type DataType = LemmyContext;
|
||||||
|
type Error = LemmyError;
|
||||||
|
|
||||||
|
fn id(&self) -> &Url {
|
||||||
|
&self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn actor(&self) -> &Url {
|
||||||
|
self.actor.inner()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(skip_all)]
|
||||||
|
async fn verify(&self, context: &Data<LemmyContext>) -> LemmyResult<()> {
|
||||||
|
verify_urls_match(self.actor.inner(), self.object.object.inner())?;
|
||||||
|
self.object.verify(context).await?;
|
||||||
|
if let Some(to) = &self.to {
|
||||||
|
verify_urls_match(to[0].inner(), self.object.actor.inner())?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(skip_all)]
|
||||||
|
async fn receive(self, context: &Data<LemmyContext>) -> LemmyResult<()> {
|
||||||
|
insert_received_activity(&self.id, context).await?;
|
||||||
|
let community = self.actor.dereference(context).await?;
|
||||||
|
let person = self.object.actor.dereference(context).await?;
|
||||||
|
|
||||||
|
// remove the follow
|
||||||
|
let form = CommunityFollowerForm::new(community.id, person.id);
|
||||||
|
CommunityFollower::unfollow(&mut context.pool(), &form).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -90,11 +90,7 @@ impl ActivityHandler for UndoFollow {
|
||||||
PersonFollower::unfollow(&mut context.pool(), &form).await?;
|
PersonFollower::unfollow(&mut context.pool(), &form).await?;
|
||||||
}
|
}
|
||||||
UserOrCommunity::Community(c) => {
|
UserOrCommunity::Community(c) => {
|
||||||
let form = CommunityFollowerForm {
|
let form = CommunityFollowerForm::new(c.id, person.id);
|
||||||
community_id: c.id,
|
|
||||||
person_id: person.id,
|
|
||||||
pending: false,
|
|
||||||
};
|
|
||||||
CommunityFollower::unfollow(&mut context.pool(), &form).await?;
|
CommunityFollower::unfollow(&mut context.pool(), &form).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ use activitypub_federation::{
|
||||||
traits::{ActivityHandler, Actor},
|
traits::{ActivityHandler, Actor},
|
||||||
};
|
};
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
|
use following::send_accept_or_reject_follow;
|
||||||
use lemmy_api_common::{
|
use lemmy_api_common::{
|
||||||
context::LemmyContext,
|
context::LemmyContext,
|
||||||
send_activity::{ActivityChannel, SendActivityData},
|
send_activity::{ActivityChannel, SendActivityData},
|
||||||
|
@ -40,6 +41,7 @@ use lemmy_db_schema::{
|
||||||
community::Community,
|
community::Community,
|
||||||
},
|
},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
|
CommunityVisibility,
|
||||||
};
|
};
|
||||||
use lemmy_db_views_actor::structs::{CommunityPersonBanView, CommunityView};
|
use lemmy_db_views_actor::structs::{CommunityPersonBanView, CommunityView};
|
||||||
use lemmy_utils::error::{FederationError, LemmyError, LemmyErrorExt, LemmyErrorType, LemmyResult};
|
use lemmy_utils::error::{FederationError, LemmyError, LemmyErrorExt, LemmyErrorType, LemmyResult};
|
||||||
|
@ -120,6 +122,28 @@ pub(crate) fn verify_is_public(to: &[Url], cc: &[Url]) -> LemmyResult<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns an error if object visibility doesnt match community visibility
|
||||||
|
/// (ie content in private community must also be private).
|
||||||
|
pub(crate) fn verify_visibility(to: &[Url], cc: &[Url], community: &Community) -> LemmyResult<()> {
|
||||||
|
use CommunityVisibility::*;
|
||||||
|
let object_is_public = [to, cc].iter().any(|set| set.contains(&public()));
|
||||||
|
match community.visibility {
|
||||||
|
Public if !object_is_public => Err(FederationError::ObjectIsNotPublic)?,
|
||||||
|
Private if object_is_public => Err(FederationError::ObjectIsNotPrivate)?,
|
||||||
|
LocalOnly => Err(LemmyErrorType::NotFound.into()),
|
||||||
|
_ => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Marks object as public only if the community is public
|
||||||
|
pub(crate) fn generate_to(community: &Community) -> LemmyResult<Url> {
|
||||||
|
if community.visibility == CommunityVisibility::Public {
|
||||||
|
Ok(public())
|
||||||
|
} else {
|
||||||
|
Ok(Url::parse(&format!("{}/followers", community.actor_id))?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn verify_community_matches<T>(a: &ObjectId<ApubCommunity>, b: T) -> LemmyResult<()>
|
pub(crate) fn verify_community_matches<T>(a: &ObjectId<ApubCommunity>, b: T) -> LemmyResult<()>
|
||||||
where
|
where
|
||||||
T: Into<ObjectId<ApubCommunity>>,
|
T: Into<ObjectId<ApubCommunity>>,
|
||||||
|
@ -367,6 +391,12 @@ pub async fn match_outgoing_activities(
|
||||||
community,
|
community,
|
||||||
reason,
|
reason,
|
||||||
} => Report::send(ObjectId::from(object_id), actor, community, reason, context).await,
|
} => Report::send(ObjectId::from(object_id), actor, community, reason, context).await,
|
||||||
|
AcceptFollower(community_id, person_id) => {
|
||||||
|
send_accept_or_reject_follow(community_id, person_id, true, &context).await
|
||||||
|
}
|
||||||
|
RejectFollower(community_id, person_id) => {
|
||||||
|
send_accept_or_reject_follow(community_id, person_id, false, &context).await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
fed_task.await?;
|
fed_task.await?;
|
||||||
|
|
|
@ -79,11 +79,7 @@ async fn vote_post(
|
||||||
context: &Data<LemmyContext>,
|
context: &Data<LemmyContext>,
|
||||||
) -> LemmyResult<()> {
|
) -> LemmyResult<()> {
|
||||||
let post_id = post.id;
|
let post_id = post.id;
|
||||||
let like_form = PostLikeForm {
|
let like_form = PostLikeForm::new(post.id, actor.id, vote_type.into());
|
||||||
post_id: post.id,
|
|
||||||
person_id: actor.id,
|
|
||||||
score: vote_type.into(),
|
|
||||||
};
|
|
||||||
let person_id = actor.id;
|
let person_id = actor.id;
|
||||||
PostLike::remove(&mut context.pool(), person_id, post_id).await?;
|
PostLike::remove(&mut context.pool(), person_id, post_id).await?;
|
||||||
PostLike::like(&mut context.pool(), &like_form).await?;
|
PostLike::like(&mut context.pool(), &like_form).await?;
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue