Merge branch 'main' into discourse-federation

This commit is contained in:
Felix Ableitner 2024-05-02 13:09:14 +02:00
commit 0af99ee0c3
223 changed files with 6081 additions and 2794 deletions

View file

@ -143,16 +143,6 @@ steps:
- diff tmp.schema crates/db_schema/src/schema.rs
when: *slow_check_paths
check_diesel_migration_revertable:
image: willsquire/diesel-cli
environment:
CARGO_HOME: .cargo_home
DATABASE_URL: postgres://lemmy:password@database:5432/lemmy
commands:
- diesel migration run
- diesel migration redo
when: *slow_check_paths
check_db_perf_tool:
image: *rust_image
environment:
@ -194,6 +184,44 @@ steps:
- cargo test --workspace --no-fail-fast
when: *slow_check_paths
check_diesel_migration:
# TODO: use willsquire/diesel-cli image when shared libraries become optional in lemmy_server
image: *rust_image
environment:
LEMMY_DATABASE_URL: postgres://lemmy:password@database:5432/lemmy
RUST_BACKTRACE: "1"
CARGO_HOME: .cargo_home
DATABASE_URL: postgres://lemmy:password@database:5432/lemmy
PGUSER: lemmy
PGPASSWORD: password
PGHOST: database
PGDATABASE: lemmy
commands:
- cargo install diesel_cli
- export PATH="$CARGO_HOME/bin:$PATH"
# Run all migrations
- diesel migration run
# Dump schema to before.sqldump (PostgreSQL apt repo is used to prevent pg_dump version mismatch error)
- apt update && apt install -y lsb-release
- sh -c 'echo "deb https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
- wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -
- apt update && apt install -y postgresql-client-16
- psql -c "DROP SCHEMA IF EXISTS r CASCADE;"
- pg_dump --no-owner --no-privileges --no-table-access-method --schema-only --no-sync -f before.sqldump
# Make sure that the newest migration is revertable without the `r` schema
- diesel migration redo
# Run schema setup twice, which fails on the 2nd time if `DROP SCHEMA IF EXISTS r CASCADE` drops the wrong things
- alias lemmy_schema_setup="target/lemmy_server --disable-scheduled-tasks --disable-http-server --disable-activity-sending"
- lemmy_schema_setup
- lemmy_schema_setup
# Make sure that the newest migration is revertable with the `r` schema
- diesel migration redo
# Check for changes in the schema, which would be caused by an incorrect migration
- psql -c "DROP SCHEMA IF EXISTS r CASCADE;"
- pg_dump --no-owner --no-privileges --no-table-access-method --schema-only --no-sync -f after.sqldump
- diff before.sqldump after.sqldump
when: *slow_check_paths
run_federation_tests:
image: node:20-bookworm-slim
environment:
@ -250,8 +278,7 @@ steps:
commands:
- cargo install cargo-workspaces
- cp -r migrations crates/db_schema/
- cargo login "$CARGO_API_TOKEN"
- cargo workspaces publish --from-git --allow-dirty --no-verify --allow-branch "${CI_COMMIT_TAG}" --yes custom "${CI_COMMIT_TAG}"
- cargo workspaces publish --token "$CARGO_API_TOKEN" --from-git --allow-dirty --no-verify --allow-branch "${CI_COMMIT_TAG}" --yes custom "${CI_COMMIT_TAG}"
secrets: [cargo_api_token]
when:
- event: tag

309
Cargo.lock generated
View file

@ -96,9 +96,9 @@ dependencies = [
[[package]]
name = "actix-form-data"
version = "0.7.0-beta.6"
version = "0.7.0-beta.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0588d156cb871d8c237d55ce398e2a65727370fb98352ba5b65c15a2f834b0f"
checksum = "6c2355a841a5d9a6c616d6a4f31336064116d206e6c1830de22730f983613a05"
dependencies = [
"actix-multipart",
"actix-web",
@ -469,9 +469,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.81"
version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247"
checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519"
dependencies = [
"backtrace",
]
@ -507,11 +507,13 @@ dependencies = [
[[package]]
name = "async-lock"
version = "2.8.0"
version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b"
checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b"
dependencies = [
"event-listener",
"event-listener 4.0.3",
"event-listener-strategy",
"pin-project-lite",
]
[[package]]
@ -538,9 +540,9 @@ dependencies = [
[[package]]
name = "async-trait"
version = "0.1.78"
version = "0.1.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "461abc97219de0eaaf81fe3ef974a540158f3d079c2ab200f891f1a2ef201e85"
checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca"
dependencies = [
"proc-macro2",
"quote",
@ -658,9 +660,9 @@ checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
[[package]]
name = "base64"
version = "0.22.0"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "base64ct"
@ -697,7 +699,7 @@ version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e65938ed058ef47d92cf8b346cc76ef48984572ade631927e9937b5ffc7662c7"
dependencies = [
"base64 0.22.0",
"base64 0.22.1",
"blowfish",
"getrandom",
"subtle",
@ -795,12 +797,6 @@ version = "3.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa"
[[package]]
name = "bytecount"
version = "0.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1e5f035d16fc623ae5f74981db80a439803888314e3a555fd6f04acd51a3205"
[[package]]
name = "bytemuck"
version = "1.15.0"
@ -828,15 +824,6 @@ dependencies = [
"bytes",
]
[[package]]
name = "camino"
version = "1.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c"
dependencies = [
"serde",
]
[[package]]
name = "captcha"
version = "0.0.9"
@ -851,28 +838,6 @@ dependencies = [
"serde_json",
]
[[package]]
name = "cargo-platform"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "694c8807f2ae16faecc43dc17d74b3eb042482789fd0eb64b39a2e04e087053f"
dependencies = [
"serde",
]
[[package]]
name = "cargo_metadata"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa"
dependencies = [
"camino",
"cargo-platform",
"semver",
"serde",
"serde_json",
]
[[package]]
name = "cc"
version = "1.0.90"
@ -897,9 +862,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.35"
version = "0.4.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a"
checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
dependencies = [
"android-tzdata",
"iana-time-zone",
@ -932,9 +897,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.3"
version = "4.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "949626d00e063efc93b6dca932419ceb5432f99769911c0b995f7e884c778813"
checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0"
dependencies = [
"clap_builder",
"clap_derive",
@ -954,9 +919,9 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.5.3"
version = "4.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90239a040c80f5e14809ca132ddc4176ab33d5e17e49691793296e3fcb34d72f"
checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64"
dependencies = [
"heck 0.5.0",
"proc-macro2",
@ -1028,6 +993,15 @@ dependencies = [
"memchr",
]
[[package]]
name = "concurrent-queue"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "config"
version = "0.14.0"
@ -1472,9 +1446,9 @@ dependencies = [
[[package]]
name = "diesel"
version = "2.1.5"
version = "2.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03fc05c17098f21b89bc7d98fe1dd3cce2c11c2ad8e145f2a44fe08ed28eb559"
checksum = "ff236accb9a5069572099f0b350a92e9560e8e63a9b8d546162f4a5e03026bb2"
dependencies = [
"bitflags 2.4.2",
"byteorder",
@ -1517,9 +1491,9 @@ dependencies = [
[[package]]
name = "diesel-derive-newtype"
version = "2.1.1"
version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4ed4d69628c8de8eb4c3f50cddb0678cba3c5b4cbe3cb1067d4d6c62ca47e4e"
checksum = "d5adf688c584fe33726ce0e2898f608a2a92578ac94a4a92fcecf73214fe0716"
dependencies = [
"proc-macro2",
"quote",
@ -1647,11 +1621,11 @@ dependencies = [
[[package]]
name = "email-encoding"
version = "0.2.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbfb21b9878cf7a348dcb8559109aabc0ec40d69924bd706fa5149846c4fef75"
checksum = "60d1d33cdaede7e24091f039632eb5d3c7469fe5b066a985281a34fc70fa317f"
dependencies = [
"base64 0.21.7",
"base64 0.22.1",
"memchr",
]
@ -1801,19 +1775,36 @@ dependencies = [
]
[[package]]
name = "error-chain"
version = "0.12.4"
name = "event-listener"
version = "4.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc"
checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e"
dependencies = [
"version_check",
"concurrent-queue",
"parking",
"pin-project-lite",
]
[[package]]
name = "event-listener"
version = "2.5.3"
version = "5.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
checksum = "6d9944b8ca13534cdfb2800775f8dd4902ff3fc75a50101466decadfdf322a24"
dependencies = [
"concurrent-queue",
"parking",
"pin-project-lite",
]
[[package]]
name = "event-listener-strategy"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3"
dependencies = [
"event-listener 4.0.3",
"pin-project-lite",
]
[[package]]
name = "eyre"
@ -1881,18 +1872,6 @@ dependencies = [
"miniz_oxide",
]
[[package]]
name = "flume"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181"
dependencies = [
"futures-core",
"futures-sink",
"nanorand",
"spin 0.9.8",
]
[[package]]
name = "fnv"
version = "1.0.7"
@ -2053,9 +2032,9 @@ dependencies = [
[[package]]
name = "getrandom"
version = "0.2.12"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c"
dependencies = [
"cfg-if",
"js-sys",
@ -2168,13 +2147,13 @@ dependencies = [
[[package]]
name = "hostname"
version = "0.3.1"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867"
checksum = "f9c7c7c8ac16c798734b8a24560c1362120597c40d5e1459f09498f8f6c8f2ba"
dependencies = [
"cfg-if",
"libc",
"match_cfg",
"winapi",
"windows",
]
[[package]]
@ -2332,7 +2311,7 @@ dependencies = [
"futures-util",
"http",
"hyper",
"rustls 0.21.10",
"rustls 0.21.12",
"tokio",
"tokio-rustls 0.24.1",
]
@ -2612,13 +2591,13 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "lemmy_api"
version = "0.19.4-beta.3"
version = "0.19.4-beta.6"
dependencies = [
"activitypub_federation",
"actix-web",
"actix-web-httpauth",
"anyhow",
"base64 0.21.7",
"base64 0.22.1",
"bcrypt",
"captcha",
"chrono",
@ -2641,7 +2620,7 @@ dependencies = [
[[package]]
name = "lemmy_api_common"
version = "0.19.4-beta.3"
version = "0.19.4-beta.6"
dependencies = [
"activitypub_federation",
"actix-web",
@ -2679,7 +2658,7 @@ dependencies = [
[[package]]
name = "lemmy_api_crud"
version = "0.19.4-beta.3"
version = "0.19.4-beta.6"
dependencies = [
"accept-language",
"activitypub_federation",
@ -2702,7 +2681,7 @@ dependencies = [
[[package]]
name = "lemmy_apub"
version = "0.19.4-beta.3"
version = "0.19.4-beta.6"
dependencies = [
"activitypub_federation",
"actix-web",
@ -2740,7 +2719,7 @@ dependencies = [
[[package]]
name = "lemmy_db_perf"
version = "0.19.4-beta.3"
version = "0.19.4-beta.6"
dependencies = [
"anyhow",
"clap",
@ -2755,7 +2734,7 @@ dependencies = [
[[package]]
name = "lemmy_db_schema"
version = "0.19.4-beta.3"
version = "0.19.4-beta.6"
dependencies = [
"activitypub_federation",
"anyhow",
@ -2776,7 +2755,7 @@ dependencies = [
"once_cell",
"pretty_assertions",
"regex",
"rustls 0.21.10",
"rustls 0.21.12",
"serde",
"serde_json",
"serde_with",
@ -2795,7 +2774,7 @@ dependencies = [
[[package]]
name = "lemmy_db_views"
version = "0.19.4-beta.3"
version = "0.19.4-beta.6"
dependencies = [
"actix-web",
"chrono",
@ -2817,7 +2796,7 @@ dependencies = [
[[package]]
name = "lemmy_db_views_actor"
version = "0.19.4-beta.3"
version = "0.19.4-beta.6"
dependencies = [
"chrono",
"diesel",
@ -2837,7 +2816,7 @@ dependencies = [
[[package]]
name = "lemmy_db_views_moderator"
version = "0.19.4-beta.3"
version = "0.19.4-beta.6"
dependencies = [
"diesel",
"diesel-async",
@ -2849,7 +2828,7 @@ dependencies = [
[[package]]
name = "lemmy_federate"
version = "0.19.4-beta.3"
version = "0.19.4-beta.6"
dependencies = [
"activitypub_federation",
"anyhow",
@ -2872,7 +2851,7 @@ dependencies = [
[[package]]
name = "lemmy_routes"
version = "0.19.4-beta.3"
version = "0.19.4-beta.6"
dependencies = [
"activitypub_federation",
"actix-web",
@ -2897,7 +2876,7 @@ dependencies = [
[[package]]
name = "lemmy_server"
version = "0.19.4-beta.3"
version = "0.19.4-beta.6"
dependencies = [
"activitypub_federation",
"actix-cors",
@ -2940,7 +2919,7 @@ dependencies = [
[[package]]
name = "lemmy_utils"
version = "0.19.4-beta.3"
version = "0.19.4-beta.6"
dependencies = [
"actix-web",
"anyhow",
@ -2979,12 +2958,12 @@ dependencies = [
[[package]]
name = "lettre"
version = "0.11.4"
version = "0.11.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "357ff5edb6d8326473a64c82cf41ddf78ab116f89668c50c4fac1b321e5e80f4"
checksum = "1a62049a808f1c4e2356a2a380bd5f2aca3b011b0b482cf3b914ba1731426969"
dependencies = [
"async-trait",
"base64 0.21.7",
"base64 0.22.1",
"chumsky",
"email-encoding",
"email_address",
@ -3148,12 +3127,6 @@ dependencies = [
"xml5ever",
]
[[package]]
name = "match_cfg"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
[[package]]
name = "matchers"
version = "0.1.0"
@ -3305,21 +3278,21 @@ dependencies = [
[[package]]
name = "moka"
version = "0.12.5"
version = "0.12.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1911e88d5831f748a4097a43862d129e3c6fca831eecac9b8db6d01d93c9de2"
checksum = "9e0d88686dc561d743b40de8269b26eaf0dc58781bde087b0984646602021d08"
dependencies = [
"async-lock",
"async-trait",
"crossbeam-channel",
"crossbeam-epoch",
"crossbeam-utils",
"event-listener 5.3.0",
"futures-util",
"once_cell",
"parking_lot 0.12.1",
"quanta",
"rustc_version",
"skeptic",
"smallvec",
"tagptr",
"thiserror",
@ -3338,9 +3311,6 @@ name = "nanorand"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3"
dependencies = [
"getrandom",
]
[[package]]
name = "native-tls"
@ -3687,6 +3657,12 @@ version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
[[package]]
name = "parking"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae"
[[package]]
name = "parking_lot"
version = "0.11.2"
@ -3830,9 +3806,9 @@ dependencies = [
[[package]]
name = "pict-rs"
version = "0.5.9"
version = "0.5.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e709cefc614ddbe5685b30298790a2fe8637523190c182c0215c18053ce7cfdf"
checksum = "7893e6e0d03847ff772f741b9b524544557274c56f2b0dad2a205260875b1d0f"
dependencies = [
"actix-form-data",
"actix-web",
@ -3849,7 +3825,6 @@ dependencies = [
"diesel",
"diesel-async",
"diesel-derive-enum",
"flume",
"futures-core",
"hex",
"md-5",
@ -4167,17 +4142,6 @@ dependencies = [
"cc",
]
[[package]]
name = "pulldown-cmark"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b"
dependencies = [
"bitflags 2.4.2",
"memchr",
"unicase",
]
[[package]]
name = "quanta"
version = "0.12.2"
@ -4343,9 +4307,9 @@ dependencies = [
[[package]]
name = "regex"
version = "1.10.3"
version = "1.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15"
checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
dependencies = [
"aho-corasick",
"memchr",
@ -4387,9 +4351,9 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]]
name = "reqwest"
version = "0.11.26"
version = "0.11.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78bf93c4af7a8bb7d879d51cebe797356ff10ae8516ace542b5182d9dcac10b2"
checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
dependencies = [
"async-compression",
"base64 0.21.7",
@ -4412,7 +4376,7 @@ dependencies = [
"once_cell",
"percent-encoding",
"pin-project-lite",
"rustls 0.21.10",
"rustls 0.21.12",
"rustls-pemfile 1.0.4",
"serde",
"serde_json",
@ -4617,9 +4581,9 @@ dependencies = [
[[package]]
name = "rustls"
version = "0.21.10"
version = "0.21.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba"
checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e"
dependencies = [
"log",
"ring 0.17.8",
@ -4817,15 +4781,12 @@ name = "semver"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
dependencies = [
"serde",
]
[[package]]
name = "serde"
version = "1.0.197"
version = "1.0.200"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f"
dependencies = [
"serde_derive",
]
@ -4841,9 +4802,9 @@ dependencies = [
[[package]]
name = "serde_derive"
version = "1.0.197"
version = "1.0.200"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb"
dependencies = [
"proc-macro2",
"quote",
@ -4852,9 +4813,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.114"
version = "1.0.116"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0"
checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813"
dependencies = [
"indexmap 2.2.5",
"itoa",
@ -4894,11 +4855,11 @@ dependencies = [
[[package]]
name = "serde_with"
version = "3.7.0"
version = "3.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee80b0e361bbf88fd2f6e242ccd19cfda072cb0faa6ae694ecee08199938569a"
checksum = "0ad483d2ab0149d5a5ebcd9972a3852711e0153d863bf5a5d0391d28883c4a20"
dependencies = [
"base64 0.21.7",
"base64 0.22.1",
"chrono",
"hex",
"indexmap 1.9.3",
@ -4912,9 +4873,9 @@ dependencies = [
[[package]]
name = "serde_with_macros"
version = "3.7.0"
version = "3.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6561dc161a9224638a31d876ccdfefbc1df91d3f3a8342eddb35f055d48c7655"
checksum = "65569b702f41443e8bc8bbb1c5779bd0450bbe723b56198980e80ec45780bce2"
dependencies = [
"darling 0.20.8",
"proc-macro2",
@ -5036,21 +4997,6 @@ dependencies = [
"xml-builder",
]
[[package]]
name = "skeptic"
version = "0.13.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8"
dependencies = [
"bytecount",
"cargo_metadata",
"error-chain",
"glob",
"pulldown-cmark",
"tempfile",
"walkdir",
]
[[package]]
name = "sketches-ddsketch"
version = "0.2.2"
@ -5120,9 +5066,6 @@ name = "spin"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
dependencies = [
"lock_api",
]
[[package]]
name = "spki"
@ -5439,9 +5382,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
version = "1.36.0"
version = "1.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931"
checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787"
dependencies = [
"backtrace",
"bytes",
@ -5522,7 +5465,7 @@ checksum = "dd5831152cb0d3f79ef5523b357319ba154795d64c7078b2daa95a803b54057f"
dependencies = [
"futures",
"ring 0.16.20",
"rustls 0.21.10",
"rustls 0.21.12",
"tokio",
"tokio-postgres",
"tokio-rustls 0.24.1",
@ -5560,7 +5503,7 @@ version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
dependencies = [
"rustls 0.21.10",
"rustls 0.21.12",
"tokio",
]
@ -6025,18 +5968,18 @@ dependencies = [
[[package]]
name = "typed-builder"
version = "0.18.1"
version = "0.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "444d8748011b93cb168770e8092458cb0f8854f931ff82fdf6ddfbd72a9c933e"
checksum = "77739c880e00693faef3d65ea3aad725f196da38b22fdc7ea6ded6e1ce4d3add"
dependencies = [
"typed-builder-macro",
]
[[package]]
name = "typed-builder-macro"
version = "0.18.1"
version = "0.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "563b3b88238ec95680aef36bdece66896eaa7ce3c0f1b4f39d38fb2435261352"
checksum = "1f718dfaf347dcb5b983bfc87608144b0bad87970aebcbea5ce44d2a30c08e63"
dependencies = [
"proc-macro2",
"quote",
@ -6416,6 +6359,16 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
dependencies = [
"windows-core",
"windows-targets 0.52.4",
]
[[package]]
name = "windows-core"
version = "0.52.0"

View file

@ -1,5 +1,5 @@
[workspace.package]
version = "0.19.4-beta.3"
version = "0.19.4-beta.6"
edition = "2021"
description = "A link aggregator for the fediverse"
license = "AGPL-3.0"
@ -88,25 +88,25 @@ unused_self = "deny"
unwrap_used = "deny"
[workspace.dependencies]
lemmy_api = { version = "=0.19.4-beta.3", path = "./crates/api" }
lemmy_api_crud = { version = "=0.19.4-beta.3", path = "./crates/api_crud" }
lemmy_apub = { version = "=0.19.4-beta.3", path = "./crates/apub" }
lemmy_utils = { version = "=0.19.4-beta.3", path = "./crates/utils", default-features = false }
lemmy_db_schema = { version = "=0.19.4-beta.3", path = "./crates/db_schema" }
lemmy_api_common = { version = "=0.19.4-beta.3", path = "./crates/api_common" }
lemmy_routes = { version = "=0.19.4-beta.3", path = "./crates/routes" }
lemmy_db_views = { version = "=0.19.4-beta.3", path = "./crates/db_views" }
lemmy_db_views_actor = { version = "=0.19.4-beta.3", path = "./crates/db_views_actor" }
lemmy_db_views_moderator = { version = "=0.19.4-beta.3", path = "./crates/db_views_moderator" }
lemmy_federate = { version = "=0.19.4-beta.3", path = "./crates/federate" }
lemmy_api = { version = "=0.19.4-beta.6", path = "./crates/api" }
lemmy_api_crud = { version = "=0.19.4-beta.6", path = "./crates/api_crud" }
lemmy_apub = { version = "=0.19.4-beta.6", path = "./crates/apub" }
lemmy_utils = { version = "=0.19.4-beta.6", path = "./crates/utils", default-features = false }
lemmy_db_schema = { version = "=0.19.4-beta.6", path = "./crates/db_schema" }
lemmy_api_common = { version = "=0.19.4-beta.6", path = "./crates/api_common" }
lemmy_routes = { version = "=0.19.4-beta.6", path = "./crates/routes" }
lemmy_db_views = { version = "=0.19.4-beta.6", path = "./crates/db_views" }
lemmy_db_views_actor = { version = "=0.19.4-beta.6", path = "./crates/db_views_actor" }
lemmy_db_views_moderator = { version = "=0.19.4-beta.6", path = "./crates/db_views_moderator" }
lemmy_federate = { version = "=0.19.4-beta.6", path = "./crates/federate" }
activitypub_federation = { version = "0.5.4", default-features = false, features = [
"actix-web",
] }
diesel = "2.1.4"
diesel = "2.1.6"
diesel_migrations = "2.1.0"
diesel-async = "0.4.1"
serde = { version = "1.0.197", features = ["derive"] }
serde_with = "3.7.0"
serde = { version = "1.0.199", features = ["derive"] }
serde_with = "3.8.1"
actix-web = { version = "4.5.1", default-features = false, features = [
"macros",
"rustls",
@ -121,28 +121,28 @@ tracing-error = "0.2.0"
tracing-log = "0.2.0"
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
url = { version = "2.5.0", features = ["serde"] }
reqwest = { version = "0.11.26", features = ["json", "blocking", "gzip"] }
reqwest-middleware = "0.2.4"
reqwest-tracing = "0.4.7"
reqwest = { version = "0.11.27", features = ["json", "blocking", "gzip"] }
reqwest-middleware = "0.2.5"
reqwest-tracing = "0.4.8"
clokwerk = "0.4.0"
doku = { version = "0.21.1", features = ["url-2"] }
bcrypt = "0.15.0"
chrono = { version = "0.4.35", features = ["serde"], default-features = false }
serde_json = { version = "1.0.114", features = ["preserve_order"] }
base64 = "0.21.7"
uuid = { version = "1.7.0", features = ["serde", "v4"] }
async-trait = "0.1.77"
bcrypt = "0.15.1"
chrono = { version = "0.4.38", features = ["serde"], default-features = false }
serde_json = { version = "1.0.116", features = ["preserve_order"] }
base64 = "0.22.1"
uuid = { version = "1.8.0", features = ["serde", "v4"] }
async-trait = "0.1.80"
captcha = "0.0.9"
anyhow = { version = "1.0.81", features = [
anyhow = { version = "1.0.82", features = [
"backtrace",
] } # backtrace is on by default on nightly, but not stable rust
diesel_ltree = "0.3.1"
typed-builder = "0.18.1"
typed-builder = "0.18.2"
serial_test = "2.0.0"
tokio = { version = "1.36.0", features = ["full"] }
regex = "1.10.3"
tokio = { version = "1.37.0", features = ["full"] }
regex = "1.10.4"
once_cell = "1.19.0"
diesel-derive-newtype = "2.1.0"
diesel-derive-newtype = "2.1.2"
diesel-derive-enum = { version = "2.1.0", features = ["postgres"] }
strum = "0.25.0"
strum_macros = "0.25.3"
@ -157,15 +157,15 @@ ts-rs = { version = "7.1.1", features = [
"chrono-impl",
"no-serde-warnings",
] }
rustls = { version = "0.21.10", features = ["dangerous_configuration"] }
rustls = { version = "0.21.11", features = ["dangerous_configuration"] }
futures-util = "0.3.30"
tokio-postgres = "0.7.10"
tokio-postgres-rustls = "0.10.0"
urlencoding = "2.1.3"
enum-map = "2.7"
moka = { version = "0.12.5", features = ["future"] }
moka = { version = "0.12.7", features = ["future"] }
i-love-jesus = { version = "0.1.0" }
clap = { version = "4.5.2", features = ["derive"] }
clap = { version = "4.5.4", features = ["derive"] }
pretty_assertions = "1.4.0"
[dependencies]
@ -196,7 +196,7 @@ tracing-opentelemetry = { workspace = true, optional = true }
opentelemetry = { workspace = true, optional = true }
console-subscriber = { version = "0.1.10", optional = true }
opentelemetry-otlp = { version = "0.12.0", optional = true }
pict-rs = { version = "0.5.9", optional = true }
pict-rs = { version = "0.5.13", optional = true }
tokio.workspace = true
actix-cors = "0.6.5"
futures-util = { workspace = true }

View file

@ -6,6 +6,7 @@
"repository": "https://github.com/LemmyNet/lemmy",
"author": "Dessalines",
"license": "AGPL-3.0",
"packageManager": "pnpm@9.0.6",
"scripts": {
"lint": "tsc --noEmit && eslint --report-unused-disable-directives --ext .js,.ts,.tsx src && prettier --check 'src/**/*.ts'",
"fix": "prettier --write src && eslint --fix src",
@ -27,7 +28,7 @@
"eslint": "^8.57.0",
"eslint-plugin-prettier": "^5.1.3",
"jest": "^29.5.0",
"lemmy-js-client": "0.19.4-alpha.16",
"lemmy-js-client": "0.19.4-alpha.18",
"prettier": "^3.2.5",
"ts-jest": "^29.1.0",
"typescript": "^5.4.4"

File diff suppressed because it is too large Load diff

View file

@ -242,7 +242,7 @@ test("Admin actions in remote community are not federated to origin", async () =
);
expect(banRes.banned).toBe(true);
// ban doesnt federate to community's origin instance alpha
// ban doesn't federate to community's origin instance alpha
let alphaPost = (await resolvePost(alpha, gammaPost.post)).post;
expect(alphaPost?.creator_banned_from_community).toBe(false);
@ -452,7 +452,7 @@ test("Dont receive community activities after unsubscribe", async () => {
);
expect(communityRes1.community_view.counts.subscribers).toBe(2);
// temporarily block alpha, so that it doesnt know about unfollow
// temporarily block alpha, so that it doesn't know about unfollow
let editSiteForm: EditSite = {};
editSiteForm.allowed_instances = ["lemmy-epsilon"];
await beta.editSite(editSiteForm);
@ -513,7 +513,7 @@ test("Fetch community, includes posts", async () => {
expect(post_listing.posts[0].post.ap_id).toBe(postRes.post_view.post.ap_id);
});
test("Content in local-only community doesnt federate", async () => {
test("Content in local-only community doesn't federate", async () => {
// create a community and set it local-only
let communityRes = (await createCommunity(alpha)).community_view.community;
let form: EditCommunity = {

View file

@ -27,9 +27,10 @@ import {
setupLogins,
waitForPost,
unfollows,
editPostThumbnail,
getPost,
waitUntil,
randomString,
createPostWithThumbnail,
} from "./shared";
const downloadFileSync = require("download-file-sync");
@ -41,7 +42,7 @@ test("Upload image and delete it", async () => {
// Before running this test, you need to delete all previous images in the DB
await deleteAllImages(alpha);
// Upload test image. We use a simple string buffer as pictrs doesnt require an actual image
// Upload test image. We use a simple string buffer as pictrs doesn't require an actual image
// in testing mode.
const upload_form: UploadImage = {
image: Buffer.from("test"),
@ -71,9 +72,14 @@ test("Upload image and delete it", async () => {
// The deleteUrl is a combination of the endpoint, delete token, and alias
let firstImage = listMediaRes.images[0];
let deleteUrl = `${alphaUrl}/pictrs/image/delete/${firstImage.pictrs_delete_token}/${firstImage.pictrs_alias}`;
let deleteUrl = `${alphaUrl}/pictrs/image/delete/${firstImage.local_image.pictrs_delete_token}/${firstImage.local_image.pictrs_alias}`;
expect(deleteUrl).toBe(upload.delete_url);
// Make sure the uploader is correct
expect(firstImage.person.actor_id).toBe(
`http://lemmy-alpha:8541/u/lemmy_alpha`,
);
// delete image
const delete_form: DeleteImage = {
token: upload.files![0].delete_token,
@ -230,7 +236,7 @@ test("No image proxying if setting is disabled", async () => {
);
expect(post.post_view.post).toBeDefined();
// remote image doesnt get proxied after upload
// remote image doesn't get proxied after upload
expect(
post.post_view.post.url?.startsWith("http://127.0.0.1:8551/pictrs/image/"),
).toBeTruthy();
@ -243,7 +249,7 @@ test("No image proxying if setting is disabled", async () => {
);
expect(betaPost.post).toBeDefined();
// remote image doesnt get proxied after federation
// remote image doesn't get proxied after federation
expect(
betaPost.post.url?.startsWith("http://127.0.0.1:8551/pictrs/image/"),
).toBeTruthy();
@ -264,10 +270,11 @@ test("Make regular post, and give it a custom thumbnail", async () => {
// Use wikipedia since it has an opengraph image
const wikipediaUrl = "https://wikipedia.org/";
let post = await createPost(
let post = await createPostWithThumbnail(
alphaImage,
community.community_view.community.id,
wikipediaUrl,
upload1.url!,
);
// Wait for the metadata to get fetched, since this is backgrounded now
@ -276,21 +283,11 @@ test("Make regular post, and give it a custom thumbnail", async () => {
p => p.post_view.post.thumbnail_url != undefined,
);
expect(post.post_view.post.url).toBe(wikipediaUrl);
expect(post.post_view.post.thumbnail_url).toBeDefined();
// Edit the thumbnail
await editPostThumbnail(alphaImage, post.post_view.post, upload1.url!);
post = await waitUntil(
() => getPost(alphaImage, post.post_view.post.id),
p => p.post_view.post.thumbnail_url == upload1.url,
);
// Make sure the thumbnail got edited.
// Make sure it uses custom thumbnail
expect(post.post_view.post.thumbnail_url).toBe(upload1.url);
});
test("Create an image post, and make sure a custom thumbnail doesnt overwrite it", async () => {
test("Create an image post, and make sure a custom thumbnail doesn't overwrite it", async () => {
const uploadForm1: UploadImage = {
image: Buffer.from("test1"),
};
@ -303,23 +300,17 @@ test("Create an image post, and make sure a custom thumbnail doesnt overwrite it
const community = await createCommunity(alphaImage);
let post = await createPost(
let post = await createPostWithThumbnail(
alphaImage,
community.community_view.community.id,
upload1.url,
upload1.url!,
upload2.url!,
);
expect(post.post_view.post.url).toBe(upload1.url);
// Edit the post
await editPostThumbnail(alphaImage, post.post_view.post, upload2.url!);
// Wait for the metadata to get fetched
post = await waitUntil(
() => getPost(alphaImage, post.post_view.post.id),
p => p.post_view.post.thumbnail_url == upload1.url,
p => p.post_view.post.thumbnail_url != undefined,
);
// Make sure the new custom thumbnail is ignored, and doesn't overwrite the image post
expect(post.post_view.post.url).toBe(upload1.url);
expect(post.post_view.post.thumbnail_url).toBe(upload1.url);
// Make sure the custom thumbnail is ignored
expect(post.post_view.post.thumbnail_url == upload2.url).toBe(false);
});

View file

@ -203,6 +203,7 @@ export async function createPost(
// use example.com for consistent title and embed description
name: string = randomString(5),
alt_text = randomString(10),
custom_thumbnail: string | undefined = undefined,
): Promise<PostResponse> {
let form: CreatePost = {
name,
@ -210,6 +211,7 @@ export async function createPost(
body,
alt_text,
community_id,
custom_thumbnail,
};
return api.createPost(form);
}
@ -226,16 +228,19 @@ export async function editPost(
return api.editPost(form);
}
export async function editPostThumbnail(
export async function createPostWithThumbnail(
api: LemmyHttp,
post: Post,
customThumbnail: string,
community_id: number,
url: string,
custom_thumbnail: string,
): Promise<PostResponse> {
let form: EditPost = {
post_id: post.id,
custom_thumbnail: customThumbnail,
let form: CreatePost = {
name: randomString(10),
url,
community_id,
custom_thumbnail,
};
return api.editPost(form);
return api.createPost(form);
}
export async function deletePost(
@ -887,8 +892,8 @@ export async function deleteAllImages(api: LemmyHttp) {
for (const image of imagesRes.images) {
const form: DeleteImage = {
token: image.pictrs_delete_token,
filename: image.pictrs_alias,
token: image.local_image.pictrs_delete_token,
filename: image.local_image.pictrs_alias,
};
await api.deleteImage(form);
}

View file

@ -49,7 +49,7 @@
cache_external_link_previews: true
# Specifies how to handle remote images, so that users don't have to connect directly to remote servers.
image_mode:
# Leave images unchanged, don't generate any local thumbnails for post urls. Instead the the
# Leave images unchanged, don't generate any local thumbnails for post urls. Instead the
# Opengraph image is directly returned as thumbnail
"None"

View file

@ -17,7 +17,9 @@ pub async fn distinguish_comment(
context: Data<LemmyContext>,
local_user_view: LocalUserView,
) -> LemmyResult<Json<CommentResponse>> {
let orig_comment = CommentView::read(&mut context.pool(), data.comment_id, None).await?;
let orig_comment = CommentView::read(&mut context.pool(), data.comment_id, None)
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?;
check_community_user_action(
&local_user_view.person,
@ -54,7 +56,8 @@ pub async fn distinguish_comment(
data.comment_id,
Some(local_user_view.person.id),
)
.await?;
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?;
Ok(Json(CommentResponse {
comment_view,

View file

@ -35,7 +35,9 @@ pub async fn like_comment(
check_bot_account(&local_user_view.person)?;
let comment_id = data.comment_id;
let orig_comment = CommentView::read(&mut context.pool(), comment_id, None).await?;
let orig_comment = CommentView::read(&mut context.pool(), comment_id, None)
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?;
check_community_user_action(
&local_user_view.person,
@ -46,9 +48,10 @@ pub async fn like_comment(
// Add parent poster or commenter to recipients
let comment_reply = CommentReply::read_by_comment(&mut context.pool(), comment_id).await;
if let Ok(reply) = comment_reply {
if let Ok(Some(reply)) = comment_reply {
let recipient_id = reply.recipient_id;
if let Ok(local_recipient) = LocalUserView::read_person(&mut context.pool(), recipient_id).await
if let Ok(Some(local_recipient)) =
LocalUserView::read_person(&mut context.pool(), recipient_id).await
{
recipient_ids.push(local_recipient.local_user.id);
}

View file

@ -5,7 +5,7 @@ use lemmy_api_common::{
utils::is_mod_or_admin,
};
use lemmy_db_views::structs::{CommentView, LocalUserView, VoteView};
use lemmy_utils::error::LemmyResult;
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
/// Lists likes for a comment
#[tracing::instrument(skip(context))]
@ -19,7 +19,9 @@ pub async fn list_comment_likes(
data.comment_id,
Some(local_user_view.person.id),
)
.await?;
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?;
is_mod_or_admin(
&mut context.pool(),
&local_user_view.person,

View file

@ -33,7 +33,9 @@ pub async fn save_comment(
let comment_id = data.comment_id;
let person_id = local_user_view.person.id;
let comment_view = CommentView::read(&mut context.pool(), comment_id, Some(person_id)).await?;
let comment_view = CommentView::read(&mut context.pool(), comment_id, Some(person_id))
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?;
Ok(Json(CommentResponse {
comment_view,

View file

@ -35,7 +35,9 @@ pub async fn create_comment_report(
let person_id = local_user_view.person.id;
let comment_id = data.comment_id;
let comment_view = CommentView::read(&mut context.pool(), comment_id, None).await?;
let comment_view = CommentView::read(&mut context.pool(), comment_id, None)
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?;
check_community_user_action(
&local_user_view.person,
@ -58,8 +60,9 @@ pub async fn create_comment_report(
.await
.with_lemmy_type(LemmyErrorType::CouldntCreateReport)?;
let comment_report_view =
CommentReportView::read(&mut context.pool(), report.id, person_id).await?;
let comment_report_view = CommentReportView::read(&mut context.pool(), report.id, person_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommentReport)?;
// Email the admins
if local_site.reports_email_admins {

View file

@ -17,7 +17,9 @@ pub async fn resolve_comment_report(
) -> LemmyResult<Json<CommentReportResponse>> {
let report_id = data.report_id;
let person_id = local_user_view.person.id;
let report = CommentReportView::read(&mut context.pool(), report_id, person_id).await?;
let report = CommentReportView::read(&mut context.pool(), report_id, person_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommentReport)?;
let person_id = local_user_view.person.id;
check_community_mod_action(
@ -39,8 +41,9 @@ pub async fn resolve_comment_report(
}
let report_id = data.report_id;
let comment_report_view =
CommentReportView::read(&mut context.pool(), report_id, person_id).await?;
let comment_report_view = CommentReportView::read(&mut context.pool(), report_id, person_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommentReport)?;
Ok(Json(CommentReportResponse {
comment_report_view,

View file

@ -33,9 +33,23 @@ pub async fn add_mod_to_community(
&mut context.pool(),
)
.await?;
let community = Community::read(&mut context.pool(), community_id).await?;
let community = Community::read(&mut context.pool(), community_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
// If user is admin and community is remote, explicitly check that he is a
// moderator. This is necessary because otherwise the action would be rejected
// by the community's home instance.
if local_user_view.local_user.admin && !community.local {
Err(LemmyErrorType::NotAModerator)?
let is_mod = CommunityModeratorView::is_community_moderator(
&mut context.pool(),
community.id,
local_user_view.person.id,
)
.await?;
if !is_mod {
Err(LemmyErrorType::NotAModerator)?
}
}
// Update in local database

View file

@ -89,7 +89,9 @@ pub async fn ban_from_community(
ModBanFromCommunity::create(&mut context.pool(), &form).await?;
let person_view = PersonView::read(&mut context.pool(), data.person_id).await?;
let person_view = PersonView::read(&mut context.pool(), data.person_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPerson)?;
ActivityChannel::submit_activity(
SendActivityData::BanFromCommunity {

View file

@ -51,7 +51,9 @@ pub async fn block_community(
}
let community_view =
CommunityView::read(&mut context.pool(), community_id, Some(person_id), false).await?;
CommunityView::read(&mut context.pool(), community_id, Some(person_id), false)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
ActivityChannel::submit_activity(
SendActivityData::FollowCommunity(

View file

@ -23,7 +23,9 @@ pub async fn follow_community(
context: Data<LemmyContext>,
local_user_view: LocalUserView,
) -> LemmyResult<Json<CommunityResponse>> {
let community = Community::read(&mut context.pool(), data.community_id).await?;
let community = Community::read(&mut context.pool(), data.community_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
let mut community_follower_form = CommunityFollowerForm {
community_id: community.id,
person_id: local_user_view.person.id,
@ -62,7 +64,10 @@ pub async fn follow_community(
let community_id = data.community_id;
let person_id = local_user_view.person.id;
let community_view =
CommunityView::read(&mut context.pool(), community_id, Some(person_id), false).await?;
CommunityView::read(&mut context.pool(), community_id, Some(person_id), false)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
let discussion_languages = CommunityLanguage::read(&mut context.pool(), community_id).await?;
Ok(Json(CommunityResponse {

View file

@ -79,8 +79,8 @@ pub async fn transfer_community(
let person_id = local_user_view.person.id;
let community_view =
CommunityView::read(&mut context.pool(), community_id, Some(person_id), false)
.await
.with_lemmy_type(LemmyErrorType::CouldntFindCommunity)?;
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
let community_id = data.community_id;
let moderators = CommunityModeratorView::for_community(&mut context.pool(), community_id)

View file

@ -252,7 +252,9 @@ pub async fn local_user_view_from_jwt(
let local_user_id = Claims::validate(jwt, context)
.await
.with_lemmy_type(LemmyErrorType::NotLoggedIn)?;
let local_user_view = LocalUserView::read(&mut context.pool(), local_user_id).await?;
let local_user_view = LocalUserView::read(&mut context.pool(), local_user_id)
.await?
.ok_or(LemmyErrorType::CouldntFindLocalUser)?;
check_user_valid(&local_user_view.person)?;
Ok(local_user_view)

View file

@ -26,8 +26,8 @@ pub async fn add_admin(
// Make sure that the person_id added is local
let added_local_user = LocalUserView::read_person(&mut context.pool(), data.person_id)
.await
.with_lemmy_type(LemmyErrorType::ObjectNotLocal)?;
.await?
.ok_or(LemmyErrorType::ObjectNotLocal)?;
let added_admin = LocalUser::update(
&mut context.pool(),

View file

@ -49,7 +49,7 @@ pub async fn ban_from_site(
// if its a local user, invalidate logins
let local_user = LocalUserView::read_person(&mut context.pool(), person.id).await;
if let Ok(local_user) = local_user {
if let Ok(Some(local_user)) = local_user {
LoginToken::invalidate_all(&mut context.pool(), local_user.local_user.id).await?;
}
@ -70,7 +70,9 @@ pub async fn ban_from_site(
ModBan::create(&mut context.pool(), &form).await?;
let person_view = PersonView::read(&mut context.pool(), person.id).await?;
let person_view = PersonView::read(&mut context.pool(), person.id)
.await?
.ok_or(LemmyErrorType::CouldntFindPerson)?;
ban_nonlocal_user_from_local_communities(
&local_user_view,

View file

@ -30,8 +30,12 @@ pub async fn block_person(
target_id,
};
let target_user = LocalUserView::read_person(&mut context.pool(), target_id).await;
if target_user.map(|t| t.local_user.admin) == Ok(true) {
let target_user = LocalUserView::read_person(&mut context.pool(), target_id)
.await
.ok()
.flatten();
if target_user.is_some_and(|t| t.local_user.admin) {
Err(LemmyErrorType::CantBlockAdmin)?
}
@ -45,7 +49,9 @@ pub async fn block_person(
.with_lemmy_type(LemmyErrorType::PersonBlockAlreadyExists)?;
}
let person_view = PersonView::read(&mut context.pool(), target_id).await?;
let person_view = PersonView::read(&mut context.pool(), target_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPerson)?;
Ok(Json(BlockPersonResponse {
person_view,
blocked: data.block,

View file

@ -20,8 +20,9 @@ pub async fn change_password_after_reset(
// Fetch the user_id from the token
let token = data.token.clone();
let local_user_id = PasswordResetRequest::read_from_token(&mut context.pool(), &token)
.await
.map(|p| p.local_user_id)?;
.await?
.ok_or(LemmyErrorType::TokenNotFound)?
.local_user_id;
password_length_check(&data.password)?;

View file

@ -17,7 +17,9 @@ pub async fn generate_totp_secret(
local_user_view: LocalUserView,
context: Data<LemmyContext>,
) -> LemmyResult<Json<GenerateTotpSecretResponse>> {
let site_view = SiteView::read_local(&mut context.pool()).await?;
let site_view = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
if local_user_view.local_user.totp_2fa_enabled {
return Err(LemmyErrorType::TotpAlreadyEnabled)?;

View file

@ -3,8 +3,7 @@ use lemmy_api_common::{
context::LemmyContext,
person::{ListMedia, ListMediaResponse},
};
use lemmy_db_schema::source::images::LocalImage;
use lemmy_db_views::structs::LocalUserView;
use lemmy_db_views::structs::{LocalImageView, LocalUserView};
use lemmy_utils::error::LemmyResult;
#[tracing::instrument(skip(context))]
@ -15,7 +14,7 @@ pub async fn list_media(
) -> LemmyResult<Json<ListMediaResponse>> {
let page = data.page;
let limit = data.limit;
let images = LocalImage::get_all_paged_by_local_user_id(
let images = LocalImageView::get_all_paged_by_local_user_id(
&mut context.pool(),
local_user_view.local_user.id,
page,

View file

@ -16,7 +16,7 @@ use lemmy_db_schema::{
RegistrationMode,
};
use lemmy_db_views::structs::{LocalUserView, SiteView};
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult};
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
#[tracing::instrument(skip(context))]
pub async fn login(
@ -24,14 +24,16 @@ pub async fn login(
req: HttpRequest,
context: Data<LemmyContext>,
) -> LemmyResult<Json<LoginResponse>> {
let site_view = SiteView::read_local(&mut context.pool()).await?;
let site_view = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
// Fetch that username / email
let username_or_email = data.username_or_email.clone();
let local_user_view =
LocalUserView::find_by_email_or_name(&mut context.pool(), &username_or_email)
.await
.with_lemmy_type(LemmyErrorType::IncorrectLogin)?;
.await?
.ok_or(LemmyErrorType::IncorrectLogin)?;
// Verify the password
let valid: bool = verify(
@ -79,7 +81,9 @@ async fn check_registration_application(
// Fetch the registration application. If no admin id is present its still pending. Otherwise it
// was processed (either accepted or denied).
let local_user_id = local_user_view.local_user.id;
let registration = RegistrationApplication::find_by_local_user_id(pool, local_user_id).await?;
let registration = RegistrationApplication::find_by_local_user_id(pool, local_user_id)
.await?
.ok_or(LemmyErrorType::CouldntFindRegistrationApplication)?;
if registration.admin_id.is_some() {
Err(LemmyErrorType::RegistrationDenied(registration.deny_reason))?
} else {

View file

@ -18,7 +18,9 @@ pub async fn mark_person_mention_as_read(
local_user_view: LocalUserView,
) -> LemmyResult<Json<PersonMentionResponse>> {
let person_mention_id = data.person_mention_id;
let read_person_mention = PersonMention::read(&mut context.pool(), person_mention_id).await?;
let read_person_mention = PersonMention::read(&mut context.pool(), person_mention_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPersonMention)?;
if local_user_view.person.id != read_person_mention.recipient_id {
Err(LemmyErrorType::CouldntUpdateComment)?
@ -37,7 +39,9 @@ pub async fn mark_person_mention_as_read(
let person_mention_id = read_person_mention.id;
let person_id = local_user_view.person.id;
let person_mention_view =
PersonMentionView::read(&mut context.pool(), person_mention_id, Some(person_id)).await?;
PersonMentionView::read(&mut context.pool(), person_mention_id, Some(person_id))
.await?
.ok_or(LemmyErrorType::CouldntFindPersonMention)?;
Ok(Json(PersonMentionResponse {
person_mention_view,

View file

@ -18,7 +18,9 @@ pub async fn mark_reply_as_read(
local_user_view: LocalUserView,
) -> LemmyResult<Json<CommentReplyResponse>> {
let comment_reply_id = data.comment_reply_id;
let read_comment_reply = CommentReply::read(&mut context.pool(), comment_reply_id).await?;
let read_comment_reply = CommentReply::read(&mut context.pool(), comment_reply_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommentReply)?;
if local_user_view.person.id != read_comment_reply.recipient_id {
Err(LemmyErrorType::CouldntUpdateComment)?
@ -38,7 +40,9 @@ pub async fn mark_reply_as_read(
let comment_reply_id = read_comment_reply.id;
let person_id = local_user_view.person.id;
let comment_reply_view =
CommentReplyView::read(&mut context.pool(), comment_reply_id, Some(person_id)).await?;
CommentReplyView::read(&mut context.pool(), comment_reply_id, Some(person_id))
.await?
.ok_or(LemmyErrorType::CouldntFindCommentReply)?;
Ok(Json(CommentReplyResponse { comment_reply_view }))
}

View file

@ -8,7 +8,7 @@ use lemmy_api_common::{
};
use lemmy_db_schema::source::password_reset_request::PasswordResetRequest;
use lemmy_db_views::structs::{LocalUserView, SiteView};
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult};
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
#[tracing::instrument(skip(context))]
pub async fn reset_password(
@ -18,8 +18,8 @@ pub async fn reset_password(
// Fetch that email
let email = data.email.to_lowercase();
let local_user_view = LocalUserView::find_by_email(&mut context.pool(), &email)
.await
.with_lemmy_type(LemmyErrorType::IncorrectLogin)?;
.await?
.ok_or(LemmyErrorType::IncorrectLogin)?;
// Check for too many attempts (to limit potential abuse)
let recent_resets_count = PasswordResetRequest::get_recent_password_resets_count(
@ -30,7 +30,9 @@ pub async fn reset_password(
if recent_resets_count >= 3 {
Err(LemmyErrorType::PasswordResetLimitReached)?
}
let site_view = SiteView::read_local(&mut context.pool()).await?;
let site_view = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
check_email_verified(&local_user_view, &site_view)?;
// Email the pure token to the user.

View file

@ -35,7 +35,9 @@ pub async fn save_user_settings(
context: Data<LemmyContext>,
local_user_view: LocalUserView,
) -> LemmyResult<Json<SuccessResponse>> {
let site_view = SiteView::read_local(&mut context.pool()).await?;
let site_view = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
let slur_regex = local_site_to_slur_regex(&site_view.local_site);
let url_blocklist = get_url_blocklist(&context).await?;

View file

@ -15,17 +15,19 @@ use lemmy_db_schema::{
RegistrationMode,
};
use lemmy_db_views::structs::SiteView;
use lemmy_utils::error::{LemmyErrorExt, LemmyErrorType, LemmyResult};
use lemmy_utils::error::{LemmyErrorType, LemmyResult};
pub async fn verify_email(
data: Json<VerifyEmail>,
context: Data<LemmyContext>,
) -> LemmyResult<Json<SuccessResponse>> {
let site_view = SiteView::read_local(&mut context.pool()).await?;
let site_view = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
let token = data.token.clone();
let verification = EmailVerification::read_for_token(&mut context.pool(), &token)
.await
.with_lemmy_type(LemmyErrorType::TokenNotFound)?;
.await?
.ok_or(LemmyErrorType::TokenNotFound)?;
let form = LocalUserUpdateForm {
// necessary in case this is a new signup
@ -44,7 +46,10 @@ pub async fn verify_email(
if site_view.local_site.registration_mode == RegistrationMode::RequireApplication
&& site_view.local_site.application_email_admins
{
let person = Person::read(&mut context.pool(), local_user.person_id).await?;
let person = Person::read(&mut context.pool(), local_user.person_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPerson)?;
send_new_applicant_email_to_admins(&person.name, &mut context.pool(), context.settings())
.await?;
}

View file

@ -16,7 +16,7 @@ use lemmy_db_schema::{
PostFeatureType,
};
use lemmy_db_views::structs::LocalUserView;
use lemmy_utils::error::LemmyResult;
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
#[tracing::instrument(skip(context))]
pub async fn feature_post(
@ -25,7 +25,9 @@ pub async fn feature_post(
local_user_view: LocalUserView,
) -> LemmyResult<Json<PostResponse>> {
let post_id = data.post_id;
let orig_post = Post::read(&mut context.pool(), post_id).await?;
let orig_post = Post::read(&mut context.pool(), post_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?;
check_community_mod_action(
&local_user_view.person,

View file

@ -11,7 +11,7 @@ pub async fn get_link_metadata(
data: Query<GetSiteMetadata>,
context: Data<LemmyContext>,
) -> LemmyResult<Json<GetSiteMetadataResponse>> {
let metadata = fetch_link_metadata(&data.url, false, &context).await?;
let metadata = fetch_link_metadata(&data.url, &context).await?;
Ok(Json(GetSiteMetadataResponse { metadata }))
}

View file

@ -38,7 +38,9 @@ pub async fn like_post(
// Check for a community ban
let post_id = data.post_id;
let post = Post::read(&mut context.pool(), post_id).await?;
let post = Post::read(&mut context.pool(), post_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?;
check_community_user_action(
&local_user_view.person,
@ -69,11 +71,15 @@ pub async fn like_post(
// Mark the post as read
mark_post_as_read(person_id, post_id, &mut context.pool()).await?;
let community = Community::read(&mut context.pool(), post.community_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
ActivityChannel::submit_activity(
SendActivityData::LikePostOrComment {
object_id: post.ap_id,
actor: local_user_view.person.clone(),
community: Community::read(&mut context.pool(), post.community_id).await?,
community,
score: data.score,
},
&context,

View file

@ -6,7 +6,7 @@ use lemmy_api_common::{
};
use lemmy_db_schema::{source::post::Post, traits::Crud};
use lemmy_db_views::structs::{LocalUserView, VoteView};
use lemmy_utils::error::LemmyResult;
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
/// Lists likes for a post
#[tracing::instrument(skip(context))]
@ -15,7 +15,9 @@ pub async fn list_post_likes(
context: Data<LemmyContext>,
local_user_view: LocalUserView,
) -> LemmyResult<Json<ListPostLikesResponse>> {
let post = Post::read(&mut context.pool(), data.post_id).await?;
let post = Post::read(&mut context.pool(), data.post_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?;
is_mod_or_admin(
&mut context.pool(),
&local_user_view.person,

View file

@ -15,7 +15,7 @@ use lemmy_db_schema::{
traits::Crud,
};
use lemmy_db_views::structs::LocalUserView;
use lemmy_utils::error::LemmyResult;
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
#[tracing::instrument(skip(context))]
pub async fn lock_post(
@ -24,7 +24,9 @@ pub async fn lock_post(
local_user_view: LocalUserView,
) -> LemmyResult<Json<PostResponse>> {
let post_id = data.post_id;
let orig_post = Post::read(&mut context.pool(), post_id).await?;
let orig_post = Post::read(&mut context.pool(), post_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?;
check_community_mod_action(
&local_user_view.person,

View file

@ -34,7 +34,9 @@ pub async fn save_post(
let post_id = data.post_id;
let person_id = local_user_view.person.id;
let post_view = PostView::read(&mut context.pool(), post_id, Some(person_id), false).await?;
let post_view = PostView::read(&mut context.pool(), post_id, Some(person_id), false)
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?;
// Mark the post as read
mark_post_as_read(person_id, post_id, &mut context.pool()).await?;

View file

@ -35,7 +35,9 @@ pub async fn create_post_report(
let person_id = local_user_view.person.id;
let post_id = data.post_id;
let post_view = PostView::read(&mut context.pool(), post_id, None, false).await?;
let post_view = PostView::read(&mut context.pool(), post_id, None, false)
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?;
check_community_user_action(
&local_user_view.person,
@ -59,7 +61,9 @@ pub async fn create_post_report(
.await
.with_lemmy_type(LemmyErrorType::CouldntCreateReport)?;
let post_report_view = PostReportView::read(&mut context.pool(), report.id, person_id).await?;
let post_report_view = PostReportView::read(&mut context.pool(), report.id, person_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPostReport)?;
// Email the admins
if local_site.reports_email_admins {

View file

@ -17,7 +17,9 @@ pub async fn resolve_post_report(
) -> LemmyResult<Json<PostReportResponse>> {
let report_id = data.report_id;
let person_id = local_user_view.person.id;
let report = PostReportView::read(&mut context.pool(), report_id, person_id).await?;
let report = PostReportView::read(&mut context.pool(), report_id, person_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPostReport)?;
let person_id = local_user_view.person.id;
check_community_mod_action(
@ -38,7 +40,9 @@ pub async fn resolve_post_report(
.with_lemmy_type(LemmyErrorType::CouldntResolveReport)?;
}
let post_report_view = PostReportView::read(&mut context.pool(), report_id, person_id).await?;
let post_report_view = PostReportView::read(&mut context.pool(), report_id, person_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPostReport)?;
Ok(Json(PostReportResponse { post_report_view }))
}

View file

@ -18,7 +18,9 @@ pub async fn mark_pm_as_read(
) -> LemmyResult<Json<PrivateMessageResponse>> {
// Checking permissions
let private_message_id = data.private_message_id;
let orig_private_message = PrivateMessage::read(&mut context.pool(), private_message_id).await?;
let orig_private_message = PrivateMessage::read(&mut context.pool(), private_message_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPrivateMessage)?;
if local_user_view.person.id != orig_private_message.recipient_id {
Err(LemmyErrorType::CouldntUpdatePrivateMessage)?
}
@ -37,7 +39,9 @@ pub async fn mark_pm_as_read(
.await
.with_lemmy_type(LemmyErrorType::CouldntUpdatePrivateMessage)?;
let view = PrivateMessageView::read(&mut context.pool(), private_message_id).await?;
let view = PrivateMessageView::read(&mut context.pool(), private_message_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPrivateMessage)?;
Ok(Json(PrivateMessageResponse {
private_message_view: view,
}))

View file

@ -29,7 +29,9 @@ pub async fn create_pm_report(
let person_id = local_user_view.person.id;
let private_message_id = data.private_message_id;
let private_message = PrivateMessage::read(&mut context.pool(), private_message_id).await?;
let private_message = PrivateMessage::read(&mut context.pool(), private_message_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPrivateMessage)?;
// Make sure that only the recipient of the private message can create a report
if person_id != private_message.recipient_id {
@ -47,8 +49,9 @@ pub async fn create_pm_report(
.await
.with_lemmy_type(LemmyErrorType::CouldntCreateReport)?;
let private_message_report_view =
PrivateMessageReportView::read(&mut context.pool(), report.id).await?;
let private_message_report_view = PrivateMessageReportView::read(&mut context.pool(), report.id)
.await?
.ok_or(LemmyErrorType::CouldntFindPrivateMessageReport)?;
// Email the admins
if local_site.reports_email_admins {

View file

@ -28,8 +28,9 @@ pub async fn resolve_pm_report(
.with_lemmy_type(LemmyErrorType::CouldntResolveReport)?;
}
let private_message_report_view =
PrivateMessageReportView::read(&mut context.pool(), report_id).await?;
let private_message_report_view = PrivateMessageReportView::read(&mut context.pool(), report_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPrivateMessageReport)?;
Ok(Json(PrivateMessageReportResponse {
private_message_report_view,

View file

@ -5,13 +5,15 @@ use lemmy_api_common::{
utils::build_federated_instances,
};
use lemmy_db_views::structs::SiteView;
use lemmy_utils::error::LemmyResult;
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
#[tracing::instrument(skip(context))]
pub async fn get_federated_instances(
context: Data<LemmyContext>,
) -> LemmyResult<Json<GetFederatedInstancesResponse>> {
let site_view = SiteView::read_local(&mut context.pool()).await?;
let site_view = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
let federated_instances =
build_federated_instances(&site_view.local_site, &mut context.pool()).await?;

View file

@ -55,7 +55,9 @@ pub async fn leave_admin(
ModAdd::create(&mut context.pool(), &form).await?;
// Reread site and admins
let site_view = SiteView::read_local(&mut context.pool()).await?;
let site_view = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
let admins = PersonView::admins(&mut context.pool()).await?;
let all_languages = Language::read_all(&mut context.pool()).await?;

View file

@ -4,8 +4,7 @@ use lemmy_api_common::{
person::{ListMedia, ListMediaResponse},
utils::is_admin,
};
use lemmy_db_schema::source::images::LocalImage;
use lemmy_db_views::structs::LocalUserView;
use lemmy_db_views::structs::{LocalImageView, LocalUserView};
use lemmy_utils::error::LemmyResult;
#[tracing::instrument(skip(context))]
@ -19,6 +18,6 @@ pub async fn list_all_media(
let page = data.page;
let limit = data.limit;
let images = LocalImage::get_all(&mut context.pool(), page, limit).await?;
let images = LocalImageView::get_all(&mut context.pool(), page, limit).await?;
Ok(Json(ListMediaResponse { images }))
}

View file

@ -15,7 +15,7 @@ use lemmy_db_schema::{
traits::Crud,
};
use lemmy_db_views::structs::{CommentView, LocalUserView};
use lemmy_utils::error::LemmyResult;
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
#[tracing::instrument(skip(context))]
pub async fn purge_comment(
@ -29,7 +29,9 @@ pub async fn purge_comment(
let comment_id = data.comment_id;
// Read the comment to get the post_id and community
let comment_view = CommentView::read(&mut context.pool(), comment_id, None).await?;
let comment_view = CommentView::read(&mut context.pool(), comment_id, None)
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?;
let post_id = comment_view.comment.post_id;

View file

@ -16,7 +16,7 @@ use lemmy_db_schema::{
traits::Crud,
};
use lemmy_db_views::structs::LocalUserView;
use lemmy_utils::error::LemmyResult;
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
#[tracing::instrument(skip(context))]
pub async fn purge_community(
@ -28,7 +28,9 @@ pub async fn purge_community(
is_admin(&local_user_view)?;
// Read the community to get its images
let community = Community::read(&mut context.pool(), data.community_id).await?;
let community = Community::read(&mut context.pool(), data.community_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
if let Some(banner) = &community.banner {
purge_image_from_pictrs(banner, &context).await.ok();

View file

@ -16,7 +16,7 @@ use lemmy_db_schema::{
traits::Crud,
};
use lemmy_db_views::structs::LocalUserView;
use lemmy_utils::error::LemmyResult;
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
#[tracing::instrument(skip(context))]
pub async fn purge_person(
@ -27,7 +27,9 @@ pub async fn purge_person(
// Only let admin purge an item
is_admin(&local_user_view)?;
let person = Person::read(&mut context.pool(), data.person_id).await?;
let person = Person::read(&mut context.pool(), data.person_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPerson)?;
ban_nonlocal_user_from_local_communities(
&local_user_view,
&person,

View file

@ -16,7 +16,7 @@ use lemmy_db_schema::{
traits::Crud,
};
use lemmy_db_views::structs::LocalUserView;
use lemmy_utils::error::LemmyResult;
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
#[tracing::instrument(skip(context))]
pub async fn purge_post(
@ -28,7 +28,9 @@ pub async fn purge_post(
is_admin(&local_user_view)?;
// Read the post to get the community_id
let post = Post::read(&mut context.pool(), data.post_id).await?;
let post = Post::read(&mut context.pool(), data.post_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?;
// Purge image
if let Some(url) = &post.url {

View file

@ -13,7 +13,7 @@ use lemmy_db_schema::{
utils::diesel_option_overwrite,
};
use lemmy_db_views::structs::{LocalUserView, RegistrationApplicationView};
use lemmy_utils::error::LemmyResult;
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
pub async fn approve_registration_application(
data: Json<ApproveRegistrationApplication>,
@ -45,8 +45,9 @@ pub async fn approve_registration_application(
LocalUser::update(&mut context.pool(), approved_user_id, &local_user_form).await?;
if data.approve {
let approved_local_user_view =
LocalUserView::read(&mut context.pool(), approved_user_id).await?;
let approved_local_user_view = LocalUserView::read(&mut context.pool(), approved_user_id)
.await?
.ok_or(LemmyErrorType::CouldntFindLocalUser)?;
if approved_local_user_view.local_user.email.is_some() {
send_application_approved_email(&approved_local_user_view, context.settings()).await?;
@ -54,8 +55,9 @@ pub async fn approve_registration_application(
}
// Read the view
let registration_application =
RegistrationApplicationView::read(&mut context.pool(), app_id).await?;
let registration_application = RegistrationApplicationView::read(&mut context.pool(), app_id)
.await?
.ok_or(LemmyErrorType::CouldntFindRegistrationApplication)?;
Ok(Json(RegistrationApplicationResponse {
registration_application,

View file

@ -72,7 +72,7 @@ webpage = { version = "1.6", default-features = false, features = [
encoding = { version = "0.2.33", optional = true }
jsonwebtoken = { version = "8.3.0", optional = true }
# necessary for wasmt compilation
getrandom = { version = "0.2.12", features = ["js"] }
getrandom = { version = "0.2.14", features = ["js"] }
[package.metadata.cargo-machete]
ignored = ["getrandom"]

View file

@ -27,6 +27,7 @@ use lemmy_db_views_actor::structs::CommunityView;
use lemmy_utils::{
error::LemmyResult,
utils::{markdown::markdown_to_html, mention::MentionData},
LemmyErrorType,
};
pub async fn build_comment_response(
@ -36,7 +37,9 @@ pub async fn build_comment_response(
recipient_ids: Vec<LocalUserId>,
) -> LemmyResult<CommentResponse> {
let person_id = local_user_view.map(|l| l.person.id);
let comment_view = CommentView::read(&mut context.pool(), comment_id, person_id).await?;
let comment_view = CommentView::read(&mut context.pool(), comment_id, person_id)
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?;
Ok(CommentResponse {
comment_view,
recipient_ids,
@ -58,7 +61,8 @@ pub async fn build_community_response(
Some(person_id),
is_mod_or_admin,
)
.await?;
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
let discussion_languages = CommunityLanguage::read(&mut context.pool(), community_id).await?;
Ok(Json(CommunityResponse {
@ -82,7 +86,8 @@ pub async fn build_post_response(
Some(person.id),
is_mod_or_admin,
)
.await?;
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?;
Ok(Json(PostResponse { post_view }))
}
@ -99,7 +104,9 @@ pub async fn send_local_notifs(
let inbox_link = format!("{}/inbox", context.settings().get_protocol_and_hostname());
// Read the comment view to get extra info
let comment_view = CommentView::read(&mut context.pool(), comment_id, None).await?;
let comment_view = CommentView::read(&mut context.pool(), comment_id, None)
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?;
let comment = comment_view.comment;
let post = comment_view.post;
let community = comment_view.community;
@ -111,7 +118,7 @@ pub async fn send_local_notifs(
{
let mention_name = mention.name.clone();
let user_view = LocalUserView::read_from_name(&mut context.pool(), &mention_name).await;
if let Ok(mention_user_view) = user_view {
if let Ok(Some(mention_user_view)) = user_view {
// TODO
// At some point, make it so you can't tag the parent creator either
// Potential duplication of notifications, one for reply and the other for mention, is handled below by checking recipient ids
@ -146,7 +153,9 @@ pub async fn send_local_notifs(
// Send comment_reply to the parent commenter / poster
if let Some(parent_comment_id) = comment.parent_comment_id() {
let parent_comment = Comment::read(&mut context.pool(), parent_comment_id).await?;
let parent_comment = Comment::read(&mut context.pool(), parent_comment_id)
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?;
// Get the parent commenter local_user
let parent_creator_id = parent_comment.creator_id;
@ -165,7 +174,7 @@ pub async fn send_local_notifs(
// Don't send a notif to yourself
if parent_comment.creator_id != person.id && !check_blocks {
let user_view = LocalUserView::read_person(&mut context.pool(), parent_creator_id).await;
if let Ok(parent_user_view) = user_view {
if let Ok(Some(parent_user_view)) = user_view {
// Don't duplicate notif if already mentioned by checking recipient ids
if !recipient_ids.contains(&parent_user_view.local_user.id) {
recipient_ids.push(parent_user_view.local_user.id);
@ -212,7 +221,7 @@ pub async fn send_local_notifs(
if post.creator_id != person.id && !check_blocks {
let creator_id = post.creator_id;
let parent_user = LocalUserView::read_person(&mut context.pool(), creator_id).await;
if let Ok(parent_user_view) = parent_user {
if let Ok(Some(parent_user_view)) = parent_user {
if !recipient_ids.contains(&parent_user_view.local_user.id) {
recipient_ids.push(parent_user_view.local_user.id);

View file

@ -99,7 +99,7 @@ mod tests {
async fn test_should_not_validate_user_token_after_password_change() {
let pool_ = build_db_pool_for_tests().await;
let pool = &mut (&pool_).into();
let secret = Secret::init(pool).await.unwrap();
let secret = Secret::init(pool).await.unwrap().unwrap();
let context = LemmyContext::create(
pool_.clone(),
ClientBuilder::new(Client::default()).build(),

View file

@ -1,13 +1,13 @@
use crate::sensitive::Sensitive;
use lemmy_db_schema::{
newtypes::{CommentReplyId, CommunityId, LanguageId, PersonId, PersonMentionId},
source::{images::LocalImage, site::Site},
source::site::Site,
CommentSortType,
ListingType,
PostListingMode,
SortType,
};
use lemmy_db_views::structs::{CommentView, PostView};
use lemmy_db_views::structs::{CommentView, LocalImageView, PostView};
use lemmy_db_views_actor::structs::{
CommentReplyView,
CommunityModeratorView,
@ -437,5 +437,5 @@ pub struct ListMedia {
#[cfg_attr(feature = "full", derive(TS))]
#[cfg_attr(feature = "full", ts(export))]
pub struct ListMediaResponse {
pub images: Vec<LocalImage>,
pub images: Vec<LocalImageView>,
}

View file

@ -270,8 +270,6 @@ pub struct LinkMetadata {
#[serde(flatten)]
pub opengraph_data: OpenGraphData,
pub content_type: Option<String>,
#[serde(skip)]
pub thumbnail: Option<DbUrl>,
}
#[skip_serializing_none]

View file

@ -42,11 +42,7 @@ pub fn client_builder(settings: &Settings) -> ClientBuilder {
/// Fetches metadata for the given link and optionally generates thumbnail.
#[tracing::instrument(skip_all)]
pub async fn fetch_link_metadata(
url: &Url,
generate_thumbnail: bool,
context: &LemmyContext,
) -> LemmyResult<LinkMetadata> {
pub async fn fetch_link_metadata(url: &Url, context: &LemmyContext) -> LemmyResult<LinkMetadata> {
info!("Fetching site metadata for url: {}", url);
let response = context.client().get(url.as_str()).send().await?;
@ -63,71 +59,65 @@ pub async fn fetch_link_metadata(
let opengraph_data = extract_opengraph_data(&html_bytes, url)
.map_err(|e| info!("{e}"))
.unwrap_or_default();
let thumbnail =
extract_thumbnail_from_opengraph_data(url, &opengraph_data, generate_thumbnail, context).await;
Ok(LinkMetadata {
opengraph_data,
content_type: content_type.map(|c| c.to_string()),
thumbnail,
})
}
#[tracing::instrument(skip_all)]
pub async fn fetch_link_metadata_opt(
url: Option<&Url>,
generate_thumbnail: bool,
context: &LemmyContext,
) -> LinkMetadata {
match &url {
Some(url) => fetch_link_metadata(url, generate_thumbnail, context)
.await
.unwrap_or_default(),
_ => Default::default(),
}
}
/// Generate post thumbnail in background task, because some sites can be very slow to respond.
///
/// Takes a callback to generate a send activity task, so that post can be federated with metadata.
///
/// TODO: `federated_thumbnail` param can be removed once we federate full metadata and can
/// write it to db directly, without calling this function.
/// https://github.com/LemmyNet/lemmy/issues/4598
pub fn generate_post_link_metadata(
post: Post,
custom_thumbnail: Option<Url>,
federated_thumbnail: Option<Url>,
send_activity: impl FnOnce(Post) -> Option<SendActivityData> + Send + 'static,
local_site: Option<LocalSite>,
context: Data<LemmyContext>,
) {
spawn_try_task(async move {
// Decide if the thumbnail should be generated
let allow_sensitive = local_site_opt_to_sensitive(&local_site);
let page_is_sensitive = post.nsfw;
let allow_generate_thumbnail = allow_sensitive || !page_is_sensitive;
let do_generate_thumbnail =
allow_generate_thumbnail && custom_thumbnail.is_none() && post.thumbnail_url.is_none();
// Generate local thumbnail only if no thumbnail was federated and 'sensitive' attributes allow it.
let metadata = fetch_link_metadata_opt(
post.url.as_ref().map(DbUrl::inner),
do_generate_thumbnail,
&context,
)
.await;
// If its an image post, it needs to overwrite the thumbnail, and take precedence
let image_url = if metadata
.content_type
.as_ref()
.is_some_and(|content_type| content_type.starts_with("image"))
{
post.url.map(Into::into)
} else {
None
let metadata = match &post.url {
Some(url) => fetch_link_metadata(url, &context).await.unwrap_or_default(),
_ => Default::default(),
};
// Build the thumbnail url based on either the post image url, custom thumbnail, metadata fetch, or existing thumbnail.
let thumbnail_url = image_url
.or(custom_thumbnail)
.or(metadata.thumbnail.map(Into::into))
.or(post.thumbnail_url.map(Into::into));
let is_image_post = metadata
.content_type
.as_ref()
.is_some_and(|content_type| content_type.starts_with("image"));
// Decide if we are allowed to generate local thumbnail
let allow_sensitive = local_site_opt_to_sensitive(&local_site);
let allow_generate_thumbnail = allow_sensitive || !post.nsfw;
// Use custom thumbnail if available and its not an image post
let thumbnail_url = if !is_image_post && custom_thumbnail.is_some() {
custom_thumbnail
}
// Use federated thumbnail if available
else if federated_thumbnail.is_some() {
federated_thumbnail
}
// Generate local thumbnail if allowed
else if allow_generate_thumbnail {
match post
.url
.filter(|_| is_image_post)
.or(metadata.opengraph_data.image)
{
Some(url) => generate_pictrs_thumbnail(&url, &context).await.ok(),
None => None,
}
}
// Otherwise use opengraph preview image directly
else {
metadata.opengraph_data.image.map(Into::into)
};
// Proxy the image fetch if necessary
let proxied_thumbnail_url = proxy_image_link_opt_apub(thumbnail_url, &context).await?;
@ -213,28 +203,6 @@ fn extract_opengraph_data(html_bytes: &[u8], url: &Url) -> LemmyResult<OpenGraph
})
}
#[tracing::instrument(skip_all)]
pub async fn extract_thumbnail_from_opengraph_data(
url: &Url,
opengraph_data: &OpenGraphData,
generate_thumbnail: bool,
context: &LemmyContext,
) -> Option<DbUrl> {
if generate_thumbnail {
let image_url = opengraph_data
.image
.as_ref()
.map(DbUrl::inner)
.unwrap_or(url);
generate_pictrs_thumbnail(image_url, context)
.await
.ok()
.map(Into::into)
} else {
opengraph_data.image.clone()
}
}
#[derive(Deserialize, Debug)]
struct PictrsResponse {
files: Vec<PictrsFile>,
@ -414,9 +382,7 @@ mod tests {
async fn test_link_metadata() {
let context = LemmyContext::init_test_context().await;
let sample_url = Url::parse("https://gitlab.com/IzzyOnDroid/repo/-/wikis/FAQ").unwrap();
let sample_res = fetch_link_metadata(&sample_url, false, &context)
.await
.unwrap();
let sample_res = fetch_link_metadata(&sample_url, &context).await.unwrap();
assert_eq!(
Some("FAQ · Wiki · IzzyOnDroid / repo · GitLab".to_string()),
sample_res.opengraph_data.title
@ -438,17 +404,8 @@ mod tests {
Some(mime::TEXT_HTML_UTF_8.to_string()),
sample_res.content_type
);
assert!(sample_res.thumbnail.is_some());
}
// #[test]
// fn test_pictshare() {
// let res = fetch_pictshare("https://upload.wikimedia.org/wikipedia/en/2/27/The_Mandalorian_logo.jpg");
// assert!(res.is_ok());
// let res_other = fetch_pictshare("https://upload.wikimedia.org/wikipedia/en/2/27/The_Mandalorian_logo.jpgaoeu");
// assert!(res_other.is_err());
// }
#[test]
fn test_resolve_image_url() {
// url that lists the opengraph fields

View file

@ -12,7 +12,7 @@ use lemmy_db_schema::{
community::{Community, CommunityModerator, CommunityUpdateForm},
community_block::CommunityBlock,
email_verification::{EmailVerification, EmailVerificationForm},
images::{LocalImage, RemoteImage},
images::RemoteImage,
instance::Instance,
instance_block::InstanceBlock,
local_site::LocalSite,
@ -27,7 +27,10 @@ use lemmy_db_schema::{
traits::Crud,
utils::DbPool,
};
use lemmy_db_views::{comment_view::CommentQuery, structs::LocalUserView};
use lemmy_db_views::{
comment_view::CommentQuery,
structs::{LocalImageView, LocalUserView},
};
use lemmy_db_views_actor::structs::{
CommunityModeratorView,
CommunityPersonBanView,
@ -139,8 +142,8 @@ pub fn is_top_mod(
#[tracing::instrument(skip_all)]
pub async fn get_post(post_id: PostId, pool: &mut DbPool<'_>) -> LemmyResult<Post> {
Post::read(pool, post_id)
.await
.with_lemmy_type(LemmyErrorType::CouldntFindPost)
.await?
.ok_or(LemmyErrorType::CouldntFindPost.into())
}
#[tracing::instrument(skip_all)]
@ -188,8 +191,8 @@ async fn check_community_deleted_removed(
pool: &mut DbPool<'_>,
) -> LemmyResult<()> {
let community = Community::read(pool, community_id)
.await
.with_lemmy_type(LemmyErrorType::CouldntFindCommunity)?;
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
if community.deleted || community.removed {
Err(LemmyErrorType::Deleted)?
}
@ -533,25 +536,8 @@ pub async fn get_url_blocklist(context: &LemmyContext) -> LemmyResult<RegexSet>
.try_get_with::<_, LemmyError>((), async {
let urls = LocalSiteUrlBlocklist::get_all(&mut context.pool()).await?;
let regexes = urls.iter().map(|url| {
let url = &url.url;
let parsed = Url::parse(url).expect("Coundln't parse URL.");
if url.ends_with('/') {
format!(
"({}://)?{}{}?",
parsed.scheme(),
escape(parsed.domain().expect("No domain.")),
escape(parsed.path())
)
} else {
format!(
"({}://)?{}{}",
parsed.scheme(),
escape(parsed.domain().expect("No domain.")),
escape(parsed.path())
)
}
});
// The urls are already validated on saving, so just escape them.
let regexes = urls.iter().map(|url| escape(&url.url));
let set = RegexSet::new(regexes)?;
Ok(set)
@ -660,15 +646,20 @@ pub async fn purge_image_posts_for_person(
/// Delete a local_user's images
async fn delete_local_user_images(person_id: PersonId, context: &LemmyContext) -> LemmyResult<()> {
if let Ok(local_user) = LocalUserView::read_person(&mut context.pool(), person_id).await {
if let Ok(Some(local_user)) = LocalUserView::read_person(&mut context.pool(), person_id).await {
let pictrs_uploads =
LocalImage::get_all_by_local_user_id(&mut context.pool(), local_user.local_user.id).await?;
LocalImageView::get_all_by_local_user_id(&mut context.pool(), local_user.local_user.id)
.await?;
// Delete their images
for upload in pictrs_uploads {
delete_image_from_pictrs(&upload.pictrs_alias, &upload.pictrs_delete_token, context)
.await
.ok();
delete_image_from_pictrs(
&upload.local_image.pictrs_alias,
&upload.local_image.pictrs_delete_token,
context,
)
.await
.ok();
}
}
Ok(())
@ -700,7 +691,9 @@ pub async fn remove_user_data(
) -> LemmyResult<()> {
let pool = &mut context.pool();
// Purge user images
let person = Person::read(pool, banned_person_id).await?;
let person = Person::read(pool, banned_person_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPerson)?;
if let Some(avatar) = person.avatar {
purge_image_from_pictrs(&avatar, context).await.ok();
}
@ -813,7 +806,9 @@ pub async fn remove_user_data_in_community(
pub async fn purge_user_account(person_id: PersonId, context: &LemmyContext) -> LemmyResult<()> {
let pool = &mut context.pool();
let person = Person::read(pool, person_id).await?;
let person = Person::read(pool, person_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPerson)?;
// Delete their local images, if they're a local user
delete_local_user_images(person_id, context).await.ok();

View file

@ -70,7 +70,8 @@ pub async fn create_comment(
Comment::read(&mut context.pool(), parent_id).await.ok()
} else {
None
};
}
.flatten();
// If there's a parent_id, check to make sure that comment is in that post
// Strange issue where sometimes the post ID of the parent comment is incorrect
@ -172,7 +173,7 @@ pub async fn create_comment(
let parent_id = parent.id;
let comment_reply =
CommentReply::read_by_comment_and_person(&mut context.pool(), parent_id, person_id).await;
if let Ok(reply) = comment_reply {
if let Ok(Some(reply)) = comment_reply {
CommentReply::update(
&mut context.pool(),
reply.id,
@ -185,7 +186,7 @@ pub async fn create_comment(
// If the parent has PersonMentions mark them as read too
let person_mention =
PersonMention::read_by_comment_and_person(&mut context.pool(), parent_id, person_id).await;
if let Ok(mention) = person_mention {
if let Ok(Some(mention)) = person_mention {
PersonMention::update(
&mut context.pool(),
mention.id,

View file

@ -21,7 +21,9 @@ pub async fn delete_comment(
local_user_view: LocalUserView,
) -> LemmyResult<Json<CommentResponse>> {
let comment_id = data.comment_id;
let orig_comment = CommentView::read(&mut context.pool(), comment_id, None).await?;
let orig_comment = CommentView::read(&mut context.pool(), comment_id, None)
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?;
// Dont delete it if its already been deleted.
if orig_comment.comment.deleted == data.deleted {

View file

@ -25,7 +25,9 @@ pub async fn remove_comment(
local_user_view: LocalUserView,
) -> LemmyResult<Json<CommentResponse>> {
let comment_id = data.comment_id;
let orig_comment = CommentView::read(&mut context.pool(), comment_id, None).await?;
let orig_comment = CommentView::read(&mut context.pool(), comment_id, None)
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?;
check_community_mod_action(
&local_user_view.person,

View file

@ -36,7 +36,9 @@ pub async fn update_comment(
let local_site = LocalSite::read(&mut context.pool()).await?;
let comment_id = data.comment_id;
let orig_comment = CommentView::read(&mut context.pool(), comment_id, None).await?;
let orig_comment = CommentView::read(&mut context.pool(), comment_id, None)
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?;
check_community_user_action(
&local_user_view.person,

View file

@ -46,7 +46,9 @@ pub async fn create_community(
context: Data<LemmyContext>,
local_user_view: LocalUserView,
) -> LemmyResult<Json<CommunityResponse>> {
let site_view = SiteView::read_local(&mut context.pool()).await?;
let site_view = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
let local_site = site_view.local_site;
if local_site.community_creation_admin_only && is_admin(&local_user_view).is_err() {

View file

@ -6,7 +6,7 @@ use lemmy_api_common::{
};
use lemmy_db_views::structs::{LocalUserView, SiteView};
use lemmy_db_views_actor::community_view::CommunityQuery;
use lemmy_utils::error::LemmyResult;
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
#[tracing::instrument(skip(context))]
pub async fn list_communities(
@ -14,7 +14,9 @@ pub async fn list_communities(
context: Data<LemmyContext>,
local_user_view: Option<LocalUserView>,
) -> LemmyResult<Json<ListCommunitiesResponse>> {
let local_site = SiteView::read_local(&mut context.pool()).await?;
let local_site = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
let is_admin = local_user_view
.as_ref()
.map(|luv| is_admin(luv).is_ok())

View file

@ -43,7 +43,9 @@ pub async fn update_community(
let description =
process_markdown_opt(&data.description, &slur_regex, &url_blocklist, &context).await?;
is_valid_body_field(&data.description, false)?;
let old_community = Community::read(&mut context.pool(), data.community_id).await?;
let old_community = Community::read(&mut context.pool(), data.community_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
replace_image(&data.icon, &old_community.icon, &context).await?;
replace_image(&data.banner, &old_community.banner, &context).await?;

View file

@ -85,7 +85,9 @@ pub async fn create_post(
.await?;
let community_id = data.community_id;
let community = Community::read(&mut context.pool(), community_id).await?;
let community = Community::read(&mut context.pool(), community_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
if community.posting_restricted_to_mods {
let community_id = data.community_id;
let is_mod = CommunityModeratorView::is_community_moderator(
@ -157,6 +159,7 @@ pub async fn create_post(
generate_post_link_metadata(
updated_post.clone(),
custom_thumbnail,
None,
|post| Some(SendActivityData::CreatePost(post)),
Some(local_site),
context.reset_request_count(),

View file

@ -21,7 +21,9 @@ pub async fn delete_post(
local_user_view: LocalUserView,
) -> LemmyResult<Json<PostResponse>> {
let post_id = data.post_id;
let orig_post = Post::read(&mut context.pool(), post_id).await?;
let orig_post = Post::read(&mut context.pool(), post_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?;
// Dont delete it if its already been deleted.
if orig_post.deleted == data.deleted {

View file

@ -22,7 +22,9 @@ pub async fn get_post(
context: Data<LemmyContext>,
local_user_view: Option<LocalUserView>,
) -> LemmyResult<Json<GetPostResponse>> {
let local_site = SiteView::read_local(&mut context.pool()).await?;
let local_site = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
check_private_instance(&local_user_view, &local_site.local_site)?;
@ -33,15 +35,19 @@ pub async fn get_post(
id
} else if let Some(comment_id) = data.comment_id {
Comment::read(&mut context.pool(), comment_id)
.await
.with_lemmy_type(LemmyErrorType::CouldntFindPost)?
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?
.post_id
} else {
Err(LemmyErrorType::CouldntFindPost)?
};
// Check to see if the person is a mod or admin, to show deleted / removed
let community_id = Post::read(&mut context.pool(), post_id).await?.community_id;
let community_id = Post::read(&mut context.pool(), post_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?
.community_id;
let is_mod_or_admin = is_mod_or_admin_opt(
&mut context.pool(),
local_user_view.as_ref(),
@ -51,8 +57,8 @@ pub async fn get_post(
.is_ok();
let post_view = PostView::read(&mut context.pool(), post_id, person_id, is_mod_or_admin)
.await
.with_lemmy_type(LemmyErrorType::CouldntFindPost)?;
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?;
// Mark the post as read
let post_id = post_view.post.id;
@ -67,8 +73,8 @@ pub async fn get_post(
person_id,
is_mod_or_admin,
)
.await
.with_lemmy_type(LemmyErrorType::CouldntFindCommunity)?;
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
// Insert into PersonPostAggregates
// to update the read_comments count

View file

@ -16,7 +16,7 @@ use lemmy_db_schema::{
traits::{Crud, Reportable},
};
use lemmy_db_views::structs::LocalUserView;
use lemmy_utils::error::LemmyResult;
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
#[tracing::instrument(skip(context))]
pub async fn remove_post(
@ -25,7 +25,9 @@ pub async fn remove_post(
local_user_view: LocalUserView,
) -> LemmyResult<Json<PostResponse>> {
let post_id = data.post_id;
let orig_post = Post::read(&mut context.pool(), post_id).await?;
let orig_post = Post::read(&mut context.pool(), post_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?;
check_community_mod_action(
&local_user_view.person,

View file

@ -70,7 +70,9 @@ pub async fn update_post(
check_url_scheme(&custom_thumbnail)?;
let post_id = data.post_id;
let orig_post = Post::read(&mut context.pool(), post_id).await?;
let orig_post = Post::read(&mut context.pool(), post_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?;
check_community_user_action(
&local_user_view.person,
@ -116,6 +118,7 @@ pub async fn update_post(
generate_post_link_metadata(
updated_post.clone(),
custom_thumbnail,
None,
|post| Some(SendActivityData::UpdatePost(post)),
Some(local_site),
context.reset_request_count(),

View file

@ -76,12 +76,16 @@ pub async fn create_private_message(
.await
.with_lemmy_type(LemmyErrorType::CouldntCreatePrivateMessage)?;
let view = PrivateMessageView::read(&mut context.pool(), inserted_private_message.id).await?;
let view = PrivateMessageView::read(&mut context.pool(), inserted_private_message.id)
.await?
.ok_or(LemmyErrorType::CouldntFindPrivateMessage)?;
// Send email to the local recipient, if one exists
if view.recipient.local {
let recipient_id = data.recipient_id;
let local_recipient = LocalUserView::read_person(&mut context.pool(), recipient_id).await?;
let local_recipient = LocalUserView::read_person(&mut context.pool(), recipient_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPerson)?;
let lang = get_interface_language(&local_recipient);
let inbox_link = format!("{}/inbox", context.settings().get_protocol_and_hostname());
let sender_name = &local_user_view.person.name;

View file

@ -20,7 +20,9 @@ pub async fn delete_private_message(
) -> LemmyResult<Json<PrivateMessageResponse>> {
// Checking permissions
let private_message_id = data.private_message_id;
let orig_private_message = PrivateMessage::read(&mut context.pool(), private_message_id).await?;
let orig_private_message = PrivateMessage::read(&mut context.pool(), private_message_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPrivateMessage)?;
if local_user_view.person.id != orig_private_message.creator_id {
Err(LemmyErrorType::EditPrivateMessageNotAllowed)?
}
@ -45,7 +47,9 @@ pub async fn delete_private_message(
)
.await?;
let view = PrivateMessageView::read(&mut context.pool(), private_message_id).await?;
let view = PrivateMessageView::read(&mut context.pool(), private_message_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPrivateMessage)?;
Ok(Json(PrivateMessageResponse {
private_message_view: view,
}))

View file

@ -30,7 +30,9 @@ pub async fn update_private_message(
// Checking permissions
let private_message_id = data.private_message_id;
let orig_private_message = PrivateMessage::read(&mut context.pool(), private_message_id).await?;
let orig_private_message = PrivateMessage::read(&mut context.pool(), private_message_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPrivateMessage)?;
if local_user_view.person.id != orig_private_message.creator_id {
Err(LemmyErrorType::EditPrivateMessageNotAllowed)?
}
@ -54,7 +56,9 @@ pub async fn update_private_message(
.await
.with_lemmy_type(LemmyErrorType::CouldntUpdatePrivateMessage)?;
let view = PrivateMessageView::read(&mut context.pool(), private_message_id).await?;
let view = PrivateMessageView::read(&mut context.pool(), private_message_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPrivateMessage)?;
ActivityChannel::submit_activity(
SendActivityData::UpdatePrivateMessage(view.clone()),

View file

@ -129,7 +129,9 @@ pub async fn create_site(
LocalSiteRateLimit::update(&mut context.pool(), &local_site_rate_limit_form).await?;
let site_view = SiteView::read_local(&mut context.pool()).await?;
let site_view = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
let new_taglines = data.taglines.clone();
let taglines = Tagline::replace(&mut context.pool(), local_site.id, new_taglines).await?;

View file

@ -41,7 +41,9 @@ pub async fn get_site(
// This data is independent from the user account so we can cache it across requests
let mut site_response = CACHE
.try_get_with::<_, LemmyError>((), async {
let site_view = SiteView::read_local(&mut context.pool()).await?;
let site_view = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
let admins = PersonView::admins(&mut context.pool()).await?;
let all_languages = Language::read_all(&mut context.pool()).await?;
let discussion_languages = SiteLanguage::read_local_raw(&mut context.pool()).await?;

View file

@ -52,7 +52,9 @@ pub async fn update_site(
context: Data<LemmyContext>,
local_user_view: LocalUserView,
) -> LemmyResult<Json<SiteResponse>> {
let site_view = SiteView::read_local(&mut context.pool()).await?;
let site_view = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
let local_site = site_view.local_site;
let site = site_view.site;
@ -181,7 +183,9 @@ pub async fn update_site(
let new_taglines = data.taglines.clone();
let taglines = Tagline::replace(&mut context.pool(), local_site.id, new_taglines).await?;
let site_view = SiteView::read_local(&mut context.pool()).await?;
let site_view = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
let rate_limit_config =
local_site_rate_limit_to_rate_limit_config(&site_view.local_site_rate_limit);

View file

@ -45,7 +45,9 @@ pub async fn register(
req: HttpRequest,
context: Data<LemmyContext>,
) -> LemmyResult<Json<LoginResponse>> {
let site_view = SiteView::read_local(&mut context.pool()).await?;
let site_view = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
let local_site = site_view.local_site;
let require_registration_application =
local_site.registration_mode == RegistrationMode::RequireApplication;

View file

@ -0,0 +1,22 @@
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://community.nodebb.org/category/31",
"url": "https://community.nodebb.org/category/31/threadiverse-working-group",
"inbox": "https://community.nodebb.org/category/31/inbox",
"outbox": "https://community.nodebb.org/category/31/outbox",
"sharedInbox": "https://community.nodebb.org/inbox",
"type": "Group",
"name": "Threadiverse Working Group",
"preferredUsername": "swicg-threadiverse-wg",
"summary": "Discussion and announcements related to the SWICG Threadiverse task force",
"icon": {
"type": "Image",
"mediaType": "image/png",
"url": "https://community.nodebb.org/assets/uploads/system/site-logo.png"
},
"publicKey": {
"id": "https://community.nodebb.org/category/31#key",
"owner": "https://community.nodebb.org/category/31",
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0/Or3Ox2/jbhBZzF8W0Y\nWuS/4lgm5O5rxQk2nDRBXU/qNaZnMPkW2FxFPuPetndUVKSD2+vWF3SUlFyZ/vhT\nITzLkbRSILMiZCUg+0mvqi6va1WMBglMe5jLkc7wdfgNsosqBzKMdyMxqDZr++mJ\n8DjuqzWHENcjWcbMfSfAa9nkZHBIQUsHGGIwxEbKNlPqF0JIB66py7xmXbboDxpD\nPVF3EMkgZNnbmDGtlkZCKbztradyNRVl/u6KJpV3fbi+m/8CZ+POc4I5sKCQY1Hr\ndslHlm6tCkJQxIIKQtz0ZJ5yCUYmk48C2gFCndfJtYoEy9iR62xSemky6y04gWVc\naQIDAQAB\n-----END PUBLIC KEY-----\n"
}
}

View file

@ -0,0 +1,38 @@
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://community.nodebb.org/topic/17908",
"type": "Page",
"to": ["https://www.w3.org/ns/activitystreams#Public"],
"cc": ["https://community.nodebb.org/uid/2/followers"],
"inReplyTo": null,
"published": "2024-03-19T20:25:39.462Z",
"url": "https://community.nodebb.org/topic/17908/threadiverse-working-group",
"attributedTo": "https://community.nodebb.org/uid/2",
"audience": "https://community.nodebb.org/category/31/threadiverse-working-group",
"sensitive": false,
"summary": null,
"name": "Threadiverse Working Group",
"content": "<p dir=\"auto\">NodeBB is at this year's FediForum, and one of the breakout sessions centred around <strong>the Theadiverse</strong>, the subset of ActivityPub-enabled applications built around a topic-centric model of content representation.</p>\n<p dir=\"auto\">Some of the topic touched upon included:</p>\n<ul>\n<li>Aligning on a standard representation for collections of Notes</li>\n<li>FEP-1b12 — Group federation and implementation thereof by Lemmy, et al.</li>\n<li>Offering a comparatively more feature-rich experience vis-a-vis restrictions re: microblogging</li>\n<li>Going forward: collaborating on building compatible threadiverse implementations</li>\n</ul>\n<p dir=\"auto\">The main action item involved <strong>the genesis of an informal working group for the threadiverse</strong>, in order to align our disparate implementations toward a common path.</p>\n<p dir=\"auto\">We intend to meet monthly at first, with the first meeting likely sometime early-to-mid April.</p>\n<p dir=\"auto\">The topic of the first WG call is: <strong>Representation of the higherlevel collection of Notes (posts, etc.) — Article vs. Page, etc?</strong></p>\n<p dir=\"auto\">Interested?</p>\n<ul>\n<li>Publicly reply to this post (NodeBB does not support non-public posts at this time) if you'd like to join the list</li>\n<li>If you prefer to remain private, please email <a href=\"mailto:julian@nodebb.org\" rel=\"nofollow ugc\">julian@nodebb.org</a></li>\n</ul>\n<hr />\n<p dir=\"auto\">As an aside, I'd love to try something new and attempt tokeep as much of this as I can on the social web. Can you do me a favour and boost this to your followers?</p>\n",
"source": {
"content": "NodeBB is at this year's FediForum, and one of the breakout sessions centred around **the Theadiverse**, the subset of ActivityPub-enabled applications built around a topic-centric model of content representation.\n\nSome of the topic touched upon included:\n\n* Aligning on a standard representation for collections of Notes\n* FEP-1b12 — Group federation and implementation thereof by Lemmy, et al.\n* Offering a comparatively more feature-rich experience vis-a-vis restrictions re: microblogging\n* Going forward: collaborating on building compatible threadiverse implementations\n\nThe main action item involved **the genesis of an informal working group for the threadiverse**, in order to align our disparate implementations toward a common path.\n\nWe intend to meet monthly at first, with the first meeting likely sometime early-to-mid April.\n\nThe topic of the first WG call is: **Representation of the higher level collection of Notes (posts, etc.) — Article vs. Page, etc?**\n\nInterested?\n\n* Publicly reply to this post (NodeBB does not support non-public postsat this time) if you'd like to join the list\n* If you prefer to remain private, please email julian@nodebb.org\n\n----\n\nAs an aside, I'd love to try something new and attempt to keep as much of this as I can on the social web. Can you do me a favour and boost this to your followers?",
"mediaType": "text/markdown"
},
"tag": [
{
"type": "Hashtag",
"href": "https://community.nodebb.org/tags/fediforum",
"name": "#fediforum"
},
{
"type": "Hashtag",
"href": "https://community.nodebb.org/tags/activitypub",
"name": "#activitypub"
},
{
"type": "Hashtag",
"href": "https://community.nodebb.org/tags/threadiverse",
"name": "#threadiverse"
}
],
"attachment": []
}

View file

@ -0,0 +1,29 @@
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://community.nodebb.org/uid/2",
"url": "https://community.nodebb.org/user/julian",
"followers": "https://community.nodebb.org/uid/2/followers",
"following": "https://community.nodebb.org/uid/2/following",
"inbox": "https://community.nodebb.org/uid/2/inbox",
"outbox": "https://community.nodebb.org/uid/2/outbox",
"sharedInbox": "https://community.nodebb.org/inbox",
"type": "Person",
"name": "julian",
"preferredUsername": "julian",
"summary": "Hi! I'm Julian, one of the co-founders of NodeBB, the forum software you are using right now.\r\n\r\nI started this company with two colleagues, Baris and Andrew, in 2013, and have been doing the startup thing since (although I think at some point along the way we stopped being a startup and just became a boring ol' small business).\r\n\r\nIn my free time I rock climb, cycle, and lift weights. I live just outside Toronto, Canada, with my wife and three children.",
"icon": {
"type": "Image",
"mediaType": "image/jpeg",
"url": "https://community.nodebb.org/assets/uploads/profile/uid-2/2-profileavatar-1701457270279.jpeg"
},
"image": {
"type": "Image",
"mediaType": "image/jpeg",
"url": "https://community.nodebb.org/assets/uploads/profile/uid-2/2-profilecover-1649468285913.jpeg"
},
"publicKey": {
"id": "https://community.nodebb.org/uid/2#key",
"owner": "https://community.nodebb.org/uid/2",
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzEr0sFdATahQzprS4EOT\nZq+KMc6UTbt2GDP20OrQi/P5AXAbMaQiRCRdGWhYGjnH0jicn5NnozNxRo+HchJT\nV6NOHxpsxqPCoaLeoBkhfhbSCLr2Gzil6mmfqf9TjnI7A7ZTtCc0G+n0ztyL9HwL\nkEAI178l2gckk4XKKYnEd+dyiIevExrq/ROLgwW1o428FZvlF5amKxhpVUEygRU8\nCd1hqWYs+xYDOJURCP5qEx/MmRPpV/yGMTMyF+/gcQc0TUZnhWAM2E4M+aq3aKh6\nJP/vsry+5YZPUaPWfopbT5Ijyt6ZSElp6Avkg56eTz0a5SRcjCVS6IFVPwiLlzOe\nYwIDAQAB\n-----END PUBLIC KEY-----\n"
}
}

View file

@ -39,7 +39,10 @@ use lemmy_db_schema::{
},
traits::{Bannable, Crud, Followable},
};
use lemmy_utils::error::{LemmyError, LemmyResult};
use lemmy_utils::{
error::{LemmyError, LemmyResult},
LemmyErrorType,
};
use url::Url;
impl BlockUser {
@ -129,7 +132,11 @@ impl ActivityHandler for BlockUser {
verify_is_public(&self.to, &self.cc)?;
match self.target.dereference(context).await? {
SiteOrCommunity::Site(site) => {
let domain = self.object.inner().domain().expect("url needs domain");
let domain = self
.object
.inner()
.domain()
.ok_or(LemmyErrorType::UrlWithoutDomain)?;
if context.settings().hostname == domain {
return Err(
anyhow!("Site bans from remote instance can't affect user's home instance").into(),

View file

@ -23,7 +23,10 @@ use lemmy_db_schema::{
utils::DbPool,
};
use lemmy_db_views::structs::SiteView;
use lemmy_utils::error::{LemmyError, LemmyResult};
use lemmy_utils::{
error::{LemmyError, LemmyResult},
LemmyErrorType,
};
use serde::Deserialize;
use url::Url;
@ -134,7 +137,13 @@ pub(crate) async fn send_ban_from_site(
expires: Option<i64>,
context: Data<LemmyContext>,
) -> LemmyResult<()> {
let site = SiteOrCommunity::Site(SiteView::read_local(&mut context.pool()).await?.site.into());
let site = SiteOrCommunity::Site(
SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?
.site
.into(),
);
let expires = check_expire_time(expires)?;
// if the action affects a local user, federate to other instances
@ -174,6 +183,7 @@ pub(crate) async fn send_ban_from_community(
) -> LemmyResult<()> {
let community: ApubCommunity = Community::read(&mut context.pool(), community_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?
.into();
let expires = check_expire_time(data.expires)?;

View file

@ -94,7 +94,12 @@ impl AnnounceActivity {
actor: community.id().into(),
to: vec![public()],
object: IdOrNestedObject::NestedObject(object),
cc: vec![community.followers_url.clone().into()],
cc: community
.followers_url
.clone()
.map(Into::into)
.into_iter()
.collect(),
kind: AnnounceType::Announce,
id,
})

View file

@ -36,7 +36,10 @@ use lemmy_db_schema::{
},
traits::{Crud, Joinable},
};
use lemmy_utils::error::{LemmyError, LemmyResult};
use lemmy_utils::{
error::{LemmyError, LemmyResult},
LemmyErrorType,
};
use url::Url;
impl CollectionAdd {
@ -126,7 +129,9 @@ impl ActivityHandler for CollectionAdd {
async fn receive(self, context: &Data<Self::DataType>) -> LemmyResult<()> {
insert_received_activity(&self.id, context).await?;
let (community, collection_type) =
Community::get_by_collection_url(&mut context.pool(), &self.target.into()).await?;
Community::get_by_collection_url(&mut context.pool(), &self.target.into())
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
match collection_type {
CollectionType::Moderators => {
let new_mod = ObjectId::<ApubPerson>::from(self.object)
@ -183,9 +188,11 @@ pub(crate) async fn send_add_mod_to_community(
let actor: ApubPerson = actor.into();
let community: ApubCommunity = Community::read(&mut context.pool(), community_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?
.into();
let updated_mod: ApubPerson = Person::read(&mut context.pool(), updated_mod_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPerson)?
.into();
if added {
CollectionAdd::send_add_mod(&community, &updated_mod, &actor, &context).await
@ -204,6 +211,7 @@ pub(crate) async fn send_feature_post(
let post: ApubPost = post.into();
let community = Community::read(&mut context.pool(), post.community_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?
.into();
if featured {
CollectionAdd::send_add_featured_post(&community, &post, &actor, &context).await

View file

@ -31,7 +31,10 @@ use lemmy_db_schema::{
},
traits::{Crud, Joinable},
};
use lemmy_utils::error::{LemmyError, LemmyResult};
use lemmy_utils::{
error::{LemmyError, LemmyResult},
LemmyErrorType,
};
use url::Url;
impl CollectionRemove {
@ -121,7 +124,9 @@ impl ActivityHandler for CollectionRemove {
async fn receive(self, context: &Data<Self::DataType>) -> LemmyResult<()> {
insert_received_activity(&self.id, context).await?;
let (community, collection_type) =
Community::get_by_collection_url(&mut context.pool(), &self.target.into()).await?;
Community::get_by_collection_url(&mut context.pool(), &self.target.into())
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
match collection_type {
CollectionType::Moderators => {
let remove_mod = ObjectId::<ApubPerson>::from(self.object)

View file

@ -31,7 +31,10 @@ use lemmy_db_schema::{
},
traits::Crud,
};
use lemmy_utils::error::{LemmyError, LemmyResult};
use lemmy_utils::{
error::{LemmyError, LemmyResult},
LemmyErrorType,
};
use url::Url;
#[async_trait::async_trait]
@ -109,6 +112,7 @@ pub(crate) async fn send_lock_post(
) -> LemmyResult<()> {
let community: ApubCommunity = Community::read(&mut context.pool(), post.community_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?
.into();
let id = generate_activity_id(
LockType::Lock,

View file

@ -29,7 +29,10 @@ use lemmy_db_schema::{
},
traits::{Crud, Reportable},
};
use lemmy_utils::error::{LemmyError, LemmyResult};
use lemmy_utils::{
error::{LemmyError, LemmyResult},
LemmyErrorType,
};
use url::Url;
impl Report {
@ -67,7 +70,9 @@ impl Report {
PostOrComment::Post(p) => p.creator_id,
PostOrComment::Comment(c) => c.creator_id,
};
let object_creator = Person::read(&mut context.pool(), object_creator_id).await?;
let object_creator = Person::read(&mut context.pool(), object_creator_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPerson)?;
let object_creator_site: Option<ApubSite> =
Site::read_from_instance_id(&mut context.pool(), object_creator.instance_id)
.await?

View file

@ -105,7 +105,7 @@ impl ActivityHandler for UpdateCommunity {
last_refreshed_at: Some(naive_now()),
icon: Some(self.object.icon.map(|i| i.url.into())),
banner: Some(self.object.image.map(|i| i.url.into())),
followers_url: Some(self.object.followers.into()),
followers_url: self.object.followers.map(Into::into),
inbox_url: Some(self.object.inbox.into()),
shared_inbox_url: Some(self.object.endpoints.map(|e| e.shared_inbox.into())),
moderators_url: self.object.attributed_to.map(Into::into),

View file

@ -19,7 +19,7 @@ use activitypub_federation::{
config::Data,
fetch::object_id::ObjectId,
kinds::public,
protocol::verification::verify_domains_match,
protocol::verification::{verify_domains_match, verify_urls_match},
traits::{ActivityHandler, Actor, Object},
};
use lemmy_api_common::{
@ -42,6 +42,7 @@ use lemmy_db_schema::{
use lemmy_utils::{
error::{LemmyError, LemmyResult},
utils::mention::scrape_text_for_mentions,
LemmyErrorType,
};
use url::Url;
@ -55,11 +56,17 @@ impl CreateOrUpdateNote {
) -> LemmyResult<()> {
// TODO: might be helpful to add a comment method to retrieve community directly
let post_id = comment.post_id;
let post = Post::read(&mut context.pool(), post_id).await?;
let post = Post::read(&mut context.pool(), post_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?;
let community_id = post.community_id;
let person: ApubPerson = Person::read(&mut context.pool(), person_id).await?.into();
let person: ApubPerson = Person::read(&mut context.pool(), person_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPerson)?
.into();
let community: ApubCommunity = Community::read(&mut context.pool(), community_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?
.into();
let id = generate_activity_id(
@ -126,6 +133,7 @@ impl ActivityHandler for CreateOrUpdateNote {
verify_domains_match(self.actor.inner(), self.object.id.inner())?;
check_community_deleted_or_removed(&community)?;
check_post_deleted_or_removed(&post)?;
verify_urls_match(self.actor.inner(), self.object.attributed_to.inner())?;
ApubComment::verify(&self.object, self.actor.inner(), context).await?;
Ok(())

View file

@ -66,15 +66,18 @@ impl CreateOrUpdatePage {
kind: CreateOrUpdateType,
context: Data<LemmyContext>,
) -> LemmyResult<()> {
let post = ApubPost(post);
let community_id = post.community_id;
let person: ApubPerson = Person::read(&mut context.pool(), person_id).await?.into();
let person: ApubPerson = Person::read(&mut context.pool(), person_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPerson)?
.into();
let community: ApubCommunity = Community::read(&mut context.pool(), community_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?
.into();
let create_or_update =
CreateOrUpdatePage::new(post, &person, &community, kind, &context).await?;
CreateOrUpdatePage::new(post.into(), &person, &community, kind, &context).await?;
let is_mod_action = create_or_update.object.is_mod_action(&context).await?;
let activity = AnnouncableActivities::CreateOrUpdatePost(create_or_update);
send_activity_in_community(

View file

@ -9,7 +9,7 @@ use crate::{
};
use activitypub_federation::{
config::Data,
protocol::verification::verify_domains_match,
protocol::verification::{verify_domains_match, verify_urls_match},
traits::{ActivityHandler, Actor, Object},
};
use lemmy_api_common::context::LemmyContext;
@ -61,6 +61,7 @@ impl ActivityHandler for CreateOrUpdateChatMessage {
verify_person(&self.actor, context).await?;
verify_domains_match(self.actor.inner(), self.object.id.inner())?;
verify_domains_match(self.to[0].inner(), self.object.to[0].inner())?;
verify_urls_match(self.actor.inner(), self.object.attributed_to.inner())?;
ApubPrivateMessage::verify(&self.object, self.actor.inner(), context).await?;
Ok(())
}

View file

@ -39,7 +39,7 @@ use lemmy_db_schema::{
},
traits::Crud,
};
use lemmy_utils::error::LemmyResult;
use lemmy_utils::{error::LemmyResult, LemmyErrorType};
use std::ops::Deref;
use url::Url;
@ -87,6 +87,7 @@ pub(crate) async fn send_apub_delete_private_message(
let recipient_id = pm.recipient_id;
let recipient: ApubPerson = Person::read(&mut context.pool(), recipient_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPerson)?
.into();
let deletable = DeletableObjects::PrivateMessage(pm.into());

View file

@ -245,7 +245,9 @@ pub async fn match_outgoing_activities(
CreateOrUpdatePage::send(post, creator_id, CreateOrUpdateType::Update, context).await
}
DeletePost(post, person, data) => {
let community = Community::read(&mut context.pool(), post.community_id).await?;
let community = Community::read(&mut context.pool(), post.community_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
send_apub_delete_in_community(
person,
community,
@ -262,7 +264,9 @@ pub async fn match_outgoing_activities(
reason,
removed,
} => {
let community = Community::read(&mut context.pool(), post.community_id).await?;
let community = Community::read(&mut context.pool(), post.community_id)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
send_apub_delete_in_community(
moderator,
community,

View file

@ -44,7 +44,7 @@ pub(crate) async fn send_like_activity(
let activity = AnnouncableActivities::Vote(vote);
send_activity_in_community(activity, &actor, &community, empty, false, &context).await
} else {
// Lemmy API doesnt distinguish between Undo/Like and Undo/Dislike, so we hardcode it here.
// Lemmy API doesn't distinguish between Undo/Like and Undo/Dislike, so we hardcode it here.
let vote = Vote::new(object_id, &actor, &community, VoteType::Like, &context)?;
let undo_vote = UndoVote::new(vote, &actor, &community, &context)?;
let activity = AnnouncableActivities::UndoVote(undo_vote);

View file

@ -58,7 +58,12 @@ pub async fn list_comments(
// If a parent_id is given, fetch the comment to get the path
let parent_path = if let Some(parent_id) = parent_id {
Some(Comment::read(&mut context.pool(), parent_id).await?.path)
Some(
Comment::read(&mut context.pool(), parent_id)
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?
.path,
)
} else {
None
};

View file

@ -23,7 +23,9 @@ pub async fn list_posts(
context: Data<LemmyContext>,
local_user_view: Option<LocalUserView>,
) -> LemmyResult<Json<GetPostsResponse>> {
let local_site = SiteView::read_local(&mut context.pool()).await?;
let local_site = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
check_private_instance(&local_user_view, &local_site.local_site)?;

View file

@ -56,8 +56,8 @@ pub async fn get_community(
person_id,
is_mod_or_admin,
)
.await
.with_lemmy_type(LemmyErrorType::CouldntFindCommunity)?;
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?;
let moderators = CommunityModeratorView::for_community(&mut context.pool(), community_id)
.await

View file

@ -26,7 +26,9 @@ pub async fn read_person(
Err(LemmyErrorType::NoIdGiven)?
}
let local_site = SiteView::read_local(&mut context.pool()).await?;
let local_site = SiteView::read_local(&mut context.pool())
.await?
.ok_or(LemmyErrorType::LocalSiteNotSetup)?;
check_private_instance(&local_user_view, &local_site.local_site)?;
@ -46,7 +48,9 @@ pub async fn read_person(
// You don't need to return settings for the user, since this comes back with GetSite
// `my_user`
let person_view = PersonView::read(&mut context.pool(), person_details_id).await?;
let person_view = PersonView::read(&mut context.pool(), person_details_id)
.await?
.ok_or(LemmyErrorType::CouldntFindPerson)?;
let sort = data.sort;
let page = data.page;

View file

@ -53,20 +53,36 @@ async fn convert_response(
match object {
Post(p) => {
removed_or_deleted = p.deleted || p.removed;
res.post = Some(PostView::read(pool, p.id, user_id, false).await?)
res.post = Some(
PostView::read(pool, p.id, user_id, false)
.await?
.ok_or(LemmyErrorType::CouldntFindPost)?,
)
}
Comment(c) => {
removed_or_deleted = c.deleted || c.removed;
res.comment = Some(CommentView::read(pool, c.id, user_id).await?)
res.comment = Some(
CommentView::read(pool, c.id, user_id)
.await?
.ok_or(LemmyErrorType::CouldntFindComment)?,
)
}
PersonOrCommunity(p) => match *p {
UserOrCommunity::User(u) => {
removed_or_deleted = u.deleted;
res.person = Some(PersonView::read(pool, u.id).await?)
res.person = Some(
PersonView::read(pool, u.id)
.await?
.ok_or(LemmyErrorType::CouldntFindPerson)?,
)
}
UserOrCommunity::Community(c) => {
removed_or_deleted = c.deleted || c.removed;
res.community = Some(CommunityView::read(pool, c.id, user_id, false).await?)
res.community = Some(
CommunityView::read(pool, c.id, user_id, false)
.await?
.ok_or(LemmyErrorType::CouldntFindCommunity)?,
)
}
},
};

Some files were not shown because too many files have changed in this diff Show more