diff --git a/.drone.yml b/.drone.yml index 807d6c991..8b9f15919 100644 --- a/.drone.yml +++ b/.drone.yml @@ -9,7 +9,7 @@ platform: steps: - name: chown repo - image: ekidd/rust-musl-builder:1.47.0 + image: ekidd/rust-musl-builder:1.50.0 user: root commands: - chown 1000:1000 . -R @@ -20,23 +20,23 @@ steps: - /root/.cargo/bin/cargo fmt -- --check - name: cargo clippy - image: ekidd/rust-musl-builder:1.47.0 + image: ekidd/rust-musl-builder:1.50.0 commands: - cargo clippy --workspace --tests --all-targets --all-features -- -D warnings -D deprecated -D clippy::perf -D clippy::complexity -D clippy::dbg_macro + - cargo clippy --workspace -- -D clippy::unwrap_used - name: cargo test - image: ekidd/rust-musl-builder:1.47.0 + image: ekidd/rust-musl-builder:1.50.0 environment: LEMMY_DATABASE_URL: postgres://lemmy:password@database:5432/lemmy RUST_BACKTRACE: 1 - RUST_TEST_THREADS: 1 commands: - sudo apt-get update - sudo apt-get -y install --no-install-recommends espeak postgresql-client - cargo test --workspace --no-fail-fast - name: cargo build - image: ekidd/rust-musl-builder:1.47.0 + image: ekidd/rust-musl-builder:1.50.0 commands: - cargo build - mv target/x86_64-unknown-linux-musl/debug/lemmy_server target/lemmy_server @@ -103,11 +103,10 @@ platform: steps: - name: cargo test - image: rust:1.47-slim-buster + image: rust:1.50-slim-buster environment: LEMMY_DATABASE_URL: postgres://lemmy:password@database:5432/lemmy RUST_BACKTRACE: 1 - RUST_TEST_THREADS: 1 commands: - apt-get update - apt-get -y install --no-install-recommends espeak postgresql-client libssl-dev pkg-config libpq-dev @@ -116,7 +115,7 @@ steps: # Using Debian here because there seems to be no official Alpine-based Rust docker image for ARM. - name: cargo build - image: rust:1.47-slim-buster + image: rust:1.50-slim-buster commands: - apt-get update - apt-get -y install --no-install-recommends libssl-dev pkg-config libpq-dev diff --git a/Cargo.lock b/Cargo.lock index 2edcca8d7..959aec106 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "activitystreams" version = "0.7.0-alpha.10" @@ -8,7 +10,7 @@ checksum = "fe7ceed015dfca322d3bcec3653909c77557e7e57df72e98cb8806e2c93cc919" dependencies = [ "chrono", "mime", - "serde 1.0.123", + "serde", "serde_json", "thiserror", "url", @@ -21,7 +23,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb8e19a0810cc25df3535061a08b7d8f8a734d309ea4411c57a9767e4a2ffa0e" dependencies = [ "activitystreams", - "serde 1.0.123", + "serde", "serde_json", ] @@ -128,7 +130,7 @@ dependencies = [ "pin-project 1.0.4", "rand 0.7.3", "regex", - "serde 1.0.123", + "serde", "serde_json", "serde_urlencoded", "sha-1 0.9.3", @@ -156,7 +158,7 @@ dependencies = [ "http", "log", "regex", - "serde 1.0.123", + "serde", ] [[package]] @@ -300,7 +302,7 @@ dependencies = [ "pin-project 1.0.4", "regex", "rustls", - "serde 1.0.123", + "serde", "serde_json", "serde_urlencoded", "socket2", @@ -389,12 +391,6 @@ version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1" -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - [[package]] name = "async-mutex" version = "1.4.0" @@ -464,7 +460,7 @@ dependencies = [ "percent-encoding", "rand 0.7.3", "rustls", - "serde 1.0.123", + "serde", "serde_json", "serde_urlencoded", ] @@ -494,7 +490,7 @@ dependencies = [ "log", "num_cpus", "rand 0.7.3", - "serde 1.0.123", + "serde", "serde_json", "thiserror", "tokio 0.2.25", @@ -513,7 +509,7 @@ dependencies = [ "async-trait", "chrono", "log", - "serde 1.0.123", + "serde", "serde_json", "thiserror", "tokio 0.2.25", @@ -733,8 +729,8 @@ checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" dependencies = [ "libc", "num-integer", - "num-traits 0.2.14", - "serde 1.0.123", + "num-traits", + "serde", "time 0.1.44", "winapi 0.3.9", ] @@ -781,18 +777,6 @@ dependencies = [ "xdg", ] -[[package]] -name = "config" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b076e143e1d9538dde65da30f8481c2a6c44040edb8e02b9bf1351edb92ce3" -dependencies = [ - "lazy_static", - "nom 5.1.2", - "serde 1.0.123", - "serde-hjson", -] - [[package]] name = "const_fn" version = "0.4.5" @@ -995,6 +979,15 @@ dependencies = [ "syn", ] +[[package]] +name = "deser-hjson" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d995b60ff81bc6af01a98f0bf5db70a7418a1ac8bd74ada633968f388139da5e" +dependencies = [ + "serde", +] + [[package]] name = "diesel" version = "1.4.5" @@ -1110,6 +1103,15 @@ dependencies = [ "termcolor", ] +[[package]] +name = "envy" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f47e0157f2cb54f5ae1bd371b30a2ae4311e1c028f575cd4e81de7353215965" +dependencies = [ + "serde", +] + [[package]] name = "event-listener" version = "2.5.1" @@ -1590,7 +1592,7 @@ dependencies = [ "jpeg-decoder", "num-iter", "num-rational", - "num-traits 0.2.14", + "num-traits", "png", "scoped_threadpool", "tiff", @@ -1684,7 +1686,7 @@ dependencies = [ "base64 0.12.3", "pem", "ring", - "serde 1.0.123", + "serde", "serde_json", "simple_asn1", ] @@ -1732,20 +1734,20 @@ dependencies = [ "http-signature-normalization-actix", "itertools", "lazy_static", + "lemmy_api_structs", "lemmy_apub", "lemmy_db_queries", "lemmy_db_schema", "lemmy_db_views", "lemmy_db_views_actor", "lemmy_db_views_moderator", - "lemmy_structs", "lemmy_utils", "lemmy_websocket", "log", "openssl", "rand 0.8.3", "reqwest", - "serde 1.0.123", + "serde", "serde_json", "sha2", "strum", @@ -1756,6 +1758,25 @@ dependencies = [ "uuid", ] +[[package]] +name = "lemmy_api_structs" +version = "0.1.0" +dependencies = [ + "actix-web", + "chrono", + "diesel", + "lemmy_db_queries", + "lemmy_db_schema", + "lemmy_db_views", + "lemmy_db_views_actor", + "lemmy_db_views_moderator", + "lemmy_utils", + "log", + "serde", + "serde_json", + "url", +] + [[package]] name = "lemmy_apub" version = "0.1.0" @@ -1780,11 +1801,11 @@ dependencies = [ "http-signature-normalization-reqwest", "itertools", "lazy_static", + "lemmy_api_structs", "lemmy_db_queries", "lemmy_db_schema", "lemmy_db_views", "lemmy_db_views_actor", - "lemmy_structs", "lemmy_utils", "lemmy_websocket", "log", @@ -1792,7 +1813,7 @@ dependencies = [ "percent-encoding", "rand 0.8.3", "reqwest", - "serde 1.0.123", + "serde", "serde_json", "sha2", "strum", @@ -1816,8 +1837,9 @@ dependencies = [ "lemmy_utils", "log", "regex", - "serde 1.0.123", + "serde", "serde_json", + "serial_test", "sha2", "strum", "strum_macros", @@ -1831,7 +1853,7 @@ dependencies = [ "chrono", "diesel", "log", - "serde 1.0.123", + "serde", "serde_json", "url", ] @@ -1844,7 +1866,8 @@ dependencies = [ "lemmy_db_queries", "lemmy_db_schema", "log", - "serde 1.0.123", + "serde", + "serial_test", "url", ] @@ -1855,7 +1878,7 @@ dependencies = [ "diesel", "lemmy_db_queries", "lemmy_db_schema", - "serde 1.0.123", + "serde", ] [[package]] @@ -1865,7 +1888,7 @@ dependencies = [ "diesel", "lemmy_db_queries", "lemmy_db_schema", - "serde 1.0.123", + "serde", ] [[package]] @@ -1880,16 +1903,16 @@ dependencies = [ "chrono", "diesel", "lazy_static", + "lemmy_api_structs", "lemmy_db_queries", "lemmy_db_schema", "lemmy_db_views", "lemmy_db_views_actor", - "lemmy_structs", "lemmy_utils", "lemmy_websocket", "log", "rss", - "serde 1.0.123", + "serde", "sha2", "strum", "url", @@ -1912,6 +1935,7 @@ dependencies = [ "env_logger", "http-signature-normalization-actix", "lemmy_api", + "lemmy_api_structs", "lemmy_apub", "lemmy_db_queries", "lemmy_db_schema", @@ -1919,38 +1943,18 @@ dependencies = [ "lemmy_db_views_actor", "lemmy_db_views_moderator", "lemmy_routes", - "lemmy_structs", "lemmy_utils", "lemmy_websocket", "log", "openssl", "reqwest", - "serde 1.0.123", + "serde", "serde_json", "strum", "tokio 0.3.7", "url", ] -[[package]] -name = "lemmy_structs" -version = "0.1.0" -dependencies = [ - "actix-web", - "chrono", - "diesel", - "lemmy_db_queries", - "lemmy_db_schema", - "lemmy_db_views", - "lemmy_db_views_actor", - "lemmy_db_views_moderator", - "lemmy_utils", - "log", - "serde 1.0.123", - "serde_json", - "url", -] - [[package]] name = "lemmy_utils" version = "0.1.0" @@ -1960,8 +1964,9 @@ dependencies = [ "anyhow", "chrono", "comrak", - "config", + "deser-hjson", "diesel", + "envy", "futures", "http", "itertools", @@ -1969,12 +1974,13 @@ dependencies = [ "lazy_static", "lettre", "log", + "merge", "openssl", "percent-encoding", "rand 0.8.3", "regex", "reqwest", - "serde 1.0.123", + "serde", "serde_json", "strum", "strum_macros", @@ -1994,14 +2000,14 @@ dependencies = [ "background-jobs", "chrono", "diesel", + "lemmy_api_structs", "lemmy_db_queries", "lemmy_db_schema", - "lemmy_structs", "lemmy_utils", "log", "rand 0.8.3", "reqwest", - "serde 1.0.123", + "serde", "serde_json", "strum", "strum_macros", @@ -2020,46 +2026,23 @@ dependencies = [ "idna", "mime", "native-tls", - "nom 6.1.0", + "nom", "once_cell", "quoted_printable", "r2d2", "rand 0.8.3", "regex", - "serde 1.0.123", + "serde", "serde_json", "uuid", ] -[[package]] -name = "lexical-core" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db65c6da02e61f55dae90a0ae427b2a5f6b3e8db09f58d10efab23af92592616" -dependencies = [ - "arrayvec", - "bitflags", - "cfg-if 0.1.10", - "ryu", - "static_assertions", -] - [[package]] name = "libc" version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cca32fa0182e8c0989459524dc356b8f2b5c10f1b9eb521b7d182c03cf8c5ff" -[[package]] -name = "linked-hash-map" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd" -dependencies = [ - "serde 0.8.23", - "serde_test", -] - [[package]] name = "linked-hash-map" version = "0.5.4" @@ -2102,7 +2085,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" dependencies = [ - "linked-hash-map 0.5.4", + "linked-hash-map", ] [[package]] @@ -2144,6 +2127,28 @@ dependencies = [ "autocfg", ] +[[package]] +name = "merge" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10bbef93abb1da61525bbc45eeaff6473a41907d19f8f9aa5168d214e10693e9" +dependencies = [ + "merge_derive", + "num-traits", +] + +[[package]] +name = "merge_derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "209d075476da2e63b4b29e72a2ef627b840589588e71400a25e3565c4f849d07" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "migrations_internals" version = "1.4.1" @@ -2271,17 +2276,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "nom" -version = "5.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" -dependencies = [ - "lexical-core", - "memchr", - "version_check", -] - [[package]] name = "nom" version = "6.1.0" @@ -2301,7 +2295,7 @@ checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" dependencies = [ "autocfg", "num-integer", - "num-traits 0.2.14", + "num-traits", ] [[package]] @@ -2311,7 +2305,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" dependencies = [ "autocfg", - "num-traits 0.2.14", + "num-traits", ] [[package]] @@ -2322,7 +2316,7 @@ checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" dependencies = [ "autocfg", "num-integer", - "num-traits 0.2.14", + "num-traits", ] [[package]] @@ -2333,16 +2327,7 @@ checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" dependencies = [ "autocfg", "num-integer", - "num-traits 0.2.14", -] - -[[package]] -name = "num-traits" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" -dependencies = [ - "num-traits 0.2.14", + "num-traits", ] [[package]] @@ -2597,6 +2582,30 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro-hack" version = "0.5.19" @@ -2838,7 +2847,7 @@ dependencies = [ "native-tls", "percent-encoding", "pin-project-lite 0.2.4", - "serde 1.0.123", + "serde", "serde_json", "serde_urlencoded", "tokio 0.2.25", @@ -3008,12 +3017,6 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -[[package]] -name = "serde" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" - [[package]] name = "serde" version = "1.0.123" @@ -3023,19 +3026,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "serde-hjson" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a3a4e0ea8a88553209f6cc6cfe8724ecad22e1acf372793c27d995290fe74f8" -dependencies = [ - "lazy_static", - "linked-hash-map 0.3.0", - "num-traits 0.1.43", - "regex", - "serde 0.8.23", -] - [[package]] name = "serde_derive" version = "1.0.123" @@ -3056,16 +3046,7 @@ dependencies = [ "indexmap", "itoa", "ryu", - "serde 1.0.123", -] - -[[package]] -name = "serde_test" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "110b3dbdf8607ec493c22d5d947753282f3bae73c0f56d322af1e8c78e4c23d5" -dependencies = [ - "serde 0.8.23", + "serde", ] [[package]] @@ -3077,7 +3058,29 @@ dependencies = [ "form_urlencoded", "itoa", "ryu", - "serde 1.0.123", + "serde", +] + +[[package]] +name = "serial_test" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0bccbcf40c8938196944a3da0e133e031a33f4d6b72db3bda3cc556e361905d" +dependencies = [ + "lazy_static", + "parking_lot", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2acd6defeddb41eb60bb468f8825d0cfd0c2a76bc03bfd235b6a1dc4f6a1ad5" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -3147,7 +3150,7 @@ checksum = "692ca13de57ce0613a363c8c2f1de925adebc81b04c923ac60c5488bb44abe4b" dependencies = [ "chrono", "num-bigint", - "num-traits 0.2.14", + "num-traits", ] [[package]] @@ -3188,12 +3191,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - [[package]] name = "stdweb" version = "0.4.20" @@ -3216,7 +3213,7 @@ checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" dependencies = [ "proc-macro2", "quote", - "serde 1.0.123", + "serde", "serde_derive", "syn", ] @@ -3230,7 +3227,7 @@ dependencies = [ "base-x", "proc-macro2", "quote", - "serde 1.0.123", + "serde", "serde_derive", "serde_json", "sha1", @@ -3658,15 +3655,15 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5909f2b0817350449ed73e8bcd81c8c3c8d9a7a5d8acba4b27db277f1868976e" +checksum = "9ccd964113622c8e9322cfac19eb1004a07e636c545f325da085d5cdde6f1f8b" dependencies = [ "form_urlencoded", "idna", "matches", "percent-encoding", - "serde 1.0.123", + "serde", ] [[package]] @@ -3676,7 +3673,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" dependencies = [ "getrandom 0.2.2", - "serde 1.0.123", + "serde", ] [[package]] @@ -3720,7 +3717,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55c0f7123de74f0dab9b7d00fd614e7b19349cd1e2f5252bbe9b1754b59433be" dependencies = [ "cfg-if 1.0.0", - "serde 1.0.123", + "serde", "serde_json", "wasm-bindgen-macro", ] diff --git a/Cargo.toml b/Cargo.toml index edec85f60..e7d92fdf1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,9 @@ name = "lemmy_server" version = "0.0.1" edition = "2018" +[lib] +doctest = false + [profile.dev] debug = 0 @@ -16,7 +19,7 @@ members = [ "crates/db_views", "crates/db_views_actor", "crates/db_views_actor", - "crates/structs", + "crates/api_structs", "crates/websocket", "crates/routes" ] @@ -30,7 +33,7 @@ lemmy_db_queries = { path = "./crates/db_queries" } lemmy_db_views = { path = "./crates/db_views" } lemmy_db_views_moderator = { path = "./crates/db_views_moderator" } lemmy_db_views_actor = { path = "./crates/db_views_actor" } -lemmy_structs = { path = "./crates/structs" } +lemmy_api_structs = { path = "crates/api_structs" } lemmy_websocket = { path = "./crates/websocket" } lemmy_routes = { path = "./crates/routes" } diesel = "1.4.5" @@ -42,7 +45,7 @@ actix-web = { version = "3.3.2", default-features = false, features = ["rustls"] log = "0.4.14" env_logger = "0.8.2" strum = "0.20.0" -url = { version = "2.2.0", features = ["serde"] } +url = { version = "2.2.1", features = ["serde"] } openssl = "0.10.32" http-signature-normalization-actix = { version = "0.4.1", default-features = false, features = ["sha-2"] } tokio = "0.3.6" diff --git a/README.md b/README.md index 551dfa1d6..eebf4fbaf 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ The overall goal is to create an easily self-hostable, decentralized alternative Each Lemmy server can set its own moderation policy; appointing site-wide admins, and community moderators to keep out the trolls, and foster a healthy, non-toxic environment where all can feel comfortable contributing. -*Note: Federation is still in active development and the WebSocket, as well as, HTTP API are currently unstable* +*Note: The WebSocket and HTTP APIs are currently unstable* ### Why's it called Lemmy? diff --git a/ansible/templates/config.hjson b/ansible/templates/config.hjson index 29da81c34..55537ca50 100644 --- a/ansible/templates/config.hjson +++ b/ansible/templates/config.hjson @@ -29,8 +29,9 @@ # https://join.lemmy.ml/docs/en/federation/administration.html#instance-allowlist-and-blocklist # # comma separated list of instances with which federation is allowed - # allowed_instances: "" + # Only one of these blocks should be uncommented + # allowed_instances: ["instance1.tld","instance2.tld"] # comma separated list of instances which are blocked from federating - # blocked_instances: "" + # blocked_instances: [] } } diff --git a/ansible/templates/docker-compose.yml b/ansible/templates/docker-compose.yml index 435fb281d..0ce715c69 100644 --- a/ansible/templates/docker-compose.yml +++ b/ansible/templates/docker-compose.yml @@ -53,6 +53,7 @@ services: volumes: - ./iframely.config.local.js:/iframely/config.local.js:ro restart: always + mem_limit: 200m postfix: image: mwader/postfix-relay diff --git a/api_tests/prepare-drone-federation-test.sh b/api_tests/prepare-drone-federation-test.sh index de9b7b844..dd357db83 100755 --- a/api_tests/prepare-drone-federation-test.sh +++ b/api_tests/prepare-drone-federation-test.sh @@ -1,13 +1,6 @@ #!/bin/bash set -e -export LEMMY_JWT_SECRET=changeme -export LEMMY_FEDERATION__ENABLED=true -export LEMMY_TLS_ENABLED=false -export LEMMY_SETUP__ADMIN_PASSWORD=lemmy -export LEMMY_RATE_LIMIT__POST=99999 -export LEMMY_RATE_LIMIT__REGISTER=99999 -export LEMMY_CAPTCHA__ENABLED=false export LEMMY_TEST_SEND_SYNC=1 export RUST_BACKTRACE=1 @@ -35,52 +28,40 @@ fi killall lemmy_server || true +echo "$PWD" + echo "start alpha" LEMMY_HOSTNAME=lemmy-alpha:8541 \ - LEMMY_PORT=8541 \ + LEMMY_CONFIG_LOCATION=./docker/federation/lemmy_alpha.hjson \ LEMMY_DATABASE_URL="${LEMMY_DATABASE_URL}/lemmy_alpha" \ - LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-beta,lemmy-gamma,lemmy-delta,lemmy-epsilon \ - LEMMY_SETUP__ADMIN_USERNAME=lemmy_alpha \ - LEMMY_SETUP__SITE_NAME=lemmy-alpha \ - target/lemmy_server >/dev/null 2>&1 & + LEMMY_HOSTNAME="lemmy-alpha:8541" \ + target/lemmy_server >/tmp/lemmy_alpha.out 2>&1 & echo "start beta" LEMMY_HOSTNAME=lemmy-beta:8551 \ - LEMMY_PORT=8551 \ + LEMMY_CONFIG_LOCATION=./docker/federation/lemmy_beta.hjson \ LEMMY_DATABASE_URL="${LEMMY_DATABASE_URL}/lemmy_beta" \ - LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-alpha,lemmy-gamma,lemmy-delta,lemmy-epsilon \ - LEMMY_SETUP__ADMIN_USERNAME=lemmy_beta \ - LEMMY_SETUP__SITE_NAME=lemmy-beta \ - target/lemmy_server >/dev/null 2>&1 & + target/lemmy_server >/tmp/lemmy_beta.out 2>&1 & echo "start gamma" LEMMY_HOSTNAME=lemmy-gamma:8561 \ - LEMMY_PORT=8561 \ + LEMMY_CONFIG_LOCATION=./docker/federation/lemmy_gamma.hjson \ LEMMY_DATABASE_URL="${LEMMY_DATABASE_URL}/lemmy_gamma" \ - LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-alpha,lemmy-beta,lemmy-delta,lemmy-epsilon \ - LEMMY_SETUP__ADMIN_USERNAME=lemmy_gamma \ - LEMMY_SETUP__SITE_NAME=lemmy-gamma \ - target/lemmy_server >/dev/null 2>&1 & + target/lemmy_server >/tmp/lemmy_gamma.out 2>&1 & echo "start delta" # An instance with only an allowlist for beta LEMMY_HOSTNAME=lemmy-delta:8571 \ - LEMMY_PORT=8571 \ + LEMMY_CONFIG_LOCATION=./docker/federation/lemmy_delta.hjson \ LEMMY_DATABASE_URL="${LEMMY_DATABASE_URL}/lemmy_delta" \ - LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-beta \ - LEMMY_SETUP__ADMIN_USERNAME=lemmy_delta \ - LEMMY_SETUP__SITE_NAME=lemmy-delta \ - target/lemmy_server >/dev/null 2>&1 & + target/lemmy_server >/tmp/lemmy_delta.out 2>&1 & echo "start epsilon" # An instance who has a blocklist, with lemmy-alpha blocked LEMMY_HOSTNAME=lemmy-epsilon:8581 \ - LEMMY_PORT=8581 \ + LEMMY_CONFIG_LOCATION=./docker/federation/lemmy_epsilon.hjson \ LEMMY_DATABASE_URL="${LEMMY_DATABASE_URL}/lemmy_epsilon" \ - LEMMY_FEDERATION__BLOCKED_INSTANCES=lemmy-alpha \ - LEMMY_SETUP__ADMIN_USERNAME=lemmy_epsilon \ - LEMMY_SETUP__SITE_NAME=lemmy-epsilon \ - target/lemmy_server >/dev/null 2>&1 & + target/lemmy_server >/tmp/lemmy_epsilon.out 2>&1 & echo "wait for all instances to start" while [[ "$(curl -s -o /dev/null -w '%{http_code}' 'localhost:8541/api/v2/site')" != "200" ]]; do sleep 1; done diff --git a/api_tests/run-federation-test.sh b/api_tests/run-federation-test.sh index d624f9c25..ebde0c04d 100755 --- a/api_tests/run-federation-test.sh +++ b/api_tests/run-federation-test.sh @@ -4,7 +4,7 @@ set -e export LEMMY_DATABASE_URL=postgres://lemmy:password@localhost:5432 pushd .. -cargo +1.47.0 build +cargo build rm target/lemmy_server || true cp target/debug/lemmy_server target/lemmy_server ./api_tests/prepare-drone-federation-test.sh diff --git a/config/defaults.hjson b/config/defaults.hjson index 6c6a68fc2..c3eaba6e5 100644 --- a/config/defaults.hjson +++ b/config/defaults.hjson @@ -66,9 +66,10 @@ # https://join.lemmy.ml/docs/en/federation/administration.html#instance-allowlist-and-blocklist # # comma separated list of instances with which federation is allowed - allowed_instances: "" + # Only one of these blocks should be uncommented + # allowed_instances: ["instance1.tld","instance2.tld"] # comma separated list of instances which are blocked from federating - blocked_instances: "" + # blocked_instances: [] } captcha: { enabled: true diff --git a/crates/api/Cargo.toml b/crates/api/Cargo.toml index e3226eb85..ea3cd625c 100644 --- a/crates/api/Cargo.toml +++ b/crates/api/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "lemmy_api" version = "0.1.0" -authors = ["Felix Ableitner "] edition = "2018" [lib] name = "lemmy_api" path = "src/lib.rs" +doctest = false [dependencies] lemmy_apub = { path = "../apub" } @@ -16,7 +16,7 @@ lemmy_db_schema = { path = "../db_schema" } lemmy_db_views = { path = "../db_views" } lemmy_db_views_moderator = { path = "../db_views_moderator" } lemmy_db_views_actor = { path = "../db_views_actor" } -lemmy_structs = { path = "../structs" } +lemmy_api_structs = { path = "../api_structs" } lemmy_websocket = { path = "../websocket" } diesel = "1.4.5" bcrypt = "0.9.0" @@ -32,7 +32,7 @@ rand = "0.8.3" strum = "0.20.0" strum_macros = "0.20.1" lazy_static = "1.4.0" -url = { version = "2.2.0", features = ["serde"] } +url = { version = "2.2.1", features = ["serde"] } openssl = "0.10.32" http = "0.2.3" http-signature-normalization-actix = { version = "0.4.1", default-features = false, features = ["sha-2"] } diff --git a/crates/api/src/comment.rs b/crates/api/src/comment.rs index bd4f33f5e..711e8e725 100644 --- a/crates/api/src/comment.rs +++ b/crates/api/src/comment.rs @@ -3,12 +3,13 @@ use crate::{ check_downvotes_enabled, collect_moderated_communities, get_post, - get_user_from_jwt, - get_user_from_jwt_opt, + get_local_user_view_from_jwt, + get_local_user_view_from_jwt_opt, is_mod_or_admin, Perform, }; use actix_web::web::Data; +use lemmy_api_structs::{blocking, comment::*, send_local_notifs}; use lemmy_apub::{generate_apub_endpoint, ApubLikeableType, ApubObjectType, EndpointType}; use lemmy_db_queries::{ source::comment::Comment_, @@ -24,7 +25,6 @@ use lemmy_db_views::{ comment_report_view::{CommentReportQueryBuilder, CommentReportView}, comment_view::{CommentQueryBuilder, CommentView}, }; -use lemmy_structs::{blocking, comment::*, send_local_notifs}; use lemmy_utils::{ utils::{remove_slurs, scrape_text_for_mentions}, ApiError, @@ -48,7 +48,7 @@ impl Perform for CreateComment { websocket_id: Option, ) -> Result { let data: &CreateComment = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; let content_slurs_removed = remove_slurs(&data.content.to_owned()); @@ -56,7 +56,7 @@ impl Perform for CreateComment { let post_id = data.post_id; let post = get_post(post_id, context.pool()).await?; - check_community_ban(user.id, post.community_id, context.pool()).await?; + check_community_ban(local_user_view.person.id, post.community_id, context.pool()).await?; // Check if post is locked, no new comments if post.locked { @@ -80,7 +80,7 @@ impl Perform for CreateComment { content: content_slurs_removed, parent_id: data.parent_id.to_owned(), post_id: data.post_id, - creator_id: user.id, + creator_id: local_user_view.person.id, removed: None, deleted: None, read: None, @@ -115,7 +115,7 @@ impl Perform for CreateComment { Err(_e) => return Err(ApiError::err("couldnt_create_comment").into()), }; - updated_comment.send_create(&user, context).await?; + updated_comment.send_create(&local_user_view.person, context).await?; // Scan the comment for user mentions, add those rows let post_id = post.id; @@ -123,7 +123,7 @@ impl Perform for CreateComment { let recipient_ids = send_local_notifs( mentions, updated_comment.clone(), - &user, + local_user_view.person.clone(), post, context.pool(), true, @@ -134,7 +134,7 @@ impl Perform for CreateComment { let like_form = CommentLikeForm { comment_id: inserted_comment.id, post_id, - person_id: user.id, + person_id: local_user_view.person.id, score: 1, }; @@ -143,17 +143,17 @@ impl Perform for CreateComment { return Err(ApiError::err("couldnt_like_comment").into()); } - updated_comment.send_like(&user, context).await?; + updated_comment.send_like(&local_user_view.person, context).await?; - let user_id = user.id; + let person_id = local_user_view.person.id; let mut comment_view = blocking(context.pool(), move |conn| { - CommentView::read(&conn, inserted_comment.id, Some(user_id)) + CommentView::read(&conn, inserted_comment.id, Some(person_id)) }) .await??; // If its a comment to yourself, mark it as read let comment_id = comment_view.comment.id; - if user.id == comment_view.get_recipient_id() { + if local_user_view.person.id == comment_view.get_recipient_id() { match blocking(context.pool(), move |conn| { Comment::update_read(conn, comment_id, true) }) @@ -193,7 +193,7 @@ impl Perform for EditComment { websocket_id: Option, ) -> Result { let data: &EditComment = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; let comment_id = data.comment_id; let orig_comment = blocking(context.pool(), move |conn| { @@ -201,10 +201,10 @@ impl Perform for EditComment { }) .await??; - check_community_ban(user.id, orig_comment.community.id, context.pool()).await?; + check_community_ban(local_user_view.person.id, orig_comment.community.id, context.pool()).await?; // Verify that only the creator can edit - if user.id != orig_comment.creator.id { + if local_user_view.person.id != orig_comment.creator.id { return Err(ApiError::err("no_comment_edit_allowed").into()); } @@ -221,7 +221,7 @@ impl Perform for EditComment { }; // Send the apub update - updated_comment.send_update(&user, context).await?; + updated_comment.send_update(&local_user_view.person, context).await?; // Do the mentions / recipients let updated_comment_content = updated_comment.content.to_owned(); @@ -229,7 +229,7 @@ impl Perform for EditComment { let recipient_ids = send_local_notifs( mentions, updated_comment, - &user, + local_user_view.person.clone(), orig_comment.post, context.pool(), false, @@ -237,9 +237,9 @@ impl Perform for EditComment { .await?; let comment_id = data.comment_id; - let user_id = user.id; + let person_id = local_user_view.person.id; let comment_view = blocking(context.pool(), move |conn| { - CommentView::read(conn, comment_id, Some(user_id)) + CommentView::read(conn, comment_id, Some(person_id)) }) .await??; @@ -269,7 +269,7 @@ impl Perform for DeleteComment { websocket_id: Option, ) -> Result { let data: &DeleteComment = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; let comment_id = data.comment_id; let orig_comment = blocking(context.pool(), move |conn| { @@ -277,10 +277,10 @@ impl Perform for DeleteComment { }) .await??; - check_community_ban(user.id, orig_comment.community.id, context.pool()).await?; + check_community_ban(local_user_view.person.id, orig_comment.community.id, context.pool()).await?; // Verify that only the creator can delete - if user.id != orig_comment.creator.id { + if local_user_view.person.id != orig_comment.creator.id { return Err(ApiError::err("no_comment_edit_allowed").into()); } @@ -297,16 +297,16 @@ impl Perform for DeleteComment { // Send the apub message if deleted { - updated_comment.send_delete(&user, context).await?; + updated_comment.send_delete(&local_user_view.person, context).await?; } else { - updated_comment.send_undo_delete(&user, context).await?; + updated_comment.send_undo_delete(&local_user_view.person, context).await?; } // Refetch it let comment_id = data.comment_id; - let user_id = user.id; + let person_id = local_user_view.person.id; let comment_view = blocking(context.pool(), move |conn| { - CommentView::read(conn, comment_id, Some(user_id)) + CommentView::read(conn, comment_id, Some(person_id)) }) .await??; @@ -316,7 +316,7 @@ impl Perform for DeleteComment { let recipient_ids = send_local_notifs( mentions, updated_comment, - &user, + local_user_view.person.clone(), comment_view_2.post, context.pool(), false, @@ -349,7 +349,7 @@ impl Perform for RemoveComment { websocket_id: Option, ) -> Result { let data: &RemoveComment = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; let comment_id = data.comment_id; let orig_comment = blocking(context.pool(), move |conn| { @@ -357,10 +357,10 @@ impl Perform for RemoveComment { }) .await??; - check_community_ban(user.id, orig_comment.community.id, context.pool()).await?; + check_community_ban(local_user_view.person.id, orig_comment.community.id, context.pool()).await?; // Verify that only a mod or admin can remove - is_mod_or_admin(context.pool(), user.id, orig_comment.community.id).await?; + is_mod_or_admin(context.pool(), local_user_view.person.id, orig_comment.community.id).await?; // Do the remove let removed = data.removed; @@ -375,7 +375,7 @@ impl Perform for RemoveComment { // Mod tables let form = ModRemoveCommentForm { - mod_person_id: user.id, + mod_person_id: local_user_view.person.id, comment_id: data.comment_id, removed: Some(removed), reason: data.reason.to_owned(), @@ -387,16 +387,16 @@ impl Perform for RemoveComment { // Send the apub message if removed { - updated_comment.send_remove(&user, context).await?; + updated_comment.send_remove(&local_user_view.person, context).await?; } else { - updated_comment.send_undo_remove(&user, context).await?; + updated_comment.send_undo_remove(&local_user_view.person, context).await?; } // Refetch it let comment_id = data.comment_id; - let user_id = user.id; + let person_id = local_user_view.person.id; let comment_view = blocking(context.pool(), move |conn| { - CommentView::read(conn, comment_id, Some(user_id)) + CommentView::read(conn, comment_id, Some(person_id)) }) .await??; @@ -407,7 +407,7 @@ impl Perform for RemoveComment { let recipient_ids = send_local_notifs( mentions, updated_comment, - &user, + local_user_view.person.clone(), comment_view_2.post, context.pool(), false, @@ -440,7 +440,7 @@ impl Perform for MarkCommentAsRead { _websocket_id: Option, ) -> Result { let data: &MarkCommentAsRead = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; let comment_id = data.comment_id; let orig_comment = blocking(context.pool(), move |conn| { @@ -448,10 +448,10 @@ impl Perform for MarkCommentAsRead { }) .await??; - check_community_ban(user.id, orig_comment.community.id, context.pool()).await?; + check_community_ban(local_user_view.person.id, orig_comment.community.id, context.pool()).await?; // Verify that only the recipient can mark as read - if user.id != orig_comment.get_recipient_id() { + if local_user_view.person.id != orig_comment.get_recipient_id() { return Err(ApiError::err("no_comment_edit_allowed").into()); } @@ -468,9 +468,9 @@ impl Perform for MarkCommentAsRead { // Refetch it let comment_id = data.comment_id; - let user_id = user.id; + let person_id = local_user_view.person.id; let comment_view = blocking(context.pool(), move |conn| { - CommentView::read(conn, comment_id, Some(user_id)) + CommentView::read(conn, comment_id, Some(person_id)) }) .await??; @@ -494,11 +494,11 @@ impl Perform for SaveComment { _websocket_id: Option, ) -> Result { let data: &SaveComment = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; let comment_saved_form = CommentSavedForm { comment_id: data.comment_id, - person_id: user.id, + person_id: local_user_view.person.id, }; if data.save { @@ -514,9 +514,9 @@ impl Perform for SaveComment { } let comment_id = data.comment_id; - let user_id = user.id; + let person_id = local_user_view.person.id; let comment_view = blocking(context.pool(), move |conn| { - CommentView::read(conn, comment_id, Some(user_id)) + CommentView::read(conn, comment_id, Some(person_id)) }) .await??; @@ -538,7 +538,7 @@ impl Perform for CreateCommentLike { websocket_id: Option, ) -> Result { let data: &CreateCommentLike = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; let mut recipient_ids = Vec::new(); @@ -551,7 +551,7 @@ impl Perform for CreateCommentLike { }) .await??; - check_community_ban(user.id, orig_comment.community.id, context.pool()).await?; + check_community_ban(local_user_view.person.id, orig_comment.community.id, context.pool()).await?; // Add parent user to recipients recipient_ids.push(orig_comment.get_recipient_id()); @@ -559,14 +559,14 @@ impl Perform for CreateCommentLike { let like_form = CommentLikeForm { comment_id: data.comment_id, post_id: orig_comment.post.id, - person_id: user.id, + person_id: local_user_view.person.id, score: data.score, }; // Remove any likes first - let user_id = user.id; + let person_id = local_user_view.person.id; blocking(context.pool(), move |conn| { - CommentLike::remove(conn, user_id, comment_id) + CommentLike::remove(conn, person_id, comment_id) }) .await??; @@ -581,19 +581,19 @@ impl Perform for CreateCommentLike { } if like_form.score == 1 { - comment.send_like(&user, context).await?; + comment.send_like(&local_user_view.person, context).await?; } else if like_form.score == -1 { - comment.send_dislike(&user, context).await?; + comment.send_dislike(&local_user_view.person, context).await?; } } else { - comment.send_undo_like(&user, context).await?; + comment.send_undo_like(&local_user_view.person, context).await?; } // Have to refetch the comment to get the current state let comment_id = data.comment_id; - let user_id = user.id; + let person_id = local_user_view.person.id; let liked_comment = blocking(context.pool(), move |conn| { - CommentView::read(conn, comment_id, Some(user_id)) + CommentView::read(conn, comment_id, Some(person_id)) }) .await??; @@ -623,8 +623,8 @@ impl Perform for GetComments { _websocket_id: Option, ) -> Result { let data: &GetComments = &self; - let user = get_user_from_jwt_opt(&data.auth, context.pool()).await?; - let user_id = user.map(|u| u.id); + let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?; + let person_id = local_user_view.map(|u| u.person.id); let type_ = ListingType::from_str(&data.type_)?; let sort = SortType::from_str(&data.sort)?; @@ -639,7 +639,7 @@ impl Perform for GetComments { .sort(&sort) .community_id(community_id) .community_name(community_name) - .my_user_id(user_id) + .my_person_id(person_id) .page(page) .limit(limit) .list() @@ -665,7 +665,7 @@ impl Perform for CreateCommentReport { websocket_id: Option, ) -> Result { let data: &CreateCommentReport = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; // check size of report and check for whitespace let reason = data.reason.trim(); @@ -676,17 +676,17 @@ impl Perform for CreateCommentReport { return Err(ApiError::err("report_too_long").into()); } - let user_id = user.id; + let person_id = local_user_view.person.id; let comment_id = data.comment_id; let comment_view = blocking(context.pool(), move |conn| { CommentView::read(&conn, comment_id, None) }) .await??; - check_community_ban(user_id, comment_view.community.id, context.pool()).await?; + check_community_ban(person_id, comment_view.community.id, context.pool()).await?; let report_form = CommentReportForm { - creator_id: user_id, + creator_id: person_id, comment_id, original_comment_text: comment_view.comment.content, reason: data.reason.to_owned(), @@ -706,7 +706,7 @@ impl Perform for CreateCommentReport { context.chat_server().do_send(SendUserRoomMessage { op: UserOperation::CreateCommentReport, response: res.clone(), - recipient_id: user.id, + recipient_id: local_user_view.person.id, websocket_id, }); @@ -732,7 +732,7 @@ impl Perform for ResolveCommentReport { websocket_id: Option, ) -> Result { let data: &ResolveCommentReport = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; let report_id = data.report_id; let report = blocking(context.pool(), move |conn| { @@ -740,15 +740,15 @@ impl Perform for ResolveCommentReport { }) .await??; - let user_id = user.id; - is_mod_or_admin(context.pool(), user_id, report.community.id).await?; + let person_id = local_user_view.person.id; + is_mod_or_admin(context.pool(), person_id, report.community.id).await?; let resolved = data.resolved; let resolve_fun = move |conn: &'_ _| { if resolved { - CommentReport::resolve(conn, report_id, user_id) + CommentReport::resolve(conn, report_id, person_id) } else { - CommentReport::unresolve(conn, report_id, user_id) + CommentReport::unresolve(conn, report_id, person_id) } }; @@ -785,12 +785,12 @@ impl Perform for ListCommentReports { websocket_id: Option, ) -> Result { let data: &ListCommentReports = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; - let user_id = user.id; + let person_id = local_user_view.person.id; let community_id = data.community; let community_ids = - collect_moderated_communities(user_id, community_id, context.pool()).await?; + collect_moderated_communities(person_id, community_id, context.pool()).await?; let page = data.page; let limit = data.limit; @@ -808,7 +808,7 @@ impl Perform for ListCommentReports { context.chat_server().do_send(SendUserRoomMessage { op: UserOperation::ListCommentReports, response: res.clone(), - recipient_id: user.id, + recipient_id: local_user_view.person.id, websocket_id, }); diff --git a/crates/api/src/community.rs b/crates/api/src/community.rs index 40dc345ec..6949a4a99 100644 --- a/crates/api/src/community.rs +++ b/crates/api/src/community.rs @@ -1,14 +1,14 @@ use crate::{ check_community_ban, - check_optional_url, - get_user_from_jwt, - get_user_from_jwt_opt, + get_local_user_view_from_jwt, + get_local_user_view_from_jwt_opt, is_admin, is_mod_or_admin, Perform, }; use actix_web::web::Data; use anyhow::Context; +use lemmy_api_structs::{blocking, community::*}; use lemmy_apub::{ generate_apub_endpoint, generate_followers_url, @@ -18,7 +18,7 @@ use lemmy_apub::{ EndpointType, }; use lemmy_db_queries::{ - diesel_option_overwrite, + diesel_option_overwrite_to_url, source::{ comment::Comment_, community::{CommunityModerator_, Community_}, @@ -41,9 +41,8 @@ use lemmy_db_views_actor::{ community_follower_view::CommunityFollowerView, community_moderator_view::CommunityModeratorView, community_view::{CommunityQueryBuilder, CommunityView}, - user_view::UserViewSafe, + person_view::PersonViewSafe, }; -use lemmy_structs::{blocking, community::*}; use lemmy_utils::{ apub::generate_actor_keypair, location_info, @@ -69,8 +68,8 @@ impl Perform for GetCommunity { _websocket_id: Option, ) -> Result { let data: &GetCommunity = &self; - let user = get_user_from_jwt_opt(&data.auth, context.pool()).await?; - let user_id = user.map(|u| u.id); + let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?; + let person_id = local_user_view.map(|u| u.person.id); let community_id = match data.id { Some(id) => id, @@ -89,7 +88,7 @@ impl Perform for GetCommunity { }; let community_view = match blocking(context.pool(), move |conn| { - CommunityView::read(conn, community_id, user_id) + CommunityView::read(conn, community_id, person_id) }) .await? { @@ -133,7 +132,7 @@ impl Perform for CreateCommunity { _websocket_id: Option, ) -> Result { let data: &CreateCommunity = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; check_slurs(&data.name)?; check_slurs(&data.title)?; @@ -155,11 +154,8 @@ impl Perform for CreateCommunity { } // Check to make sure the icon and banners are urls - let icon = diesel_option_overwrite(&data.icon); - let banner = diesel_option_overwrite(&data.banner); - - check_optional_url(&icon)?; - check_optional_url(&banner)?; + let icon = diesel_option_overwrite_to_url(&data.icon)?; + let banner = diesel_option_overwrite_to_url(&data.banner)?; // When you create a community, make sure the user becomes a moderator and a follower let keypair = generate_actor_keypair()?; @@ -170,7 +166,7 @@ impl Perform for CreateCommunity { description: data.description.to_owned(), icon, banner, - creator_id: user.id, + creator_id: local_user_view.person.id, removed: None, deleted: None, nsfw: data.nsfw, @@ -198,7 +194,7 @@ impl Perform for CreateCommunity { // The community creator becomes a moderator let community_moderator_form = CommunityModeratorForm { community_id: inserted_community.id, - person_id: user.id, + person_id: local_user_view.person.id, }; let join = move |conn: &'_ _| CommunityModerator::join(conn, &community_moderator_form); @@ -209,7 +205,7 @@ impl Perform for CreateCommunity { // Follow your own community let community_follower_form = CommunityFollowerForm { community_id: inserted_community.id, - person_id: user.id, + person_id: local_user_view.person.id, pending: false, }; @@ -218,9 +214,9 @@ impl Perform for CreateCommunity { return Err(ApiError::err("community_follower_already_exists").into()); } - let user_id = user.id; + let person_id = local_user_view.person.id; let community_view = blocking(context.pool(), move |conn| { - CommunityView::read(conn, inserted_community.id, Some(user_id)) + CommunityView::read(conn, inserted_community.id, Some(person_id)) }) .await??; @@ -238,7 +234,7 @@ impl Perform for EditCommunity { websocket_id: Option, ) -> Result { let data: &EditCommunity = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; check_slurs(&data.title)?; check_slurs_opt(&data.description)?; @@ -250,7 +246,7 @@ impl Perform for EditCommunity { .map(|v| v.into_iter().map(|m| m.moderator.id).collect()) }) .await??; - if !mods.contains(&user.id) { + if !mods.contains(&local_user_view.person.id) { return Err(ApiError::err("not_a_moderator").into()); } @@ -260,11 +256,8 @@ impl Perform for EditCommunity { }) .await??; - let icon = diesel_option_overwrite(&data.icon); - let banner = diesel_option_overwrite(&data.banner); - - check_optional_url(&icon)?; - check_optional_url(&banner)?; + let icon = diesel_option_overwrite_to_url(&data.icon)?; + let banner = diesel_option_overwrite_to_url(&data.banner)?; let community_form = CommunityForm { name: read_community.name, @@ -302,9 +295,9 @@ impl Perform for EditCommunity { // process for communities and users let community_id = data.community_id; - let user_id = user.id; + let person_id = local_user_view.person.id; let community_view = blocking(context.pool(), move |conn| { - CommunityView::read(conn, community_id, Some(user_id)) + CommunityView::read(conn, community_id, Some(person_id)) }) .await??; @@ -326,7 +319,7 @@ impl Perform for DeleteCommunity { websocket_id: Option, ) -> Result { let data: &DeleteCommunity = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; // Verify its the creator (only a creator can delete the community) let community_id = data.community_id; @@ -334,7 +327,7 @@ impl Perform for DeleteCommunity { Community::read(conn, community_id) }) .await??; - if read_community.creator_id != user.id { + if read_community.creator_id != local_user_view.person.id { return Err(ApiError::err("no_community_edit_allowed").into()); } @@ -358,9 +351,9 @@ impl Perform for DeleteCommunity { } let community_id = data.community_id; - let user_id = user.id; + let person_id = local_user_view.person.id; let community_view = blocking(context.pool(), move |conn| { - CommunityView::read(conn, community_id, Some(user_id)) + CommunityView::read(conn, community_id, Some(person_id)) }) .await??; @@ -382,10 +375,10 @@ impl Perform for RemoveCommunity { websocket_id: Option, ) -> Result { let data: &RemoveCommunity = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; // Verify its an admin (only an admin can remove a community) - is_admin(context.pool(), user.id).await?; + is_admin(&local_user_view)?; // Do the remove let community_id = data.community_id; @@ -405,7 +398,7 @@ impl Perform for RemoveCommunity { None => None, }; let form = ModRemoveCommunityForm { - mod_person_id: user.id, + mod_person_id: local_user_view.person.id, community_id: data.community_id, removed: Some(removed), reason: data.reason.to_owned(), @@ -424,9 +417,9 @@ impl Perform for RemoveCommunity { } let community_id = data.community_id; - let user_id = user.id; + let person_id = local_user_view.person.id; let community_view = blocking(context.pool(), move |conn| { - CommunityView::read(conn, community_id, Some(user_id)) + CommunityView::read(conn, community_id, Some(person_id)) }) .await??; @@ -448,15 +441,16 @@ impl Perform for ListCommunities { _websocket_id: Option, ) -> Result { let data: &ListCommunities = &self; - let user = get_user_from_jwt_opt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?; - let user_id = match &user { - Some(user) => Some(user.id), + let person_id = match &local_user_view { + Some(uv) => Some(uv.person.id), None => None, }; - let show_nsfw = match &user { - Some(user) => user.show_nsfw, + // Don't show NSFW by default + let show_nsfw = match &local_user_view { + Some(uv) => uv.local_user.show_nsfw, None => false, }; @@ -470,7 +464,7 @@ impl Perform for ListCommunities { .listing_type(&type_) .sort(&sort) .show_nsfw(show_nsfw) - .my_user_id(user_id) + .my_person_id(person_id) .page(page) .limit(limit) .list() @@ -492,7 +486,7 @@ impl Perform for FollowCommunity { _websocket_id: Option, ) -> Result { let data: &FollowCommunity = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; let community_id = data.community_id; let community = blocking(context.pool(), move |conn| { @@ -501,13 +495,13 @@ impl Perform for FollowCommunity { .await??; let community_follower_form = CommunityFollowerForm { community_id: data.community_id, - person_id: user.id, + person_id: local_user_view.person.id, pending: false, }; if community.local { if data.follow { - check_community_ban(user.id, community_id, context.pool()).await?; + check_community_ban(local_user_view.person.id, community_id, context.pool()).await?; let follow = move |conn: &'_ _| CommunityFollower::follow(conn, &community_follower_form); if blocking(context.pool(), follow).await?.is_err() { @@ -523,9 +517,9 @@ impl Perform for FollowCommunity { } else if data.follow { // Dont actually add to the community followers here, because you need // to wait for the accept - user.send_follow(&community.actor_id(), context).await?; + local_user_view.person.send_follow(&community.actor_id(), context).await?; } else { - user.send_unfollow(&community.actor_id(), context).await?; + local_user_view.person.send_unfollow(&community.actor_id(), context).await?; let unfollow = move |conn: &'_ _| CommunityFollower::unfollow(conn, &community_follower_form); if blocking(context.pool(), unfollow).await?.is_err() { return Err(ApiError::err("community_follower_already_exists").into()); @@ -533,9 +527,9 @@ impl Perform for FollowCommunity { } let community_id = data.community_id; - let user_id = user.id; + let person_id = local_user_view.person.id; let mut community_view = blocking(context.pool(), move |conn| { - CommunityView::read(conn, community_id, Some(user_id)) + CommunityView::read(conn, community_id, Some(person_id)) }) .await??; @@ -560,11 +554,11 @@ impl Perform for GetFollowedCommunities { _websocket_id: Option, ) -> Result { let data: &GetFollowedCommunities = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; - let user_id = user.id; + let person_id = local_user_view.person.id; let communities = match blocking(context.pool(), move |conn| { - CommunityFollowerView::for_user(conn, user_id) + CommunityFollowerView::for_person(conn, person_id) }) .await? { @@ -587,17 +581,17 @@ impl Perform for BanFromCommunity { websocket_id: Option, ) -> Result { let data: &BanFromCommunity = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; let community_id = data.community_id; - let banned_user_id = data.user_id; + let banned_person_id = data.person_id; // Verify that only mods or admins can ban - is_mod_or_admin(context.pool(), user.id, community_id).await?; + is_mod_or_admin(context.pool(), local_user_view.person.id, community_id).await?; let community_user_ban_form = CommunityPersonBanForm { community_id: data.community_id, - person_id: data.user_id, + person_id: data.person_id, }; if data.ban { @@ -609,7 +603,7 @@ impl Perform for BanFromCommunity { // Also unsubscribe them from the community, if they are subscribed let community_follower_form = CommunityFollowerForm { community_id: data.community_id, - person_id: banned_user_id, + person_id: banned_person_id, pending: false, }; blocking(context.pool(), move |conn: &'_ _| { @@ -628,7 +622,7 @@ impl Perform for BanFromCommunity { if data.remove_data { // Posts blocking(context.pool(), move |conn: &'_ _| { - Post::update_removed_for_creator(conn, banned_user_id, Some(community_id), true) + Post::update_removed_for_creator(conn, banned_person_id, Some(community_id), true) }) .await??; @@ -636,7 +630,7 @@ impl Perform for BanFromCommunity { // TODO Diesel doesn't allow updates with joins, so this has to be a loop let comments = blocking(context.pool(), move |conn| { CommentQueryBuilder::create(conn) - .creator_id(banned_user_id) + .creator_id(banned_person_id) .community_id(community_id) .limit(std::i64::MAX) .list() @@ -660,8 +654,8 @@ impl Perform for BanFromCommunity { }; let form = ModBanFromCommunityForm { - mod_person_id: user.id, - other_person_id: data.user_id, + mod_person_id: local_user_view.person.id, + other_person_id: data.person_id, community_id: data.community_id, reason: data.reason.to_owned(), banned: Some(data.ban), @@ -672,14 +666,14 @@ impl Perform for BanFromCommunity { }) .await??; - let user_id = data.user_id; - let user_view = blocking(context.pool(), move |conn| { - UserViewSafe::read(conn, user_id) + let person_id = data.person_id; + let person_view = blocking(context.pool(), move |conn| { + PersonViewSafe::read(conn, person_id) }) .await??; let res = BanFromCommunityResponse { - user_view, + person_view, banned: data.ban, }; @@ -704,17 +698,17 @@ impl Perform for AddModToCommunity { websocket_id: Option, ) -> Result { let data: &AddModToCommunity = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; let community_moderator_form = CommunityModeratorForm { community_id: data.community_id, - person_id: data.user_id, + person_id: data.person_id, }; let community_id = data.community_id; // Verify that only mods or admins can add mod - is_mod_or_admin(context.pool(), user.id, community_id).await?; + is_mod_or_admin(context.pool(), local_user_view.person.id, community_id).await?; if data.added { let join = move |conn: &'_ _| CommunityModerator::join(conn, &community_moderator_form); @@ -730,8 +724,8 @@ impl Perform for AddModToCommunity { // Mod tables let form = ModAddCommunityForm { - mod_person_id: user.id, - other_person_id: data.user_id, + mod_person_id: local_user_view.person.id, + other_person_id: data.person_id, community_id: data.community_id, removed: Some(!data.added), }; @@ -769,7 +763,7 @@ impl Perform for TransferCommunity { _websocket_id: Option, ) -> Result { let data: &TransferCommunity = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; let community_id = data.community_id; let read_community = blocking(context.pool(), move |conn| { @@ -782,25 +776,25 @@ impl Perform for TransferCommunity { }) .await??; - let mut admins = blocking(context.pool(), move |conn| UserViewSafe::admins(conn)).await??; + let mut admins = blocking(context.pool(), move |conn| PersonViewSafe::admins(conn)).await??; // Making sure the creator, if an admin, is at the top let creator_index = admins .iter() - .position(|r| r.user.id == site_creator_id) + .position(|r| r.person.id == site_creator_id) .context(location_info!())?; - let creator_user = admins.remove(creator_index); - admins.insert(0, creator_user); + let creator_person = admins.remove(creator_index); + admins.insert(0, creator_person); // Make sure user is the creator, or an admin - if user.id != read_community.creator_id - && !admins.iter().map(|a| a.user.id).any(|x| x == user.id) + if local_user_view.person.id != read_community.creator_id + && !admins.iter().map(|a| a.person.id).any(|x| x == local_user_view.person.id) { return Err(ApiError::err("not_an_admin").into()); } let community_id = data.community_id; - let new_creator = data.user_id; + let new_creator = data.person_id; let update = move |conn: &'_ _| Community::update_creator(conn, community_id, new_creator); if blocking(context.pool(), update).await?.is_err() { return Err(ApiError::err("couldnt_update_community").into()); @@ -814,10 +808,10 @@ impl Perform for TransferCommunity { .await??; let creator_index = community_mods .iter() - .position(|r| r.moderator.id == data.user_id) + .position(|r| r.moderator.id == data.person_id) .context(location_info!())?; - let creator_user = community_mods.remove(creator_index); - community_mods.insert(0, creator_user); + let creator_person = community_mods.remove(creator_index); + community_mods.insert(0, creator_person); let community_id = data.community_id; blocking(context.pool(), move |conn| { @@ -840,8 +834,8 @@ impl Perform for TransferCommunity { // Mod tables let form = ModAddCommunityForm { - mod_person_id: user.id, - other_person_id: data.user_id, + mod_person_id: local_user_view.person.id, + other_person_id: data.person_id, community_id: data.community_id, removed: Some(false), }; @@ -851,9 +845,9 @@ impl Perform for TransferCommunity { .await??; let community_id = data.community_id; - let user_id = user.id; + let person_id = local_user_view.person.id; let community_view = match blocking(context.pool(), move |conn| { - CommunityView::read(conn, community_id, Some(user_id)) + CommunityView::read(conn, community_id, Some(person_id)) }) .await? { @@ -886,7 +880,7 @@ fn send_community_websocket( websocket_id: Option, op: UserOperation, ) { - // Strip out the user id and subscribed when sending to others + // Strip out the person id and subscribed when sending to others let mut res_sent = res.clone(); res_sent.community_view.subscribed = false; diff --git a/crates/api/src/lib.rs b/crates/api/src/lib.rs index ab0bc8ac1..3fe3bc7ab 100644 --- a/crates/api/src/lib.rs +++ b/crates/api/src/lib.rs @@ -1,9 +1,19 @@ use actix_web::{web, web::Data}; +use lemmy_api_structs::{ + blocking, + comment::*, + community::*, + post::*, + site::*, + person::*, + websocket::*, +}; use lemmy_db_queries::{ source::{ community::{CommunityModerator_, Community_}, site::Site_, - user::UserSafeSettings_, + local_user::LocalUserSettings_, + local_user::LocalUser_, }, Crud, DbPool, @@ -12,14 +22,22 @@ use lemmy_db_schema::source::{ community::{Community, CommunityModerator}, post::Post, site::Site, - user::{UserSafeSettings, User_}, + person::{Person, PersonSafe}, + local_user::LocalUserSettings, + local_user::LocalUser, }; use lemmy_db_views_actor::{ - community_user_ban_view::CommunityUserBanView, + community_person_ban_view::CommunityPersonBanView, community_view::CommunityView, }; -use lemmy_structs::{blocking, comment::*, community::*, post::*, site::*, user::*, websocket::*}; -use lemmy_utils::{claims::Claims, settings::Settings, ApiError, ConnectionId, LemmyError}; +use lemmy_db_views::local_user_view::{LocalUserView, LocalUserSettingsView}; +use lemmy_utils::{ + claims::Claims, + settings::structs::Settings, + ApiError, + ConnectionId, + LemmyError, +}; use lemmy_websocket::{serialize_websocket_message, LemmyContext, UserOperation}; use serde::Deserialize; use std::process::Command; @@ -46,11 +64,11 @@ pub trait Perform { pub(crate) async fn is_mod_or_admin( pool: &DbPool, - user_id: i32, + person_id: i32, community_id: i32, ) -> Result<(), LemmyError> { let is_mod_or_admin = blocking(pool, move |conn| { - CommunityView::is_mod_or_admin(conn, user_id, community_id) + CommunityView::is_mod_or_admin(conn, person_id, community_id) }) .await?; if !is_mod_or_admin { @@ -58,9 +76,18 @@ pub(crate) async fn is_mod_or_admin( } Ok(()) } -pub async fn is_admin(pool: &DbPool, user_id: i32) -> Result<(), LemmyError> { - let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??; - if !user.admin { + +// TODO this probably isn't necessary anymore +// pub async fn is_admin(pool: &DbPool, person_id: i32) -> Result<(), LemmyError> { +// let user = blocking(pool, move |conn| LocalUser::read(conn, person_id)).await??; +// if !user.admin { +// return Err(ApiError::err("not_an_admin").into()); +// } +// Ok(()) +// } + +pub fn is_admin(local_user_view: &LocalUserView) -> Result<(), LemmyError> { + if !local_user_view.local_user.admin { return Err(ApiError::err("not_an_admin").into()); } Ok(()) @@ -73,63 +100,60 @@ pub(crate) async fn get_post(post_id: i32, pool: &DbPool) -> Result Result { +pub(crate) async fn get_local_user_view_from_jwt(jwt: &str, pool: &DbPool) -> Result { let claims = match Claims::decode(&jwt) { Ok(claims) => claims.claims, Err(_e) => return Err(ApiError::err("not_logged_in").into()), }; - let user_id = claims.id; - let user = blocking(pool, move |conn| User_::read(conn, user_id)).await??; + let person_id = claims.id; + let local_user_view = blocking(pool, move |conn| LocalUserView::read(conn, person_id)).await??; // Check for a site ban - if user.banned { + if local_user_view.person.banned { return Err(ApiError::err("site_ban").into()); } - Ok(user) + Ok(local_user_view) } -pub(crate) async fn get_user_from_jwt_opt( +pub(crate) async fn get_local_user_view_from_jwt_opt( jwt: &Option, pool: &DbPool, -) -> Result, LemmyError> { +) -> Result, LemmyError> { match jwt { - Some(jwt) => Ok(Some(get_user_from_jwt(jwt, pool).await?)), + Some(jwt) => Ok(Some(get_local_user_view_from_jwt(jwt, pool).await?)), None => Ok(None), } } -pub(crate) async fn get_user_safe_settings_from_jwt( - jwt: &str, - pool: &DbPool, -) -> Result { +pub(crate) async fn get_local_user_settings_view_from_jwt(jwt: &str, pool: &DbPool) -> Result { let claims = match Claims::decode(&jwt) { Ok(claims) => claims.claims, Err(_e) => return Err(ApiError::err("not_logged_in").into()), }; - let user_id = claims.id; - let user = blocking(pool, move |conn| UserSafeSettings::read(conn, user_id)).await??; + let person_id = claims.id; + let local_user_view = blocking(pool, move |conn| LocalUserSettingsView::read(conn, person_id)).await??; // Check for a site ban - if user.banned { + if local_user_view.person.banned { return Err(ApiError::err("site_ban").into()); } - Ok(user) + Ok(local_user_view) } -pub(crate) async fn get_user_safe_settings_from_jwt_opt( +pub(crate) async fn get_local_user_settings_view_from_jwt_opt( jwt: &Option, pool: &DbPool, -) -> Result, LemmyError> { +) -> Result, LemmyError> { match jwt { - Some(jwt) => Ok(Some(get_user_safe_settings_from_jwt(jwt, pool).await?)), + Some(jwt) => Ok(Some(get_local_user_settings_view_from_jwt(jwt, pool).await?)), None => Ok(None), } } pub(crate) async fn check_community_ban( - user_id: i32, + person_id: i32, community_id: i32, pool: &DbPool, ) -> Result<(), LemmyError> { - let is_banned = move |conn: &'_ _| CommunityUserBanView::get(conn, user_id, community_id).is_ok(); + let is_banned = move |conn: &'_ _| CommunityPersonBanView::get(conn, person_id, community_id).is_ok(); if blocking(pool, is_banned).await? { Err(ApiError::err("community_ban").into()) } else { @@ -172,19 +196,10 @@ pub(crate) async fn collect_moderated_communities( } } -pub(crate) fn check_optional_url(item: &Option>) -> Result<(), LemmyError> { - if let Some(Some(item)) = &item { - if Url::parse(item).is_err() { - return Err(ApiError::err("invalid_url").into()); - } - } - Ok(()) -} - pub(crate) async fn build_federated_instances( pool: &DbPool, ) -> Result, LemmyError> { - if Settings::get().federation.enabled { + if Settings::get().federation().enabled { let distinct_communities = blocking(pool, move |conn| { Community::distinct_federated_communities(conn) }) @@ -198,8 +213,13 @@ pub(crate) async fn build_federated_instances( .map(|actor_id| Ok(Url::parse(actor_id)?.host_str().unwrap_or("").to_string())) .collect::, LemmyError>>()?; - linked.extend_from_slice(&allowed); - linked.retain(|a| !blocked.contains(a) && !a.eq("") && !a.eq(&Settings::get().hostname)); + if let Some(allowed) = allowed.as_ref() { + linked.extend_from_slice(allowed); + } + + if let Some(blocked) = blocked.as_ref() { + linked.retain(|a| !blocked.contains(a) && !a.eq(&Settings::get().hostname())); + } // Sort and remove dupes linked.sort_unstable(); @@ -226,17 +246,17 @@ pub async fn match_websocket_operation( UserOperation::Login => do_websocket_operation::(context, id, op, data).await, UserOperation::Register => do_websocket_operation::(context, id, op, data).await, UserOperation::GetCaptcha => do_websocket_operation::(context, id, op, data).await, - UserOperation::GetUserDetails => { - do_websocket_operation::(context, id, op, data).await + UserOperation::GetPersonDetails => { + do_websocket_operation::(context, id, op, data).await } UserOperation::GetReplies => do_websocket_operation::(context, id, op, data).await, UserOperation::AddAdmin => do_websocket_operation::(context, id, op, data).await, - UserOperation::BanUser => do_websocket_operation::(context, id, op, data).await, - UserOperation::GetUserMentions => { - do_websocket_operation::(context, id, op, data).await + UserOperation::BanPerson => do_websocket_operation::(context, id, op, data).await, + UserOperation::GetPersonMentions => { + do_websocket_operation::(context, id, op, data).await } - UserOperation::MarkUserMentionAsRead => { - do_websocket_operation::(context, id, op, data).await + UserOperation::MarkPersonMentionAsRead => { + do_websocket_operation::(context, id, op, data).await } UserOperation::MarkAllAsRead => { do_websocket_operation::(context, id, op, data).await @@ -455,6 +475,15 @@ pub(crate) fn espeak_wav_base64(text: &str) -> Result { Ok(base64) } +/// Checks the password length +pub(crate) fn password_length_check(pass: &str) -> Result<(), LemmyError> { + if pass.len() > 60 { + Err(ApiError::err("invalid_password").into()) + } else { + Ok(()) + } +} + #[cfg(test)] mod tests { use crate::captcha_espeak_wav_base64; diff --git a/crates/api/src/post.rs b/crates/api/src/post.rs index 33983a4e1..922261715 100644 --- a/crates/api/src/post.rs +++ b/crates/api/src/post.rs @@ -1,14 +1,14 @@ use crate::{ check_community_ban, check_downvotes_enabled, - check_optional_url, collect_moderated_communities, - get_user_from_jwt, - get_user_from_jwt_opt, + get_local_user_view_from_jwt, + get_local_user_view_from_jwt_opt, is_mod_or_admin, Perform, }; use actix_web::web::Data; +use lemmy_api_structs::{blocking, post::*}; use lemmy_apub::{generate_apub_endpoint, ApubLikeableType, ApubObjectType, EndpointType}; use lemmy_db_queries::{ source::post::Post_, @@ -36,7 +36,6 @@ use lemmy_db_views_actor::{ community_moderator_view::CommunityModeratorView, community_view::CommunityView, }; -use lemmy_structs::{blocking, post::*}; use lemmy_utils::{ request::fetch_iframely_and_pictrs_data, utils::{check_slurs, check_slurs_opt, is_valid_post_title}, @@ -61,7 +60,7 @@ impl Perform for CreatePost { websocket_id: Option, ) -> Result { let data: &CreatePost = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; check_slurs(&data.name)?; check_slurs_opt(&data.body)?; @@ -70,20 +69,19 @@ impl Perform for CreatePost { return Err(ApiError::err("invalid_post_title").into()); } - check_community_ban(user.id, data.community_id, context.pool()).await?; - - check_optional_url(&Some(data.url.to_owned()))?; + check_community_ban(local_user_view.person.id, data.community_id, context.pool()).await?; // Fetch Iframely and pictrs cached image + let data_url = data.url.as_ref(); let (iframely_title, iframely_description, iframely_html, pictrs_thumbnail) = - fetch_iframely_and_pictrs_data(context.client(), data.url.to_owned()).await; + fetch_iframely_and_pictrs_data(context.client(), data_url).await; let post_form = PostForm { name: data.name.trim().to_owned(), - url: data.url.to_owned(), + url: data_url.map(|u| u.to_owned().into()), body: data.body.to_owned(), community_id: data.community_id, - creator_id: user.id, + creator_id: local_user_view.person.id, removed: None, deleted: None, nsfw: data.nsfw, @@ -93,7 +91,7 @@ impl Perform for CreatePost { embed_title: iframely_title, embed_description: iframely_description, embed_html: iframely_html, - thumbnail_url: pictrs_thumbnail, + thumbnail_url: pictrs_thumbnail.map(|u| u.into()), ap_id: None, local: true, published: None, @@ -124,12 +122,12 @@ impl Perform for CreatePost { Err(_e) => return Err(ApiError::err("couldnt_create_post").into()), }; - updated_post.send_create(&user, context).await?; + updated_post.send_create(&local_user_view.person, context).await?; // They like their own post by default let like_form = PostLikeForm { post_id: inserted_post.id, - person_id: user.id, + person_id: local_user_view.person.id, score: 1, }; @@ -138,12 +136,12 @@ impl Perform for CreatePost { return Err(ApiError::err("couldnt_like_post").into()); } - updated_post.send_like(&user, context).await?; + updated_post.send_like(&local_user_view.person, context).await?; // Refetch the view let inserted_post_id = inserted_post.id; let post_view = match blocking(context.pool(), move |conn| { - PostView::read(conn, inserted_post_id, Some(user.id)) + PostView::read(conn, inserted_post_id, Some(local_user_view.person.id)) }) .await? { @@ -173,12 +171,12 @@ impl Perform for GetPost { _websocket_id: Option, ) -> Result { let data: &GetPost = &self; - let user = get_user_from_jwt_opt(&data.auth, context.pool()).await?; - let user_id = user.map(|u| u.id); + let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?; + let person_id = local_user_view.map(|u| u.person.id); let id = data.id; let post_view = match blocking(context.pool(), move |conn| { - PostView::read(conn, id, user_id) + PostView::read(conn, id, person_id) }) .await? { @@ -189,7 +187,7 @@ impl Perform for GetPost { let id = data.id; let comments = blocking(context.pool(), move |conn| { CommentQueryBuilder::create(conn) - .my_user_id(user_id) + .my_person_id(person_id) .post_id(id) .limit(9999) .list() @@ -204,7 +202,7 @@ impl Perform for GetPost { // Necessary for the sidebar let community_view = match blocking(context.pool(), move |conn| { - CommunityView::read(conn, community_id, user_id) + CommunityView::read(conn, community_id, person_id) }) .await? { @@ -239,15 +237,15 @@ impl Perform for GetPosts { _websocket_id: Option, ) -> Result { let data: &GetPosts = &self; - let user = get_user_from_jwt_opt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?; - let user_id = match &user { - Some(user) => Some(user.id), + let person_id = match &local_user_view { + Some(uv) => Some(uv.person.id), None => None, }; - let show_nsfw = match &user { - Some(user) => user.show_nsfw, + let show_nsfw = match &local_user_view { + Some(uv) => uv.local_user.show_nsfw, None => false, }; @@ -265,7 +263,7 @@ impl Perform for GetPosts { .show_nsfw(show_nsfw) .community_id(community_id) .community_name(community_name) - .my_user_id(user_id) + .my_person_id(person_id) .page(page) .limit(limit) .list() @@ -290,7 +288,7 @@ impl Perform for CreatePostLike { websocket_id: Option, ) -> Result { let data: &CreatePostLike = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; // Don't do a downvote if site has downvotes disabled check_downvotes_enabled(data.score, context.pool()).await?; @@ -299,18 +297,18 @@ impl Perform for CreatePostLike { let post_id = data.post_id; let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; - check_community_ban(user.id, post.community_id, context.pool()).await?; + check_community_ban(local_user_view.person.id, post.community_id, context.pool()).await?; let like_form = PostLikeForm { post_id: data.post_id, - person_id: user.id, + person_id: local_user_view.person.id, score: data.score, }; // Remove any likes first - let user_id = user.id; + let person_id = local_user_view.person.id; blocking(context.pool(), move |conn| { - PostLike::remove(conn, user_id, post_id) + PostLike::remove(conn, person_id, post_id) }) .await??; @@ -324,18 +322,18 @@ impl Perform for CreatePostLike { } if like_form.score == 1 { - post.send_like(&user, context).await?; + post.send_like(&local_user_view.person, context).await?; } else if like_form.score == -1 { - post.send_dislike(&user, context).await?; + post.send_dislike(&local_user_view.person, context).await?; } } else { - post.send_undo_like(&user, context).await?; + post.send_undo_like(&local_user_view.person, context).await?; } let post_id = data.post_id; - let user_id = user.id; + let person_id = local_user_view.person.id; let post_view = match blocking(context.pool(), move |conn| { - PostView::read(conn, post_id, Some(user_id)) + PostView::read(conn, post_id, Some(person_id)) }) .await? { @@ -365,7 +363,7 @@ impl Perform for EditPost { websocket_id: Option, ) -> Result { let data: &EditPost = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; check_slurs(&data.name)?; check_slurs_opt(&data.body)?; @@ -377,20 +375,21 @@ impl Perform for EditPost { let post_id = data.post_id; let orig_post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; - check_community_ban(user.id, orig_post.community_id, context.pool()).await?; + check_community_ban(local_user_view.person.id, orig_post.community_id, context.pool()).await?; // Verify that only the creator can edit - if !Post::is_post_creator(user.id, orig_post.creator_id) { + if !Post::is_post_creator(local_user_view.person.id, orig_post.creator_id) { return Err(ApiError::err("no_post_edit_allowed").into()); } // Fetch Iframely and Pictrs cached image + let data_url = data.url.as_ref(); let (iframely_title, iframely_description, iframely_html, pictrs_thumbnail) = - fetch_iframely_and_pictrs_data(context.client(), data.url.to_owned()).await; + fetch_iframely_and_pictrs_data(context.client(), data_url).await; let post_form = PostForm { name: data.name.trim().to_owned(), - url: data.url.to_owned(), + url: data_url.map(|u| u.to_owned().into()), body: data.body.to_owned(), nsfw: data.nsfw, creator_id: orig_post.creator_id.to_owned(), @@ -403,7 +402,7 @@ impl Perform for EditPost { embed_title: iframely_title, embed_description: iframely_description, embed_html: iframely_html, - thumbnail_url: pictrs_thumbnail, + thumbnail_url: pictrs_thumbnail.map(|u| u.into()), ap_id: Some(orig_post.ap_id), local: orig_post.local, published: None, @@ -428,11 +427,11 @@ impl Perform for EditPost { }; // Send apub update - updated_post.send_update(&user, context).await?; + updated_post.send_update(&local_user_view.person, context).await?; let post_id = data.post_id; let post_view = blocking(context.pool(), move |conn| { - PostView::read(conn, post_id, Some(user.id)) + PostView::read(conn, post_id, Some(local_user_view.person.id)) }) .await??; @@ -458,15 +457,15 @@ impl Perform for DeletePost { websocket_id: Option, ) -> Result { let data: &DeletePost = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; let post_id = data.post_id; let orig_post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; - check_community_ban(user.id, orig_post.community_id, context.pool()).await?; + check_community_ban(local_user_view.person.id, orig_post.community_id, context.pool()).await?; // Verify that only the creator can delete - if !Post::is_post_creator(user.id, orig_post.creator_id) { + if !Post::is_post_creator(local_user_view.person.id, orig_post.creator_id) { return Err(ApiError::err("no_post_edit_allowed").into()); } @@ -480,15 +479,15 @@ impl Perform for DeletePost { // apub updates if deleted { - updated_post.send_delete(&user, context).await?; + updated_post.send_delete(&local_user_view.person, context).await?; } else { - updated_post.send_undo_delete(&user, context).await?; + updated_post.send_undo_delete(&local_user_view.person, context).await?; } // Refetch the post let post_id = data.post_id; let post_view = blocking(context.pool(), move |conn| { - PostView::read(conn, post_id, Some(user.id)) + PostView::read(conn, post_id, Some(local_user_view.person.id)) }) .await??; @@ -514,15 +513,15 @@ impl Perform for RemovePost { websocket_id: Option, ) -> Result { let data: &RemovePost = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; let post_id = data.post_id; let orig_post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; - check_community_ban(user.id, orig_post.community_id, context.pool()).await?; + check_community_ban(local_user_view.person.id, orig_post.community_id, context.pool()).await?; // Verify that only the mods can remove - is_mod_or_admin(context.pool(), user.id, orig_post.community_id).await?; + is_mod_or_admin(context.pool(), local_user_view.person.id, orig_post.community_id).await?; // Update the post let post_id = data.post_id; @@ -534,7 +533,7 @@ impl Perform for RemovePost { // Mod tables let form = ModRemovePostForm { - mod_person_id: user.id, + mod_person_id: local_user_view.person.id, post_id: data.post_id, removed: Some(removed), reason: data.reason.to_owned(), @@ -546,16 +545,16 @@ impl Perform for RemovePost { // apub updates if removed { - updated_post.send_remove(&user, context).await?; + updated_post.send_remove(&local_user_view.person, context).await?; } else { - updated_post.send_undo_remove(&user, context).await?; + updated_post.send_undo_remove(&local_user_view.person, context).await?; } // Refetch the post let post_id = data.post_id; - let user_id = user.id; + let person_id = local_user_view.person.id; let post_view = blocking(context.pool(), move |conn| { - PostView::read(conn, post_id, Some(user_id)) + PostView::read(conn, post_id, Some(person_id)) }) .await??; @@ -581,15 +580,15 @@ impl Perform for LockPost { websocket_id: Option, ) -> Result { let data: &LockPost = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; let post_id = data.post_id; let orig_post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; - check_community_ban(user.id, orig_post.community_id, context.pool()).await?; + check_community_ban(local_user_view.person.id, orig_post.community_id, context.pool()).await?; // Verify that only the mods can lock - is_mod_or_admin(context.pool(), user.id, orig_post.community_id).await?; + is_mod_or_admin(context.pool(), local_user_view.person.id, orig_post.community_id).await?; // Update the post let post_id = data.post_id; @@ -601,19 +600,19 @@ impl Perform for LockPost { // Mod tables let form = ModLockPostForm { - mod_person_id: user.id, + mod_person_id: local_user_view.person.id, post_id: data.post_id, locked: Some(locked), }; blocking(context.pool(), move |conn| ModLockPost::create(conn, &form)).await??; // apub updates - updated_post.send_update(&user, context).await?; + updated_post.send_update(&local_user_view.person, context).await?; // Refetch the post let post_id = data.post_id; let post_view = blocking(context.pool(), move |conn| { - PostView::read(conn, post_id, Some(user.id)) + PostView::read(conn, post_id, Some(local_user_view.person.id)) }) .await??; @@ -639,15 +638,15 @@ impl Perform for StickyPost { websocket_id: Option, ) -> Result { let data: &StickyPost = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; let post_id = data.post_id; let orig_post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; - check_community_ban(user.id, orig_post.community_id, context.pool()).await?; + check_community_ban(local_user_view.person.id, orig_post.community_id, context.pool()).await?; // Verify that only the mods can sticky - is_mod_or_admin(context.pool(), user.id, orig_post.community_id).await?; + is_mod_or_admin(context.pool(), local_user_view.person.id, orig_post.community_id).await?; // Update the post let post_id = data.post_id; @@ -659,7 +658,7 @@ impl Perform for StickyPost { // Mod tables let form = ModStickyPostForm { - mod_person_id: user.id, + mod_person_id: local_user_view.person.id, post_id: data.post_id, stickied: Some(stickied), }; @@ -670,12 +669,12 @@ impl Perform for StickyPost { // Apub updates // TODO stickied should pry work like locked for ease of use - updated_post.send_update(&user, context).await?; + updated_post.send_update(&local_user_view.person, context).await?; // Refetch the post let post_id = data.post_id; let post_view = blocking(context.pool(), move |conn| { - PostView::read(conn, post_id, Some(user.id)) + PostView::read(conn, post_id, Some(local_user_view.person.id)) }) .await??; @@ -701,11 +700,11 @@ impl Perform for SavePost { _websocket_id: Option, ) -> Result { let data: &SavePost = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; let post_saved_form = PostSavedForm { post_id: data.post_id, - person_id: user.id, + person_id: local_user_view.person.id, }; if data.save { @@ -721,9 +720,9 @@ impl Perform for SavePost { } let post_id = data.post_id; - let user_id = user.id; + let person_id = local_user_view.person.id; let post_view = blocking(context.pool(), move |conn| { - PostView::read(conn, post_id, Some(user_id)) + PostView::read(conn, post_id, Some(person_id)) }) .await??; @@ -742,7 +741,7 @@ impl Perform for CreatePostReport { websocket_id: Option, ) -> Result { let data: &CreatePostReport = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; // check size of report and check for whitespace let reason = data.reason.trim(); @@ -753,17 +752,17 @@ impl Perform for CreatePostReport { return Err(ApiError::err("report_too_long").into()); } - let user_id = user.id; + let person_id = local_user_view.person.id; let post_id = data.post_id; let post_view = blocking(context.pool(), move |conn| { PostView::read(&conn, post_id, None) }) .await??; - check_community_ban(user_id, post_view.community.id, context.pool()).await?; + check_community_ban(person_id, post_view.community.id, context.pool()).await?; let report_form = PostReportForm { - creator_id: user_id, + creator_id: person_id, post_id, original_post_name: post_view.post.name, original_post_url: post_view.post.url, @@ -785,7 +784,7 @@ impl Perform for CreatePostReport { context.chat_server().do_send(SendUserRoomMessage { op: UserOperation::CreatePostReport, response: res.clone(), - recipient_id: user.id, + recipient_id: local_user_view.person.id, websocket_id, }); @@ -811,7 +810,7 @@ impl Perform for ResolvePostReport { websocket_id: Option, ) -> Result { let data: &ResolvePostReport = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; let report_id = data.report_id; let report = blocking(context.pool(), move |conn| { @@ -819,15 +818,15 @@ impl Perform for ResolvePostReport { }) .await??; - let user_id = user.id; - is_mod_or_admin(context.pool(), user_id, report.community.id).await?; + let person_id = local_user_view.person.id; + is_mod_or_admin(context.pool(), person_id, report.community.id).await?; let resolved = data.resolved; let resolve_fun = move |conn: &'_ _| { if resolved { - PostReport::resolve(conn, report_id, user_id) + PostReport::resolve(conn, report_id, person_id) } else { - PostReport::unresolve(conn, report_id, user_id) + PostReport::unresolve(conn, report_id, person_id) } }; @@ -863,12 +862,12 @@ impl Perform for ListPostReports { websocket_id: Option, ) -> Result { let data: &ListPostReports = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; - let user_id = user.id; + let person_id = local_user_view.person.id; let community_id = data.community; let community_ids = - collect_moderated_communities(user_id, community_id, context.pool()).await?; + collect_moderated_communities(person_id, community_id, context.pool()).await?; let page = data.page; let limit = data.limit; @@ -886,7 +885,7 @@ impl Perform for ListPostReports { context.chat_server().do_send(SendUserRoomMessage { op: UserOperation::ListPostReports, response: res.clone(), - recipient_id: user.id, + recipient_id: local_user_view.person.id, websocket_id, }); diff --git a/crates/api/src/routes.rs b/crates/api/src/routes.rs index 7ca609f1a..0c70dc0d3 100644 --- a/crates/api/src/routes.rs +++ b/crates/api/src/routes.rs @@ -1,6 +1,6 @@ use crate::Perform; use actix_web::{error::ErrorBadRequest, *}; -use lemmy_structs::{comment::*, community::*, post::*, site::*, user::*, websocket::*}; +use lemmy_api_structs::{comment::*, community::*, post::*, site::*, person::*, websocket::*}; use lemmy_utils::rate_limit::RateLimit; use lemmy_websocket::{routes::chat_route, LemmyContext}; use serde::Deserialize; @@ -137,11 +137,11 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) { .service( web::scope("/user") .wrap(rate_limit.message()) - .route("", web::get().to(route_get::)) - .route("/mention", web::get().to(route_get::)) + .route("", web::get().to(route_get::)) + .route("/mention", web::get().to(route_get::)) .route( "/mention/mark_as_read", - web::post().to(route_post::), + web::post().to(route_post::), ) .route("/replies", web::get().to(route_get::)) .route( @@ -150,7 +150,7 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) { ) .route("/join", web::post().to(route_post::)) // Admin action. I don't like that it's in /user - .route("/ban", web::post().to(route_post::)) + .route("/ban", web::post().to(route_post::)) // Account actions. I don't like that they're in /user maybe /accounts .route("/login", web::post().to(route_post::)) .route("/get_captcha", web::get().to(route_get::)) diff --git a/crates/api/src/site.rs b/crates/api/src/site.rs index 56f14dea7..5acd099c4 100644 --- a/crates/api/src/site.rs +++ b/crates/api/src/site.rs @@ -1,16 +1,22 @@ use crate::{ build_federated_instances, - get_user_from_jwt, - get_user_from_jwt_opt, - get_user_safe_settings_from_jwt, - get_user_safe_settings_from_jwt_opt, + get_local_user_view_from_jwt, + get_local_user_view_from_jwt_opt, + get_local_user_settings_view_from_jwt_opt, is_admin, Perform, }; use actix_web::web::Data; use anyhow::Context; +use lemmy_api_structs::{blocking, site::*, person::Register}; use lemmy_apub::fetcher::search::search_by_apub_id; -use lemmy_db_queries::{diesel_option_overwrite, source::site::Site_, Crud, SearchType, SortType}; +use lemmy_db_queries::{ + diesel_option_overwrite_to_url, + source::site::Site_, + Crud, + SearchType, + SortType, +}; use lemmy_db_schema::{ naive_now, source::{ @@ -25,7 +31,7 @@ use lemmy_db_views::{ }; use lemmy_db_views_actor::{ community_view::CommunityQueryBuilder, - user_view::{UserQueryBuilder, UserViewSafe}, + person_view::{PersonQueryBuilder, PersonViewSafe}, }; use lemmy_db_views_moderator::{ mod_add_community_view::ModAddCommunityView, @@ -38,10 +44,9 @@ use lemmy_db_views_moderator::{ mod_remove_post_view::ModRemovePostView, mod_sticky_post_view::ModStickyPostView, }; -use lemmy_structs::{blocking, site::*, user::Register}; use lemmy_utils::{ location_info, - settings::Settings, + settings::structs::Settings, utils::{check_slurs, check_slurs_opt}, version, ApiError, @@ -68,36 +73,36 @@ impl Perform for GetModlog { let data: &GetModlog = &self; let community_id = data.community_id; - let mod_user_id = data.mod_user_id; + let mod_person_id = data.mod_person_id; let page = data.page; let limit = data.limit; let removed_posts = blocking(context.pool(), move |conn| { - ModRemovePostView::list(conn, community_id, mod_user_id, page, limit) + ModRemovePostView::list(conn, community_id, mod_person_id, page, limit) }) .await??; let locked_posts = blocking(context.pool(), move |conn| { - ModLockPostView::list(conn, community_id, mod_user_id, page, limit) + ModLockPostView::list(conn, community_id, mod_person_id, page, limit) }) .await??; let stickied_posts = blocking(context.pool(), move |conn| { - ModStickyPostView::list(conn, community_id, mod_user_id, page, limit) + ModStickyPostView::list(conn, community_id, mod_person_id, page, limit) }) .await??; let removed_comments = blocking(context.pool(), move |conn| { - ModRemoveCommentView::list(conn, community_id, mod_user_id, page, limit) + ModRemoveCommentView::list(conn, community_id, mod_person_id, page, limit) }) .await??; let banned_from_community = blocking(context.pool(), move |conn| { - ModBanFromCommunityView::list(conn, community_id, mod_user_id, page, limit) + ModBanFromCommunityView::list(conn, community_id, mod_person_id, page, limit) }) .await??; let added_to_community = blocking(context.pool(), move |conn| { - ModAddCommunityView::list(conn, community_id, mod_user_id, page, limit) + ModAddCommunityView::list(conn, community_id, mod_person_id, page, limit) }) .await??; @@ -105,9 +110,9 @@ impl Perform for GetModlog { let (removed_communities, banned, added) = if data.community_id.is_none() { blocking(context.pool(), move |conn| { Ok(( - ModRemoveCommunityView::list(conn, mod_user_id, page, limit)?, - ModBanView::list(conn, mod_user_id, page, limit)?, - ModAddView::list(conn, mod_user_id, page, limit)?, + ModRemoveCommunityView::list(conn, mod_person_id, page, limit)?, + ModBanView::list(conn, mod_person_id, page, limit)?, + ModAddView::list(conn, mod_person_id, page, limit)?, )) as Result<_, LemmyError> }) .await?? @@ -146,20 +151,20 @@ impl Perform for CreateSite { return Err(ApiError::err("site_already_exists").into()); }; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; check_slurs(&data.name)?; check_slurs_opt(&data.description)?; // Make sure user is an admin - is_admin(context.pool(), user.id).await?; + is_admin(&local_user_view)?; let site_form = SiteForm { name: data.name.to_owned(), description: data.description.to_owned(), - icon: Some(data.icon.to_owned()), - banner: Some(data.banner.to_owned()), - creator_id: user.id, + icon: Some(data.icon.to_owned().map(|url| url.into())), + banner: Some(data.banner.to_owned().map(|url| url.into())), + creator_id: local_user_view.person.id, enable_downvotes: data.enable_downvotes, open_registration: data.open_registration, enable_nsfw: data.enable_nsfw, @@ -186,18 +191,18 @@ impl Perform for EditSite { websocket_id: Option, ) -> Result { let data: &EditSite = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; check_slurs(&data.name)?; check_slurs_opt(&data.description)?; // Make sure user is an admin - is_admin(context.pool(), user.id).await?; + is_admin(&local_user_view)?; let found_site = blocking(context.pool(), move |conn| Site::read_simple(conn)).await??; - let icon = diesel_option_overwrite(&data.icon); - let banner = diesel_option_overwrite(&data.banner); + let icon = diesel_option_overwrite_to_url(&data.icon)?; + let banner = diesel_option_overwrite_to_url(&data.banner)?; let site_form = SiteForm { name: data.name.to_owned(), @@ -245,7 +250,7 @@ impl Perform for GetSite { Ok(site_view) => Some(site_view), // If the site isn't created yet, check the setup Err(_) => { - if let Some(setup) = Settings::get().setup.as_ref() { + if let Some(setup) = Settings::get().setup().as_ref() { let register = Register { username: setup.admin_username.to_owned(), email: setup.admin_email.to_owned(), @@ -277,20 +282,20 @@ impl Perform for GetSite { } }; - let mut admins = blocking(context.pool(), move |conn| UserViewSafe::admins(conn)).await??; + let mut admins = blocking(context.pool(), move |conn| PersonViewSafe::admins(conn)).await??; // Make sure the site creator is the top admin if let Some(site_view) = site_view.to_owned() { let site_creator_id = site_view.creator.id; // TODO investigate why this is sometimes coming back null // Maybe user_.admin isn't being set to true? - if let Some(creator_index) = admins.iter().position(|r| r.user.id == site_creator_id) { - let creator_user = admins.remove(creator_index); - admins.insert(0, creator_user); + if let Some(creator_index) = admins.iter().position(|r| r.person.id == site_creator_id) { + let creator_person = admins.remove(creator_index); + admins.insert(0, creator_person); } } - let banned = blocking(context.pool(), move |conn| UserViewSafe::banned(conn)).await??; + let banned = blocking(context.pool(), move |conn| PersonViewSafe::banned(conn)).await??; let online = context .chat_server() @@ -298,7 +303,7 @@ impl Perform for GetSite { .await .unwrap_or(1); - let my_user = get_user_safe_settings_from_jwt_opt(&data.auth, context.pool()).await?; + let my_user = get_local_user_settings_view_from_jwt_opt(&data.auth, context.pool()).await?; let federated_instances = build_federated_instances(context.pool()).await?; Ok(GetSiteResponse { @@ -329,8 +334,8 @@ impl Perform for Search { Err(e) => debug!("Failed to resolve search query as activitypub ID: {}", e), } - let user = get_user_from_jwt_opt(&data.auth, context.pool()).await?; - let user_id = user.map(|u| u.id); + let local_user_view = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?; + let person_id = local_user_view.map(|u| u.person.id); let type_ = SearchType::from_str(&data.type_)?; @@ -355,7 +360,7 @@ impl Perform for Search { .show_nsfw(true) .community_id(community_id) .community_name(community_name) - .my_user_id(user_id) + .my_person_id(person_id) .search_term(q) .page(page) .limit(limit) @@ -368,7 +373,7 @@ impl Perform for Search { CommentQueryBuilder::create(&conn) .sort(&sort) .search_term(q) - .my_user_id(user_id) + .my_person_id(person_id) .page(page) .limit(limit) .list() @@ -380,7 +385,7 @@ impl Perform for Search { CommunityQueryBuilder::create(conn) .sort(&sort) .search_term(q) - .my_user_id(user_id) + .my_person_id(person_id) .page(page) .limit(limit) .list() @@ -389,7 +394,7 @@ impl Perform for Search { } SearchType::Users => { users = blocking(context.pool(), move |conn| { - UserQueryBuilder::create(conn) + PersonQueryBuilder::create(conn) .sort(&sort) .search_term(q) .page(page) @@ -405,7 +410,7 @@ impl Perform for Search { .show_nsfw(true) .community_id(community_id) .community_name(community_name) - .my_user_id(user_id) + .my_person_id(person_id) .search_term(q) .page(page) .limit(limit) @@ -420,7 +425,7 @@ impl Perform for Search { CommentQueryBuilder::create(conn) .sort(&sort) .search_term(q) - .my_user_id(user_id) + .my_person_id(person_id) .page(page) .limit(limit) .list() @@ -434,7 +439,7 @@ impl Perform for Search { CommunityQueryBuilder::create(conn) .sort(&sort) .search_term(q) - .my_user_id(user_id) + .my_person_id(person_id) .page(page) .limit(limit) .list() @@ -445,7 +450,7 @@ impl Perform for Search { let sort = SortType::from_str(&data.sort)?; users = blocking(context.pool(), move |conn| { - UserQueryBuilder::create(conn) + PersonQueryBuilder::create(conn) .sort(&sort) .search_term(q) .page(page) @@ -459,7 +464,7 @@ impl Perform for Search { PostQueryBuilder::create(conn) .sort(&sort) .show_nsfw(true) - .my_user_id(user_id) + .my_person_id(person_id) .community_id(community_id) .community_name(community_name) .url_search(q) @@ -492,18 +497,18 @@ impl Perform for TransferSite { _websocket_id: Option, ) -> Result { let data: &TransferSite = &self; - let user = get_user_safe_settings_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; - is_admin(context.pool(), user.id).await?; + is_admin(&local_user_view)?; let read_site = blocking(context.pool(), move |conn| Site::read_simple(conn)).await??; // Make sure user is the creator - if read_site.creator_id != user.id { + if read_site.creator_id != local_user_view.person.id { return Err(ApiError::err("not_an_admin").into()); } - let new_creator_id = data.user_id; + let new_creator_id = data.person_id; let transfer_site = move |conn: &'_ _| Site::transfer(conn, new_creator_id); if blocking(context.pool(), transfer_site).await?.is_err() { return Err(ApiError::err("couldnt_update_site").into()); @@ -511,8 +516,8 @@ impl Perform for TransferSite { // Mod tables let form = ModAddForm { - mod_person_id: user.id, - other_person_id: data.user_id, + mod_person_id: local_user_view.person.id, + other_person_id: data.person_id, removed: Some(false), }; @@ -520,15 +525,15 @@ impl Perform for TransferSite { let site_view = blocking(context.pool(), move |conn| SiteView::read(conn)).await??; - let mut admins = blocking(context.pool(), move |conn| UserViewSafe::admins(conn)).await??; + let mut admins = blocking(context.pool(), move |conn| PersonViewSafe::admins(conn)).await??; let creator_index = admins .iter() - .position(|r| r.user.id == site_view.creator.id) + .position(|r| r.person.id == site_view.creator.id) .context(location_info!())?; - let creator_user = admins.remove(creator_index); - admins.insert(0, creator_user); + let creator_person = admins.remove(creator_index); + admins.insert(0, creator_person); - let banned = blocking(context.pool(), move |conn| UserViewSafe::banned(conn)).await??; + let banned = blocking(context.pool(), move |conn| PersonViewSafe::banned(conn)).await??; let federated_instances = build_federated_instances(context.pool()).await?; Ok(GetSiteResponse { @@ -537,7 +542,7 @@ impl Perform for TransferSite { banned, online: 0, version: version::VERSION.to_string(), - my_user: Some(user), + my_user: Some(local_user_view), federated_instances, }) } @@ -553,10 +558,10 @@ impl Perform for GetSiteConfig { _websocket_id: Option, ) -> Result { let data: &GetSiteConfig = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; // Only let admins read this - is_admin(context.pool(), user.id).await?; + is_admin(&local_user_view)?; let config_hjson = Settings::read_config_file()?; @@ -574,11 +579,11 @@ impl Perform for SaveSiteConfig { _websocket_id: Option, ) -> Result { let data: &SaveSiteConfig = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; // Only let admins read this - let user_id = user.id; - is_admin(context.pool(), user_id).await?; + let person_id = local_user_view.person.id; + is_admin(&local_user_view)?; // Make sure docker doesn't have :ro at the end of the volume, so its not a read-only filesystem let config_hjson = match Settings::save_config_file(&data.config_hjson) { diff --git a/crates/api/src/user.rs b/crates/api/src/user.rs index a8f1477f8..112814904 100644 --- a/crates/api/src/user.rs +++ b/crates/api/src/user.rs @@ -1,10 +1,10 @@ use crate::{ captcha_espeak_wav_base64, - check_optional_url, collect_moderated_communities, - get_user_from_jwt, - get_user_from_jwt_opt, + get_local_user_view_from_jwt, + get_local_user_view_from_jwt_opt, is_admin, + password_length_check, Perform, }; use actix_web::web::Data; @@ -12,6 +12,7 @@ use anyhow::Context; use bcrypt::verify; use captcha::{gen, Difficulty}; use chrono::Duration; +use lemmy_api_structs::{blocking, send_email_to_user, person::*}; use lemmy_apub::{ generate_apub_endpoint, generate_followers_url, @@ -22,6 +23,7 @@ use lemmy_apub::{ }; use lemmy_db_queries::{ diesel_option_overwrite, + diesel_option_overwrite_to_url, source::{ comment::Comment_, community::Community_, @@ -29,8 +31,8 @@ use lemmy_db_queries::{ post::Post_, private_message::PrivateMessage_, site::Site_, - user::User, - user_mention::UserMention_, + person::Person_, + person_mention::PersonMention_, }, Crud, Followable, @@ -38,40 +40,27 @@ use lemmy_db_queries::{ ListingType, SortType, }; -use lemmy_db_schema::{ - naive_now, - source::{ - comment::Comment, - community::*, - moderator::*, - password_reset_request::*, - post::Post, - private_message::*, - site::*, - user::*, - user_mention::*, - }, -}; +use lemmy_db_schema::{naive_now, source::{comment::Comment, community::*, local_user::LocalUserForm, moderator::*, password_reset_request::*, person::*, person_mention::*, post::Post, private_message::*, site::*}}; use lemmy_db_views::{ comment_report_view::CommentReportView, comment_view::CommentQueryBuilder, post_report_view::PostReportView, post_view::PostQueryBuilder, private_message_view::{PrivateMessageQueryBuilder, PrivateMessageView}, + local_user_view::LocalUserView, }; use lemmy_db_views_actor::{ community_follower_view::CommunityFollowerView, community_moderator_view::CommunityModeratorView, - user_mention_view::{UserMentionQueryBuilder, UserMentionView}, - user_view::UserViewSafe, + person_mention_view::{PersonMentionQueryBuilder, PersonMentionView}, + person_view::PersonViewSafe, }; -use lemmy_structs::{blocking, send_email_to_user, user::*}; use lemmy_utils::{ apub::generate_actor_keypair, claims::Claims, email::send_email, location_info, - settings::Settings, + settings::structs::Settings, utils::{ check_slurs, generate_random_string, @@ -104,24 +93,24 @@ impl Perform for Login { // Fetch that username / email let username_or_email = data.username_or_email.clone(); - let user = match blocking(context.pool(), move |conn| { - User_::find_by_email_or_username(conn, &username_or_email) + let local_user_view = match blocking(context.pool(), move |conn| { + LocalUserView::find_by_email_or_name(conn, &username_or_email) }) .await? { - Ok(user) => user, + Ok(uv) => uv, Err(_e) => return Err(ApiError::err("couldnt_find_that_username_or_email").into()), }; // Verify the password - let valid: bool = verify(&data.password, &user.password_encrypted).unwrap_or(false); + let valid: bool = verify(&data.password, &local_user_view.local_user.password_encrypted).unwrap_or(false); if !valid { return Err(ApiError::err("password_incorrect").into()); } // Return the jwt Ok(LoginResponse { - jwt: Claims::jwt(user.id, Settings::get().hostname)?, + jwt: Claims::jwt(local_user_view.person.id, Settings::get().hostname())?, }) } } @@ -144,10 +133,7 @@ impl Perform for Register { } } - // Password length check - if data.password.len() > 60 { - return Err(ApiError::err("invalid_password").into()); - } + password_length_check(&data.password)?; // Make sure passwords match if data.password != data.password_verify { @@ -156,12 +142,12 @@ impl Perform for Register { // Check if there are admins. False if admins exist let no_admins = blocking(context.pool(), move |conn| { - UserViewSafe::admins(conn).map(|a| a.is_empty()) + PersonViewSafe::admins(conn).map(|a| a.is_empty()) }) .await??; // If its not the admin, check the captcha - if !no_admins && Settings::get().captcha.enabled { + if !no_admins && Settings::get().captcha().enabled { let check = context .chat_server() .send(CheckCaptcha { @@ -182,25 +168,24 @@ impl Perform for Register { check_slurs(&data.username)?; - let user_keypair = generate_actor_keypair()?; + let actor_keypair = generate_actor_keypair()?; if !is_valid_username(&data.username) { return Err(ApiError::err("invalid_username").into()); } - let user_actor_id = generate_apub_endpoint(EndpointType::User, &data.username)?; + let actor_id = generate_apub_endpoint(EndpointType::Person, &data.username)?; - // Register the new user - let user_form = UserForm { + // We have to create both a person, and local_user + + // Register the new person + let person_form = PersonForm { name: data.username.to_owned(), - email: Some(data.email.to_owned()), - matrix_user_id: None, avatar: None, banner: None, - password_encrypted: data.password.to_owned(), preferred_username: None, published: None, updated: None, - admin: no_admins, - banned: Some(false), + banned: None, + deleted: None, show_nsfw: data.show_nsfw, theme: "browser".into(), default_sort_type: SortType::Active as i16, @@ -208,35 +193,60 @@ impl Perform for Register { lang: "browser".into(), show_avatars: true, send_notifications_to_email: false, - actor_id: Some(user_actor_id.clone()), + actor_id: Some(actor_id.clone()), bio: None, local: true, - private_key: Some(user_keypair.private_key), - public_key: Some(user_keypair.public_key), + private_key: Some(actor_keypair.private_key), + public_key: Some(actor_keypair.public_key), last_refreshed_at: None, - inbox_url: Some(generate_inbox_url(&user_actor_id)?), - shared_inbox_url: Some(Some(generate_shared_inbox_url(&user_actor_id)?)), + inbox_url: Some(generate_inbox_url(&actor_id)?), + shared_inbox_url: Some(Some(generate_shared_inbox_url(&actor_id)?)), }; - // Create the user - let inserted_user = match blocking(context.pool(), move |conn| { - User_::register(conn, &user_form) + // insert the person + let inserted_person = match blocking(context.pool(), move |conn| { + Person::create(conn, &person_form) }) .await? { Ok(user) => user, + Err(e) => { + return Err(ApiError::err("user_already_exists").into()); + } + }; + + // Create the local user + let local_user_form = LocalUserForm { + person_id: inserted_person.id, + email: Some(data.email.to_owned()), + matrix_user_id: None, + password_encrypted: data.password.to_owned(), + admin: no_admins, + + }; + + let inserted_local_user = match blocking(context.pool(), move |conn| { + LocalUser::register(conn, &local_user_form) + }) + .await? + { + Ok(lu) => lu, Err(e) => { let err_type = if e.to_string() - == "duplicate key value violates unique constraint \"user__email_key\"" + == "duplicate key value violates unique constraint \"local_user_email_key\"" { "email_already_exists" } else { "user_already_exists" }; + // If the local user creation errored, then delete that person + blocking(context.pool(), move |conn| Person::delete(&conn, inserted_person.id)).await??; + return Err(ApiError::err(err_type).into()); } }; + let main_community_keypair = generate_actor_keypair()?; @@ -252,7 +262,7 @@ impl Perform for Register { title: "The Default Community".to_string(), description: Some("The Default Community".to_string()), nsfw: false, - creator_id: inserted_user.id, + creator_id: inserted_person.id, removed: None, deleted: None, updated: None, @@ -278,7 +288,7 @@ impl Perform for Register { // Sign them up for main community no matter what let community_follower_form = CommunityFollowerForm { community_id: main_community.id, - person_id: inserted_user.id, + person_id: inserted_person.id, pending: false, }; @@ -291,7 +301,7 @@ impl Perform for Register { if no_admins { let community_moderator_form = CommunityModeratorForm { community_id: main_community.id, - person_id: inserted_user.id, + person_id: inserted_person.id, }; let join = move |conn: &'_ _| CommunityModerator::join(conn, &community_moderator_form); @@ -302,7 +312,7 @@ impl Perform for Register { // Return the jwt Ok(LoginResponse { - jwt: Claims::jwt(inserted_user.id, Settings::get().hostname)?, + jwt: Claims::jwt(inserted_person.id, Settings::get().hostname())?, }) } } @@ -316,7 +326,7 @@ impl Perform for GetCaptcha { context: &Data, _websocket_id: Option, ) -> Result { - let captcha_settings = Settings::get().captcha; + let captcha_settings = Settings::get().captcha(); if !captcha_settings.enabled { return Ok(GetCaptchaResponse { ok: None }); @@ -364,19 +374,15 @@ impl Perform for SaveUserSettings { _websocket_id: Option, ) -> Result { let data: &SaveUserSettings = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let user = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; - let avatar = diesel_option_overwrite(&data.avatar); - let banner = diesel_option_overwrite(&data.banner); + let avatar = diesel_option_overwrite_to_url(&data.avatar)?; + let banner = diesel_option_overwrite_to_url(&data.banner)?; let email = diesel_option_overwrite(&data.email); let bio = diesel_option_overwrite(&data.bio); let preferred_username = diesel_option_overwrite(&data.preferred_username); let matrix_user_id = diesel_option_overwrite(&data.matrix_user_id); - // Check to make sure the avatar and banners are urls - check_optional_url(&avatar)?; - check_optional_url(&banner)?; - if let Some(Some(bio)) = &bio { if bio.chars().count() > 300 { return Err(ApiError::err("bio_length_overflow").into()); @@ -394,6 +400,8 @@ impl Perform for SaveUserSettings { Some(new_password) => { match &data.new_password_verify { Some(new_password_verify) => { + password_length_check(&new_password)?; + // Make sure passwords match if new_password != new_password_verify { return Err(ApiError::err("passwords_dont_match").into()); @@ -475,7 +483,7 @@ impl Perform for SaveUserSettings { // Return the jwt Ok(LoginResponse { - jwt: Claims::jwt(updated_user.id, Settings::get().hostname)?, + jwt: Claims::jwt(updated_user.id, Settings::get().hostname())?, }) } } @@ -490,7 +498,7 @@ impl Perform for GetUserDetails { _websocket_id: Option, ) -> Result { let data: &GetUserDetails = &self; - let user = get_user_from_jwt_opt(&data.auth, context.pool()).await?; + let user = get_local_user_view_from_jwt_opt(&data.auth, context.pool()).await?; let show_nsfw = match &user { Some(user) => user.show_nsfw, @@ -542,7 +550,7 @@ impl Perform for GetUserDetails { .limit(limit); let mut comments_query = CommentQueryBuilder::create(conn) - .my_user_id(user_id) + .my_person_id(user_id) .sort(&sort) .saved_only(saved_only) .page(page) @@ -572,7 +580,7 @@ impl Perform for GetUserDetails { } }; let moderates = blocking(context.pool(), move |conn| { - CommunityModeratorView::for_user(conn, user_details_id) + CommunityModeratorView::for_person(conn, user_details_id) }) .await??; @@ -597,7 +605,7 @@ impl Perform for AddAdmin { websocket_id: Option, ) -> Result { let data: &AddAdmin = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let user = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; // Make sure user is an admin is_admin(context.pool(), user.id).await?; @@ -653,7 +661,7 @@ impl Perform for BanUser { websocket_id: Option, ) -> Result { let data: &BanUser = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let user = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; // Make sure user is an admin is_admin(context.pool(), user.id).await?; @@ -714,7 +722,7 @@ impl Perform for BanUser { }; context.chat_server().do_send(SendAllMessage { - op: UserOperation::BanUser, + op: UserOperation::BanPerson, response: res.clone(), websocket_id, }); @@ -733,7 +741,7 @@ impl Perform for GetReplies { _websocket_id: Option, ) -> Result { let data: &GetReplies = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let user = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; let sort = SortType::from_str(&data.sort)?; @@ -746,7 +754,7 @@ impl Perform for GetReplies { .sort(&sort) .unread_only(unread_only) .recipient_id(user_id) - .my_user_id(user_id) + .my_person_id(user_id) .page(page) .limit(limit) .list() @@ -767,7 +775,7 @@ impl Perform for GetUserMentions { _websocket_id: Option, ) -> Result { let data: &GetUserMentions = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let user = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; let sort = SortType::from_str(&data.sort)?; @@ -801,7 +809,7 @@ impl Perform for MarkUserMentionAsRead { _websocket_id: Option, ) -> Result { let data: &MarkUserMentionAsRead = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let user = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; let user_mention_id = data.user_mention_id; let read_user_mention = blocking(context.pool(), move |conn| { @@ -841,12 +849,12 @@ impl Perform for MarkAllAsRead { _websocket_id: Option, ) -> Result { let data: &MarkAllAsRead = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let user = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; let user_id = user.id; let replies = blocking(context.pool(), move |conn| { CommentQueryBuilder::create(conn) - .my_user_id(user_id) + .my_person_id(user_id) .recipient_id(user_id) .unread_only(true) .page(1) @@ -895,7 +903,7 @@ impl Perform for DeleteAccount { _websocket_id: Option, ) -> Result { let data: &DeleteAccount = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let user = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; // Verify the password let valid: bool = verify(&data.password, &user.password_encrypted).unwrap_or(false); @@ -993,6 +1001,8 @@ impl Perform for PasswordChange { }) .await??; + password_length_check(&data.password)?; + // Make sure passwords match if data.password != data.password_verify { return Err(ApiError::err("passwords_dont_match").into()); @@ -1011,7 +1021,7 @@ impl Perform for PasswordChange { // Return the jwt Ok(LoginResponse { - jwt: Claims::jwt(updated_user.id, Settings::get().hostname)?, + jwt: Claims::jwt(updated_user.id, Settings::get().hostname())?, }) } } @@ -1026,7 +1036,7 @@ impl Perform for CreatePrivateMessage { websocket_id: Option, ) -> Result { let data: &CreatePrivateMessage = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let user = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; let content_slurs_removed = remove_slurs(&data.content.to_owned()); @@ -1119,7 +1129,7 @@ impl Perform for EditPrivateMessage { websocket_id: Option, ) -> Result { let data: &EditPrivateMessage = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let user = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; // Checking permissions let private_message_id = data.private_message_id; @@ -1178,7 +1188,7 @@ impl Perform for DeletePrivateMessage { websocket_id: Option, ) -> Result { let data: &DeletePrivateMessage = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let user = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; // Checking permissions let private_message_id = data.private_message_id; @@ -1243,7 +1253,7 @@ impl Perform for MarkPrivateMessageAsRead { websocket_id: Option, ) -> Result { let data: &MarkPrivateMessageAsRead = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let user = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; // Checking permissions let private_message_id = data.private_message_id; @@ -1301,7 +1311,7 @@ impl Perform for GetPrivateMessages { _websocket_id: Option, ) -> Result { let data: &GetPrivateMessages = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let user = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; let user_id = user.id; let page = data.page; @@ -1332,7 +1342,7 @@ impl Perform for GetReportCount { websocket_id: Option, ) -> Result { let data: &GetReportCount = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let user = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; let user_id = user.id; let community_id = data.community; diff --git a/crates/api/src/websocket.rs b/crates/api/src/websocket.rs index 4342f15b8..47e21091f 100644 --- a/crates/api/src/websocket.rs +++ b/crates/api/src/websocket.rs @@ -1,6 +1,6 @@ -use crate::{get_user_from_jwt, Perform}; +use crate::{get_local_user_view_from_jwt, Perform}; use actix_web::web::Data; -use lemmy_structs::websocket::*; +use lemmy_api_structs::websocket::*; use lemmy_utils::{ConnectionId, LemmyError}; use lemmy_websocket::{ messages::{JoinCommunityRoom, JoinModRoom, JoinPostRoom, JoinUserRoom}, @@ -17,11 +17,12 @@ impl Perform for UserJoin { websocket_id: Option, ) -> Result { let data: &UserJoin = &self; - let user = get_user_from_jwt(&data.auth, context.pool()).await?; + let local_user_view = get_local_user_view_from_jwt(&data.auth, context.pool()).await?; if let Some(ws_id) = websocket_id { context.chat_server().do_send(JoinUserRoom { - user_id: user.id, + // TODO this should probably be the local_user_id + user_id: local_user_view.person.id, id: ws_id, }); } diff --git a/crates/structs/Cargo.toml b/crates/api_structs/Cargo.toml similarity index 84% rename from crates/structs/Cargo.toml rename to crates/api_structs/Cargo.toml index f895a8c95..242383e6f 100644 --- a/crates/structs/Cargo.toml +++ b/crates/api_structs/Cargo.toml @@ -1,12 +1,12 @@ [package] -name = "lemmy_structs" +name = "lemmy_api_structs" version = "0.1.0" -authors = ["Felix Ableitner "] edition = "2018" [lib] -name = "lemmy_structs" +name = "lemmy_api_structs" path = "src/lib.rs" +doctest = false [dependencies] lemmy_db_queries = { path = "../db_queries" } @@ -21,4 +21,4 @@ diesel = "1.4.5" actix-web = "3.3.2" chrono = { version = "0.4.19", features = ["serde"] } serde_json = { version = "1.0.61", features = ["preserve_order"] } -url = "2.2.0" +url = "2.2.1" diff --git a/crates/structs/src/comment.rs b/crates/api_structs/src/comment.rs similarity index 100% rename from crates/structs/src/comment.rs rename to crates/api_structs/src/comment.rs diff --git a/crates/structs/src/community.rs b/crates/api_structs/src/community.rs similarity index 93% rename from crates/structs/src/community.rs rename to crates/api_structs/src/community.rs index fbbf2e403..d9313ce98 100644 --- a/crates/structs/src/community.rs +++ b/crates/api_structs/src/community.rs @@ -2,7 +2,7 @@ use lemmy_db_views_actor::{ community_follower_view::CommunityFollowerView, community_moderator_view::CommunityModeratorView, community_view::CommunityView, - user_view::UserViewSafe, + person_view::PersonViewSafe, }; use serde::{Deserialize, Serialize}; @@ -27,7 +27,6 @@ pub struct CreateCommunity { pub description: Option, pub icon: Option, pub banner: Option, - pub category_id: i32, pub nsfw: bool, pub auth: String, } @@ -54,7 +53,7 @@ pub struct ListCommunitiesResponse { #[derive(Deserialize, Clone)] pub struct BanFromCommunity { pub community_id: i32, - pub user_id: i32, + pub person_id: i32, pub ban: bool, pub remove_data: bool, pub reason: Option, @@ -64,14 +63,14 @@ pub struct BanFromCommunity { #[derive(Serialize, Clone)] pub struct BanFromCommunityResponse { - pub user_view: UserViewSafe, + pub person_view: PersonViewSafe, pub banned: bool, } #[derive(Deserialize)] pub struct AddModToCommunity { pub community_id: i32, - pub user_id: i32, + pub person_id: i32, pub added: bool, pub auth: String, } @@ -88,7 +87,6 @@ pub struct EditCommunity { pub description: Option, pub icon: Option, pub banner: Option, - pub category_id: i32, pub nsfw: bool, pub auth: String, } @@ -129,6 +127,6 @@ pub struct GetFollowedCommunitiesResponse { #[derive(Deserialize)] pub struct TransferCommunity { pub community_id: i32, - pub user_id: i32, + pub person_id: i32, pub auth: String, } diff --git a/crates/structs/src/lib.rs b/crates/api_structs/src/lib.rs similarity index 56% rename from crates/structs/src/lib.rs rename to crates/api_structs/src/lib.rs index 8b56fab6b..b28cb37f9 100644 --- a/crates/structs/src/lib.rs +++ b/crates/api_structs/src/lib.rs @@ -2,18 +2,19 @@ pub mod comment; pub mod community; pub mod post; pub mod site; -pub mod user; +pub mod person; pub mod websocket; use diesel::PgConnection; -use lemmy_db_queries::{source::user::User, Crud, DbPool}; +use lemmy_db_queries::{Crud, DbPool}; use lemmy_db_schema::source::{ comment::Comment, post::Post, - user::User_, - user_mention::{UserMention, UserMentionForm}, + person::Person, + person_mention::{PersonMention, PersonMentionForm}, }; -use lemmy_utils::{email::send_email, settings::Settings, utils::MentionData, LemmyError}; +use lemmy_db_views::local_user_view::LocalUserView; +use lemmy_utils::{email::send_email, settings::structs::Settings, utils::MentionData, LemmyError}; use log::error; use serde::{Deserialize, Serialize}; use url::Url; @@ -54,25 +55,25 @@ where pub async fn send_local_notifs( mentions: Vec, comment: Comment, - user: &User_, + person: Person, post: Post, pool: &DbPool, do_send_email: bool, ) -> Result, LemmyError> { - let user2 = user.clone(); let ids = blocking(pool, move |conn| { - do_send_local_notifs(conn, &mentions, &comment, &user2, &post, do_send_email) + do_send_local_notifs(conn, &mentions, &comment, &person, &post, do_send_email) }) .await?; Ok(ids) } +// TODO should this really use person_ids as recipient ids? or local_user_ids ? fn do_send_local_notifs( conn: &PgConnection, mentions: &[MentionData], comment: &Comment, - user: &User_, + person: &Person, post: &Post, do_send_email: bool, ) -> Vec { @@ -81,31 +82,32 @@ fn do_send_local_notifs( // Send the local mentions for mention in mentions .iter() - .filter(|m| m.is_local() && m.name.ne(&user.name)) + .filter(|m| m.is_local() && m.name.ne(&person.name)) .collect::>() { - if let Ok(mention_user) = User_::read_from_name(&conn, &mention.name) { + // TODO do a local user fetch + if let Ok(mention_user_view) = LocalUserView::read_from_name(&conn, &mention.name) { // TODO // At some point, make it so you can't tag the parent creator either // This can cause two notifications, one for reply and the other for mention - recipient_ids.push(mention_user.id); + recipient_ids.push(mention_user_view.person.id); - let user_mention_form = UserMentionForm { - recipient_id: mention_user.id, + let user_mention_form = PersonMentionForm { + recipient_id: mention_user_view.person.id, comment_id: comment.id, read: None, }; // Allow this to fail softly, since comment edits might re-update or replace it // Let the uniqueness handle this fail - let _ = UserMention::create(&conn, &user_mention_form); + PersonMention::create(&conn, &user_mention_form).ok(); // Send an email to those users that have notifications on - if do_send_email && mention_user.send_notifications_to_email { + if do_send_email && mention_user_view.local_user.send_notifications_to_email { send_email_to_user( - mention_user, + mention_user_view, "Mentioned by", - "User Mention", + "Person Mention", &comment.content, ) } @@ -116,12 +118,12 @@ fn do_send_local_notifs( match comment.parent_id { Some(parent_id) => { if let Ok(parent_comment) = Comment::read(&conn, parent_id) { - if parent_comment.creator_id != user.id { - if let Ok(parent_user) = User_::read(&conn, parent_comment.creator_id) { - recipient_ids.push(parent_user.id); + if parent_comment.creator_id != person.id { + if let Ok(parent_user_view) = LocalUserView::read(&conn, parent_comment.creator_id) { + recipient_ids.push(parent_user_view.person.id); - if do_send_email && parent_user.send_notifications_to_email { - send_email_to_user(parent_user, "Reply from", "Comment Reply", &comment.content) + if do_send_email && parent_user_view.local_user.send_notifications_to_email { + send_email_to_user(parent_user_view, "Reply from", "Comment Reply", &comment.content) } } } @@ -129,12 +131,12 @@ fn do_send_local_notifs( } // Its a post None => { - if post.creator_id != user.id { - if let Ok(parent_user) = User_::read(&conn, post.creator_id) { - recipient_ids.push(parent_user.id); + if post.creator_id != person.id { + if let Ok(parent_user_view) = LocalUserView::read(&conn, post.creator_id) { + recipient_ids.push(parent_user_view.person.id); - if do_send_email && parent_user.send_notifications_to_email { - send_email_to_user(parent_user, "Reply from", "Post Reply", &comment.content) + if do_send_email && parent_user_view.local_user.send_notifications_to_email { + send_email_to_user(parent_user_view, "Reply from", "Post Reply", &comment.content) } } } @@ -143,26 +145,26 @@ fn do_send_local_notifs( recipient_ids } -pub fn send_email_to_user(user: User_, subject_text: &str, body_text: &str, comment_content: &str) { - if user.banned { +pub fn send_email_to_user(local_user_view: LocalUserView, subject_text: &str, body_text: &str, comment_content: &str) { + if local_user_view.person.banned { return; } - if let Some(user_email) = user.email { + if let Some(user_email) = local_user_view.local_user.email { let subject = &format!( "{} - {} {}", subject_text, - Settings::get().hostname, - user.name, + Settings::get().hostname(), + local_user_view.person.name, ); let html = &format!( "

{}


{} - {}

inbox", body_text, - user.name, + local_user_view.person.name, comment_content, Settings::get().get_protocol_and_hostname() ); - match send_email(subject, &user_email, &user.name, html) { + match send_email(subject, &user_email, &local_user_view.person.name, html) { Ok(_o) => _o, Err(e) => error!("{}", e), }; diff --git a/crates/structs/src/user.rs b/crates/api_structs/src/person.rs similarity index 87% rename from crates/structs/src/user.rs rename to crates/api_structs/src/person.rs index dcc35f06c..ac1cca858 100644 --- a/crates/structs/src/user.rs +++ b/crates/api_structs/src/person.rs @@ -6,8 +6,8 @@ use lemmy_db_views::{ use lemmy_db_views_actor::{ community_follower_view::CommunityFollowerView, community_moderator_view::CommunityModeratorView, - user_mention_view::UserMentionView, - user_view::UserViewSafe, + person_mention_view::PersonMentionView, + person_view::PersonViewSafe, }; use serde::{Deserialize, Serialize}; @@ -70,8 +70,8 @@ pub struct LoginResponse { } #[derive(Deserialize)] -pub struct GetUserDetails { - pub user_id: Option, +pub struct GetPersonDetails { + pub person_id: Option, pub username: Option, pub sort: String, pub page: Option, @@ -82,8 +82,8 @@ pub struct GetUserDetails { } #[derive(Serialize)] -pub struct GetUserDetailsResponse { - pub user_view: UserViewSafe, +pub struct GetPersonDetailsResponse { + pub person_view: PersonViewSafe, pub follows: Vec, pub moderates: Vec, pub comments: Vec, @@ -96,8 +96,8 @@ pub struct GetRepliesResponse { } #[derive(Serialize)] -pub struct GetUserMentionsResponse { - pub mentions: Vec, +pub struct GetPersonMentionsResponse { + pub mentions: Vec, } #[derive(Deserialize)] @@ -107,19 +107,19 @@ pub struct MarkAllAsRead { #[derive(Deserialize)] pub struct AddAdmin { - pub user_id: i32, + pub person_id: i32, pub added: bool, pub auth: String, } #[derive(Serialize, Clone)] pub struct AddAdminResponse { - pub admins: Vec, + pub admins: Vec, } #[derive(Deserialize)] -pub struct BanUser { - pub user_id: i32, +pub struct BanPerson { + pub person_id: i32, pub ban: bool, pub remove_data: bool, pub reason: Option, @@ -128,8 +128,8 @@ pub struct BanUser { } #[derive(Serialize, Clone)] -pub struct BanUserResponse { - pub user_view: UserViewSafe, +pub struct BanPersonResponse { + pub person_view: PersonViewSafe, pub banned: bool, } @@ -143,7 +143,7 @@ pub struct GetReplies { } #[derive(Deserialize)] -pub struct GetUserMentions { +pub struct GetPersonMentions { pub sort: String, pub page: Option, pub limit: Option, @@ -152,15 +152,15 @@ pub struct GetUserMentions { } #[derive(Deserialize)] -pub struct MarkUserMentionAsRead { - pub user_mention_id: i32, +pub struct MarkPersonMentionAsRead { + pub person_mention_id: i32, pub read: bool, pub auth: String, } #[derive(Serialize, Clone)] -pub struct UserMentionResponse { - pub user_mention_view: UserMentionView, +pub struct PersonMentionResponse { + pub person_mention_view: PersonMentionView, } #[derive(Deserialize)] diff --git a/crates/structs/src/post.rs b/crates/api_structs/src/post.rs similarity index 97% rename from crates/structs/src/post.rs rename to crates/api_structs/src/post.rs index 4e2011e91..82be66170 100644 --- a/crates/structs/src/post.rs +++ b/crates/api_structs/src/post.rs @@ -8,11 +8,12 @@ use lemmy_db_views_actor::{ community_view::CommunityView, }; use serde::{Deserialize, Serialize}; +use url::Url; #[derive(Deserialize, Debug)] pub struct CreatePost { pub name: String, - pub url: Option, + pub url: Option, pub body: Option, pub nsfw: bool, pub community_id: i32, @@ -66,7 +67,7 @@ pub struct CreatePostLike { pub struct EditPost { pub post_id: i32, pub name: String, - pub url: Option, + pub url: Option, pub body: Option, pub nsfw: bool, pub auth: String, diff --git a/crates/structs/src/site.rs b/crates/api_structs/src/site.rs similarity index 85% rename from crates/structs/src/site.rs rename to crates/api_structs/src/site.rs index ef878ba52..d574a1604 100644 --- a/crates/structs/src/site.rs +++ b/crates/api_structs/src/site.rs @@ -1,6 +1,5 @@ -use lemmy_db_schema::source::user::UserSafeSettings; -use lemmy_db_views::{comment_view::CommentView, post_view::PostView, site_view::SiteView}; -use lemmy_db_views_actor::{community_view::CommunityView, user_view::UserViewSafe}; +use lemmy_db_views::{comment_view::CommentView, post_view::PostView, site_view::SiteView, local_user_view::LocalUserSettingsView}; +use lemmy_db_views_actor::{community_view::CommunityView, person_view::PersonViewSafe}; use lemmy_db_views_moderator::{ mod_add_community_view::ModAddCommunityView, mod_add_view::ModAddView, @@ -13,6 +12,7 @@ use lemmy_db_views_moderator::{ mod_sticky_post_view::ModStickyPostView, }; use serde::{Deserialize, Serialize}; +use url::Url; #[derive(Deserialize, Debug)] pub struct Search { @@ -32,12 +32,12 @@ pub struct SearchResponse { pub comments: Vec, pub posts: Vec, pub communities: Vec, - pub users: Vec, + pub users: Vec, } #[derive(Deserialize)] pub struct GetModlog { - pub mod_user_id: Option, + pub mod_person_id: Option, pub community_id: Option, pub page: Option, pub limit: Option, @@ -60,8 +60,8 @@ pub struct GetModlogResponse { pub struct CreateSite { pub name: String, pub description: Option, - pub icon: Option, - pub banner: Option, + pub icon: Option, + pub banner: Option, pub enable_downvotes: bool, pub open_registration: bool, pub enable_nsfw: bool, @@ -93,17 +93,17 @@ pub struct SiteResponse { #[derive(Serialize)] pub struct GetSiteResponse { pub site_view: Option, // Because the site might not be set up yet - pub admins: Vec, - pub banned: Vec, + pub admins: Vec, + pub banned: Vec, pub online: usize, pub version: String, - pub my_user: Option, + pub my_user: Option, pub federated_instances: Option, // Federation may be disabled } #[derive(Deserialize)] pub struct TransferSite { - pub user_id: i32, + pub person_id: i32, pub auth: String, } @@ -126,6 +126,6 @@ pub struct SaveSiteConfig { #[derive(Serialize)] pub struct FederatedInstances { pub linked: Vec, - pub allowed: Vec, - pub blocked: Vec, + pub allowed: Option>, + pub blocked: Option>, } diff --git a/crates/structs/src/websocket.rs b/crates/api_structs/src/websocket.rs similarity index 100% rename from crates/structs/src/websocket.rs rename to crates/api_structs/src/websocket.rs diff --git a/crates/apub/Cargo.toml b/crates/apub/Cargo.toml index f2ad96838..b0538af6a 100644 --- a/crates/apub/Cargo.toml +++ b/crates/apub/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "lemmy_apub" version = "0.1.0" -authors = ["Felix Ableitner "] edition = "2018" [lib] name = "lemmy_apub" path = "src/lib.rs" +doctest = false [dependencies] lemmy_utils = { path = "../utils" } @@ -14,7 +14,7 @@ lemmy_db_queries = { path = "../db_queries" } lemmy_db_schema = { path = "../db_schema" } lemmy_db_views = { path = "../db_views" } lemmy_db_views_actor = { path = "../db_views_actor" } -lemmy_structs = { path = "../structs" } +lemmy_api_structs = { path = "../api_structs" } lemmy_websocket = { path = "../websocket" } diesel = "1.4.5" activitystreams = "0.7.0-alpha.10" @@ -32,7 +32,7 @@ rand = "0.8.3" strum = "0.20.0" strum_macros = "0.20.1" lazy_static = "1.4.0" -url = { version = "2.2.0", features = ["serde"] } +url = { version = "2.2.1", features = ["serde"] } percent-encoding = "2.1.0" openssl = "0.10.32" http = "0.2.3" diff --git a/crates/apub/src/activities/receive/comment.rs b/crates/apub/src/activities/receive/comment.rs index 6d1817938..5e01533d9 100644 --- a/crates/apub/src/activities/receive/comment.rs +++ b/crates/apub/src/activities/receive/comment.rs @@ -1,16 +1,16 @@ -use crate::{activities::receive::get_actor_as_user, objects::FromApub, ActorType, NoteExt}; +use crate::{activities::receive::get_actor_as_person, objects::FromApub, ActorType, NoteExt}; use activitystreams::{ activity::{ActorAndObjectRefExt, Create, Dislike, Like, Remove, Update}, base::ExtendsExt, }; use anyhow::Context; +use lemmy_api_structs::{blocking, comment::CommentResponse, send_local_notifs}; use lemmy_db_queries::{source::comment::Comment_, Crud, Likeable}; use lemmy_db_schema::source::{ comment::{Comment, CommentLike, CommentLikeForm}, post::Post, }; use lemmy_db_views::comment_view::CommentView; -use lemmy_structs::{blocking, comment::CommentResponse, send_local_notifs}; use lemmy_utils::{location_info, utils::scrape_text_for_mentions, LemmyError}; use lemmy_websocket::{messages::SendComment, LemmyContext, UserOperation}; @@ -19,11 +19,11 @@ pub(crate) async fn receive_create_comment( context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { - let user = get_actor_as_user(&create, context, request_counter).await?; + let person = get_actor_as_person(&create, context, request_counter).await?; let note = NoteExt::from_any_base(create.object().to_owned().one().context(location_info!())?)? .context(location_info!())?; - let comment = Comment::from_apub(¬e, context, user.actor_id(), request_counter).await?; + let comment = Comment::from_apub(¬e, context, person.actor_id(), request_counter).await?; let post_id = comment.post_id; let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; @@ -34,7 +34,7 @@ pub(crate) async fn receive_create_comment( // anyway. let mentions = scrape_text_for_mentions(&comment.content); let recipient_ids = - send_local_notifs(mentions, comment.clone(), &user, post, context.pool(), true).await?; + send_local_notifs(mentions, comment.clone(), person, post, context.pool(), true).await?; // Refetch the view let comment_view = blocking(context.pool(), move |conn| { @@ -64,9 +64,9 @@ pub(crate) async fn receive_update_comment( ) -> Result<(), LemmyError> { let note = NoteExt::from_any_base(update.object().to_owned().one().context(location_info!())?)? .context(location_info!())?; - let user = get_actor_as_user(&update, context, request_counter).await?; + let person = get_actor_as_person(&update, context, request_counter).await?; - let comment = Comment::from_apub(¬e, context, user.actor_id(), request_counter).await?; + let comment = Comment::from_apub(¬e, context, person.actor_id(), request_counter).await?; let comment_id = comment.id; let post_id = comment.post_id; @@ -74,7 +74,7 @@ pub(crate) async fn receive_update_comment( let mentions = scrape_text_for_mentions(&comment.content); let recipient_ids = - send_local_notifs(mentions, comment, &user, post, context.pool(), false).await?; + send_local_notifs(mentions, comment, person, post, context.pool(), false).await?; // Refetch the view let comment_view = blocking(context.pool(), move |conn| { @@ -103,18 +103,18 @@ pub(crate) async fn receive_like_comment( context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { - let user = get_actor_as_user(&like, context, request_counter).await?; + let person = get_actor_as_person(&like, context, request_counter).await?; let comment_id = comment.id; let like_form = CommentLikeForm { comment_id, post_id: comment.post_id, - person_id: user.id, + person_id: person.id, score: 1, }; - let user_id = user.id; + let person_id = person.id; blocking(context.pool(), move |conn| { - CommentLike::remove(conn, user_id, comment_id)?; + CommentLike::remove(conn, person_id, comment_id)?; CommentLike::like(conn, &like_form) }) .await??; @@ -148,18 +148,18 @@ pub(crate) async fn receive_dislike_comment( context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { - let user = get_actor_as_user(&dislike, context, request_counter).await?; + let person = get_actor_as_person(&dislike, context, request_counter).await?; let comment_id = comment.id; let like_form = CommentLikeForm { comment_id, post_id: comment.post_id, - person_id: user.id, + person_id: person.id, score: -1, }; - let user_id = user.id; + let person_id = person.id; blocking(context.pool(), move |conn| { - CommentLike::remove(conn, user_id, comment_id)?; + CommentLike::remove(conn, person_id, comment_id)?; CommentLike::like(conn, &like_form) }) .await??; diff --git a/crates/apub/src/activities/receive/comment_undo.rs b/crates/apub/src/activities/receive/comment_undo.rs index 5dc021ad3..22594f338 100644 --- a/crates/apub/src/activities/receive/comment_undo.rs +++ b/crates/apub/src/activities/receive/comment_undo.rs @@ -1,9 +1,9 @@ -use crate::activities::receive::get_actor_as_user; +use crate::activities::receive::get_actor_as_person; use activitystreams::activity::{Dislike, Like}; +use lemmy_api_structs::{blocking, comment::CommentResponse}; use lemmy_db_queries::{source::comment::Comment_, Likeable}; use lemmy_db_schema::source::comment::{Comment, CommentLike}; use lemmy_db_views::comment_view::CommentView; -use lemmy_structs::{blocking, comment::CommentResponse}; use lemmy_utils::LemmyError; use lemmy_websocket::{messages::SendComment, LemmyContext, UserOperation}; @@ -13,12 +13,12 @@ pub(crate) async fn receive_undo_like_comment( context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { - let user = get_actor_as_user(like, context, request_counter).await?; + let person = get_actor_as_person(like, context, request_counter).await?; let comment_id = comment.id; - let user_id = user.id; + let person_id = person.id; blocking(context.pool(), move |conn| { - CommentLike::remove(conn, user_id, comment_id) + CommentLike::remove(conn, person_id, comment_id) }) .await??; @@ -51,12 +51,12 @@ pub(crate) async fn receive_undo_dislike_comment( context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { - let user = get_actor_as_user(dislike, context, request_counter).await?; + let person = get_actor_as_person(dislike, context, request_counter).await?; let comment_id = comment.id; - let user_id = user.id; + let person_id = person.id; blocking(context.pool(), move |conn| { - CommentLike::remove(conn, user_id, comment_id) + CommentLike::remove(conn, person_id, comment_id) }) .await??; diff --git a/crates/apub/src/activities/receive/community.rs b/crates/apub/src/activities/receive/community.rs index 54a8cdb7a..854e75f26 100644 --- a/crates/apub/src/activities/receive/community.rs +++ b/crates/apub/src/activities/receive/community.rs @@ -4,10 +4,10 @@ use activitystreams::{ base::{AnyBase, ExtendsExt}, }; use anyhow::Context; +use lemmy_api_structs::{blocking, community::CommunityResponse}; use lemmy_db_queries::{source::community::Community_, ApubObject}; use lemmy_db_schema::source::community::Community; use lemmy_db_views_actor::community_view::CommunityView; -use lemmy_structs::{blocking, community::CommunityResponse}; use lemmy_utils::{location_info, LemmyError}; use lemmy_websocket::{messages::SendCommunityRoomMessage, LemmyContext, UserOperation}; use url::Url; diff --git a/crates/apub/src/activities/receive/mod.rs b/crates/apub/src/activities/receive/mod.rs index a03e1ef52..1d5fcc300 100644 --- a/crates/apub/src/activities/receive/mod.rs +++ b/crates/apub/src/activities/receive/mod.rs @@ -1,11 +1,11 @@ -use crate::fetcher::user::get_or_fetch_and_upsert_user; +use crate::fetcher::person::get_or_fetch_and_upsert_person; use activitystreams::{ activity::{ActorAndObjectRef, ActorAndObjectRefExt}, base::{AsBase, BaseExt}, error::DomainError, }; use anyhow::{anyhow, Context}; -use lemmy_db_schema::source::user::User_; +use lemmy_db_schema::source::person::Person; use lemmy_utils::{location_info, LemmyError}; use lemmy_websocket::LemmyContext; use log::debug; @@ -28,18 +28,18 @@ where Err(anyhow!("Activity not supported").into()) } -/// Reads the actor field of an activity and returns the corresponding `User_`. -pub(crate) async fn get_actor_as_user( +/// Reads the actor field of an activity and returns the corresponding `Person`. +pub(crate) async fn get_actor_as_person( activity: &T, context: &LemmyContext, request_counter: &mut i32, -) -> Result +) -> Result where T: AsBase + ActorAndObjectRef, { let actor = activity.actor()?; - let user_uri = actor.as_single_xsd_any_uri().context(location_info!())?; - get_or_fetch_and_upsert_user(&user_uri, context, request_counter).await + let person_uri = actor.as_single_xsd_any_uri().context(location_info!())?; + get_or_fetch_and_upsert_person(&person_uri, context, request_counter).await } /// Ensure that the ID of an incoming activity comes from the same domain as the actor. Optionally diff --git a/crates/apub/src/activities/receive/post.rs b/crates/apub/src/activities/receive/post.rs index 4f1530045..528b1276a 100644 --- a/crates/apub/src/activities/receive/post.rs +++ b/crates/apub/src/activities/receive/post.rs @@ -1,13 +1,13 @@ -use crate::{activities::receive::get_actor_as_user, objects::FromApub, ActorType, PageExt}; +use crate::{activities::receive::get_actor_as_person, objects::FromApub, ActorType, PageExt}; use activitystreams::{ activity::{Create, Dislike, Like, Remove, Update}, prelude::*, }; use anyhow::Context; +use lemmy_api_structs::{blocking, post::PostResponse}; use lemmy_db_queries::{source::post::Post_, Likeable}; use lemmy_db_schema::source::post::{Post, PostLike, PostLikeForm}; use lemmy_db_views::post_view::PostView; -use lemmy_structs::{blocking, post::PostResponse}; use lemmy_utils::{location_info, LemmyError}; use lemmy_websocket::{messages::SendPost, LemmyContext, UserOperation}; @@ -16,11 +16,11 @@ pub(crate) async fn receive_create_post( context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { - let user = get_actor_as_user(&create, context, request_counter).await?; + let person = get_actor_as_person(&create, context, request_counter).await?; let page = PageExt::from_any_base(create.object().to_owned().one().context(location_info!())?)? .context(location_info!())?; - let post = Post::from_apub(&page, context, user.actor_id(), request_counter).await?; + let post = Post::from_apub(&page, context, person.actor_id(), request_counter).await?; // Refetch the view let post_id = post.id; @@ -45,11 +45,11 @@ pub(crate) async fn receive_update_post( context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { - let user = get_actor_as_user(&update, context, request_counter).await?; + let person = get_actor_as_person(&update, context, request_counter).await?; let page = PageExt::from_any_base(update.object().to_owned().one().context(location_info!())?)? .context(location_info!())?; - let post = Post::from_apub(&page, context, user.actor_id(), request_counter).await?; + let post = Post::from_apub(&page, context, person.actor_id(), request_counter).await?; let post_id = post.id; // Refetch the view @@ -75,17 +75,17 @@ pub(crate) async fn receive_like_post( context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { - let user = get_actor_as_user(&like, context, request_counter).await?; + let person = get_actor_as_person(&like, context, request_counter).await?; let post_id = post.id; let like_form = PostLikeForm { post_id, - person_id: user.id, + person_id: person.id, score: 1, }; - let user_id = user.id; + let person_id = person.id; blocking(context.pool(), move |conn| { - PostLike::remove(conn, user_id, post_id)?; + PostLike::remove(conn, person_id, post_id)?; PostLike::like(conn, &like_form) }) .await??; @@ -113,17 +113,17 @@ pub(crate) async fn receive_dislike_post( context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { - let user = get_actor_as_user(&dislike, context, request_counter).await?; + let person = get_actor_as_person(&dislike, context, request_counter).await?; let post_id = post.id; let like_form = PostLikeForm { post_id, - person_id: user.id, + person_id: person.id, score: -1, }; - let user_id = user.id; + let person_id = person.id; blocking(context.pool(), move |conn| { - PostLike::remove(conn, user_id, post_id)?; + PostLike::remove(conn, person_id, post_id)?; PostLike::like(conn, &like_form) }) .await??; diff --git a/crates/apub/src/activities/receive/post_undo.rs b/crates/apub/src/activities/receive/post_undo.rs index 0b9d6f4a4..67cc20df7 100644 --- a/crates/apub/src/activities/receive/post_undo.rs +++ b/crates/apub/src/activities/receive/post_undo.rs @@ -1,9 +1,9 @@ -use crate::activities::receive::get_actor_as_user; +use crate::activities::receive::get_actor_as_person; use activitystreams::activity::{Dislike, Like}; +use lemmy_api_structs::{blocking, post::PostResponse}; use lemmy_db_queries::{source::post::Post_, Likeable}; use lemmy_db_schema::source::post::{Post, PostLike}; use lemmy_db_views::post_view::PostView; -use lemmy_structs::{blocking, post::PostResponse}; use lemmy_utils::LemmyError; use lemmy_websocket::{messages::SendPost, LemmyContext, UserOperation}; @@ -13,12 +13,12 @@ pub(crate) async fn receive_undo_like_post( context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { - let user = get_actor_as_user(like, context, request_counter).await?; + let person = get_actor_as_person(like, context, request_counter).await?; let post_id = post.id; - let user_id = user.id; + let person_id = person.id; blocking(context.pool(), move |conn| { - PostLike::remove(conn, user_id, post_id) + PostLike::remove(conn, person_id, post_id) }) .await??; @@ -45,12 +45,12 @@ pub(crate) async fn receive_undo_dislike_post( context: &LemmyContext, request_counter: &mut i32, ) -> Result<(), LemmyError> { - let user = get_actor_as_user(dislike, context, request_counter).await?; + let person = get_actor_as_person(dislike, context, request_counter).await?; let post_id = post.id; - let user_id = user.id; + let person_id = person.id; blocking(context.pool(), move |conn| { - PostLike::remove(conn, user_id, post_id) + PostLike::remove(conn, person_id, post_id) }) .await??; diff --git a/crates/apub/src/activities/receive/private_message.rs b/crates/apub/src/activities/receive/private_message.rs index 160b20ece..45d4a689d 100644 --- a/crates/apub/src/activities/receive/private_message.rs +++ b/crates/apub/src/activities/receive/private_message.rs @@ -1,7 +1,7 @@ use crate::{ activities::receive::verify_activity_domains_valid, check_is_apub_id_valid, - fetcher::user::get_or_fetch_and_upsert_user, + fetcher::person::get_or_fetch_and_upsert_person, inbox::get_activity_to_and_cc, objects::FromApub, NoteExt, @@ -13,10 +13,10 @@ use activitystreams::{ public, }; use anyhow::{anyhow, Context}; +use lemmy_api_structs::{blocking, person::PrivateMessageResponse}; use lemmy_db_queries::source::private_message::PrivateMessage_; use lemmy_db_schema::source::private_message::PrivateMessage; use lemmy_db_views::private_message_view::PrivateMessageView; -use lemmy_structs::{blocking, user::PrivateMessageResponse}; use lemmy_utils::{location_info, LemmyError}; use lemmy_websocket::{messages::SendUserRoomMessage, LemmyContext, UserOperation}; use url::Url; @@ -181,19 +181,19 @@ where { let to_and_cc = get_activity_to_and_cc(activity); if to_and_cc.len() != 1 { - return Err(anyhow!("Private message can only be addressed to one user").into()); + return Err(anyhow!("Private message can only be addressed to one person").into()); } if to_and_cc.contains(&public()) { return Err(anyhow!("Private message cant be public").into()); } - let user_id = activity + let person_id = activity .actor()? .to_owned() .single_xsd_any_uri() .context(location_info!())?; - check_is_apub_id_valid(&user_id)?; - // check that the sender is a user, not a community - get_or_fetch_and_upsert_user(&user_id, &context, request_counter).await?; + check_is_apub_id_valid(&person_id)?; + // check that the sender is a person, not a community + get_or_fetch_and_upsert_person(&person_id, &context, request_counter).await?; Ok(()) } diff --git a/crates/apub/src/activities/send/comment.rs b/crates/apub/src/activities/send/comment.rs index f007cda42..c11e86b73 100644 --- a/crates/apub/src/activities/send/comment.rs +++ b/crates/apub/src/activities/send/comment.rs @@ -2,7 +2,7 @@ use crate::{ activities::send::generate_activity_id, activity_queue::{send_comment_mentions, send_to_community}, extensions::context::lemmy_context, - fetcher::user::get_or_fetch_and_upsert_user, + fetcher::person::get_or_fetch_and_upsert_person, objects::ToApub, ActorType, ApubLikeableType, @@ -26,12 +26,12 @@ use activitystreams::{ }; use anyhow::anyhow; use itertools::Itertools; +use lemmy_api_structs::{blocking, WebFingerResponse}; use lemmy_db_queries::{Crud, DbPool}; -use lemmy_db_schema::source::{comment::Comment, community::Community, post::Post, user::User_}; -use lemmy_structs::{blocking, WebFingerResponse}; +use lemmy_db_schema::source::{comment::Comment, community::Community, post::Post, person::Person}; use lemmy_utils::{ request::{retry, RecvError}, - settings::Settings, + settings::structs::Settings, utils::{scrape_text_for_mentions, MentionData}, LemmyError, }; @@ -44,8 +44,8 @@ use url::Url; #[async_trait::async_trait(?Send)] impl ApubObjectType for Comment { /// Send out information about a newly created comment, to the followers of the community and - /// mentioned users. - async fn send_create(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> { + /// mentioned persons. + async fn send_create(&self, creator: &Person, context: &LemmyContext) -> Result<(), LemmyError> { let note = self.to_apub(context.pool()).await?; let post_id = self.post_id; @@ -77,8 +77,8 @@ impl ApubObjectType for Comment { } /// Send out information about an edited post, to the followers of the community and mentioned - /// users. - async fn send_update(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> { + /// persons. + async fn send_update(&self, creator: &Person, context: &LemmyContext) -> Result<(), LemmyError> { let note = self.to_apub(context.pool()).await?; let post_id = self.post_id; @@ -109,7 +109,7 @@ impl ApubObjectType for Comment { Ok(()) } - async fn send_delete(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> { + async fn send_delete(&self, creator: &Person, context: &LemmyContext) -> Result<(), LemmyError> { let post_id = self.post_id; let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; @@ -135,7 +135,7 @@ impl ApubObjectType for Comment { async fn send_undo_delete( &self, - creator: &User_, + creator: &Person, context: &LemmyContext, ) -> Result<(), LemmyError> { let post_id = self.post_id; @@ -173,7 +173,7 @@ impl ApubObjectType for Comment { Ok(()) } - async fn send_remove(&self, mod_: &User_, context: &LemmyContext) -> Result<(), LemmyError> { + async fn send_remove(&self, mod_: &Person, context: &LemmyContext) -> Result<(), LemmyError> { let post_id = self.post_id; let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; @@ -197,7 +197,7 @@ impl ApubObjectType for Comment { Ok(()) } - async fn send_undo_remove(&self, mod_: &User_, context: &LemmyContext) -> Result<(), LemmyError> { + async fn send_undo_remove(&self, mod_: &Person, context: &LemmyContext) -> Result<(), LemmyError> { let post_id = self.post_id; let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; @@ -236,7 +236,7 @@ impl ApubObjectType for Comment { #[async_trait::async_trait(?Send)] impl ApubLikeableType for Comment { - async fn send_like(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> { + async fn send_like(&self, creator: &Person, context: &LemmyContext) -> Result<(), LemmyError> { let post_id = self.post_id; let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; @@ -260,7 +260,7 @@ impl ApubLikeableType for Comment { Ok(()) } - async fn send_dislike(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> { + async fn send_dislike(&self, creator: &Person, context: &LemmyContext) -> Result<(), LemmyError> { let post_id = self.post_id; let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??; @@ -286,7 +286,7 @@ impl ApubLikeableType for Comment { async fn send_undo_like( &self, - creator: &User_, + creator: &Person, context: &LemmyContext, ) -> Result<(), LemmyError> { let post_id = self.post_id; @@ -342,7 +342,7 @@ impl MentionsAndAddresses { /// This takes a comment, and builds a list of to_addresses, inboxes, /// and mention tags, so they know where to be sent to. -/// Addresses are the users / addresses that go in the cc field. +/// Addresses are the persons / addresses that go in the cc field. async fn collect_non_local_mentions( comment: &Comment, community: &Community, @@ -356,7 +356,7 @@ async fn collect_non_local_mentions( // Add the mention tag let mut tags = Vec::new(); - // Get the user IDs for any mentions + // Get the person IDs for any mentions let mentions = scrape_text_for_mentions(&comment.content) .into_iter() // Filter only the non-local ones @@ -369,8 +369,8 @@ async fn collect_non_local_mentions( debug!("mention actor_id: {}", actor_id); addressed_ccs.push(actor_id.to_owned().to_string().parse()?); - let mention_user = get_or_fetch_and_upsert_user(&actor_id, context, &mut 0).await?; - inboxes.push(mention_user.get_shared_inbox_or_inbox_url()); + let mention_person = get_or_fetch_and_upsert_person(&actor_id, context, &mut 0).await?; + inboxes.push(mention_person.get_shared_inbox_or_inbox_url()); let mut mention_tag = Mention::new(); mention_tag.set_href(actor_id).set_name(mention.full_name()); @@ -387,9 +387,9 @@ async fn collect_non_local_mentions( }) } -/// Returns the apub ID of the user this comment is responding to. Meaning, in case this is a +/// Returns the apub ID of the person this comment is responding to. Meaning, in case this is a /// top-level comment, the creator of the post, otherwise the creator of the parent comment. -async fn get_comment_parent_creator(pool: &DbPool, comment: &Comment) -> Result { +async fn get_comment_parent_creator(pool: &DbPool, comment: &Comment) -> Result { let parent_creator_id = if let Some(parent_comment_id) = comment.parent_id { let parent_comment = blocking(pool, move |conn| Comment::read(conn, parent_comment_id)).await??; @@ -399,10 +399,10 @@ async fn get_comment_parent_creator(pool: &DbPool, comment: &Comment) -> Result< let parent_post = blocking(pool, move |conn| Post::read(conn, parent_post_id)).await??; parent_post.creator_id }; - Ok(blocking(pool, move |conn| User_::read(conn, parent_creator_id)).await??) + Ok(blocking(pool, move |conn| Person::read(conn, parent_creator_id)).await??) } -/// Turns a user id like `@name@example.com` into an apub ID, like `https://example.com/user/name`, +/// Turns a person id like `@name@example.com` into an apub ID, like `https://example.com/user/name`, /// using webfinger. async fn fetch_webfinger_url(mention: &MentionData, client: &Client) -> Result { let fetch_url = format!( diff --git a/crates/apub/src/activities/send/community.rs b/crates/apub/src/activities/send/community.rs index a574c7b85..9cef95b60 100644 --- a/crates/apub/src/activities/send/community.rs +++ b/crates/apub/src/activities/send/community.rs @@ -3,7 +3,7 @@ use crate::{ activity_queue::{send_activity_single_dest, send_to_community_followers}, check_is_apub_id_valid, extensions::context::lemmy_context, - fetcher::user::get_or_fetch_and_upsert_user, + fetcher::person::get_or_fetch_and_upsert_person, ActorType, }; use activitystreams::{ @@ -23,10 +23,10 @@ use activitystreams::{ }; use anyhow::Context; use itertools::Itertools; +use lemmy_api_structs::blocking; use lemmy_db_queries::DbPool; use lemmy_db_schema::source::community::Community; use lemmy_db_views_actor::community_follower_view::CommunityFollowerView; -use lemmy_structs::blocking; use lemmy_utils::{location_info, LemmyError}; use lemmy_websocket::LemmyContext; use url::Url; @@ -70,7 +70,7 @@ impl ActorType for Community { unimplemented!() } - /// As a local community, accept the follow request from a remote user. + /// As a local community, accept the follow request from a remote person. async fn send_accept_follow( &self, follow: Follow, @@ -80,7 +80,7 @@ impl ActorType for Community { .actor()? .as_single_xsd_any_uri() .context(location_info!())?; - let user = get_or_fetch_and_upsert_user(actor_uri, context, &mut 0).await?; + let person = get_or_fetch_and_upsert_person(actor_uri, context, &mut 0).await?; let mut accept = Accept::new( self.actor_id.to_owned().into_inner(), @@ -89,9 +89,9 @@ impl ActorType for Community { accept .set_many_contexts(lemmy_context()?) .set_id(generate_activity_id(AcceptType::Accept)?) - .set_to(user.actor_id()); + .set_to(person.actor_id()); - send_activity_single_dest(accept, self, user.inbox_url.into(), context).await?; + send_activity_single_dest(accept, self, person.inbox_url.into(), context).await?; Ok(()) } diff --git a/crates/apub/src/activities/send/mod.rs b/crates/apub/src/activities/send/mod.rs index 166855e20..7f19d0426 100644 --- a/crates/apub/src/activities/send/mod.rs +++ b/crates/apub/src/activities/send/mod.rs @@ -1,4 +1,4 @@ -use lemmy_utils::settings::Settings; +use lemmy_utils::settings::structs::Settings; use url::{ParseError, Url}; use uuid::Uuid; @@ -6,7 +6,7 @@ pub(crate) mod comment; pub(crate) mod community; pub(crate) mod post; pub(crate) mod private_message; -pub(crate) mod user; +pub(crate) mod person; /// Generate a unique ID for an activity, in the format: /// `http(s)://example.com/receive/create/202daf0a-1489-45df-8d2e-c8a3173fed36` diff --git a/crates/apub/src/activities/send/user.rs b/crates/apub/src/activities/send/person.rs similarity index 96% rename from crates/apub/src/activities/send/user.rs rename to crates/apub/src/activities/send/person.rs index 13ec73400..40cc14228 100644 --- a/crates/apub/src/activities/send/user.rs +++ b/crates/apub/src/activities/send/person.rs @@ -13,18 +13,18 @@ use activitystreams::{ base::{AnyBase, BaseExt, ExtendsExt}, object::ObjectExt, }; +use lemmy_api_structs::blocking; use lemmy_db_queries::{ApubObject, DbPool, Followable}; use lemmy_db_schema::source::{ community::{Community, CommunityFollower, CommunityFollowerForm}, - user::User_, + person::Person, }; -use lemmy_structs::blocking; use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; use url::Url; #[async_trait::async_trait(?Send)] -impl ActorType for User_ { +impl ActorType for Person { fn is_local(&self) -> bool { self.local } @@ -48,7 +48,7 @@ impl ActorType for User_ { .into() } - /// As a given local user, send out a follow request to a remote community. + /// As a given local person, send out a follow request to a remote community. async fn send_follow( &self, follow_actor_id: &Url, diff --git a/crates/apub/src/activities/send/post.rs b/crates/apub/src/activities/send/post.rs index ce74d20a5..0fe3f6344 100644 --- a/crates/apub/src/activities/send/post.rs +++ b/crates/apub/src/activities/send/post.rs @@ -21,16 +21,16 @@ use activitystreams::{ prelude::*, public, }; +use lemmy_api_structs::blocking; use lemmy_db_queries::Crud; -use lemmy_db_schema::source::{community::Community, post::Post, user::User_}; -use lemmy_structs::blocking; +use lemmy_db_schema::source::{community::Community, post::Post, person::Person}; use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; #[async_trait::async_trait(?Send)] impl ApubObjectType for Post { /// Send out information about a newly created post, to the followers of the community. - async fn send_create(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> { + async fn send_create(&self, creator: &Person, context: &LemmyContext) -> Result<(), LemmyError> { let page = self.to_apub(context.pool()).await?; let community_id = self.community_id; @@ -54,7 +54,7 @@ impl ApubObjectType for Post { } /// Send out information about an edited post, to the followers of the community. - async fn send_update(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> { + async fn send_update(&self, creator: &Person, context: &LemmyContext) -> Result<(), LemmyError> { let page = self.to_apub(context.pool()).await?; let community_id = self.community_id; @@ -77,7 +77,7 @@ impl ApubObjectType for Post { Ok(()) } - async fn send_delete(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> { + async fn send_delete(&self, creator: &Person, context: &LemmyContext) -> Result<(), LemmyError> { let community_id = self.community_id; let community = blocking(context.pool(), move |conn| { Community::read(conn, community_id) @@ -100,7 +100,7 @@ impl ApubObjectType for Post { async fn send_undo_delete( &self, - creator: &User_, + creator: &Person, context: &LemmyContext, ) -> Result<(), LemmyError> { let community_id = self.community_id; @@ -134,7 +134,7 @@ impl ApubObjectType for Post { Ok(()) } - async fn send_remove(&self, mod_: &User_, context: &LemmyContext) -> Result<(), LemmyError> { + async fn send_remove(&self, mod_: &Person, context: &LemmyContext) -> Result<(), LemmyError> { let community_id = self.community_id; let community = blocking(context.pool(), move |conn| { Community::read(conn, community_id) @@ -155,7 +155,7 @@ impl ApubObjectType for Post { Ok(()) } - async fn send_undo_remove(&self, mod_: &User_, context: &LemmyContext) -> Result<(), LemmyError> { + async fn send_undo_remove(&self, mod_: &Person, context: &LemmyContext) -> Result<(), LemmyError> { let community_id = self.community_id; let community = blocking(context.pool(), move |conn| { Community::read(conn, community_id) @@ -190,7 +190,7 @@ impl ApubObjectType for Post { #[async_trait::async_trait(?Send)] impl ApubLikeableType for Post { - async fn send_like(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> { + async fn send_like(&self, creator: &Person, context: &LemmyContext) -> Result<(), LemmyError> { let community_id = self.community_id; let community = blocking(context.pool(), move |conn| { Community::read(conn, community_id) @@ -211,7 +211,7 @@ impl ApubLikeableType for Post { Ok(()) } - async fn send_dislike(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> { + async fn send_dislike(&self, creator: &Person, context: &LemmyContext) -> Result<(), LemmyError> { let community_id = self.community_id; let community = blocking(context.pool(), move |conn| { Community::read(conn, community_id) @@ -234,7 +234,7 @@ impl ApubLikeableType for Post { async fn send_undo_like( &self, - creator: &User_, + creator: &Person, context: &LemmyContext, ) -> Result<(), LemmyError> { let community_id = self.community_id; diff --git a/crates/apub/src/activities/send/private_message.rs b/crates/apub/src/activities/send/private_message.rs index 31184a702..cf0046fa4 100644 --- a/crates/apub/src/activities/send/private_message.rs +++ b/crates/apub/src/activities/send/private_message.rs @@ -16,20 +16,20 @@ use activitystreams::{ }, prelude::*, }; +use lemmy_api_structs::blocking; use lemmy_db_queries::Crud; -use lemmy_db_schema::source::{private_message::PrivateMessage, user::User_}; -use lemmy_structs::blocking; +use lemmy_db_schema::source::{private_message::PrivateMessage, person::Person}; use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; #[async_trait::async_trait(?Send)] impl ApubObjectType for PrivateMessage { /// Send out information about a newly created private message - async fn send_create(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> { + async fn send_create(&self, creator: &Person, context: &LemmyContext) -> Result<(), LemmyError> { let note = self.to_apub(context.pool()).await?; let recipient_id = self.recipient_id; - let recipient = blocking(context.pool(), move |conn| User_::read(conn, recipient_id)).await??; + let recipient = blocking(context.pool(), move |conn| Person::read(conn, recipient_id)).await??; let mut create = Create::new( creator.actor_id.to_owned().into_inner(), @@ -46,11 +46,11 @@ impl ApubObjectType for PrivateMessage { } /// Send out information about an edited private message, to the followers of the community. - async fn send_update(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> { + async fn send_update(&self, creator: &Person, context: &LemmyContext) -> Result<(), LemmyError> { let note = self.to_apub(context.pool()).await?; let recipient_id = self.recipient_id; - let recipient = blocking(context.pool(), move |conn| User_::read(conn, recipient_id)).await??; + let recipient = blocking(context.pool(), move |conn| Person::read(conn, recipient_id)).await??; let mut update = Update::new( creator.actor_id.to_owned().into_inner(), @@ -65,9 +65,9 @@ impl ApubObjectType for PrivateMessage { Ok(()) } - async fn send_delete(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError> { + async fn send_delete(&self, creator: &Person, context: &LemmyContext) -> Result<(), LemmyError> { let recipient_id = self.recipient_id; - let recipient = blocking(context.pool(), move |conn| User_::read(conn, recipient_id)).await??; + let recipient = blocking(context.pool(), move |conn| Person::read(conn, recipient_id)).await??; let mut delete = Delete::new( creator.actor_id.to_owned().into_inner(), @@ -84,11 +84,11 @@ impl ApubObjectType for PrivateMessage { async fn send_undo_delete( &self, - creator: &User_, + creator: &Person, context: &LemmyContext, ) -> Result<(), LemmyError> { let recipient_id = self.recipient_id; - let recipient = blocking(context.pool(), move |conn| User_::read(conn, recipient_id)).await??; + let recipient = blocking(context.pool(), move |conn| Person::read(conn, recipient_id)).await??; let mut delete = Delete::new( creator.actor_id.to_owned().into_inner(), @@ -113,13 +113,13 @@ impl ApubObjectType for PrivateMessage { Ok(()) } - async fn send_remove(&self, _mod_: &User_, _context: &LemmyContext) -> Result<(), LemmyError> { + async fn send_remove(&self, _mod_: &Person, _context: &LemmyContext) -> Result<(), LemmyError> { unimplemented!() } async fn send_undo_remove( &self, - _mod_: &User_, + _mod_: &Person, _context: &LemmyContext, ) -> Result<(), LemmyError> { unimplemented!() diff --git a/crates/apub/src/activity_queue.rs b/crates/apub/src/activity_queue.rs index c0c4ac468..ccee1b903 100644 --- a/crates/apub/src/activity_queue.rs +++ b/crates/apub/src/activity_queue.rs @@ -21,8 +21,8 @@ use background_jobs::{ }; use itertools::Itertools; use lemmy_db_queries::DbPool; -use lemmy_db_schema::source::{community::Community, user::User_}; -use lemmy_utils::{location_info, settings::Settings, LemmyError}; +use lemmy_db_schema::source::{community::Community, person::Person}; +use lemmy_utils::{location_info, settings::structs::Settings, LemmyError}; use lemmy_websocket::LemmyContext; use log::{debug, warn}; use reqwest::Client; @@ -88,7 +88,7 @@ where .await? .iter() .unique() - .filter(|inbox| inbox.host_str() != Some(&Settings::get().hostname)) + .filter(|inbox| inbox.host_str() != Some(&Settings::get().hostname())) .filter(|inbox| check_is_apub_id_valid(inbox).is_ok()) .map(|inbox| inbox.to_owned()) .collect(); @@ -112,7 +112,7 @@ where Ok(()) } -/// Sends an activity from a local user to a remote community. +/// Sends an activity from a local person to a remote community. /// /// * `activity` the activity to send /// * `creator` the creator of the activity @@ -120,7 +120,7 @@ where /// pub(crate) async fn send_to_community( activity: T, - creator: &User_, + creator: &Person, community: &Community, context: &LemmyContext, ) -> Result<(), LemmyError> @@ -157,13 +157,13 @@ where Ok(()) } -/// Sends notification to any users mentioned in a comment +/// Sends notification to any persons mentioned in a comment /// -/// * `creator` user who created the comment -/// * `mentions` list of inboxes of users which are mentioned in the comment +/// * `creator` person who created the comment +/// * `mentions` list of inboxes of persons which are mentioned in the comment /// * `activity` either a `Create/Note` or `Update/Note` pub(crate) async fn send_comment_mentions( - creator: &User_, + creator: &Person, mentions: Vec, activity: T, context: &LemmyContext, @@ -215,7 +215,7 @@ where Kind: Serialize, >::Error: From + Send + Sync + 'static, { - if !Settings::get().federation.enabled || inboxes.is_empty() { + if !Settings::get().federation().enabled || inboxes.is_empty() { return Ok(()); } @@ -223,7 +223,7 @@ where let hostname = Settings::get().get_hostname_without_port()?; let inboxes: Vec<&Url> = inboxes .iter() - .filter(|i| i.domain().unwrap() != hostname) + .filter(|i| i.domain().expect("valid inbox url") != hostname) .collect(); let activity = activity.into_any_base()?; diff --git a/crates/apub/src/extensions/context.rs b/crates/apub/src/extensions/context.rs index fe52ab95d..b670e60d8 100644 --- a/crates/apub/src/extensions/context.rs +++ b/crates/apub/src/extensions/context.rs @@ -6,12 +6,11 @@ pub(crate) fn lemmy_context() -> Result, LemmyError> { let context_ext = AnyBase::from_arbitrary_json(json!( { "sc": "http://schema.org#", - "category": "sc:category", "sensitive": "as:sensitive", "stickied": "as:stickied", "comments_enabled": { - "kind": "sc:Boolean", - "id": "pt:commentsEnabled" + "kind": "sc:Boolean", + "id": "pt:commentsEnabled" } }))?; Ok(vec![AnyBase::from(context()), context_ext]) diff --git a/crates/apub/src/extensions/signatures.rs b/crates/apub/src/extensions/signatures.rs index ebbf9a0a4..a9b4cfbdf 100644 --- a/crates/apub/src/extensions/signatures.rs +++ b/crates/apub/src/extensions/signatures.rs @@ -95,7 +95,7 @@ pub(crate) fn verify_signature( } } -/// Extension for actor public key, which is needed on user and community for HTTP signatures. +/// Extension for actor public key, which is needed on person and community for HTTP signatures. /// /// Taken from: https://docs.rs/activitystreams/0.5.0-alpha.17/activitystreams/ext/index.html #[derive(Clone, Debug, Deserialize, Serialize)] diff --git a/crates/apub/src/fetcher/community.rs b/crates/apub/src/fetcher/community.rs index e1211f33b..12821bbe8 100644 --- a/crates/apub/src/fetcher/community.rs +++ b/crates/apub/src/fetcher/community.rs @@ -1,11 +1,11 @@ use crate::{ fetcher::{ fetch::fetch_remote_object, - get_or_fetch_and_upsert_user, + get_or_fetch_and_upsert_person, is_deleted, should_refetch_actor, }, - inbox::user_inbox::receive_announce, + inbox::person_inbox::receive_announce, objects::FromApub, GroupExt, }; @@ -16,9 +16,9 @@ use activitystreams::{ }; use anyhow::Context; use diesel::result::Error::NotFound; +use lemmy_api_structs::blocking; use lemmy_db_queries::{source::community::Community_, ApubObject, Joinable}; use lemmy_db_schema::source::community::{Community, CommunityModerator, CommunityModeratorForm}; -use lemmy_structs::blocking; use lemmy_utils::{location_info, LemmyError}; use lemmy_websocket::LemmyContext; use log::debug; @@ -92,7 +92,7 @@ async fn fetch_remote_community( let mut creator_and_moderators = Vec::new(); for uri in creator_and_moderator_uris { - let c_or_m = get_or_fetch_and_upsert_user(uri, context, recursion_counter).await?; + let c_or_m = get_or_fetch_and_upsert_person(uri, context, recursion_counter).await?; creator_and_moderators.push(c_or_m); } diff --git a/crates/apub/src/fetcher/mod.rs b/crates/apub/src/fetcher/mod.rs index 593b163fa..2c1b6b9af 100644 --- a/crates/apub/src/fetcher/mod.rs +++ b/crates/apub/src/fetcher/mod.rs @@ -2,13 +2,13 @@ pub(crate) mod community; mod fetch; pub(crate) mod objects; pub mod search; -pub(crate) mod user; +pub(crate) mod person; use crate::{ fetcher::{ community::get_or_fetch_and_upsert_community, fetch::FetchError, - user::get_or_fetch_and_upsert_user, + person::get_or_fetch_and_upsert_person, }, ActorType, }; @@ -37,8 +37,8 @@ where false } -/// Get a remote actor from its apub ID (either a user or a community). Thin wrapper around -/// `get_or_fetch_and_upsert_user()` and `get_or_fetch_and_upsert_community()`. +/// Get a remote actor from its apub ID (either a person or a community). Thin wrapper around +/// `get_or_fetch_and_upsert_person()` and `get_or_fetch_and_upsert_community()`. /// /// If it exists locally and `!should_refetch_actor()`, it is returned directly from the database. /// Otherwise it is fetched from the remote instance, stored and returned. @@ -50,7 +50,7 @@ pub(crate) async fn get_or_fetch_and_upsert_actor( let community = get_or_fetch_and_upsert_community(apub_id, context, recursion_counter).await; let actor: Box = match community { Ok(c) => Box::new(c), - Err(_) => Box::new(get_or_fetch_and_upsert_user(apub_id, context, recursion_counter).await?), + Err(_) => Box::new(get_or_fetch_and_upsert_person(apub_id, context, recursion_counter).await?), }; Ok(actor) } diff --git a/crates/apub/src/fetcher/objects.rs b/crates/apub/src/fetcher/objects.rs index df33bf740..6e0369bde 100644 --- a/crates/apub/src/fetcher/objects.rs +++ b/crates/apub/src/fetcher/objects.rs @@ -1,9 +1,9 @@ use crate::{fetcher::fetch::fetch_remote_object, objects::FromApub, NoteExt, PageExt}; use anyhow::anyhow; use diesel::result::Error::NotFound; +use lemmy_api_structs::blocking; use lemmy_db_queries::{ApubObject, Crud}; use lemmy_db_schema::source::{comment::Comment, post::Post}; -use lemmy_structs::blocking; use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; use log::debug; diff --git a/crates/apub/src/fetcher/user.rs b/crates/apub/src/fetcher/person.rs similarity index 55% rename from crates/apub/src/fetcher/user.rs rename to crates/apub/src/fetcher/person.rs index 21cdfb348..120ff8453 100644 --- a/crates/apub/src/fetcher/user.rs +++ b/crates/apub/src/fetcher/person.rs @@ -5,66 +5,66 @@ use crate::{ }; use anyhow::anyhow; use diesel::result::Error::NotFound; -use lemmy_db_queries::{source::user::User, ApubObject}; -use lemmy_db_schema::source::user::User_; -use lemmy_structs::blocking; +use lemmy_api_structs::blocking; +use lemmy_db_queries::{source::person::Person_, ApubObject}; +use lemmy_db_schema::source::person::Person; use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; use log::debug; use url::Url; -/// Get a user from its apub ID. +/// Get a person from its apub ID. /// /// If it exists locally and `!should_refetch_actor()`, it is returned directly from the database. /// Otherwise it is fetched from the remote instance, stored and returned. -pub(crate) async fn get_or_fetch_and_upsert_user( +pub(crate) async fn get_or_fetch_and_upsert_person( apub_id: &Url, context: &LemmyContext, recursion_counter: &mut i32, -) -> Result { +) -> Result { let apub_id_owned = apub_id.to_owned(); - let user = blocking(context.pool(), move |conn| { - User_::read_from_apub_id(conn, &apub_id_owned.into()) + let person = blocking(context.pool(), move |conn| { + Person::read_from_apub_id(conn, &apub_id_owned.into()) }) .await?; - match user { + match person { // If its older than a day, re-fetch it Ok(u) if !u.local && should_refetch_actor(u.last_refreshed_at) => { - debug!("Fetching and updating from remote user: {}", apub_id); + debug!("Fetching and updating from remote person: {}", apub_id); let person = fetch_remote_object::(context.client(), apub_id, recursion_counter).await; if is_deleted(&person) { - // TODO: use User_::update_deleted() once implemented + // TODO: use Person::update_deleted() once implemented blocking(context.pool(), move |conn| { - User_::delete_account(conn, u.id) + Person::delete_account(conn, u.id) }) .await??; - return Err(anyhow!("User was deleted by remote instance").into()); + return Err(anyhow!("Person was deleted by remote instance").into()); } else if person.is_err() { return Ok(u); } - let user = User_::from_apub(&person?, context, apub_id.to_owned(), recursion_counter).await?; + let person = Person::from_apub(&person?, context, apub_id.to_owned(), recursion_counter).await?; - let user_id = user.id; + let person_id = person.id; blocking(context.pool(), move |conn| { - User_::mark_as_updated(conn, user_id) + Person::mark_as_updated(conn, person_id) }) .await??; - Ok(user) + Ok(person) } Ok(u) => Ok(u), Err(NotFound {}) => { - debug!("Fetching and creating remote user: {}", apub_id); + debug!("Fetching and creating remote person: {}", apub_id); let person = fetch_remote_object::(context.client(), apub_id, recursion_counter).await?; - let user = User_::from_apub(&person, context, apub_id.to_owned(), recursion_counter).await?; + let person = Person::from_apub(&person, context, apub_id.to_owned(), recursion_counter).await?; - Ok(user) + Ok(person) } Err(e) => Err(e.into()), } diff --git a/crates/apub/src/fetcher/search.rs b/crates/apub/src/fetcher/search.rs index a831ac404..0b2921c7b 100644 --- a/crates/apub/src/fetcher/search.rs +++ b/crates/apub/src/fetcher/search.rs @@ -2,7 +2,7 @@ use crate::{ fetcher::{ fetch::fetch_remote_object, get_or_fetch_and_upsert_community, - get_or_fetch_and_upsert_user, + get_or_fetch_and_upsert_person, is_deleted, }, find_object_by_id, @@ -15,13 +15,14 @@ use crate::{ }; use activitystreams::base::BaseExt; use anyhow::{anyhow, Context}; +use lemmy_api_structs::{blocking, site::SearchResponse}; use lemmy_db_queries::{ source::{ comment::Comment_, community::Community_, post::Post_, private_message::PrivateMessage_, - user::User, + person::Person_, }, SearchType, }; @@ -30,12 +31,11 @@ use lemmy_db_schema::source::{ community::Community, post::Post, private_message::PrivateMessage, - user::User_, + person::Person, }; use lemmy_db_views::{comment_view::CommentView, post_view::PostView}; -use lemmy_db_views_actor::{community_view::CommunityView, user_view::UserViewSafe}; -use lemmy_structs::{blocking, site::SearchResponse}; -use lemmy_utils::{settings::Settings, LemmyError}; +use lemmy_db_views_actor::{community_view::CommunityView, person_view::PersonViewSafe}; +use lemmy_utils::{settings::structs::Settings, LemmyError}; use lemmy_websocket::LemmyContext; use log::debug; use url::Url; @@ -66,7 +66,7 @@ pub async fn search_by_apub_id( debug!("Search for {}", query); let split = query.split('@').collect::>(); - // User type will look like ['', username, instance] + // Person type will look like ['', username, instance] // Community will look like [!community, instance] let (name, instance) = if split.len() == 3 { (format!("/u/{}", split[1]), split[2]) @@ -122,13 +122,13 @@ async fn build_response( match fetch_response { SearchAcceptedObjects::Person(p) => { - let user_uri = p.inner.id(domain)?.context("person has no id")?; + let person_uri = p.inner.id(domain)?.context("person has no id")?; - let user = get_or_fetch_and_upsert_user(&user_uri, context, recursion_counter).await?; + let person = get_or_fetch_and_upsert_person(&person_uri, context, recursion_counter).await?; response.users = vec![ blocking(context.pool(), move |conn| { - UserViewSafe::read(conn, user.id) + PersonViewSafe::read(conn, person.id) }) .await??, ]; @@ -182,10 +182,10 @@ async fn delete_object_locally(query_url: &Url, context: &LemmyContext) -> Resul }) .await??; } - Object::User(u) => { + Object::Person(u) => { // TODO: implement update_deleted() for user, move it to ApubObject trait blocking(context.pool(), move |conn| { - User_::delete_account(conn, u.id) + Person::delete_account(conn, u.id) }) .await??; } diff --git a/crates/apub/src/http/comment.rs b/crates/apub/src/http/comment.rs index 44397db60..d4287224c 100644 --- a/crates/apub/src/http/comment.rs +++ b/crates/apub/src/http/comment.rs @@ -4,9 +4,9 @@ use crate::{ }; use actix_web::{body::Body, web, web::Path, HttpResponse}; use diesel::result::Error::NotFound; +use lemmy_api_structs::blocking; use lemmy_db_queries::Crud; use lemmy_db_schema::source::comment::Comment; -use lemmy_structs::blocking; use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; use serde::Deserialize; diff --git a/crates/apub/src/http/community.rs b/crates/apub/src/http/community.rs index 964ac2a15..2306286a7 100644 --- a/crates/apub/src/http/community.rs +++ b/crates/apub/src/http/community.rs @@ -9,10 +9,10 @@ use activitystreams::{ collection::{CollectionExt, OrderedCollection, UnorderedCollection}, }; use actix_web::{body::Body, web, HttpResponse}; +use lemmy_api_structs::blocking; use lemmy_db_queries::source::{activity::Activity_, community::Community_}; use lemmy_db_schema::source::{activity::Activity, community::Community}; use lemmy_db_views_actor::community_follower_view::CommunityFollowerView; -use lemmy_structs::blocking; use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; use serde::Deserialize; diff --git a/crates/apub/src/http/mod.rs b/crates/apub/src/http/mod.rs index f0ffbcb1e..5a1add8d7 100644 --- a/crates/apub/src/http/mod.rs +++ b/crates/apub/src/http/mod.rs @@ -1,17 +1,18 @@ use crate::APUB_JSON_CONTENT_TYPE; use actix_web::{body::Body, web, HttpResponse}; use http::StatusCode; +use lemmy_api_structs::blocking; use lemmy_db_queries::source::activity::Activity_; use lemmy_db_schema::source::activity::Activity; -use lemmy_structs::blocking; -use lemmy_utils::{settings::Settings, LemmyError}; +use lemmy_utils::{settings::structs::Settings, LemmyError}; use lemmy_websocket::LemmyContext; use serde::{Deserialize, Serialize}; +use url::Url; pub mod comment; pub mod community; pub mod post; -pub mod user; +pub mod person; /// Convert the data to json and turn it into an HTTP Response with the correct ActivityPub /// headers. @@ -46,12 +47,13 @@ pub async fn get_activity( context: web::Data, ) -> Result, LemmyError> { let settings = Settings::get(); - let activity_id = format!( + let activity_id = Url::parse(&format!( "{}/activities/{}/{}", settings.get_protocol_and_hostname(), info.type_, info.id - ); + ))? + .into(); let activity = blocking(context.pool(), move |conn| { Activity::read_from_apub_id(&conn, &activity_id) }) diff --git a/crates/apub/src/http/user.rs b/crates/apub/src/http/person.rs similarity index 51% rename from crates/apub/src/http/user.rs rename to crates/apub/src/http/person.rs index 7c7653e57..89d678cf5 100644 --- a/crates/apub/src/http/user.rs +++ b/crates/apub/src/http/person.rs @@ -9,70 +9,70 @@ use activitystreams::{ collection::{CollectionExt, OrderedCollection}, }; use actix_web::{body::Body, web, HttpResponse}; -use lemmy_db_queries::source::user::User; -use lemmy_db_schema::source::user::User_; -use lemmy_structs::blocking; +use lemmy_api_structs::blocking; +use lemmy_db_queries::source::person::Person_; +use lemmy_db_schema::source::person::Person; use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; use serde::Deserialize; use url::Url; #[derive(Deserialize)] -pub struct UserQuery { +pub struct PersonQuery { user_name: String, } -/// Return the ActivityPub json representation of a local user over HTTP. -pub async fn get_apub_user_http( - info: web::Path, +/// Return the ActivityPub json representation of a local person over HTTP. +pub async fn get_apub_person_http( + info: web::Path, context: web::Data, ) -> Result, LemmyError> { let user_name = info.into_inner().user_name; - // TODO: this needs to be able to read deleted users, so that it can send tombstones - let user = blocking(context.pool(), move |conn| { - User_::find_by_email_or_username(conn, &user_name) + // TODO: this needs to be able to read deleted persons, so that it can send tombstones + let person = blocking(context.pool(), move |conn| { + Person::find_by_name(conn, &user_name) }) .await??; - if !user.deleted { - let apub = user.to_apub(context.pool()).await?; + if !person.deleted { + let apub = person.to_apub(context.pool()).await?; Ok(create_apub_response(&apub)) } else { - Ok(create_apub_tombstone_response(&user.to_tombstone()?)) + Ok(create_apub_tombstone_response(&person.to_tombstone()?)) } } -pub async fn get_apub_user_outbox( - info: web::Path, +pub async fn get_apub_person_outbox( + info: web::Path, context: web::Data, ) -> Result, LemmyError> { - let user = blocking(context.pool(), move |conn| { - User_::read_from_name(&conn, &info.user_name) + let person = blocking(context.pool(), move |conn| { + Person::find_by_name(&conn, &info.user_name) }) .await??; - // TODO: populate the user outbox + // TODO: populate the person outbox let mut collection = OrderedCollection::new(); collection .set_many_items(Vec::::new()) .set_many_contexts(lemmy_context()?) - .set_id(user.get_outbox_url()?) + .set_id(person.get_outbox_url()?) .set_total_items(0_u64); Ok(create_apub_response(&collection)) } -pub async fn get_apub_user_inbox( - info: web::Path, +pub async fn get_apub_person_inbox( + info: web::Path, context: web::Data, ) -> Result, LemmyError> { - let user = blocking(context.pool(), move |conn| { - User_::read_from_name(&conn, &info.user_name) + let person = blocking(context.pool(), move |conn| { + Person::find_by_name(&conn, &info.user_name) }) .await??; let mut collection = OrderedCollection::new(); collection - .set_id(format!("{}/inbox", user.actor_id.into_inner()).parse()?) + .set_id(format!("{}/inbox", person.actor_id.into_inner()).parse()?) .set_many_contexts(lemmy_context()?); Ok(create_apub_response(&collection)) } diff --git a/crates/apub/src/http/post.rs b/crates/apub/src/http/post.rs index 66adae3ac..8bdded2a0 100644 --- a/crates/apub/src/http/post.rs +++ b/crates/apub/src/http/post.rs @@ -4,9 +4,9 @@ use crate::{ }; use actix_web::{body::Body, web, HttpResponse}; use diesel::result::Error::NotFound; +use lemmy_api_structs::blocking; use lemmy_db_queries::Crud; use lemmy_db_schema::source::post::Post; -use lemmy_structs::blocking; use lemmy_utils::LemmyError; use lemmy_websocket::LemmyContext; use serde::Deserialize; diff --git a/crates/apub/src/inbox/community_inbox.rs b/crates/apub/src/inbox/community_inbox.rs index 6a51f9fd7..f82b1b55f 100644 --- a/crates/apub/src/inbox/community_inbox.rs +++ b/crates/apub/src/inbox/community_inbox.rs @@ -26,13 +26,13 @@ use activitystreams::{ }; use actix_web::{web, HttpRequest, HttpResponse}; use anyhow::{anyhow, Context}; +use lemmy_api_structs::blocking; use lemmy_db_queries::{source::community::Community_, ApubObject, DbPool, Followable}; use lemmy_db_schema::source::{ community::{Community, CommunityFollower, CommunityFollowerForm}, - user::User_, + person::Person, }; -use lemmy_db_views_actor::community_user_ban_view::CommunityUserBanView; -use lemmy_structs::blocking; +use lemmy_db_views_actor::community_person_ban_view::CommunityPersonBanView; use lemmy_utils::{location_info, LemmyError}; use lemmy_websocket::LemmyContext; use log::info; @@ -44,8 +44,8 @@ use url::Url; #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Deserialize, Serialize)] #[serde(rename_all = "PascalCase")] pub enum CommunityValidTypes { - Follow, // follow request from a user - Undo, // unfollow from a user + Follow, // follow request from a person + Undo, // unfollow from a person Create, // create post or comment Update, // update post or comment Like, // upvote post or comment @@ -113,21 +113,21 @@ pub(crate) async fn community_receive_message( context: &LemmyContext, request_counter: &mut i32, ) -> Result { - // Only users can send activities to the community, so we can get the actor as user + // Only persons can send activities to the community, so we can get the actor as person // unconditionally. let actor_id = actor.actor_id(); - let user = blocking(&context.pool(), move |conn| { - User_::read_from_apub_id(&conn, &actor_id.into()) + let person = blocking(&context.pool(), move |conn| { + Person::read_from_apub_id(&conn, &actor_id.into()) }) .await??; - check_community_or_site_ban(&user, to_community.id, context.pool()).await?; + check_community_or_site_ban(&person, to_community.id, context.pool()).await?; let any_base = activity.clone().into_any_base()?; let actor_url = actor.actor_id(); let activity_kind = activity.kind().context(location_info!())?; let do_announce = match activity_kind { CommunityValidTypes::Follow => { - handle_follow(any_base.clone(), user, &to_community, &context).await?; + handle_follow(any_base.clone(), person, &to_community, &context).await?; false } CommunityValidTypes::Undo => { @@ -162,7 +162,7 @@ pub(crate) async fn community_receive_message( } CommunityValidTypes::Remove => { // TODO: we dont support remote mods, so this is ignored for now - //receive_remove_for_community(context, any_base.clone(), &user_url).await? + //receive_remove_for_community(context, any_base.clone(), &person_url).await? false } }; @@ -178,20 +178,20 @@ pub(crate) async fn community_receive_message( Ok(HttpResponse::Ok().finish()) } -/// Handle a follow request from a remote user, adding the user as follower and returning an +/// Handle a follow request from a remote person, adding the person as follower and returning an /// Accept activity. async fn handle_follow( activity: AnyBase, - user: User_, + person: Person, community: &Community, context: &LemmyContext, ) -> Result { let follow = Follow::from_any_base(activity)?.context(location_info!())?; - verify_activity_domains_valid(&follow, &user.actor_id(), false)?; + verify_activity_domains_valid(&follow, &person.actor_id(), false)?; let community_follower_form = CommunityFollowerForm { community_id: community.id, - person_id: user.id, + person_id: person.id, pending: false, }; @@ -226,27 +226,27 @@ async fn handle_undo( } } -/// Handle `Undo/Follow` from a user, removing the user from followers list. +/// Handle `Undo/Follow` from a person, removing the person from followers list. async fn handle_undo_follow( activity: AnyBase, - user_url: Url, + person_url: Url, community: &Community, context: &LemmyContext, ) -> Result<(), LemmyError> { let undo = Undo::from_any_base(activity)?.context(location_info!())?; - verify_activity_domains_valid(&undo, &user_url, true)?; + verify_activity_domains_valid(&undo, &person_url, true)?; let object = undo.object().to_owned().one().context(location_info!())?; let follow = Follow::from_any_base(object)?.context(location_info!())?; - verify_activity_domains_valid(&follow, &user_url, false)?; + verify_activity_domains_valid(&follow, &person_url, false)?; - let user = blocking(&context.pool(), move |conn| { - User_::read_from_apub_id(&conn, &user_url.into()) + let person = blocking(&context.pool(), move |conn| { + Person::read_from_apub_id(&conn, &person_url.into()) }) .await??; let community_follower_form = CommunityFollowerForm { community_id: community.id, - person_id: user.id, + person_id: person.id, pending: false, }; @@ -260,17 +260,17 @@ async fn handle_undo_follow( } pub(crate) async fn check_community_or_site_ban( - user: &User_, + person: &Person, community_id: i32, pool: &DbPool, ) -> Result<(), LemmyError> { - if user.banned { - return Err(anyhow!("User is banned from site").into()); + if person.banned { + return Err(anyhow!("Person is banned from site").into()); } - let user_id = user.id; - let is_banned = move |conn: &'_ _| CommunityUserBanView::get(conn, user_id, community_id).is_ok(); + let person_id = person.id; + let is_banned = move |conn: &'_ _| CommunityPersonBanView::get(conn, person_id, community_id).is_ok(); if blocking(pool, is_banned).await? { - return Err(anyhow!("User is banned from community").into()); + return Err(anyhow!("Person is banned from community").into()); } Ok(()) diff --git a/crates/apub/src/inbox/mod.rs b/crates/apub/src/inbox/mod.rs index 765d5dff4..71d1c1338 100644 --- a/crates/apub/src/inbox/mod.rs +++ b/crates/apub/src/inbox/mod.rs @@ -12,14 +12,14 @@ use activitystreams::{ }; use actix_web::HttpRequest; use anyhow::{anyhow, Context}; +use lemmy_api_structs::blocking; use lemmy_db_queries::{ source::{activity::Activity_, community::Community_}, ApubObject, DbPool, }; -use lemmy_db_schema::source::{activity::Activity, community::Community, user::User_}; -use lemmy_structs::blocking; -use lemmy_utils::{location_info, settings::Settings, LemmyError}; +use lemmy_db_schema::source::{activity::Activity, community::Community, person::Person}; +use lemmy_utils::{location_info, settings::structs::Settings, LemmyError}; use lemmy_websocket::LemmyContext; use serde::Serialize; use std::fmt::Debug; @@ -28,7 +28,7 @@ use url::Url; pub mod community_inbox; mod receive_for_community; pub mod shared_inbox; -pub mod user_inbox; +pub mod person_inbox; pub(crate) fn get_activity_id(activity: &T, creator_uri: &Url) -> Result where @@ -45,7 +45,7 @@ pub(crate) async fn is_activity_already_known( pool: &DbPool, activity_id: &Url, ) -> Result { - let activity_id = activity_id.to_string(); + let activity_id = activity_id.to_owned().into(); let existing = blocking(pool, move |conn| { Activity::read_from_apub_id(&conn, &activity_id) }) @@ -119,17 +119,17 @@ where } /// Returns true if `to_and_cc` contains at least one local user. -pub(crate) async fn is_addressed_to_local_user( +pub(crate) async fn is_addressed_to_local_person( to_and_cc: &[Url], pool: &DbPool, ) -> Result { for url in to_and_cc { let url = url.to_owned(); - let user = blocking(&pool, move |conn| { - User_::read_from_apub_id(&conn, &url.into()) + let person = blocking(&pool, move |conn| { + Person::read_from_apub_id(&conn, &url.into()) }) .await?; - if let Ok(u) = user { + if let Ok(u) = person { if u.local { return Ok(true); } @@ -167,7 +167,7 @@ where let id = activity.id_unchecked().context(location_info!())?; let activity_domain = id.domain().context(location_info!())?; - if activity_domain == Settings::get().hostname { + if activity_domain == Settings::get().hostname() { return Err( anyhow!( "Error: received activity which was sent by local instance: {:?}", diff --git a/crates/apub/src/inbox/user_inbox.rs b/crates/apub/src/inbox/person_inbox.rs similarity index 85% rename from crates/apub/src/inbox/user_inbox.rs rename to crates/apub/src/inbox/person_inbox.rs index 5657faf1e..c83c5037b 100644 --- a/crates/apub/src/inbox/user_inbox.rs +++ b/crates/apub/src/inbox/person_inbox.rs @@ -25,7 +25,7 @@ use crate::{ inbox_verify_http_signature, is_activity_already_known, is_addressed_to_community_followers, - is_addressed_to_local_user, + is_addressed_to_local_person, is_addressed_to_public, receive_for_community::{ receive_create_for_community, @@ -48,13 +48,13 @@ use activitystreams::{ use actix_web::{web, HttpRequest, HttpResponse}; use anyhow::{anyhow, Context}; use diesel::NotFound; -use lemmy_db_queries::{source::user::User, ApubObject, Followable}; +use lemmy_api_structs::blocking; +use lemmy_db_queries::{source::person::Person_, ApubObject, Followable}; use lemmy_db_schema::source::{ community::{Community, CommunityFollower}, private_message::PrivateMessage, - user::User_, + person::Person, }; -use lemmy_structs::blocking; use lemmy_utils::{location_info, LemmyError}; use lemmy_websocket::LemmyContext; use log::debug; @@ -63,10 +63,10 @@ use std::fmt::Debug; use strum_macros::EnumString; use url::Url; -/// Allowed activities for user inbox. +/// Allowed activities for person inbox. #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Deserialize, Serialize)] #[serde(rename_all = "PascalCase")] -pub enum UserValidTypes { +pub enum PersonValidTypes { Accept, // community accepted our follow request Create, // create private message Update, // edit private message @@ -76,12 +76,12 @@ pub enum UserValidTypes { Announce, // post, comment or vote in community } -pub type UserAcceptedActivities = ActorAndObject; +pub type PersonAcceptedActivities = ActorAndObject; -/// Handler for all incoming activities to user inboxes. -pub async fn user_inbox( +/// Handler for all incoming activities to person inboxes. +pub async fn person_inbox( request: HttpRequest, - input: web::Json, + input: web::Json, path: web::Path, context: web::Data, ) -> Result { @@ -98,29 +98,29 @@ pub async fn user_inbox( // Check if the activity is actually meant for us let username = path.into_inner(); - let user = blocking(&context.pool(), move |conn| { - User_::read_from_name(&conn, &username) + let person = blocking(&context.pool(), move |conn| { + Person::find_by_name(&conn, &username) }) .await??; let to_and_cc = get_activity_to_and_cc(&activity); // TODO: we should also accept activities that are sent to community followers - if !to_and_cc.contains(&&user.actor_id()) { - return Err(anyhow!("Activity delivered to wrong user").into()); + if !to_and_cc.contains(&&person.actor_id()) { + return Err(anyhow!("Activity delivered to wrong person").into()); } assert_activity_not_local(&activity)?; insert_activity(&activity_id, activity.clone(), false, true, context.pool()).await?; debug!( - "User {} received activity {:?} from {}", - user.name, + "Person {} received activity {:?} from {}", + person.name, &activity.id_unchecked(), &actor.actor_id() ); - user_receive_message( + person_receive_message( activity.clone(), - Some(user.clone()), + Some(person.clone()), actor.as_ref(), &context, request_counter, @@ -129,36 +129,43 @@ pub async fn user_inbox( } /// Receives Accept/Follow, Announce, private messages and community (undo) remove, (undo) delete -pub(crate) async fn user_receive_message( - activity: UserAcceptedActivities, - to_user: Option, +pub(crate) async fn person_receive_message( + activity: PersonAcceptedActivities, + to_person: Option, actor: &dyn ActorType, context: &LemmyContext, request_counter: &mut i32, ) -> Result { - is_for_user_inbox(context, &activity).await?; + is_for_person_inbox(context, &activity).await?; let any_base = activity.clone().into_any_base()?; let kind = activity.kind().context(location_info!())?; let actor_url = actor.actor_id(); match kind { - UserValidTypes::Accept => { - receive_accept(&context, any_base, actor, to_user.unwrap(), request_counter).await?; + PersonValidTypes::Accept => { + receive_accept( + &context, + any_base, + actor, + to_person.expect("person provided"), + request_counter, + ) + .await?; } - UserValidTypes::Announce => { + PersonValidTypes::Announce => { receive_announce(&context, any_base, actor, request_counter).await? } - UserValidTypes::Create => { + PersonValidTypes::Create => { receive_create(&context, any_base, actor_url, request_counter).await? } - UserValidTypes::Update => { + PersonValidTypes::Update => { receive_update(&context, any_base, actor_url, request_counter).await? } - UserValidTypes::Delete => { + PersonValidTypes::Delete => { receive_delete(context, any_base, &actor_url, request_counter).await? } - UserValidTypes::Undo => receive_undo(context, any_base, &actor_url, request_counter).await?, - UserValidTypes::Remove => receive_remove_community(&context, any_base, &actor_url).await?, + PersonValidTypes::Undo => receive_undo(context, any_base, &actor_url, request_counter).await?, + PersonValidTypes::Remove => receive_remove_community(&context, any_base, &actor_url).await?, }; // TODO: would be logical to move websocket notification code here @@ -166,16 +173,16 @@ pub(crate) async fn user_receive_message( Ok(HttpResponse::Ok().finish()) } -/// Returns true if the activity is addressed directly to one or more local users, or if it is -/// addressed to the followers collection of a remote community, and at least one local user follows +/// Returns true if the activity is addressed directly to one or more local persons, or if it is +/// addressed to the followers collection of a remote community, and at least one local person follows /// it. -async fn is_for_user_inbox( +async fn is_for_person_inbox( context: &LemmyContext, - activity: &UserAcceptedActivities, + activity: &PersonAcceptedActivities, ) -> Result<(), LemmyError> { let to_and_cc = get_activity_to_and_cc(activity); - // Check if it is addressed directly to any local user - if is_addressed_to_local_user(&to_and_cc, context.pool()).await? { + // Check if it is addressed directly to any local person + if is_addressed_to_local_person(&to_and_cc, context.pool()).await? { return Ok(()); } @@ -198,7 +205,7 @@ async fn is_for_user_inbox( } } - Err(anyhow!("Not addressed for any local user").into()) + Err(anyhow!("Not addressed for any local person").into()) } /// Handle accepted follows. @@ -206,7 +213,7 @@ async fn receive_accept( context: &LemmyContext, activity: AnyBase, actor: &dyn ActorType, - user: User_, + person: Person, request_counter: &mut i32, ) -> Result<(), LemmyError> { let accept = Accept::from_any_base(activity)?.context(location_info!())?; @@ -214,7 +221,7 @@ async fn receive_accept( let object = accept.object().to_owned().one().context(location_info!())?; let follow = Follow::from_any_base(object)?.context(location_info!())?; - verify_activity_domains_valid(&follow, &user.actor_id(), false)?; + verify_activity_domains_valid(&follow, &person.actor_id(), false)?; let community_uri = accept .actor()? @@ -226,10 +233,10 @@ async fn receive_accept( get_or_fetch_and_upsert_community(&community_uri, context, request_counter).await?; let community_id = community.id; - let user_id = user.id; + let person_id = person.id; // This will throw an error if no follow was requested blocking(&context.pool(), move |conn| { - CommunityFollower::follow_accepted(conn, community_id, user_id) + CommunityFollower::follow_accepted(conn, community_id, person_id) }) .await??; diff --git a/crates/apub/src/inbox/receive_for_community.rs b/crates/apub/src/inbox/receive_for_community.rs index e3704d97a..3c5c23034 100644 --- a/crates/apub/src/inbox/receive_for_community.rs +++ b/crates/apub/src/inbox/receive_for_community.rs @@ -43,9 +43,9 @@ use activitystreams::{ }; use anyhow::Context; use diesel::result::Error::NotFound; +use lemmy_api_structs::blocking; use lemmy_db_queries::Crud; use lemmy_db_schema::source::site::Site; -use lemmy_structs::blocking; use lemmy_utils::{location_info, LemmyError}; use lemmy_websocket::LemmyContext; use strum_macros::EnumString; @@ -58,7 +58,7 @@ enum PageOrNote { } /// This file is for post/comment activities received by the community, and for post/comment -/// activities announced by the community and received by the user. +/// activities announced by the community and received by the person. /// A post or comment being created pub(in crate::inbox) async fn receive_create_for_community( @@ -115,11 +115,14 @@ pub(in crate::inbox) async fn receive_like_for_community( verify_activity_domains_valid(&like, &expected_domain, false)?; is_addressed_to_public(&like)?; - let object_id = get_like_object_id(&like)?; + let object_id = like + .object() + .as_single_xsd_any_uri() + .context(location_info!())?; match fetch_post_or_comment_by_id(&object_id, context, request_counter).await? { - PostOrComment::Post(post) => receive_like_post(like, post, context, request_counter).await, + PostOrComment::Post(post) => receive_like_post(like, *post, context, request_counter).await, PostOrComment::Comment(comment) => { - receive_like_comment(like, comment, context, request_counter).await + receive_like_comment(like, *comment, context, request_counter).await } } } @@ -143,13 +146,16 @@ pub(in crate::inbox) async fn receive_dislike_for_community( verify_activity_domains_valid(&dislike, &expected_domain, false)?; is_addressed_to_public(&dislike)?; - let object_id = get_like_object_id(&dislike)?; + let object_id = dislike + .object() + .as_single_xsd_any_uri() + .context(location_info!())?; match fetch_post_or_comment_by_id(&object_id, context, request_counter).await? { PostOrComment::Post(post) => { - receive_dislike_post(dislike, post, context, request_counter).await + receive_dislike_post(dislike, *post, context, request_counter).await } PostOrComment::Comment(comment) => { - receive_dislike_comment(dislike, comment, context, request_counter).await + receive_dislike_comment(dislike, *comment, context, request_counter).await } } } @@ -171,8 +177,8 @@ pub(in crate::inbox) async fn receive_delete_for_community( .context(location_info!())?; match find_post_or_comment_by_id(context, object).await { - Ok(PostOrComment::Post(p)) => receive_delete_post(context, p).await, - Ok(PostOrComment::Comment(c)) => receive_delete_comment(context, c).await, + Ok(PostOrComment::Post(p)) => receive_delete_post(context, *p).await, + Ok(PostOrComment::Comment(c)) => receive_delete_comment(context, *c).await, // if we dont have the object, no need to do anything Err(_) => Ok(()), } @@ -209,8 +215,8 @@ pub(in crate::inbox) async fn receive_remove_for_community( remove.id(community_id.domain().context(location_info!())?)?; match find_post_or_comment_by_id(context, object).await { - Ok(PostOrComment::Post(p)) => receive_remove_post(context, remove, p).await, - Ok(PostOrComment::Comment(c)) => receive_remove_comment(context, remove, c).await, + Ok(PostOrComment::Post(p)) => receive_remove_post(context, remove, *p).await, + Ok(PostOrComment::Comment(c)) => receive_remove_comment(context, remove, *c).await, // if we dont have the object, no need to do anything Err(_) => Ok(()), } @@ -270,8 +276,8 @@ pub(in crate::inbox) async fn receive_undo_delete_for_community( .single_xsd_any_uri() .context(location_info!())?; match find_post_or_comment_by_id(context, object).await { - Ok(PostOrComment::Post(p)) => receive_undo_delete_post(context, p).await, - Ok(PostOrComment::Comment(c)) => receive_undo_delete_comment(context, c).await, + Ok(PostOrComment::Post(p)) => receive_undo_delete_post(context, *p).await, + Ok(PostOrComment::Comment(c)) => receive_undo_delete_comment(context, *c).await, // if we dont have the object, no need to do anything Err(_) => Ok(()), } @@ -294,8 +300,8 @@ pub(in crate::inbox) async fn receive_undo_remove_for_community( .single_xsd_any_uri() .context(location_info!())?; match find_post_or_comment_by_id(context, object).await { - Ok(PostOrComment::Post(p)) => receive_undo_remove_post(context, p).await, - Ok(PostOrComment::Comment(c)) => receive_undo_remove_comment(context, c).await, + Ok(PostOrComment::Post(p)) => receive_undo_remove_post(context, *p).await, + Ok(PostOrComment::Comment(c)) => receive_undo_remove_comment(context, *c).await, // if we dont have the object, no need to do anything Err(_) => Ok(()), } @@ -313,13 +319,16 @@ pub(in crate::inbox) async fn receive_undo_like_for_community( verify_activity_domains_valid(&like, &expected_domain, false)?; is_addressed_to_public(&like)?; - let object_id = get_like_object_id(&like)?; + let object_id = like + .object() + .as_single_xsd_any_uri() + .context(location_info!())?; match fetch_post_or_comment_by_id(&object_id, context, request_counter).await? { PostOrComment::Post(post) => { - receive_undo_like_post(&like, post, context, request_counter).await + receive_undo_like_post(&like, *post, context, request_counter).await } PostOrComment::Comment(comment) => { - receive_undo_like_comment(&like, comment, context, request_counter).await + receive_undo_like_comment(&like, *comment, context, request_counter).await } } } @@ -336,13 +345,16 @@ pub(in crate::inbox) async fn receive_undo_dislike_for_community( verify_activity_domains_valid(&dislike, &expected_domain, false)?; is_addressed_to_public(&dislike)?; - let object_id = get_like_object_id(&dislike)?; + let object_id = dislike + .object() + .as_single_xsd_any_uri() + .context(location_info!())?; match fetch_post_or_comment_by_id(&object_id, context, request_counter).await? { PostOrComment::Post(post) => { - receive_undo_dislike_post(&dislike, post, context, request_counter).await + receive_undo_dislike_post(&dislike, *post, context, request_counter).await } PostOrComment::Comment(comment) => { - receive_undo_dislike_comment(&dislike, comment, context, request_counter).await + receive_undo_dislike_comment(&dislike, *comment, context, request_counter).await } } } @@ -353,35 +365,12 @@ async fn fetch_post_or_comment_by_id( request_counter: &mut i32, ) -> Result { if let Ok(post) = get_or_fetch_and_insert_post(apub_id, context, request_counter).await { - return Ok(PostOrComment::Post(post)); + return Ok(PostOrComment::Post(Box::new(post))); } if let Ok(comment) = get_or_fetch_and_insert_comment(apub_id, context, request_counter).await { - return Ok(PostOrComment::Comment(comment)); + return Ok(PostOrComment::Comment(Box::new(comment))); } Err(NotFound.into()) } - -fn get_like_object_id(like_or_dislike: &Activity) -> Result -where - Activity: ActorAndObjectRefExt, -{ - // TODO: For backwards compatibility with older Lemmy versions where like.object contains a full - // post/comment. This can be removed after some time, using - // `activity.oject().as_single_xsd_any_uri()` instead. - let object = like_or_dislike.object(); - if let Some(xsd_uri) = object.as_single_xsd_any_uri() { - Ok(xsd_uri.to_owned()) - } else { - Ok( - object - .to_owned() - .one() - .context(location_info!())? - .id() - .context(location_info!())? - .to_owned(), - ) - } -} diff --git a/crates/apub/src/inbox/shared_inbox.rs b/crates/apub/src/inbox/shared_inbox.rs index 93df6e728..dd82110a9 100644 --- a/crates/apub/src/inbox/shared_inbox.rs +++ b/crates/apub/src/inbox/shared_inbox.rs @@ -7,17 +7,17 @@ use crate::{ inbox_verify_http_signature, is_activity_already_known, is_addressed_to_community_followers, - is_addressed_to_local_user, - user_inbox::{user_receive_message, UserAcceptedActivities}, + is_addressed_to_local_person, + person_inbox::{person_receive_message, PersonAcceptedActivities}, }, insert_activity, }; use activitystreams::{activity::ActorAndObject, prelude::*}; use actix_web::{web, HttpRequest, HttpResponse}; use anyhow::Context; +use lemmy_api_structs::blocking; use lemmy_db_queries::{ApubObject, DbPool}; use lemmy_db_schema::source::community::Community; -use lemmy_structs::blocking; use lemmy_utils::{location_info, LemmyError}; use lemmy_websocket::LemmyContext; use serde::{Deserialize, Serialize}; @@ -69,9 +69,9 @@ pub async fn shared_inbox( let mut res: Option = None; let to_and_cc = get_activity_to_and_cc(&activity); // Handle community first, so in case the sender is banned by the community, it will error out. - // If we handled the user receive first, the activity would be inserted to the database before the + // If we handled the person receive first, the activity would be inserted to the database before the // community could check for bans. - // Note that an activity can be addressed to a community and to a user (or multiple users) at the + // Note that an activity can be addressed to a community and to a person (or multiple persons) at the // same time. In this case we still only handle it once, to avoid duplicate websocket // notifications. let community = extract_local_community_from_destinations(&to_and_cc, context.pool()).await?; @@ -88,13 +88,13 @@ pub async fn shared_inbox( ) .await?, ); - } else if is_addressed_to_local_user(&to_and_cc, context.pool()).await? { - let user_activity = UserAcceptedActivities::from_any_base(activity_any_base.clone())? + } else if is_addressed_to_local_person(&to_and_cc, context.pool()).await? { + let person_activity = PersonAcceptedActivities::from_any_base(activity_any_base.clone())? .context(location_info!())?; - // `to_user` is only used for follow activities (which we dont receive here), so no need to pass + // `to_person` is only used for follow activities (which we dont receive here), so no need to pass // it in - user_receive_message( - user_activity, + person_receive_message( + person_activity, None, actor.as_ref(), &context, @@ -105,11 +105,11 @@ pub async fn shared_inbox( .await? .is_some() { - let user_activity = UserAcceptedActivities::from_any_base(activity_any_base.clone())? + let person_activity = PersonAcceptedActivities::from_any_base(activity_any_base.clone())? .context(location_info!())?; res = Some( - user_receive_message( - user_activity, + person_receive_message( + person_activity, None, actor.as_ref(), &context, diff --git a/crates/apub/src/lib.rs b/crates/apub/src/lib.rs index 388d57e6a..2def37d91 100644 --- a/crates/apub/src/lib.rs +++ b/crates/apub/src/lib.rs @@ -24,17 +24,20 @@ use activitystreams::{ use activitystreams_ext::{Ext1, Ext2}; use anyhow::{anyhow, Context}; use diesel::NotFound; +use lemmy_api_structs::blocking; use lemmy_db_queries::{source::activity::Activity_, ApubObject, DbPool}; -use lemmy_db_schema::source::{ - activity::Activity, - comment::Comment, - community::Community, - post::Post, - private_message::PrivateMessage, - user::User_, +use lemmy_db_schema::{ + source::{ + activity::Activity, + comment::Comment, + community::Community, + post::Post, + private_message::PrivateMessage, + person::Person as DbPerson, + }, + DbUrl, }; -use lemmy_structs::blocking; -use lemmy_utils::{location_info, settings::Settings, LemmyError}; +use lemmy_utils::{location_info, settings::structs::Settings, LemmyError}; use lemmy_websocket::LemmyContext; use serde::Serialize; use std::net::IpAddr; @@ -42,7 +45,7 @@ use url::{ParseError, Url}; /// Activitystreams type for community type GroupExt = Ext2>, GroupExtension, PublicKeyExtension>; -/// Activitystreams type for user +/// Activitystreams type for person type PersonExt = Ext1>, PublicKeyExtension>; /// Activitystreams type for post type PageExt = Ext1, PageExtension>; @@ -64,7 +67,7 @@ fn check_is_apub_id_valid(apub_id: &Url) -> Result<(), LemmyError> { let domain = apub_id.domain().context(location_info!())?.to_string(); let local_instance = settings.get_hostname_without_port()?; - if !settings.federation.enabled { + if !settings.federation().enabled { return if domain == local_instance { Ok(()) } else { @@ -88,22 +91,23 @@ fn check_is_apub_id_valid(apub_id: &Url) -> Result<(), LemmyError> { return Err(anyhow!("invalid apub id scheme {}: {}", apub_id.scheme(), apub_id).into()); } - let mut allowed_instances = Settings::get().get_allowed_instances(); + let allowed_instances = Settings::get().get_allowed_instances(); let blocked_instances = Settings::get().get_blocked_instances(); - if allowed_instances.is_empty() && blocked_instances.is_empty() { + + if allowed_instances.is_none() && blocked_instances.is_none() { Ok(()) - } else if !allowed_instances.is_empty() { + } else if let Some(mut allowed) = allowed_instances { // need to allow this explicitly because apub receive might contain objects from our local // instance. split is needed to remove the port in our federation test setup. - allowed_instances.push(local_instance); + allowed.push(local_instance); - if allowed_instances.contains(&domain) { + if allowed.contains(&domain) { Ok(()) } else { Err(anyhow!("{} not in federation allowlist", domain).into()) } - } else if !blocked_instances.is_empty() { - if blocked_instances.contains(&domain) { + } else if let Some(blocked) = blocked_instances { + if blocked.contains(&domain) { Err(anyhow!("{} is in federation blocklist", domain).into()) } else { Ok(()) @@ -117,27 +121,27 @@ fn check_is_apub_id_valid(apub_id: &Url) -> Result<(), LemmyError> { /// and actors in Lemmy. #[async_trait::async_trait(?Send)] pub trait ApubObjectType { - async fn send_create(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError>; - async fn send_update(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError>; - async fn send_delete(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError>; + async fn send_create(&self, creator: &DbPerson, context: &LemmyContext) -> Result<(), LemmyError>; + async fn send_update(&self, creator: &DbPerson, context: &LemmyContext) -> Result<(), LemmyError>; + async fn send_delete(&self, creator: &DbPerson, context: &LemmyContext) -> Result<(), LemmyError>; async fn send_undo_delete( &self, - creator: &User_, + creator: &DbPerson, context: &LemmyContext, ) -> Result<(), LemmyError>; - async fn send_remove(&self, mod_: &User_, context: &LemmyContext) -> Result<(), LemmyError>; - async fn send_undo_remove(&self, mod_: &User_, context: &LemmyContext) -> Result<(), LemmyError>; + async fn send_remove(&self, mod_: &DbPerson, context: &LemmyContext) -> Result<(), LemmyError>; + async fn send_undo_remove(&self, mod_: &DbPerson, context: &LemmyContext) -> Result<(), LemmyError>; } #[async_trait::async_trait(?Send)] pub trait ApubLikeableType { - async fn send_like(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError>; - async fn send_dislike(&self, creator: &User_, context: &LemmyContext) -> Result<(), LemmyError>; - async fn send_undo_like(&self, creator: &User_, context: &LemmyContext) + async fn send_like(&self, creator: &DbPerson, context: &LemmyContext) -> Result<(), LemmyError>; + async fn send_dislike(&self, creator: &DbPerson, context: &LemmyContext) -> Result<(), LemmyError>; + async fn send_undo_like(&self, creator: &DbPerson, context: &LemmyContext) -> Result<(), LemmyError>; } -/// Common methods provided by ActivityPub actors (community and user). Not all methods are +/// Common methods provided by ActivityPub actors (community and person). Not all methods are /// implemented by all actors. #[async_trait::async_trait(?Send)] pub trait ActorType { @@ -205,7 +209,7 @@ pub trait ActorType { pub enum EndpointType { Community, - User, + Person, Post, Comment, PrivateMessage, @@ -215,10 +219,10 @@ pub enum EndpointType { pub fn generate_apub_endpoint( endpoint_type: EndpointType, name: &str, -) -> Result { +) -> Result { let point = match endpoint_type { EndpointType::Community => "c", - EndpointType::User => "u", + EndpointType::Person => "u", EndpointType::Post => "post", EndpointType::Comment => "comment", EndpointType::PrivateMessage => "private_message", @@ -235,21 +239,15 @@ pub fn generate_apub_endpoint( ) } -pub fn generate_followers_url( - actor_id: &lemmy_db_schema::Url, -) -> Result { +pub fn generate_followers_url(actor_id: &DbUrl) -> Result { Ok(Url::parse(&format!("{}/followers", actor_id))?.into()) } -pub fn generate_inbox_url( - actor_id: &lemmy_db_schema::Url, -) -> Result { +pub fn generate_inbox_url(actor_id: &DbUrl) -> Result { Ok(Url::parse(&format!("{}/inbox", actor_id))?.into()) } -pub fn generate_shared_inbox_url( - actor_id: &lemmy_db_schema::Url, -) -> Result { +pub fn generate_shared_inbox_url(actor_id: &DbUrl) -> Result { let actor_id = actor_id.clone().into_inner(); let url = format!( "{}://{}{}/inbox", @@ -276,7 +274,7 @@ pub(crate) async fn insert_activity( where T: Serialize + std::fmt::Debug + Send + 'static, { - let ap_id = ap_id.to_string(); + let ap_id = ap_id.to_owned().into(); blocking(pool, move |conn| { Activity::insert(conn, ap_id, &activity, local, sensitive) }) @@ -285,8 +283,8 @@ where } pub(crate) enum PostOrComment { - Comment(Comment), - Post(Post), + Comment(Box), + Post(Box), } /// Tries to find a post or comment in the local database, without any network requests. @@ -302,7 +300,7 @@ pub(crate) async fn find_post_or_comment_by_id( }) .await?; if let Ok(p) = post { - return Ok(PostOrComment::Post(p)); + return Ok(PostOrComment::Post(Box::new(p))); } let ap_id = apub_id.clone(); @@ -311,7 +309,7 @@ pub(crate) async fn find_post_or_comment_by_id( }) .await?; if let Ok(c) = comment { - return Ok(PostOrComment::Comment(c)); + return Ok(PostOrComment::Comment(Box::new(c))); } Err(NotFound.into()) @@ -321,7 +319,7 @@ pub(crate) enum Object { Comment(Comment), Post(Post), Community(Community), - User(User_), + Person(DbPerson), PrivateMessage(PrivateMessage), } @@ -332,18 +330,18 @@ pub(crate) async fn find_object_by_id( let ap_id = apub_id.clone(); if let Ok(pc) = find_post_or_comment_by_id(context, ap_id.to_owned()).await { return Ok(match pc { - PostOrComment::Post(p) => Object::Post(p), - PostOrComment::Comment(c) => Object::Comment(c), + PostOrComment::Post(p) => Object::Post(*p), + PostOrComment::Comment(c) => Object::Comment(*c), }); } let ap_id = apub_id.clone(); - let user = blocking(context.pool(), move |conn| { - User_::read_from_apub_id(conn, &ap_id.into()) + let person = blocking(context.pool(), move |conn| { + DbPerson::read_from_apub_id(conn, &ap_id.into()) }) .await?; - if let Ok(u) = user { - return Ok(Object::User(u)); + if let Ok(u) = person { + return Ok(Object::Person(u)); } let ap_id = apub_id.clone(); diff --git a/crates/apub/src/objects/comment.rs b/crates/apub/src/objects/comment.rs index 8452f3787..ae5537e3f 100644 --- a/crates/apub/src/objects/comment.rs +++ b/crates/apub/src/objects/comment.rs @@ -6,7 +6,7 @@ use crate::{ check_object_for_community_or_site_ban, create_tombstone, get_object_from_apub, - get_or_fetch_and_upsert_user, + get_or_fetch_and_upsert_person, get_source_markdown_value, set_content_and_source, FromApub, @@ -21,13 +21,13 @@ use activitystreams::{ public, }; use anyhow::{anyhow, Context}; +use lemmy_api_structs::blocking; use lemmy_db_queries::{Crud, DbPool}; use lemmy_db_schema::source::{ comment::{Comment, CommentForm}, post::Post, - user::User_, + person::Person, }; -use lemmy_structs::blocking; use lemmy_utils::{ location_info, utils::{convert_datetime, remove_slurs}, @@ -44,7 +44,7 @@ impl ToApub for Comment { let mut comment = ApObject::new(Note::new()); let creator_id = self.creator_id; - let creator = blocking(pool, move |conn| User_::read(conn, creator_id)).await??; + let creator = blocking(pool, move |conn| Person::read(conn, creator_id)).await??; let post_id = self.post_id; let post = blocking(pool, move |conn| Post::read(conn, post_id)).await??; @@ -135,7 +135,7 @@ impl FromApubToForm for CommentForm { .as_single_xsd_any_uri() .context(location_info!())?; - let creator = get_or_fetch_and_upsert_user(creator_actor_id, context, request_counter).await?; + let creator = get_or_fetch_and_upsert_person(creator_actor_id, context, request_counter).await?; let mut in_reply_tos = note .in_reply_to() diff --git a/crates/apub/src/objects/community.rs b/crates/apub/src/objects/community.rs index 827eae294..936938130 100644 --- a/crates/apub/src/objects/community.rs +++ b/crates/apub/src/objects/community.rs @@ -1,6 +1,6 @@ use crate::{ extensions::{context::lemmy_context, group_extensions::GroupExtension}, - fetcher::user::get_or_fetch_and_upsert_user, + fetcher::person::get_or_fetch_and_upsert_person, objects::{ check_object_domain, create_tombstone, @@ -22,13 +22,13 @@ use activitystreams::{ }; use activitystreams_ext::Ext2; use anyhow::Context; +use lemmy_api_structs::blocking; use lemmy_db_queries::DbPool; use lemmy_db_schema::{ naive_now, source::community::{Community, CommunityForm}, }; use lemmy_db_views_actor::community_moderator_view::CommunityModeratorView; -use lemmy_structs::blocking; use lemmy_utils::{ location_info, utils::{check_slurs, check_slurs_opt, convert_datetime}, @@ -73,13 +73,13 @@ impl ToApub for Community { if let Some(icon_url) = &self.icon { let mut image = Image::new(); - image.set_url(Url::parse(icon_url)?); + image.set_url::(icon_url.to_owned().into()); group.set_icon(image.into_any_base()?); } if let Some(banner_url) = &self.banner { let mut image = Image::new(); - image.set_url(Url::parse(banner_url)?); + image.set_url::(banner_url.to_owned().into()); group.set_image(image.into_any_base()?); } @@ -143,7 +143,7 @@ impl FromApubToForm for CommunityForm { .as_xsd_any_uri() .context(location_info!())?; - let creator = get_or_fetch_and_upsert_user(creator_uri, context, request_counter).await?; + let creator = get_or_fetch_and_upsert_person(creator_uri, context, request_counter).await?; let name = group .inner .preferred_username() @@ -173,7 +173,7 @@ impl FromApubToForm for CommunityForm { .url() .context(location_info!())? .as_single_xsd_any_uri() - .map(|u| u.to_string()), + .map(|u| u.to_owned().into()), ), None => None, }; @@ -185,7 +185,7 @@ impl FromApubToForm for CommunityForm { .url() .context(location_info!())? .as_single_xsd_any_uri() - .map(|u| u.to_string()), + .map(|u| u.to_owned().into()), ), None => None, }; diff --git a/crates/apub/src/objects/mod.rs b/crates/apub/src/objects/mod.rs index 79b9ad405..235d5223c 100644 --- a/crates/apub/src/objects/mod.rs +++ b/crates/apub/src/objects/mod.rs @@ -1,6 +1,6 @@ use crate::{ check_is_apub_id_valid, - fetcher::{community::get_or_fetch_and_upsert_community, user::get_or_fetch_and_upsert_user}, + fetcher::{community::get_or_fetch_and_upsert_community, person::get_or_fetch_and_upsert_person}, inbox::community_inbox::check_community_or_site_ban, }; use activitystreams::{ @@ -12,10 +12,15 @@ use activitystreams::{ use anyhow::{anyhow, Context}; use chrono::NaiveDateTime; use diesel::result::Error::NotFound; +use lemmy_api_structs::blocking; use lemmy_db_queries::{ApubObject, Crud, DbPool}; -use lemmy_db_schema::source::community::Community; -use lemmy_structs::blocking; -use lemmy_utils::{location_info, settings::Settings, utils::convert_datetime, LemmyError}; +use lemmy_db_schema::{source::community::Community, DbUrl}; +use lemmy_utils::{ + location_info, + settings::structs::Settings, + utils::{convert_datetime, markdown_to_html}, + LemmyError, +}; use lemmy_websocket::LemmyContext; use url::Url; @@ -23,7 +28,7 @@ pub(crate) mod comment; pub(crate) mod community; pub(crate) mod post; pub(crate) mod private_message; -pub(crate) mod user; +pub(crate) mod person; /// Trait for converting an object or actor into the respective ActivityPub type. #[async_trait::async_trait(?Send)] @@ -91,7 +96,7 @@ where pub(in crate::objects) fn check_object_domain( apub: &T, expected_domain: Url, -) -> Result +) -> Result where T: Base + AsBase, { @@ -114,11 +119,8 @@ where .set_media_type(mime_markdown()?); object.set_source(source.into_any_base()?); - // set `content` to markdown for compatibility with older Lemmy versions - // TODO: change this to HTML in a while - object.set_content(markdown_text); - object.set_media_type(mime_markdown()?); - //object.set_content(markdown_to_html(markdown_text)); + object.set_content(markdown_to_html(markdown_text)); + object.set_media_type(mime_html()?); Ok(()) } @@ -134,32 +136,28 @@ where .flatten() .map(|s| s.to_string()); if content.is_some() { - let source = object.source(); - // updated lemmy version, read markdown from `source.content` - if let Some(source) = source { - let source = Object::<()>::from_any_base(source.to_owned())?.context(location_info!())?; - check_is_markdown(source.media_type())?; - let source_content = source - .content() - .map(|s| s.as_single_xsd_string()) - .flatten() - .context(location_info!())? - .to_string(); - return Ok(Some(source_content)); - } - // older lemmy version, read markdown from `content` - // TODO: remove this after a while - else { - return Ok(content); - } + let source = object.source().context(location_info!())?; + let source = Object::<()>::from_any_base(source.to_owned())?.context(location_info!())?; + check_is_markdown(source.media_type())?; + let source_content = source + .content() + .map(|s| s.as_single_xsd_string()) + .flatten() + .context(location_info!())? + .to_string(); + return Ok(Some(source_content)); } Ok(None) } -pub(in crate::objects) fn mime_markdown() -> Result { +fn mime_markdown() -> Result { "text/markdown".parse() } +fn mime_html() -> Result { + "text/html".parse() +} + pub(in crate::objects) fn check_is_markdown(mime: Option<&Mime>) -> Result<(), LemmyError> { let mime = mime.context(location_info!())?; if !mime.eq(&mime_markdown()?) { @@ -189,7 +187,7 @@ where let domain = object_id.domain().context(location_info!())?; // if its a local object, return it directly from the database - if Settings::get().hostname == domain { + if Settings::get().hostname() == domain { let object = blocking(context.pool(), move |conn| { To::read_from_apub_id(conn, &object_id.into()) }) @@ -214,13 +212,13 @@ pub(in crate::objects) async fn check_object_for_community_or_site_ban( where T: ObjectExt, { - let user_id = object + let person_id = object .attributed_to() .context(location_info!())? .as_single_xsd_any_uri() .context(location_info!())?; - let user = get_or_fetch_and_upsert_user(user_id, context, request_counter).await?; - check_community_or_site_ban(&user, community_id, context.pool()).await + let person = get_or_fetch_and_upsert_person(person_id, context, request_counter).await?; + check_community_or_site_ban(&person, community_id, context.pool()).await } pub(in crate::objects) async fn get_to_community( diff --git a/crates/apub/src/objects/user.rs b/crates/apub/src/objects/person.rs similarity index 73% rename from crates/apub/src/objects/user.rs rename to crates/apub/src/objects/person.rs index 8a911de27..a632fcdb0 100644 --- a/crates/apub/src/objects/user.rs +++ b/crates/apub/src/objects/person.rs @@ -18,15 +18,15 @@ use activitystreams::{ }; use activitystreams_ext::Ext1; use anyhow::Context; +use lemmy_api_structs::blocking; use lemmy_db_queries::{ApubObject, DbPool}; use lemmy_db_schema::{ naive_now, - source::user::{UserForm, User_}, + source::person::{PersonForm, Person as DbPerson}, }; -use lemmy_structs::blocking; use lemmy_utils::{ location_info, - settings::Settings, + settings::structs::Settings, utils::{check_slurs, check_slurs_opt, convert_datetime}, LemmyError, }; @@ -34,7 +34,7 @@ use lemmy_websocket::LemmyContext; use url::Url; #[async_trait::async_trait(?Send)] -impl ToApub for User_ { +impl ToApub for DbPerson { type ApubType = PersonExt; async fn to_apub(&self, _pool: &DbPool) -> Result { @@ -50,21 +50,18 @@ impl ToApub for User_ { if let Some(avatar_url) = &self.avatar { let mut image = Image::new(); - image.set_url(Url::parse(avatar_url)?); + image.set_url::(avatar_url.to_owned().into()); person.set_icon(image.into_any_base()?); } if let Some(banner_url) = &self.banner { let mut image = Image::new(); - image.set_url(Url::parse(banner_url)?); + image.set_url::(banner_url.to_owned().into()); person.set_image(image.into_any_base()?); } if let Some(bio) = &self.bio { set_content_and_source(&mut person, bio)?; - // Also set summary for compatibility with older Lemmy versions. - // TODO: remove this after a while. - person.set_summary(bio.to_owned()); } if let Some(i) = self.preferred_username.to_owned() { @@ -88,7 +85,7 @@ impl ToApub for User_ { } #[async_trait::async_trait(?Send)] -impl FromApub for User_ { +impl FromApub for DbPerson { type ApubType = PersonExt; async fn from_apub( @@ -96,26 +93,26 @@ impl FromApub for User_ { context: &LemmyContext, expected_domain: Url, request_counter: &mut i32, - ) -> Result { - let user_id = person.id_unchecked().context(location_info!())?.to_owned(); - let domain = user_id.domain().context(location_info!())?; - if domain == Settings::get().hostname { - let user = blocking(context.pool(), move |conn| { - User_::read_from_apub_id(conn, &user_id.into()) + ) -> Result { + let person_id = person.id_unchecked().context(location_info!())?.to_owned(); + let domain = person_id.domain().context(location_info!())?; + if domain == Settings::get().hostname() { + let person = blocking(context.pool(), move |conn| { + DbPerson::read_from_apub_id(conn, &person_id.into()) }) .await??; - Ok(user) + Ok(person) } else { - let user_form = - UserForm::from_apub(person, context, expected_domain, request_counter).await?; - let user = blocking(context.pool(), move |conn| User_::upsert(conn, &user_form)).await??; - Ok(user) + let person_form = + PersonForm::from_apub(person, context, expected_domain, request_counter).await?; + let person = blocking(context.pool(), move |conn| DbPerson::upsert(conn, &person_form)).await??; + Ok(person) } } } #[async_trait::async_trait(?Send)] -impl FromApubToForm for UserForm { +impl FromApubToForm for PersonForm { async fn from_apub( person: &PersonExt, _context: &LemmyContext, @@ -129,7 +126,7 @@ impl FromApubToForm for UserForm { .url() .context(location_info!())? .as_single_xsd_any_uri() - .map(|u| u.to_string()), + .map(|url| url.to_owned()), ), None => None, }; @@ -142,7 +139,7 @@ impl FromApubToForm for UserForm { .url() .context(location_info!())? .as_single_xsd_any_uri() - .map(|u| u.to_string()), + .map(|url| url.to_owned()), ), None => None, }; @@ -170,30 +167,20 @@ impl FromApubToForm for UserForm { check_slurs_opt(&preferred_username)?; check_slurs_opt(&bio)?; - Ok(UserForm { + Ok(PersonForm { name, preferred_username: Some(preferred_username), - password_encrypted: "".to_string(), - admin: false, banned: None, - email: None, - avatar, - banner, + deleted: None, + avatar: avatar.map(|o| o.map(|i| i.into())), + banner: banner.map(|o| o.map(|i| i.into())), published: person.inner.published().map(|u| u.to_owned().naive_local()), updated: person.updated().map(|u| u.to_owned().naive_local()), - show_nsfw: false, - theme: "".to_string(), - default_sort_type: 0, - default_listing_type: 0, - lang: "".to_string(), - show_avatars: false, - send_notifications_to_email: false, - matrix_user_id: None, actor_id: Some(check_object_domain(person, expected_domain)?), bio: Some(bio), - local: false, + local: Some(false), private_key: None, - public_key: Some(person.ext_one.public_key.to_owned().public_key_pem), + public_key: Some(Some(person.ext_one.public_key.to_owned().public_key_pem)), last_refreshed_at: Some(naive_now()), inbox_url: Some(person.inner.inbox()?.to_owned().into()), shared_inbox_url: Some(shared_inbox), diff --git a/crates/apub/src/objects/post.rs b/crates/apub/src/objects/post.rs index 2cac67ea4..a189c2dee 100644 --- a/crates/apub/src/objects/post.rs +++ b/crates/apub/src/objects/post.rs @@ -1,6 +1,6 @@ use crate::{ extensions::{context::lemmy_context, page_extension::PageExtension}, - fetcher::user::get_or_fetch_and_upsert_user, + fetcher::person::get_or_fetch_and_upsert_person, objects::{ check_object_domain, check_object_for_community_or_site_ban, @@ -22,13 +22,16 @@ use activitystreams::{ }; use activitystreams_ext::Ext1; use anyhow::Context; +use lemmy_api_structs::blocking; use lemmy_db_queries::{Crud, DbPool}; -use lemmy_db_schema::source::{ - community::Community, - post::{Post, PostForm}, - user::User_, +use lemmy_db_schema::{ + self, + source::{ + community::Community, + post::{Post, PostForm}, + person::Person, + }, }; -use lemmy_structs::blocking; use lemmy_utils::{ location_info, request::fetch_iframely_and_pictrs_data, @@ -47,7 +50,7 @@ impl ToApub for Post { let mut page = ApObject::new(Page::new()); let creator_id = self.creator_id; - let creator = blocking(pool, move |conn| User_::read(conn, creator_id)).await??; + let creator = blocking(pool, move |conn| Person::read(conn, creator_id)).await??; let community_id = self.community_id; let community = blocking(pool, move |conn| Community::read(conn, community_id)).await??; @@ -70,16 +73,13 @@ impl ToApub for Post { set_content_and_source(&mut page, &body)?; } - // TODO: hacky code because we get self.url == Some("") - // https://github.com/LemmyNet/lemmy/issues/602 - let url = self.url.as_ref().filter(|u| !u.is_empty()); - if let Some(u) = url { - page.set_url(Url::parse(u)?); + if let Some(url) = &self.url { + page.set_url::(url.to_owned().into()); } if let Some(thumbnail_url) = &self.thumbnail_url { let mut image = Image::new(); - image.set_url(Url::parse(thumbnail_url)?); + image.set_url::(thumbnail_url.to_owned().into()); page.set_image(image.into_any_base()?); } @@ -142,11 +142,11 @@ impl FromApubToForm for PostForm { .as_single_xsd_any_uri() .context(location_info!())?; - let creator = get_or_fetch_and_upsert_user(creator_actor_id, context, request_counter).await?; + let creator = get_or_fetch_and_upsert_person(creator_actor_id, context, request_counter).await?; let community = get_to_community(page, context, request_counter).await?; - let thumbnail_url = match &page.inner.image() { + let thumbnail_url: Option = match &page.inner.image() { Some(any_image) => Image::from_any_base( any_image .to_owned() @@ -158,7 +158,7 @@ impl FromApubToForm for PostForm { .url() .context(location_info!())? .as_single_xsd_any_uri() - .map(|u| u.to_string()), + .map(|url| url.to_owned()), None => None, }; let url = page @@ -166,11 +166,11 @@ impl FromApubToForm for PostForm { .url() .map(|u| u.as_single_xsd_any_uri()) .flatten() - .map(|s| s.to_string()); + .map(|u| u.to_owned()); let (iframely_title, iframely_description, iframely_html, pictrs_thumbnail) = if let Some(url) = &url { - fetch_iframely_and_pictrs_data(context.client(), Some(url.to_owned())).await + fetch_iframely_and_pictrs_data(context.client(), Some(url)).await } else { (None, None, None, thumbnail_url) }; @@ -192,7 +192,7 @@ impl FromApubToForm for PostForm { let body_slurs_removed = body.map(|b| remove_slurs(&b)); Ok(PostForm { name, - url, + url: url.map(|u| u.into()), body: body_slurs_removed, creator_id: creator.id, community_id: community.id, @@ -214,7 +214,7 @@ impl FromApubToForm for PostForm { embed_title: iframely_title, embed_description: iframely_description, embed_html: iframely_html, - thumbnail_url: pictrs_thumbnail, + thumbnail_url: pictrs_thumbnail.map(|u| u.into()), ap_id: Some(check_object_domain(page, expected_domain)?), local: false, }) diff --git a/crates/apub/src/objects/private_message.rs b/crates/apub/src/objects/private_message.rs index df91b03f0..09b49dd08 100644 --- a/crates/apub/src/objects/private_message.rs +++ b/crates/apub/src/objects/private_message.rs @@ -1,7 +1,7 @@ use crate::{ check_is_apub_id_valid, extensions::context::lemmy_context, - fetcher::user::get_or_fetch_and_upsert_user, + fetcher::person::get_or_fetch_and_upsert_person, objects::{ check_object_domain, create_tombstone, @@ -19,12 +19,12 @@ use activitystreams::{ prelude::*, }; use anyhow::Context; +use lemmy_api_structs::blocking; use lemmy_db_queries::{Crud, DbPool}; use lemmy_db_schema::source::{ private_message::{PrivateMessage, PrivateMessageForm}, - user::User_, + person::Person, }; -use lemmy_structs::blocking; use lemmy_utils::{location_info, utils::convert_datetime, LemmyError}; use lemmy_websocket::LemmyContext; use url::Url; @@ -37,10 +37,10 @@ impl ToApub for PrivateMessage { let mut private_message = ApObject::new(Note::new()); let creator_id = self.creator_id; - let creator = blocking(pool, move |conn| User_::read(conn, creator_id)).await??; + let creator = blocking(pool, move |conn| Person::read(conn, creator_id)).await??; let recipient_id = self.recipient_id; - let recipient = blocking(pool, move |conn| User_::read(conn, recipient_id)).await??; + let recipient = blocking(pool, move |conn| Person::read(conn, recipient_id)).await??; private_message .set_many_contexts(lemmy_context()?) @@ -97,7 +97,7 @@ impl FromApubToForm for PrivateMessageForm { .single_xsd_any_uri() .context(location_info!())?; - let creator = get_or_fetch_and_upsert_user(&creator_actor_id, context, request_counter).await?; + let creator = get_or_fetch_and_upsert_person(&creator_actor_id, context, request_counter).await?; let recipient_actor_id = note .to() .context(location_info!())? @@ -105,7 +105,7 @@ impl FromApubToForm for PrivateMessageForm { .single_xsd_any_uri() .context(location_info!())?; let recipient = - get_or_fetch_and_upsert_user(&recipient_actor_id, context, request_counter).await?; + get_or_fetch_and_upsert_person(&recipient_actor_id, context, request_counter).await?; let ap_id = note.id_unchecked().context(location_info!())?.to_string(); check_is_apub_id_valid(&Url::parse(&ap_id)?)?; diff --git a/crates/apub/src/routes.rs b/crates/apub/src/routes.rs index 3717a894f..6cc887785 100644 --- a/crates/apub/src/routes.rs +++ b/crates/apub/src/routes.rs @@ -9,31 +9,29 @@ use crate::{ }, get_activity, post::get_apub_post, - user::{get_apub_user_http, get_apub_user_inbox, get_apub_user_outbox}, + person::{get_apub_person_http, get_apub_person_inbox, get_apub_person_outbox}, }, - inbox::{community_inbox::community_inbox, shared_inbox::shared_inbox, user_inbox::user_inbox}, + inbox::{community_inbox::community_inbox, shared_inbox::shared_inbox, person_inbox::person_inbox}, APUB_JSON_CONTENT_TYPE, }; use actix_web::*; use http_signature_normalization_actix::digest::middleware::VerifyDigest; -use lemmy_utils::settings::Settings; +use lemmy_utils::settings::structs::Settings; use sha2::{Digest, Sha256}; static APUB_JSON_CONTENT_TYPE_LONG: &str = "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""; pub fn config(cfg: &mut web::ServiceConfig) { - if Settings::get().federation.enabled { - println!("federation enabled, host is {}", Settings::get().hostname); + if Settings::get().federation().enabled { + println!("federation enabled, host is {}", Settings::get().hostname()); let digest_verifier = VerifyDigest::new(Sha256::new()); let header_guard_accept = guard::Any(guard::Header("Accept", APUB_JSON_CONTENT_TYPE)) .or(guard::Header("Accept", APUB_JSON_CONTENT_TYPE_LONG)); let header_guard_content_type = guard::Any(guard::Header("Content-Type", APUB_JSON_CONTENT_TYPE)) - .or(guard::Header("Content-Type", APUB_JSON_CONTENT_TYPE_LONG)) - // TODO: compatibility with previous lemmy versions, remove this later - .or(guard::Header("Content-Type", "application/json")); + .or(guard::Header("Content-Type", APUB_JSON_CONTENT_TYPE_LONG)); cfg .service( @@ -55,9 +53,9 @@ pub fn config(cfg: &mut web::ServiceConfig) { "/c/{community_name}/inbox", web::get().to(get_apub_community_inbox), ) - .route("/u/{user_name}", web::get().to(get_apub_user_http)) - .route("/u/{user_name}/outbox", web::get().to(get_apub_user_outbox)) - .route("/u/{user_name}/inbox", web::get().to(get_apub_user_inbox)) + .route("/u/{user_name}", web::get().to(get_apub_person_http)) + .route("/u/{user_name}/outbox", web::get().to(get_apub_person_outbox)) + .route("/u/{user_name}/inbox", web::get().to(get_apub_person_inbox)) .route("/post/{post_id}", web::get().to(get_apub_post)) .route("/comment/{comment_id}", web::get().to(get_apub_comment)) .route("/activities/{type_}/{id}", web::get().to(get_activity)), @@ -68,7 +66,7 @@ pub fn config(cfg: &mut web::ServiceConfig) { .wrap(digest_verifier) .guard(header_guard_content_type) .route("/c/{community_name}/inbox", web::post().to(community_inbox)) - .route("/u/{user_name}/inbox", web::post().to(user_inbox)) + .route("/u/{user_name}/inbox", web::post().to(person_inbox)) .route("/inbox", web::post().to(shared_inbox)), ); } diff --git a/crates/db_queries/Cargo.toml b/crates/db_queries/Cargo.toml index c396b39a3..c950eea95 100644 --- a/crates/db_queries/Cargo.toml +++ b/crates/db_queries/Cargo.toml @@ -6,6 +6,7 @@ edition = "2018" [lib] name = "lemmy_db_queries" path = "src/lib.rs" +doctest = false [dependencies] lemmy_utils = { path = "../utils" } @@ -19,7 +20,10 @@ strum = "0.20.0" strum_macros = "0.20.1" log = "0.4.14" sha2 = "0.9.3" -url = { version = "2.2.0", features = ["serde"] } +url = { version = "2.2.1", features = ["serde"] } lazy_static = "1.4.0" regex = "1.4.3" bcrypt = "0.9.0" + +[dev-dependencies] +serial_test = "0.5.1" \ No newline at end of file diff --git a/crates/db_queries/src/aggregates/comment_aggregates.rs b/crates/db_queries/src/aggregates/comment_aggregates.rs index 9f7d678e2..5d4fe5dc2 100644 --- a/crates/db_queries/src/aggregates/comment_aggregates.rs +++ b/crates/db_queries/src/aggregates/comment_aggregates.rs @@ -28,8 +28,6 @@ mod tests { establish_unpooled_connection, Crud, Likeable, - ListingType, - SortType, }; use lemmy_db_schema::source::{ comment::{Comment, CommentForm, CommentLike, CommentLikeForm}, @@ -37,8 +35,10 @@ mod tests { post::{Post, PostForm}, person::{PersonForm, Person}, }; + use serial_test::serial; #[test] + #[serial] fn test_crud() { let conn = establish_unpooled_connection(); diff --git a/crates/db_queries/src/aggregates/community_aggregates.rs b/crates/db_queries/src/aggregates/community_aggregates.rs index 159b323e8..23fbe8bd6 100644 --- a/crates/db_queries/src/aggregates/community_aggregates.rs +++ b/crates/db_queries/src/aggregates/community_aggregates.rs @@ -32,8 +32,6 @@ mod tests { establish_unpooled_connection, Crud, Followable, - ListingType, - SortType, }; use lemmy_db_schema::source::{ comment::{Comment, CommentForm}, @@ -41,8 +39,10 @@ mod tests { post::{Post, PostForm}, person::{PersonForm, Person}, }; + use serial_test::serial; #[test] + #[serial] fn test_crud() { let conn = establish_unpooled_connection(); @@ -51,13 +51,13 @@ mod tests { preferred_username: None, avatar: None, banner: None, - banned: Some(false), - deleted: false, + banned: None, + deleted: None, published: None, updated: None, actor_id: None, bio: None, - local: true, + local: None, private_key: None, public_key: None, last_refreshed_at: None, @@ -72,13 +72,13 @@ mod tests { preferred_username: None, avatar: None, banner: None, - banned: Some(false), - deleted: false, + banned: None, + deleted: None, published: None, updated: None, actor_id: None, bio: None, - local: true, + local: None, private_key: None, public_key: None, last_refreshed_at: None, diff --git a/crates/db_queries/src/aggregates/person_aggregates.rs b/crates/db_queries/src/aggregates/person_aggregates.rs index ccbba8db0..cebf70b02 100644 --- a/crates/db_queries/src/aggregates/person_aggregates.rs +++ b/crates/db_queries/src/aggregates/person_aggregates.rs @@ -28,8 +28,6 @@ mod tests { establish_unpooled_connection, Crud, Likeable, - ListingType, - SortType, }; use lemmy_db_schema::source::{ comment::{Comment, CommentForm, CommentLike, CommentLikeForm}, @@ -37,8 +35,10 @@ mod tests { post::{Post, PostForm, PostLike, PostLikeForm}, person::{PersonForm, Person}, }; + use serial_test::serial; #[test] + #[serial] fn test_crud() { let conn = establish_unpooled_connection(); @@ -47,13 +47,13 @@ mod tests { preferred_username: None, avatar: None, banner: None, - banned: Some(false), - deleted: false, + banned: None, + deleted: None, published: None, updated: None, actor_id: None, bio: None, - local: true, + local: None, private_key: None, public_key: None, last_refreshed_at: None, @@ -68,13 +68,13 @@ mod tests { preferred_username: None, avatar: None, banner: None, - banned: Some(false), - deleted: false, + banned: None, + deleted: None, published: None, updated: None, actor_id: None, bio: None, - local: true, + local: None, private_key: None, public_key: None, last_refreshed_at: None, diff --git a/crates/db_queries/src/aggregates/post_aggregates.rs b/crates/db_queries/src/aggregates/post_aggregates.rs index f272e4f8c..be4e8dc72 100644 --- a/crates/db_queries/src/aggregates/post_aggregates.rs +++ b/crates/db_queries/src/aggregates/post_aggregates.rs @@ -31,6 +31,7 @@ mod tests { aggregates::post_aggregates::PostAggregates, establish_unpooled_connection, Crud, + Likeable, }; use lemmy_db_schema::source::{ comment::{Comment, CommentForm}, @@ -38,8 +39,10 @@ mod tests { post::{Post, PostForm, PostLike, PostLikeForm}, person::{PersonForm, Person}, }; + use serial_test::serial; #[test] + #[serial] fn test_crud() { let conn = establish_unpooled_connection(); @@ -48,13 +51,13 @@ mod tests { preferred_username: None, avatar: None, banner: None, - banned: Some(false), - deleted: false, + banned: None, + deleted: None, published: None, updated: None, actor_id: None, bio: None, - local: true, + local: None, private_key: None, public_key: None, last_refreshed_at: None, @@ -69,13 +72,13 @@ mod tests { preferred_username: None, avatar: None, banner: None, - banned: Some(false), - deleted: false, + banned: None, + deleted: None, published: None, updated: None, actor_id: None, bio: None, - local: true, + local: None, private_key: None, public_key: None, last_refreshed_at: None, diff --git a/crates/db_queries/src/aggregates/site_aggregates.rs b/crates/db_queries/src/aggregates/site_aggregates.rs index 2f33b507d..fe25c969d 100644 --- a/crates/db_queries/src/aggregates/site_aggregates.rs +++ b/crates/db_queries/src/aggregates/site_aggregates.rs @@ -28,6 +28,7 @@ mod tests { use crate::{ aggregates::site_aggregates::SiteAggregates, establish_unpooled_connection, + Crud, }; use lemmy_db_schema::source::{ comment::{Comment, CommentForm}, @@ -36,8 +37,10 @@ mod tests { site::{Site, SiteForm}, person::{PersonForm, Person}, }; + use serial_test::serial; #[test] + #[serial] fn test_crud() { let conn = establish_unpooled_connection(); @@ -46,13 +49,13 @@ mod tests { preferred_username: None, avatar: None, banner: None, - banned: Some(false), - deleted: false, + banned: None, + deleted: None, published: None, updated: None, actor_id: None, bio: None, - local: true, + local: None, private_key: None, public_key: None, last_refreshed_at: None, diff --git a/crates/db_queries/src/lib.rs b/crates/db_queries/src/lib.rs index bf0de3366..f19d36263 100644 --- a/crates/db_queries/src/lib.rs +++ b/crates/db_queries/src/lib.rs @@ -9,11 +9,16 @@ extern crate lazy_static; #[macro_use] extern crate diesel_migrations; +#[cfg(test)] +extern crate serial_test; + use diesel::{result::Error, *}; -use lemmy_db_schema::Url; +use lemmy_db_schema::DbUrl; +use lemmy_utils::ApiError; use regex::Regex; use serde::{Deserialize, Serialize}; use std::{env, env::VarError}; +use url::Url; pub mod aggregates; pub mod source; @@ -109,7 +114,7 @@ pub trait Reportable { } pub trait ApubObject { - fn read_from_apub_id(conn: &PgConnection, object_id: &Url) -> Result + fn read_from_apub_id(conn: &PgConnection, object_id: &DbUrl) -> Result where Self: Sized; fn upsert(conn: &PgConnection, user_form: &T) -> Result @@ -216,6 +221,20 @@ pub fn diesel_option_overwrite(opt: &Option) -> Option> { } } +pub fn diesel_option_overwrite_to_url( + opt: &Option, +) -> Result>, ApiError> { + match opt.as_ref().map(|s| s.as_str()) { + // An empty string is an erase + Some("") => Ok(Some(None)), + Some(str_url) => match Url::parse(str_url) { + Ok(url) => Ok(Some(Some(url.into()))), + Err(_) => Err(ApiError::err("invalid_url")), + }, + None => Ok(None), + } +} + embed_migrations!(); pub fn establish_unpooled_connection() -> PgConnection { @@ -228,13 +247,14 @@ pub fn establish_unpooled_connection() -> PgConnection { }; let conn = PgConnection::establish(&db_url).unwrap_or_else(|_| panic!("Error connecting to {}", db_url)); - embedded_migrations::run(&conn).unwrap(); + embedded_migrations::run(&conn).expect("load migrations"); conn } lazy_static! { static ref EMAIL_REGEX: Regex = - Regex::new(r"^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$").unwrap(); + Regex::new(r"^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$") + .expect("compile email regex"); } pub mod functions { @@ -247,7 +267,7 @@ pub mod functions { #[cfg(test)] mod tests { - use super::fuzzy_search; + use super::{fuzzy_search, *}; use crate::is_email_regex; #[test] @@ -261,4 +281,32 @@ mod tests { assert!(is_email_regex("gush@gmail.com")); assert!(!is_email_regex("nada_neutho")); } + + #[test] + fn test_diesel_option_overwrite() { + assert_eq!(diesel_option_overwrite(&None), None); + assert_eq!(diesel_option_overwrite(&Some("".to_string())), Some(None)); + assert_eq!( + diesel_option_overwrite(&Some("test".to_string())), + Some(Some("test".to_string())) + ); + } + + #[test] + fn test_diesel_option_overwrite_to_url() { + assert!(matches!(diesel_option_overwrite_to_url(&None), Ok(None))); + assert!(matches!( + diesel_option_overwrite_to_url(&Some("".to_string())), + Ok(Some(None)) + )); + assert!(matches!( + diesel_option_overwrite_to_url(&Some("invalid_url".to_string())), + Err(_) + )); + let example_url = "https://example.com"; + assert!(matches!( + diesel_option_overwrite_to_url(&Some(example_url.to_string())), + Ok(Some(Some(url))) if url == Url::parse(&example_url).unwrap().into() + )); + } } diff --git a/crates/db_queries/src/source/activity.rs b/crates/db_queries/src/source/activity.rs index 7c00681e4..06b9bd875 100644 --- a/crates/db_queries/src/source/activity.rs +++ b/crates/db_queries/src/source/activity.rs @@ -1,6 +1,6 @@ use crate::Crud; use diesel::{dsl::*, result::Error, sql_types::Text, *}; -use lemmy_db_schema::{source::activity::*, Url}; +use lemmy_db_schema::{source::activity::*, DbUrl}; use log::debug; use serde::Serialize; use serde_json::Value; @@ -41,7 +41,7 @@ impl Crud for Activity { pub trait Activity_ { fn insert( conn: &PgConnection, - ap_id: String, + ap_id: DbUrl, data: &T, local: bool, sensitive: bool, @@ -49,20 +49,20 @@ pub trait Activity_ { where T: Serialize + Debug; - fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result; + fn read_from_apub_id(conn: &PgConnection, object_id: &DbUrl) -> Result; fn delete_olds(conn: &PgConnection) -> Result; /// Returns up to 20 activities of type `Announce/Create/Page` from the community fn read_community_outbox( conn: &PgConnection, - community_actor_id: &Url, + community_actor_id: &DbUrl, ) -> Result, Error>; } impl Activity_ for Activity { fn insert( conn: &PgConnection, - ap_id: String, + ap_id: DbUrl, data: &T, local: bool, sensitive: bool, @@ -88,7 +88,7 @@ impl Activity_ for Activity { } } - fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result { + fn read_from_apub_id(conn: &PgConnection, object_id: &DbUrl) -> Result { use lemmy_db_schema::schema::activity::dsl::*; activity.filter(ap_id.eq(object_id)).first::(conn) } @@ -100,7 +100,7 @@ impl Activity_ for Activity { fn read_community_outbox( conn: &PgConnection, - community_actor_id: &Url, + community_actor_id: &DbUrl, ) -> Result, Error> { use lemmy_db_schema::schema::activity::dsl::*; let res: Vec = activity @@ -121,6 +121,7 @@ impl Activity_ for Activity { #[cfg(test)] mod tests { + use super::*; use crate::{ establish_unpooled_connection, source::activity::Activity_, @@ -130,8 +131,11 @@ mod tests { person::{PersonForm, Person}, }; use serde_json::Value; + use serial_test::serial; + use url::Url; #[test] + #[serial] fn test_crud() { let conn = establish_unpooled_connection(); @@ -156,8 +160,11 @@ mod tests { let inserted_creator = Person::create(&conn, &creator_form).unwrap(); - let ap_id = - "https://enterprise.lemmy.ml/activities/delete/f1b5d57c-80f8-4e03-a615-688d552e946c"; + let ap_id: DbUrl = Url::parse( + "https://enterprise.lemmy.ml/activities/delete/f1b5d57c-80f8-4e03-a615-688d552e946c", + ) + .unwrap() + .into(); let test_json: Value = serde_json::from_str( r#"{ "@context": "https://www.w3.org/ns/activitystreams", @@ -173,7 +180,7 @@ mod tests { ) .unwrap(); let activity_form = ActivityForm { - ap_id: ap_id.to_string(), + ap_id: ap_id.clone(), data: test_json.to_owned(), local: true, sensitive: false, @@ -183,7 +190,7 @@ mod tests { let inserted_activity = Activity::create(&conn, &activity_form).unwrap(); let expected_activity = Activity { - ap_id: Some(ap_id.to_string()), + ap_id: Some(ap_id.clone()), id: inserted_activity.id, data: test_json, local: true, @@ -193,7 +200,7 @@ mod tests { }; let read_activity = Activity::read(&conn, inserted_activity.id).unwrap(); - let read_activity_by_apub_id = Activity::read_from_apub_id(&conn, ap_id).unwrap(); + let read_activity_by_apub_id = Activity::read_from_apub_id(&conn, &ap_id).unwrap(); Person::delete(&conn, inserted_creator.id).unwrap(); Activity::delete(&conn, inserted_activity.id).unwrap(); diff --git a/crates/db_queries/src/source/comment.rs b/crates/db_queries/src/source/comment.rs index 583a59e6d..e4feef80c 100644 --- a/crates/db_queries/src/source/comment.rs +++ b/crates/db_queries/src/source/comment.rs @@ -10,11 +10,11 @@ use lemmy_db_schema::{ CommentSaved, CommentSavedForm, }, - Url, + DbUrl, }; pub trait Comment_ { - fn update_ap_id(conn: &PgConnection, comment_id: i32, apub_id: Url) -> Result; + fn update_ap_id(conn: &PgConnection, comment_id: i32, apub_id: DbUrl) -> Result; fn permadelete_for_creator( conn: &PgConnection, for_creator_id: i32, @@ -43,7 +43,7 @@ pub trait Comment_ { } impl Comment_ for Comment { - fn update_ap_id(conn: &PgConnection, comment_id: i32, apub_id: Url) -> Result { + fn update_ap_id(conn: &PgConnection, comment_id: i32, apub_id: DbUrl) -> Result { use lemmy_db_schema::schema::comment::dsl::*; diesel::update(comment.find(comment_id)) @@ -145,7 +145,7 @@ impl Crud for Comment { } impl ApubObject for Comment { - fn read_from_apub_id(conn: &PgConnection, object_id: &Url) -> Result { + fn read_from_apub_id(conn: &PgConnection, object_id: &DbUrl) -> Result { use lemmy_db_schema::schema::comment::dsl::*; comment.filter(ap_id.eq(object_id)).first::(conn) } @@ -187,7 +187,7 @@ impl Saveable for CommentSaved { use lemmy_db_schema::schema::comment_saved::dsl::*; insert_into(comment_saved) .values(comment_saved_form) - .on_conflict((comment_id, user_id)) + .on_conflict((comment_id, person_id)) .do_update() .set(comment_saved_form) .get_result::(conn) @@ -197,7 +197,7 @@ impl Saveable for CommentSaved { diesel::delete( comment_saved .filter(comment_id.eq(comment_saved_form.comment_id)) - .filter(user_id.eq(comment_saved_form.person_id)), + .filter(person_id.eq(comment_saved_form.person_id)), ) .execute(conn) } @@ -205,15 +205,17 @@ impl Saveable for CommentSaved { #[cfg(test)] mod tests { - use crate::{establish_unpooled_connection, Crud, Likeable, ListingType, Saveable, SortType}; + use crate::{establish_unpooled_connection, Crud, Likeable, Saveable}; use lemmy_db_schema::source::{ comment::*, community::{Community, CommunityForm}, post::*, person::{PersonForm, Person}, }; + use serial_test::serial; #[test] + #[serial] fn test_crud() { let conn = establish_unpooled_connection(); @@ -222,13 +224,13 @@ mod tests { preferred_username: None, avatar: None, banner: None, - banned: Some(false), - deleted: false, + banned: None, + deleted: None, published: None, updated: None, actor_id: None, bio: None, - local: true, + local: None, private_key: None, public_key: None, last_refreshed_at: None, @@ -236,13 +238,13 @@ mod tests { shared_inbox_url: None, }; - let inserted_persod = Person::create(&conn, &new_person).unwrap(); + let inserted_person = Person::create(&conn, &new_person).unwrap(); let new_community = CommunityForm { name: "test community".to_string(), title: "nada".to_owned(), description: None, - creator_id: inserted_persod.id, + creator_id: inserted_person.id, removed: None, deleted: None, updated: None, @@ -264,7 +266,7 @@ mod tests { let new_post = PostForm { name: "A test post".into(), - creator_id: inserted_persod.id, + creator_id: inserted_person.id, url: None, body: None, community_id: inserted_community.id, @@ -287,7 +289,7 @@ mod tests { let comment_form = CommentForm { content: "A test comment".into(), - creator_id: inserted_persod.id, + creator_id: inserted_person.id, post_id: inserted_post.id, removed: None, deleted: None, @@ -304,7 +306,7 @@ mod tests { let expected_comment = Comment { id: inserted_comment.id, content: "A test comment".into(), - creator_id: inserted_persod.id, + creator_id: inserted_person.id, post_id: inserted_post.id, removed: false, deleted: false, @@ -318,7 +320,7 @@ mod tests { let child_comment_form = CommentForm { content: "A child comment".into(), - creator_id: inserted_persod.id, + creator_id: inserted_person.id, post_id: inserted_post.id, parent_id: Some(inserted_comment.id), removed: None, @@ -336,7 +338,7 @@ mod tests { let comment_like_form = CommentLikeForm { comment_id: inserted_comment.id, post_id: inserted_post.id, - person_id: inserted_persod.id, + person_id: inserted_person.id, score: 1, }; @@ -346,7 +348,7 @@ mod tests { id: inserted_comment_like.id, comment_id: inserted_comment.id, post_id: inserted_post.id, - person_id: inserted_persod.id, + person_id: inserted_person.id, published: inserted_comment_like.published, score: 1, }; @@ -354,7 +356,7 @@ mod tests { // Comment Saved let comment_saved_form = CommentSavedForm { comment_id: inserted_comment.id, - person_id: inserted_persod.id, + person_id: inserted_person.id, }; let inserted_comment_saved = CommentSaved::save(&conn, &comment_saved_form).unwrap(); @@ -362,19 +364,19 @@ mod tests { let expected_comment_saved = CommentSaved { id: inserted_comment_saved.id, comment_id: inserted_comment.id, - person_id: inserted_persod.id, + person_id: inserted_person.id, published: inserted_comment_saved.published, }; let read_comment = Comment::read(&conn, inserted_comment.id).unwrap(); let updated_comment = Comment::update(&conn, inserted_comment.id, &comment_form).unwrap(); - let like_removed = CommentLike::remove(&conn, inserted_persod.id, inserted_comment.id).unwrap(); + let like_removed = CommentLike::remove(&conn, inserted_person.id, inserted_comment.id).unwrap(); let saved_removed = CommentSaved::unsave(&conn, &comment_saved_form).unwrap(); let num_deleted = Comment::delete(&conn, inserted_comment.id).unwrap(); Comment::delete(&conn, inserted_child_comment.id).unwrap(); Post::delete(&conn, inserted_post.id).unwrap(); Community::delete(&conn, inserted_community.id).unwrap(); - Person::delete(&conn, inserted_persod.id).unwrap(); + Person::delete(&conn, inserted_person.id).unwrap(); assert_eq!(expected_comment, read_comment); assert_eq!(expected_comment, inserted_comment); diff --git a/crates/db_queries/src/source/community.rs b/crates/db_queries/src/source/community.rs index 2b61d312f..9a6a0560f 100644 --- a/crates/db_queries/src/source/community.rs +++ b/crates/db_queries/src/source/community.rs @@ -12,7 +12,7 @@ use lemmy_db_schema::{ CommunityPersonBan, CommunityPersonBanForm, }, - Url, + DbUrl, }; mod safe_type { @@ -90,7 +90,7 @@ impl Crud for Community { } impl ApubObject for Community { - fn read_from_apub_id(conn: &PgConnection, for_actor_id: &Url) -> Result { + fn read_from_apub_id(conn: &PgConnection, for_actor_id: &DbUrl) -> Result { use lemmy_db_schema::schema::community::dsl::*; community .filter(actor_id.eq(for_actor_id)) @@ -131,7 +131,10 @@ pub trait Community_ { new_creator_id: i32, ) -> Result; fn distinct_federated_communities(conn: &PgConnection) -> Result, Error>; - fn read_from_followers_url(conn: &PgConnection, followers_url: &Url) -> Result; + fn read_from_followers_url( + conn: &PgConnection, + followers_url: &DbUrl, + ) -> Result; } impl Community_ for Community { @@ -194,7 +197,7 @@ impl Community_ for Community { fn read_from_followers_url( conn: &PgConnection, - followers_url_: &Url, + followers_url_: &DbUrl, ) -> Result { use lemmy_db_schema::schema::community::dsl::*; community @@ -287,12 +290,12 @@ impl Followable for CommunityFollower { use lemmy_db_schema::schema::community_follower::dsl::*; insert_into(community_follower) .values(community_follower_form) - .on_conflict((community_id, user_id)) + .on_conflict((community_id, person_id)) .do_update() .set(community_follower_form) .get_result::(conn) } - fn follow_accepted(conn: &PgConnection, community_id_: i32, user_id_: i32) -> Result + fn follow_accepted(conn: &PgConnection, community_id_: i32, person_id_: i32) -> Result where Self: Sized, { @@ -300,7 +303,7 @@ impl Followable for CommunityFollower { diesel::update( community_follower .filter(community_id.eq(community_id_)) - .filter(user_id.eq(user_id_)), + .filter(person_id.eq(person_id_)), ) .set(pending.eq(true)) .get_result::(conn) @@ -313,7 +316,7 @@ impl Followable for CommunityFollower { diesel::delete( community_follower .filter(community_id.eq(&community_follower_form.community_id)) - .filter(user_id.eq(&community_follower_form.person_id)), + .filter(person_id.eq(&community_follower_form.person_id)), ) .execute(conn) } @@ -336,12 +339,12 @@ mod tests { Crud, Followable, Joinable, - ListingType, - SortType, }; use lemmy_db_schema::source::{community::*, person::*}; + use serial_test::serial; #[test] + #[serial] fn test_crud() { let conn = establish_unpooled_connection(); @@ -350,13 +353,13 @@ mod tests { preferred_username: None, avatar: None, banner: None, - banned: Some(false), - deleted: false, + banned: None, + deleted: None, published: None, updated: None, actor_id: None, bio: None, - local: true, + local: None, private_key: None, public_key: None, last_refreshed_at: None, diff --git a/crates/db_queries/src/source/local_user.rs b/crates/db_queries/src/source/local_user.rs index 537438642..644c3eacb 100644 --- a/crates/db_queries/src/source/local_user.rs +++ b/crates/db_queries/src/source/local_user.rs @@ -1,18 +1,43 @@ -use crate::{is_email_regex, ApubObject, Crud, ToSafeSettings}; +use crate::{is_email_regex, Crud, ToSafeSettings}; +use diesel::{dsl::*, result::Error, *}; +use lemmy_db_schema::source::local_user::LocalUserSettings; +use lemmy_db_schema::schema::local_user::dsl::*; +use lemmy_db_schema::source::local_user::{LocalUser, LocalUserForm}; +use bcrypt::{hash, DEFAULT_COST}; + +mod safe_type { + use crate::ToSafe; + use lemmy_db_schema::{schema::local_user::columns::*, source::local_user::LocalUser}; + + type Columns = ( + id, + person_id, + admin, + matrix_user_id, + ); + + impl ToSafe for LocalUser { + type SafeColumns = Columns; + fn safe_columns_tuple() -> Self::SafeColumns { + ( + id, + person_id, + admin, + matrix_user_id, + ) + } + } +} + mod safe_settings_type { use crate::ToSafeSettings; - use lemmy_db_schema::{schema::user_::columns::*, source::user::User_}; + use lemmy_db_schema::{schema::local_user::columns::*, source::local_user::LocalUser}; type Columns = ( id, - name, - preferred_username, + person_id, email, - avatar, admin, - banned, - published, - updated, show_nsfw, theme, default_sort_type, @@ -21,27 +46,18 @@ mod safe_settings_type { show_avatars, send_notifications_to_email, matrix_user_id, - actor_id, - bio, - local, - last_refreshed_at, - banner, - deleted, ); - impl ToSafeSettings for User_ { + impl ToSafeSettings for LocalUser { type SafeSettingsColumns = Columns; + + /// Includes everything but the hashed password fn safe_settings_columns_tuple() -> Self::SafeSettingsColumns { ( id, - name, - preferred_username, + person_id, email, - avatar, admin, - banned, - published, - updated, show_nsfw, theme, default_sort_type, @@ -50,26 +66,93 @@ mod safe_settings_type { show_avatars, send_notifications_to_email, matrix_user_id, - actor_id, - bio, - local, - last_refreshed_at, - banner, - deleted, ) } } } -pub trait UserSafeSettings_ { - fn read(conn: &PgConnection, user_id: i32) -> Result; +pub trait LocalUser_ { + fn register(conn: &PgConnection, form: &LocalUserForm) -> Result; + fn update_password(conn: &PgConnection, person_id: i32, new_password: &str) + -> Result; + fn add_admin(conn: &PgConnection, local_user_id: i32, added: bool) -> Result; + fn find_by_email(conn: &PgConnection, from_email: &str) -> Result; + fn find_by_person(conn: &PgConnection, from_person_id: i32) -> Result; } -impl UserSafeSettings_ for UserSafeSettings { +impl LocalUser_ for LocalUser { + fn register(conn: &PgConnection, form: &LocalUserForm) -> Result { + let mut edited_user = form.clone(); + let password_hash = + hash(&form.password_encrypted, DEFAULT_COST).expect("Couldn't hash password"); + edited_user.password_encrypted = password_hash; + + Self::create(&conn, &edited_user) + } + + // TODO do more individual updates like these + fn update_password(conn: &PgConnection, local_user_id: i32, new_password: &str) -> Result { + let password_hash = hash(new_password, DEFAULT_COST).expect("Couldn't hash password"); + + diesel::update(local_user.find(local_user_id)) + .set(( + password_encrypted.eq(password_hash), + )) + .get_result::(conn) + } + + // TODO is this used? + fn add_admin(conn: &PgConnection, local_user_id: i32, added: bool) -> Result { + diesel::update(local_user.find(local_user_id)) + .set(admin.eq(added)) + .get_result::(conn) + } + + // TODO is this used? + fn find_by_email(conn: &PgConnection, from_email: &str) -> Result { + local_user + .filter(email.eq(from_email)) + .first::(conn) + } + + // TODO is this used? + fn find_by_person(conn: &PgConnection, for_person_id: i32) -> Result { + local_user + .filter(person_id.eq(for_person_id)) + .first::(conn) + } + +} + +impl Crud for LocalUser { + fn read(conn: &PgConnection, local_user_id: i32) -> Result { + local_user + .find(local_user_id) + .first::(conn) + } + fn delete(conn: &PgConnection, local_user_id: i32) -> Result { + diesel::delete(local_user.find(local_user_id)).execute(conn) + } + fn create(conn: &PgConnection, form: &LocalUserForm) -> Result { + insert_into(local_user).values(form).get_result::(conn) + } + fn update(conn: &PgConnection, local_user_id: i32, form: &LocalUserForm) -> Result { + diesel::update(local_user.find(local_user_id)) + .set(form) + .get_result::(conn) + } +} + +// TODO is this used? +pub trait LocalUserSettings_ { + fn read(conn: &PgConnection, user_id: i32) -> Result; +} + +// TODO is this used? +impl LocalUserSettings_ for LocalUserSettings { fn read(conn: &PgConnection, user_id: i32) -> Result { - user_ - .select(User_::safe_settings_columns_tuple()) - .filter(deleted.eq(false)) + local_user + .select(LocalUser::safe_settings_columns_tuple()) .find(user_id) .first::(conn) } diff --git a/crates/db_queries/src/source/moderator.rs b/crates/db_queries/src/source/moderator.rs index 36d90fdd3..4477b55e4 100644 --- a/crates/db_queries/src/source/moderator.rs +++ b/crates/db_queries/src/source/moderator.rs @@ -197,11 +197,13 @@ impl Crud for ModAdd { #[cfg(test)] mod tests { - use crate::{establish_unpooled_connection, Crud, ListingType, SortType}; + use crate::{establish_unpooled_connection, Crud}; use lemmy_db_schema::source::{comment::*, community::*, moderator::*, post::*, person::*}; + use serial_test::serial; // use Crud; #[test] + #[serial] fn test_crud() { let conn = establish_unpooled_connection(); @@ -210,13 +212,13 @@ mod tests { preferred_username: None, avatar: None, banner: None, - banned: Some(false), - deleted: false, + banned: None, + deleted: None, published: None, updated: None, actor_id: None, bio: None, - local: true, + local: None, private_key: None, public_key: None, last_refreshed_at: None, @@ -231,13 +233,13 @@ mod tests { preferred_username: None, avatar: None, banner: None, - banned: Some(false), - deleted: false, + banned: None, + deleted: None, published: None, updated: None, actor_id: None, bio: None, - local: true, + local: None, private_key: None, public_key: None, last_refreshed_at: None, diff --git a/crates/db_queries/src/source/password_reset_request.rs b/crates/db_queries/src/source/password_reset_request.rs index a8524cfb5..96fd06477 100644 --- a/crates/db_queries/src/source/password_reset_request.rs +++ b/crates/db_queries/src/source/password_reset_request.rs @@ -76,12 +76,12 @@ mod tests { establish_unpooled_connection, source::password_reset_request::PasswordResetRequest_, Crud, - ListingType, - SortType, }; use lemmy_db_schema::source::{password_reset_request::PasswordResetRequest, person::*}; + use serial_test::serial; #[test] + #[serial] fn test_crud() { let conn = establish_unpooled_connection(); @@ -90,13 +90,13 @@ mod tests { preferred_username: None, avatar: None, banner: None, - banned: Some(false), - deleted: false, + banned: None, + deleted: None, published: None, updated: None, actor_id: None, bio: None, - local: true, + local: None, private_key: None, public_key: None, last_refreshed_at: None, diff --git a/crates/db_queries/src/source/person.rs b/crates/db_queries/src/source/person.rs index e17fcda5a..86b04925d 100644 --- a/crates/db_queries/src/source/person.rs +++ b/crates/db_queries/src/source/person.rs @@ -1,13 +1,12 @@ -use crate::{is_email_regex, ApubObject, Crud, ToSafeSettings}; -use bcrypt::{hash, DEFAULT_COST}; +use crate::{is_email_regex, ApubObject, Crud}; use diesel::{dsl::*, result::Error, *}; use lemmy_db_schema::{ naive_now, schema::person::dsl::*, source::person::{PersonForm, Person}, - Url, + DbUrl, }; -use lemmy_utils::settings::Settings; +use lemmy_utils::settings::structs::Settings; mod safe_type { use crate::ToSafe; @@ -24,7 +23,6 @@ mod safe_type { actor_id, bio, local, - last_refreshed_at, banner, deleted, inbox_url, @@ -45,7 +43,6 @@ mod safe_type { actor_id, bio, local, - last_refreshed_at, banner, deleted, inbox_url, @@ -70,7 +67,6 @@ mod safe_type_alias_1 { actor_id, bio, local, - last_refreshed_at, banner, deleted, inbox_url, @@ -91,7 +87,6 @@ mod safe_type_alias_1 { actor_id, bio, local, - last_refreshed_at, banner, deleted, inbox_url, @@ -116,7 +111,6 @@ mod safe_type_alias_2 { actor_id, bio, local, - last_refreshed_at, banner, deleted, inbox_url, @@ -137,7 +131,6 @@ mod safe_type_alias_2 { actor_id, bio, local, - last_refreshed_at, banner, deleted, inbox_url, @@ -168,7 +161,7 @@ impl Crud for Person { } impl ApubObject for Person { - fn read_from_apub_id(conn: &PgConnection, object_id: &Url) -> Result { + fn read_from_apub_id(conn: &PgConnection, object_id: &DbUrl) -> Result { use lemmy_db_schema::schema::person::dsl::*; person .filter(deleted.eq(false)) @@ -187,58 +180,18 @@ impl ApubObject for Person { } pub trait Person_ { - fn register(conn: &PgConnection, form: &PersonForm) -> Result; - fn update_password(conn: &PgConnection, person_id: i32, new_password: &str) - -> Result; - fn read_from_name(conn: &PgConnection, from_name: &str) -> Result; - fn add_admin(conn: &PgConnection, person_id: i32, added: bool) -> Result; fn ban_person(conn: &PgConnection, person_id: i32, ban: bool) -> Result; - fn find_by_email_or_name( - conn: &PgConnection, - name_or_email: &str, - ) -> Result; + // TODO + // fn find_by_email_or_name( + // conn: &PgConnection, + // name_or_email: &str, + // ) -> Result; fn find_by_name(conn: &PgConnection, name: &str) -> Result; - fn find_by_email(conn: &PgConnection, from_email: &str) -> Result; - fn get_profile_url(&self, hostname: &str) -> String; fn mark_as_updated(conn: &PgConnection, person_id: i32) -> Result; fn delete_account(conn: &PgConnection, person_id: i32) -> Result; } impl Person_ for Person { - fn register(conn: &PgConnection, form: &PersonForm) -> Result { - let mut edited_person = form.clone(); - let password_hash = - hash(&form.password_encrypted, DEFAULT_COST).expect("Couldn't hash password"); - edited_person.password_encrypted = password_hash; - - Self::create(&conn, &edited_person) - } - - // TODO do more individual updates like these - fn update_password(conn: &PgConnection, person_id: i32, new_password: &str) -> Result { - let password_hash = hash(new_password, DEFAULT_COST).expect("Couldn't hash password"); - - diesel::update(person.find(person_id)) - .set(( - password_encrypted.eq(password_hash), - updated.eq(naive_now()), - )) - .get_result::(conn) - } - - fn read_from_name(conn: &PgConnection, from_name: &str) -> Result { - person - .filter(local.eq(true)) - .filter(deleted.eq(false)) - .filter(name.eq(from_name)) - .first::(conn) - } - - fn add_admin(conn: &PgConnection, person_id: i32, added: bool) -> Result { - diesel::update(person.find(person_id)) - .set(admin.eq(added)) - .get_result::(conn) - } fn ban_person(conn: &PgConnection, person_id: i32, ban: bool) -> Result { diesel::update(person.find(person_id)) @@ -246,42 +199,26 @@ impl Person_ for Person { .get_result::(conn) } - fn find_by_email_or_name( - conn: &PgConnection, - name_or_email: &str, - ) -> Result { - if is_email_regex(name_or_email) { - Self::find_by_email(conn, name_or_email) - } else { - Self::find_by_name(conn, name_or_email) - } - } + // TODO this needs to get moved to aggregates i think + // fn find_by_email_or_name( + // conn: &PgConnection, + // name_or_email: &str, + // ) -> Result { + // if is_email_regex(name_or_email) { + // Self::find_by_email(conn, name_or_email) + // } else { + // Self::find_by_name(conn, name_or_email) + // } + // } - fn find_by_name(conn: &PgConnection, name: &str) -> Result { + fn find_by_name(conn: &PgConnection, from_name: &str) -> Result { person .filter(deleted.eq(false)) .filter(local.eq(true)) - .filter(name.ilike(name)) + .filter(name.ilike(from_name)) .first::(conn) } - fn find_by_email(conn: &PgConnection, from_email: &str) -> Result { - person - .filter(deleted.eq(false)) - .filter(local.eq(true)) - .filter(email.eq(from_email)) - .first::(conn) - } - - fn get_profile_url(&self, hostname: &str) -> String { - format!( - "{}://{}/u/{}", - Settings::get().get_protocol_string(), - hostname, - self.name - ) - } - fn mark_as_updated(conn: &PgConnection, person_id: i32) -> Result { diesel::update(person.find(person_id)) .set((last_refreshed_at.eq(naive_now()),)) @@ -289,11 +226,19 @@ impl Person_ for Person { } fn delete_account(conn: &PgConnection, person_id: i32) -> Result { + use lemmy_db_schema::schema::local_user; + + // Set the local user info to none + diesel::update(local_user::table.filter(local_user::person_id.eq(person_id))) + .set(( + local_user::email.eq::>(None), + local_user::matrix_user_id.eq::>(None), + )) + .execute(conn)?; + diesel::update(person.find(person_id)) .set(( preferred_username.eq::>(None), - email.eq::>(None), - matrix_user_id.eq::>(None), bio.eq::>(None), deleted.eq(true), updated.eq(naive_now()), @@ -304,7 +249,7 @@ impl Person_ for Person { #[cfg(test)] mod tests { - use crate::{establish_unpooled_connection, source::person::*, ListingType, SortType}; + use crate::{establish_unpooled_connection, source::person::*}; #[test] fn test_crud() { @@ -315,13 +260,13 @@ mod tests { preferred_username: None, avatar: None, banner: None, - banned: Some(false), - deleted: false, + banned: None, + deleted: None, published: None, updated: None, actor_id: None, bio: None, - local: true, + local: None, private_key: None, public_key: None, last_refreshed_at: None, @@ -347,7 +292,6 @@ mod tests { private_key: None, public_key: None, last_refreshed_at: inserted_person.published, - deleted: false, inbox_url: inserted_person.inbox_url.to_owned(), shared_inbox_url: None, }; diff --git a/crates/db_queries/src/source/person_mention.rs b/crates/db_queries/src/source/person_mention.rs index 73543b959..ba40c17fe 100644 --- a/crates/db_queries/src/source/person_mention.rs +++ b/crates/db_queries/src/source/person_mention.rs @@ -73,7 +73,7 @@ impl PersonMention_ for PersonMention { #[cfg(test)] mod tests { - use crate::{establish_unpooled_connection, Crud, ListingType, SortType}; + use crate::{establish_unpooled_connection, Crud}; use lemmy_db_schema::source::{ comment::*, community::{Community, CommunityForm}, @@ -81,8 +81,10 @@ mod tests { person::*, person_mention::*, }; + use serial_test::serial; #[test] + #[serial] fn test_crud() { let conn = establish_unpooled_connection(); @@ -91,13 +93,13 @@ mod tests { preferred_username: None, avatar: None, banner: None, - banned: Some(false), - deleted: false, + banned: None, + deleted: None, published: None, updated: None, actor_id: None, bio: None, - local: true, + local: None, private_key: None, public_key: None, last_refreshed_at: None, @@ -112,13 +114,13 @@ mod tests { preferred_username: None, avatar: None, banner: None, - banned: Some(false), - deleted: false, + banned: None, + deleted: None, published: None, updated: None, actor_id: None, bio: None, - local: true, + local: None, private_key: None, public_key: None, last_refreshed_at: None, diff --git a/crates/db_queries/src/source/post.rs b/crates/db_queries/src/source/post.rs index 6a66a79c1..6ac5039e0 100644 --- a/crates/db_queries/src/source/post.rs +++ b/crates/db_queries/src/source/post.rs @@ -12,7 +12,7 @@ use lemmy_db_schema::{ PostSaved, PostSavedForm, }, - Url, + DbUrl, }; impl Crud for Post { @@ -42,7 +42,7 @@ impl Crud for Post { pub trait Post_ { //fn read(conn: &PgConnection, post_id: i32) -> Result; fn list_for_community(conn: &PgConnection, the_community_id: i32) -> Result, Error>; - fn update_ap_id(conn: &PgConnection, post_id: i32, apub_id: Url) -> Result; + fn update_ap_id(conn: &PgConnection, post_id: i32, apub_id: DbUrl) -> Result; fn permadelete_for_creator(conn: &PgConnection, for_creator_id: i32) -> Result, Error>; fn update_deleted(conn: &PgConnection, post_id: i32, new_deleted: bool) -> Result; fn update_removed(conn: &PgConnection, post_id: i32, new_removed: bool) -> Result; @@ -68,7 +68,7 @@ impl Post_ for Post { .load::(conn) } - fn update_ap_id(conn: &PgConnection, post_id: i32, apub_id: Url) -> Result { + fn update_ap_id(conn: &PgConnection, post_id: i32, apub_id: DbUrl) -> Result { use lemmy_db_schema::schema::post::dsl::*; diesel::update(post.find(post_id)) @@ -147,7 +147,7 @@ impl Post_ for Post { } impl ApubObject for Post { - fn read_from_apub_id(conn: &PgConnection, object_id: &Url) -> Result { + fn read_from_apub_id(conn: &PgConnection, object_id: &DbUrl) -> Result { use lemmy_db_schema::schema::post::dsl::*; post.filter(ap_id.eq(object_id)).first::(conn) } @@ -226,13 +226,15 @@ impl Readable for PostRead { #[cfg(test)] mod tests { - use crate::{establish_unpooled_connection, source::post::*, ListingType, SortType}; + use crate::{establish_unpooled_connection, source::post::*}; use lemmy_db_schema::source::{ community::{Community, CommunityForm}, person::*, }; + use serial_test::serial; #[test] + #[serial] fn test_crud() { let conn = establish_unpooled_connection(); @@ -241,13 +243,13 @@ mod tests { preferred_username: None, avatar: None, banner: None, - banned: Some(false), - deleted: false, + banned: None, + deleted: None, published: None, updated: None, actor_id: None, bio: None, - local: true, + local: None, private_key: None, public_key: None, last_refreshed_at: None, diff --git a/crates/db_queries/src/source/private_message.rs b/crates/db_queries/src/source/private_message.rs index e4ca3c6b3..c0f74367f 100644 --- a/crates/db_queries/src/source/private_message.rs +++ b/crates/db_queries/src/source/private_message.rs @@ -1,6 +1,6 @@ use crate::{ApubObject, Crud}; use diesel::{dsl::*, result::Error, *}; -use lemmy_db_schema::{naive_now, source::private_message::*, Url}; +use lemmy_db_schema::{naive_now, source::private_message::*, DbUrl}; impl Crud for PrivateMessage { fn read(conn: &PgConnection, private_message_id: i32) -> Result { @@ -28,7 +28,7 @@ impl Crud for PrivateMessage { } impl ApubObject for PrivateMessage { - fn read_from_apub_id(conn: &PgConnection, object_id: &Url) -> Result + fn read_from_apub_id(conn: &PgConnection, object_id: &DbUrl) -> Result where Self: Sized, { @@ -53,7 +53,7 @@ pub trait PrivateMessage_ { fn update_ap_id( conn: &PgConnection, private_message_id: i32, - apub_id: Url, + apub_id: DbUrl, ) -> Result; fn update_content( conn: &PgConnection, @@ -80,7 +80,7 @@ impl PrivateMessage_ for PrivateMessage { fn update_ap_id( conn: &PgConnection, private_message_id: i32, - apub_id: Url, + apub_id: DbUrl, ) -> Result { use lemmy_db_schema::schema::private_message::dsl::*; @@ -143,12 +143,12 @@ mod tests { establish_unpooled_connection, source::private_message::PrivateMessage_, Crud, - ListingType, - SortType, }; use lemmy_db_schema::source::{private_message::*, person::*}; + use serial_test::serial; #[test] + #[serial] fn test_crud() { let conn = establish_unpooled_connection(); @@ -157,13 +157,13 @@ mod tests { preferred_username: None, avatar: None, banner: None, - banned: Some(false), - deleted: false, + banned: None, + deleted: None, published: None, updated: None, actor_id: None, bio: None, - local: true, + local: None, private_key: None, public_key: None, last_refreshed_at: None, @@ -178,13 +178,13 @@ mod tests { preferred_username: None, avatar: None, banner: None, - banned: Some(false), - deleted: false, + banned: None, + deleted: None, published: None, updated: None, actor_id: None, bio: None, - local: true, + local: None, private_key: None, public_key: None, last_refreshed_at: None, diff --git a/crates/db_queries/src/source/user.rs b/crates/db_queries/src/source/user.rs new file mode 100644 index 000000000..077b3e783 --- /dev/null +++ b/crates/db_queries/src/source/user.rs @@ -0,0 +1,459 @@ +use crate::{is_email_regex, ApubObject, Crud, ToSafeSettings}; +use bcrypt::{hash, DEFAULT_COST}; +use diesel::{dsl::*, result::Error, *}; +use lemmy_db_schema::{ + naive_now, + schema::user_::dsl::*, + source::user::{UserForm, UserSafeSettings, User_}, + DbUrl, +}; +use lemmy_utils::settings::structs::Settings; + +mod safe_type { + use crate::ToSafe; + use lemmy_db_schema::{schema::user_::columns::*, source::user::User_}; + + type Columns = ( + id, + name, + preferred_username, + avatar, + admin, + banned, + published, + updated, + matrix_user_id, + actor_id, + bio, + local, + banner, + deleted, + inbox_url, + shared_inbox_url, + ); + + impl ToSafe for User_ { + type SafeColumns = Columns; + fn safe_columns_tuple() -> Self::SafeColumns { + ( + id, + name, + preferred_username, + avatar, + admin, + banned, + published, + updated, + matrix_user_id, + actor_id, + bio, + local, + banner, + deleted, + inbox_url, + shared_inbox_url, + ) + } + } +} + +mod safe_type_alias_1 { + use crate::ToSafe; + use lemmy_db_schema::{schema::user_alias_1::columns::*, source::user::UserAlias1}; + + type Columns = ( + id, + name, + preferred_username, + avatar, + admin, + banned, + published, + updated, + matrix_user_id, + actor_id, + bio, + local, + banner, + deleted, + ); + + impl ToSafe for UserAlias1 { + type SafeColumns = Columns; + fn safe_columns_tuple() -> Self::SafeColumns { + ( + id, + name, + preferred_username, + avatar, + admin, + banned, + published, + updated, + matrix_user_id, + actor_id, + bio, + local, + banner, + deleted, + ) + } + } +} + +mod safe_type_alias_2 { + use crate::ToSafe; + use lemmy_db_schema::{schema::user_alias_2::columns::*, source::user::UserAlias2}; + + type Columns = ( + id, + name, + preferred_username, + avatar, + admin, + banned, + published, + updated, + matrix_user_id, + actor_id, + bio, + local, + banner, + deleted, + ); + + impl ToSafe for UserAlias2 { + type SafeColumns = Columns; + fn safe_columns_tuple() -> Self::SafeColumns { + ( + id, + name, + preferred_username, + avatar, + admin, + banned, + published, + updated, + matrix_user_id, + actor_id, + bio, + local, + banner, + deleted, + ) + } + } +} + +mod safe_settings_type { + use crate::ToSafeSettings; + use lemmy_db_schema::{schema::user_::columns::*, source::user::User_}; + + type Columns = ( + id, + name, + preferred_username, + email, + avatar, + admin, + banned, + published, + updated, + show_nsfw, + theme, + default_sort_type, + default_listing_type, + lang, + show_avatars, + send_notifications_to_email, + matrix_user_id, + actor_id, + bio, + local, + last_refreshed_at, + banner, + deleted, + ); + + impl ToSafeSettings for User_ { + type SafeSettingsColumns = Columns; + fn safe_settings_columns_tuple() -> Self::SafeSettingsColumns { + ( + id, + name, + preferred_username, + email, + avatar, + admin, + banned, + published, + updated, + show_nsfw, + theme, + default_sort_type, + default_listing_type, + lang, + show_avatars, + send_notifications_to_email, + matrix_user_id, + actor_id, + bio, + local, + last_refreshed_at, + banner, + deleted, + ) + } + } +} + +pub trait UserSafeSettings_ { + fn read(conn: &PgConnection, user_id: i32) -> Result; +} + +impl UserSafeSettings_ for UserSafeSettings { + fn read(conn: &PgConnection, user_id: i32) -> Result { + user_ + .select(User_::safe_settings_columns_tuple()) + .filter(deleted.eq(false)) + .find(user_id) + .first::(conn) + } +} + +impl Crud for User_ { + fn read(conn: &PgConnection, user_id: i32) -> Result { + user_ + .filter(deleted.eq(false)) + .find(user_id) + .first::(conn) + } + fn delete(conn: &PgConnection, user_id: i32) -> Result { + diesel::delete(user_.find(user_id)).execute(conn) + } + fn create(conn: &PgConnection, form: &UserForm) -> Result { + insert_into(user_).values(form).get_result::(conn) + } + fn update(conn: &PgConnection, user_id: i32, form: &UserForm) -> Result { + diesel::update(user_.find(user_id)) + .set(form) + .get_result::(conn) + } +} + +impl ApubObject for User_ { + fn read_from_apub_id(conn: &PgConnection, object_id: &DbUrl) -> Result { + use lemmy_db_schema::schema::user_::dsl::*; + user_ + .filter(deleted.eq(false)) + .filter(actor_id.eq(object_id)) + .first::(conn) + } + + fn upsert(conn: &PgConnection, user_form: &UserForm) -> Result { + insert_into(user_) + .values(user_form) + .on_conflict(actor_id) + .do_update() + .set(user_form) + .get_result::(conn) + } +} + +pub trait User { + fn register(conn: &PgConnection, form: &UserForm) -> Result; + fn update_password(conn: &PgConnection, user_id: i32, new_password: &str) + -> Result; + fn read_from_name(conn: &PgConnection, from_user_name: &str) -> Result; + fn add_admin(conn: &PgConnection, user_id: i32, added: bool) -> Result; + fn ban_user(conn: &PgConnection, user_id: i32, ban: bool) -> Result; + fn find_by_email_or_username( + conn: &PgConnection, + username_or_email: &str, + ) -> Result; + fn find_by_username(conn: &PgConnection, username: &str) -> Result; + fn get_profile_url(&self, hostname: &str) -> String; + fn mark_as_updated(conn: &PgConnection, user_id: i32) -> Result; + fn delete_account(conn: &PgConnection, user_id: i32) -> Result; +} + +impl User for User_ { + fn register(conn: &PgConnection, form: &UserForm) -> Result { + let mut edited_user = form.clone(); + let password_hash = + hash(&form.password_encrypted, DEFAULT_COST).expect("Couldn't hash password"); + edited_user.password_encrypted = password_hash; + + Self::create(&conn, &edited_user) + } + + // TODO do more individual updates like these + fn update_password(conn: &PgConnection, user_id: i32, new_password: &str) -> Result { + let password_hash = hash(new_password, DEFAULT_COST).expect("Couldn't hash password"); + + diesel::update(user_.find(user_id)) + .set(( + password_encrypted.eq(password_hash), + updated.eq(naive_now()), + )) + .get_result::(conn) + } + + fn read_from_name(conn: &PgConnection, from_user_name: &str) -> Result { + user_ + .filter(local.eq(true)) + .filter(deleted.eq(false)) + .filter(name.eq(from_user_name)) + .first::(conn) + } + + fn add_admin(conn: &PgConnection, user_id: i32, added: bool) -> Result { + diesel::update(user_.find(user_id)) + .set(admin.eq(added)) + .get_result::(conn) + } + + fn ban_user(conn: &PgConnection, user_id: i32, ban: bool) -> Result { + diesel::update(user_.find(user_id)) + .set(banned.eq(ban)) + .get_result::(conn) + } + + fn find_by_email_or_username( + conn: &PgConnection, + username_or_email: &str, + ) -> Result { + if is_email_regex(username_or_email) { + Self::find_by_email(conn, username_or_email) + } else { + Self::find_by_username(conn, username_or_email) + } + } + + fn find_by_username(conn: &PgConnection, username: &str) -> Result { + user_ + .filter(deleted.eq(false)) + .filter(local.eq(true)) + .filter(name.ilike(username)) + .first::(conn) + } + + fn find_by_email(conn: &PgConnection, from_email: &str) -> Result { + user_ + .filter(deleted.eq(false)) + .filter(local.eq(true)) + .filter(email.eq(from_email)) + .first::(conn) + } + + fn get_profile_url(&self, hostname: &str) -> String { + format!( + "{}://{}/u/{}", + Settings::get().get_protocol_string(), + hostname, + self.name + ) + } + + fn mark_as_updated(conn: &PgConnection, user_id: i32) -> Result { + diesel::update(user_.find(user_id)) + .set((last_refreshed_at.eq(naive_now()),)) + .get_result::(conn) + } + + fn delete_account(conn: &PgConnection, user_id: i32) -> Result { + diesel::update(user_.find(user_id)) + .set(( + preferred_username.eq::>(None), + email.eq::>(None), + matrix_user_id.eq::>(None), + bio.eq::>(None), + deleted.eq(true), + updated.eq(naive_now()), + )) + .get_result::(conn) + } +} + +#[cfg(test)] +mod tests { + use crate::{establish_unpooled_connection, source::user::*, ListingType, SortType}; + use serial_test::serial; + + #[test] + #[serial] + fn test_crud() { + let conn = establish_unpooled_connection(); + + let new_user = UserForm { + name: "thommy".into(), + preferred_username: None, + password_encrypted: "nope".into(), + email: None, + matrix_user_id: None, + avatar: None, + banner: None, + admin: false, + banned: Some(false), + published: None, + updated: None, + show_nsfw: false, + theme: "browser".into(), + default_sort_type: SortType::Hot as i16, + default_listing_type: ListingType::Subscribed as i16, + lang: "browser".into(), + show_avatars: true, + send_notifications_to_email: false, + actor_id: None, + bio: None, + local: true, + private_key: None, + public_key: None, + last_refreshed_at: None, + inbox_url: None, + shared_inbox_url: None, + }; + + let inserted_user = User_::create(&conn, &new_user).unwrap(); + + let expected_user = User_ { + id: inserted_user.id, + name: "thommy".into(), + preferred_username: None, + password_encrypted: "nope".into(), + email: None, + matrix_user_id: None, + avatar: None, + banner: None, + admin: false, + banned: false, + published: inserted_user.published, + updated: None, + show_nsfw: false, + theme: "browser".into(), + default_sort_type: SortType::Hot as i16, + default_listing_type: ListingType::Subscribed as i16, + lang: "browser".into(), + show_avatars: true, + send_notifications_to_email: false, + actor_id: inserted_user.actor_id.to_owned(), + bio: None, + local: true, + private_key: None, + public_key: None, + last_refreshed_at: inserted_user.published, + deleted: false, + inbox_url: inserted_user.inbox_url.to_owned(), + shared_inbox_url: None, + }; + + let read_user = User_::read(&conn, inserted_user.id).unwrap(); + let updated_user = User_::update(&conn, inserted_user.id, &new_user).unwrap(); + let num_deleted = User_::delete(&conn, inserted_user.id).unwrap(); + + assert_eq!(expected_user, read_user); + assert_eq!(expected_user, inserted_user); + assert_eq!(expected_user, updated_user); + assert_eq!(1, num_deleted); + } +} diff --git a/crates/db_schema/Cargo.toml b/crates/db_schema/Cargo.toml index a175f80e4..1da8b68fb 100644 --- a/crates/db_schema/Cargo.toml +++ b/crates/db_schema/Cargo.toml @@ -3,10 +3,13 @@ name = "lemmy_db_schema" version = "0.1.0" edition = "2018" +[lib] +doctest = false + [dependencies] diesel = { version = "1.4.5", features = ["postgres","chrono","r2d2","serde_json"] } chrono = { version = "0.4.19", features = ["serde"] } serde = { version = "1.0.123", features = ["derive"] } serde_json = { version = "1.0.61", features = ["preserve_order"] } log = "0.4.14" -url = { version = "2.2.0", features = ["serde"] } +url = { version = "2.2.1", features = ["serde"] } diff --git a/crates/db_schema/src/lib.rs b/crates/db_schema/src/lib.rs index b0733884e..f44567b90 100644 --- a/crates/db_schema/src/lib.rs +++ b/crates/db_schema/src/lib.rs @@ -8,21 +8,22 @@ use diesel::{ serialize::{Output, ToSql}, sql_types::Text, }; -use serde::Serialize; +use serde::{Deserialize, Serialize}; use std::{ fmt::{Display, Formatter}, io::Write, }; +use url::Url; pub mod schema; pub mod source; #[repr(transparent)] -#[derive(Clone, PartialEq, Serialize, Debug, AsExpression, FromSqlRow)] +#[derive(Clone, PartialEq, Serialize, Deserialize, Debug, AsExpression, FromSqlRow)] #[sql_type = "Text"] -pub struct Url(url::Url); +pub struct DbUrl(Url); -impl ToSql for Url +impl ToSql for DbUrl where String: ToSql, { @@ -31,37 +32,37 @@ where } } -impl FromSql for Url +impl FromSql for DbUrl where String: FromSql, { fn from_sql(bytes: Option<&DB::RawValue>) -> diesel::deserialize::Result { let str = String::from_sql(bytes)?; - Ok(Url(url::Url::parse(&str)?)) + Ok(DbUrl(Url::parse(&str)?)) } } -impl Url { - pub fn into_inner(self) -> url::Url { +impl DbUrl { + pub fn into_inner(self) -> Url { self.0 } } -impl Display for Url { +impl Display for DbUrl { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { self.to_owned().into_inner().fmt(f) } } -impl From for url::Url { - fn from(url: Url) -> Self { +impl From for Url { + fn from(url: DbUrl) -> Self { url.0 } } -impl From for Url { - fn from(url: url::Url) -> Self { - Url(url) +impl From for DbUrl { + fn from(url: Url) -> Self { + DbUrl(url) } } diff --git a/crates/db_schema/src/schema.rs b/crates/db_schema/src/schema.rs index 0641bdee0..c5bf7d2fe 100644 --- a/crates/db_schema/src/schema.rs +++ b/crates/db_schema/src/schema.rs @@ -89,8 +89,8 @@ table! { private_key -> Nullable, public_key -> Nullable, last_refreshed_at -> Timestamp, - icon -> Nullable, - banner -> Nullable, + icon -> Nullable, + banner -> Nullable, followers_url -> Varchar, inbox_url -> Varchar, shared_inbox_url -> Nullable, @@ -272,7 +272,7 @@ table! { id -> Int4, name -> Varchar, preferred_username -> Nullable, - avatar -> Nullable, + avatar -> Nullable, banned -> Bool, published -> Timestamp, updated -> Nullable, @@ -282,7 +282,7 @@ table! { private_key -> Nullable, public_key -> Nullable, last_refreshed_at -> Timestamp, - banner -> Nullable, + banner -> Nullable, deleted -> Bool, inbox_url -> Varchar, shared_inbox_url -> Nullable, @@ -322,7 +322,7 @@ table! { post (id) { id -> Int4, name -> Varchar, - url -> Nullable, + url -> Nullable, body -> Nullable, creator_id -> Int4, community_id -> Int4, @@ -427,8 +427,8 @@ table! { enable_downvotes -> Bool, open_registration -> Bool, enable_nsfw -> Bool, - icon -> Nullable, - banner -> Nullable, + icon -> Nullable, + banner -> Nullable, } } @@ -470,7 +470,7 @@ table! { id -> Int4, name -> Varchar, preferred_username -> Nullable, - avatar -> Nullable, + avatar -> Nullable, banned -> Bool, published -> Timestamp, updated -> Nullable, @@ -480,7 +480,7 @@ table! { private_key -> Nullable, public_key -> Nullable, last_refreshed_at -> Timestamp, - banner -> Nullable, + banner -> Nullable, deleted -> Bool, inbox_url -> Varchar, shared_inbox_url -> Nullable, @@ -492,7 +492,7 @@ table! { id -> Int4, name -> Varchar, preferred_username -> Nullable, - avatar -> Nullable, + avatar -> Nullable, banned -> Bool, published -> Timestamp, updated -> Nullable, @@ -502,7 +502,7 @@ table! { private_key -> Nullable, public_key -> Nullable, last_refreshed_at -> Timestamp, - banner -> Nullable, + banner -> Nullable, deleted -> Bool, inbox_url -> Varchar, shared_inbox_url -> Nullable, diff --git a/crates/db_schema/src/source/activity.rs b/crates/db_schema/src/source/activity.rs index cf81ab8c8..7b7f4aba3 100644 --- a/crates/db_schema/src/source/activity.rs +++ b/crates/db_schema/src/source/activity.rs @@ -1,4 +1,4 @@ -use crate::schema::activity; +use crate::{schema::activity, DbUrl}; use serde_json::Value; use std::fmt::Debug; @@ -10,7 +10,7 @@ pub struct Activity { pub local: bool, pub published: chrono::NaiveDateTime, pub updated: Option, - pub ap_id: Option, + pub ap_id: Option, pub sensitive: Option, } @@ -20,6 +20,6 @@ pub struct ActivityForm { pub data: Value, pub local: bool, pub updated: Option, - pub ap_id: String, + pub ap_id: DbUrl, pub sensitive: bool, } diff --git a/crates/db_schema/src/source/comment.rs b/crates/db_schema/src/source/comment.rs index 7871d1dd0..e323a9ade 100644 --- a/crates/db_schema/src/source/comment.rs +++ b/crates/db_schema/src/source/comment.rs @@ -1,7 +1,7 @@ use crate::{ schema::{comment, comment_alias_1, comment_like, comment_saved}, source::post::Post, - Url, + DbUrl, }; use serde::Serialize; @@ -26,7 +26,7 @@ pub struct Comment { pub published: chrono::NaiveDateTime, pub updated: Option, pub deleted: bool, - pub ap_id: Url, + pub ap_id: DbUrl, pub local: bool, } @@ -44,7 +44,7 @@ pub struct CommentAlias1 { pub published: chrono::NaiveDateTime, pub updated: Option, pub deleted: bool, - pub ap_id: Url, + pub ap_id: DbUrl, pub local: bool, } @@ -60,7 +60,7 @@ pub struct CommentForm { pub published: Option, pub updated: Option, pub deleted: Option, - pub ap_id: Option, + pub ap_id: Option, pub local: bool, } diff --git a/crates/db_schema/src/source/community.rs b/crates/db_schema/src/source/community.rs index bc99a575a..98c302dc7 100644 --- a/crates/db_schema/src/source/community.rs +++ b/crates/db_schema/src/source/community.rs @@ -1,6 +1,6 @@ use crate::{ schema::{community, community_follower, community_moderator, community_person_ban}, - Url, + DbUrl, }; use serde::Serialize; @@ -17,16 +17,16 @@ pub struct Community { pub updated: Option, pub deleted: bool, pub nsfw: bool, - pub actor_id: Url, + pub actor_id: DbUrl, pub local: bool, pub private_key: Option, pub public_key: Option, pub last_refreshed_at: chrono::NaiveDateTime, - pub icon: Option, - pub banner: Option, - pub followers_url: Url, - pub inbox_url: Url, - pub shared_inbox_url: Option, + pub icon: Option, + pub banner: Option, + pub followers_url: DbUrl, + pub inbox_url: DbUrl, + pub shared_inbox_url: Option, } /// A safe representation of community, without the sensitive info @@ -43,10 +43,10 @@ pub struct CommunitySafe { pub updated: Option, pub deleted: bool, pub nsfw: bool, - pub actor_id: Url, + pub actor_id: DbUrl, pub local: bool, - pub icon: Option, - pub banner: Option, + pub icon: Option, + pub banner: Option, } #[derive(Insertable, AsChangeset, Debug)] @@ -61,16 +61,16 @@ pub struct CommunityForm { pub updated: Option, pub deleted: Option, pub nsfw: bool, - pub actor_id: Option, + pub actor_id: Option, pub local: bool, pub private_key: Option, pub public_key: Option, pub last_refreshed_at: Option, - pub icon: Option>, - pub banner: Option>, - pub followers_url: Option, - pub inbox_url: Option, - pub shared_inbox_url: Option>, + pub icon: Option>, + pub banner: Option>, + pub followers_url: Option, + pub inbox_url: Option, + pub shared_inbox_url: Option>, } #[derive(Identifiable, Queryable, Associations, PartialEq, Debug)] diff --git a/crates/db_schema/src/source/local_user.rs b/crates/db_schema/src/source/local_user.rs index c4300dfdb..68a8bdcfc 100644 --- a/crates/db_schema/src/source/local_user.rs +++ b/crates/db_schema/src/source/local_user.rs @@ -37,16 +37,6 @@ pub struct LocalUserForm { pub matrix_user_id: Option>, } -/// A safe local user view, without settings, password, or email -#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize)] -#[table_name = "local_user"] -pub struct LocalUserSafe { - pub id: i32, - pub person_id: i32, - pub admin: bool, - pub matrix_user_id: Option, -} - /// A local user view that removes password encrypted #[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize)] #[table_name = "local_user"] diff --git a/crates/db_schema/src/source/password_reset_request.rs b/crates/db_schema/src/source/password_reset_request.rs index ce1a423f1..f03bcb038 100644 --- a/crates/db_schema/src/source/password_reset_request.rs +++ b/crates/db_schema/src/source/password_reset_request.rs @@ -4,9 +4,9 @@ use crate::schema::password_reset_request; #[table_name = "password_reset_request"] pub struct PasswordResetRequest { pub id: i32, - pub local_user_id: i32, pub token_encrypted: String, pub published: chrono::NaiveDateTime, + pub local_user_id: i32, } #[derive(Insertable, AsChangeset)] diff --git a/crates/db_schema/src/source/person.rs b/crates/db_schema/src/source/person.rs index cd0720776..5971d9303 100644 --- a/crates/db_schema/src/source/person.rs +++ b/crates/db_schema/src/source/person.rs @@ -1,6 +1,6 @@ use crate::{ schema::{person, person_alias_1, person_alias_2}, - Url, + DbUrl, }; use serde::Serialize; @@ -10,20 +10,20 @@ pub struct Person { pub id: i32, pub name: String, pub preferred_username: Option, - pub avatar: Option, + pub avatar: Option, pub banned: bool, pub published: chrono::NaiveDateTime, pub updated: Option, - pub actor_id: Url, + pub actor_id: DbUrl, pub bio: Option, pub local: bool, pub private_key: Option, pub public_key: Option, pub last_refreshed_at: chrono::NaiveDateTime, - pub banner: Option, + pub banner: Option, pub deleted: bool, - pub inbox_url: Url, - pub shared_inbox_url: Option, + pub inbox_url: DbUrl, + pub shared_inbox_url: Option, } /// A safe representation of user, without the sensitive info @@ -33,18 +33,17 @@ pub struct PersonSafe { pub id: i32, pub name: String, pub preferred_username: Option, - pub avatar: Option, + pub avatar: Option, pub banned: bool, pub published: chrono::NaiveDateTime, pub updated: Option, - pub actor_id: Url, + pub actor_id: DbUrl, pub bio: Option, pub local: bool, - pub last_refreshed_at: chrono::NaiveDateTime, - pub banner: Option, + pub banner: Option, pub deleted: bool, - pub inbox_url: Url, - pub shared_inbox_url: Option, + pub inbox_url: DbUrl, + pub shared_inbox_url: Option, } @@ -54,20 +53,20 @@ pub struct PersonAlias1 { pub id: i32, pub name: String, pub preferred_username: Option, - pub avatar: Option, + pub avatar: Option, pub banned: bool, pub published: chrono::NaiveDateTime, pub updated: Option, - pub actor_id: Url, + pub actor_id: DbUrl, pub bio: Option, pub local: bool, pub private_key: Option, pub public_key: Option, pub last_refreshed_at: chrono::NaiveDateTime, - pub banner: Option, + pub banner: Option, pub deleted: bool, - pub inbox_url: Url, - pub shared_inbox_url: Option, + pub inbox_url: DbUrl, + pub shared_inbox_url: Option, } #[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize)] @@ -76,18 +75,17 @@ pub struct PersonSafeAlias1 { pub id: i32, pub name: String, pub preferred_username: Option, - pub avatar: Option, + pub avatar: Option, pub banned: bool, pub published: chrono::NaiveDateTime, pub updated: Option, - pub actor_id: Url, + pub actor_id: DbUrl, pub bio: Option, pub local: bool, - pub last_refreshed_at: chrono::NaiveDateTime, - pub banner: Option, + pub banner: Option, pub deleted: bool, - pub inbox_url: Url, - pub shared_inbox_url: Option, + pub inbox_url: DbUrl, + pub shared_inbox_url: Option, } #[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize)] @@ -96,20 +94,20 @@ pub struct PersonAlias2 { pub id: i32, pub name: String, pub preferred_username: Option, - pub avatar: Option, + pub avatar: Option, pub banned: bool, pub published: chrono::NaiveDateTime, pub updated: Option, - pub actor_id: Url, + pub actor_id: DbUrl, pub bio: Option, pub local: bool, pub private_key: Option, pub public_key: Option, pub last_refreshed_at: chrono::NaiveDateTime, - pub banner: Option, + pub banner: Option, pub deleted: bool, - pub inbox_url: Url, - pub shared_inbox_url: Option, + pub inbox_url: DbUrl, + pub shared_inbox_url: Option, } #[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize)] @@ -118,18 +116,17 @@ pub struct PersonSafeAlias2 { pub id: i32, pub name: String, pub preferred_username: Option, - pub avatar: Option, + pub avatar: Option, pub banned: bool, pub published: chrono::NaiveDateTime, pub updated: Option, - pub actor_id: Url, + pub actor_id: DbUrl, pub bio: Option, pub local: bool, - pub last_refreshed_at: chrono::NaiveDateTime, - pub banner: Option, + pub banner: Option, pub deleted: bool, - pub inbox_url: Url, - pub shared_inbox_url: Option, + pub inbox_url: DbUrl, + pub shared_inbox_url: Option, } #[derive(Insertable, AsChangeset, Clone)] @@ -137,18 +134,18 @@ pub struct PersonSafeAlias2 { pub struct PersonForm { pub name: String, pub preferred_username: Option>, - pub avatar: Option>, + pub avatar: Option>, pub banned: Option, pub published: Option, pub updated: Option, - pub actor_id: Option, + pub actor_id: Option, pub bio: Option>, pub local: Option, pub private_key: Option>, pub public_key: Option>, pub last_refreshed_at: Option, - pub banner: Option>, + pub banner: Option>, pub deleted: Option, - pub inbox_url: Option, - pub shared_inbox_url: Option>, + pub inbox_url: Option, + pub shared_inbox_url: Option>, } diff --git a/crates/db_schema/src/source/post.rs b/crates/db_schema/src/source/post.rs index 03d6e7e85..38616f128 100644 --- a/crates/db_schema/src/source/post.rs +++ b/crates/db_schema/src/source/post.rs @@ -1,6 +1,6 @@ use crate::{ schema::{post, post_like, post_read, post_saved}, - Url, + DbUrl, }; use serde::Serialize; @@ -9,7 +9,7 @@ use serde::Serialize; pub struct Post { pub id: i32, pub name: String, - pub url: Option, + pub url: Option, pub body: Option, pub creator_id: i32, pub community_id: i32, @@ -23,8 +23,8 @@ pub struct Post { pub embed_title: Option, pub embed_description: Option, pub embed_html: Option, - pub thumbnail_url: Option, - pub ap_id: Url, + pub thumbnail_url: Option, + pub ap_id: DbUrl, pub local: bool, } @@ -32,7 +32,7 @@ pub struct Post { #[table_name = "post"] pub struct PostForm { pub name: String, - pub url: Option, + pub url: Option, pub body: Option, pub creator_id: i32, pub community_id: i32, @@ -46,8 +46,8 @@ pub struct PostForm { pub embed_title: Option, pub embed_description: Option, pub embed_html: Option, - pub thumbnail_url: Option, - pub ap_id: Option, + pub thumbnail_url: Option, + pub ap_id: Option, pub local: bool, } diff --git a/crates/db_schema/src/source/post_report.rs b/crates/db_schema/src/source/post_report.rs index b75fb954a..62ef31cd8 100644 --- a/crates/db_schema/src/source/post_report.rs +++ b/crates/db_schema/src/source/post_report.rs @@ -1,4 +1,4 @@ -use crate::{schema::post_report, source::post::Post}; +use crate::{schema::post_report, source::post::Post, DbUrl}; use serde::{Deserialize, Serialize}; #[derive( @@ -11,7 +11,7 @@ pub struct PostReport { pub creator_id: i32, pub post_id: i32, pub original_post_name: String, - pub original_post_url: Option, + pub original_post_url: Option, pub original_post_body: Option, pub reason: String, pub resolved: bool, @@ -26,7 +26,7 @@ pub struct PostReportForm { pub creator_id: i32, pub post_id: i32, pub original_post_name: String, - pub original_post_url: Option, + pub original_post_url: Option, pub original_post_body: Option, pub reason: String, } diff --git a/crates/db_schema/src/source/private_message.rs b/crates/db_schema/src/source/private_message.rs index 376728a1b..949c97709 100644 --- a/crates/db_schema/src/source/private_message.rs +++ b/crates/db_schema/src/source/private_message.rs @@ -1,4 +1,4 @@ -use crate::{schema::private_message, Url}; +use crate::{schema::private_message, DbUrl}; use serde::Serialize; #[derive(Clone, Queryable, Associations, Identifiable, PartialEq, Debug, Serialize)] @@ -12,7 +12,7 @@ pub struct PrivateMessage { pub read: bool, pub published: chrono::NaiveDateTime, pub updated: Option, - pub ap_id: Url, + pub ap_id: DbUrl, pub local: bool, } @@ -26,6 +26,6 @@ pub struct PrivateMessageForm { pub read: Option, pub published: Option, pub updated: Option, - pub ap_id: Option, + pub ap_id: Option, pub local: bool, } diff --git a/crates/db_schema/src/source/site.rs b/crates/db_schema/src/source/site.rs index 66319548e..998e9f9d1 100644 --- a/crates/db_schema/src/source/site.rs +++ b/crates/db_schema/src/source/site.rs @@ -1,4 +1,4 @@ -use crate::schema::site; +use crate::{schema::site, DbUrl}; use serde::Serialize; #[derive(Queryable, Identifiable, PartialEq, Debug, Clone, Serialize)] @@ -13,8 +13,8 @@ pub struct Site { pub enable_downvotes: bool, pub open_registration: bool, pub enable_nsfw: bool, - pub icon: Option, - pub banner: Option, + pub icon: Option, + pub banner: Option, } #[derive(Insertable, AsChangeset)] @@ -28,6 +28,6 @@ pub struct SiteForm { pub open_registration: bool, pub enable_nsfw: bool, // when you want to null out a column, you have to send Some(None)), since sending None means you just don't want to update that column. - pub icon: Option>, - pub banner: Option>, + pub icon: Option>, + pub banner: Option>, } diff --git a/crates/db_schema/src/source/user.rs b/crates/db_schema/src/source/user.rs new file mode 100644 index 000000000..f04b9a609 --- /dev/null +++ b/crates/db_schema/src/source/user.rs @@ -0,0 +1,220 @@ +use crate::{ + schema::{user_, user_alias_1, user_alias_2}, + DbUrl, +}; +use serde::Serialize; + +#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize)] +#[table_name = "user_"] +pub struct User_ { + pub id: i32, + pub name: String, + pub preferred_username: Option, + pub password_encrypted: String, + pub email: Option, + pub avatar: Option, + pub admin: bool, + pub banned: bool, + pub published: chrono::NaiveDateTime, + pub updated: Option, + pub show_nsfw: bool, + pub theme: String, + pub default_sort_type: i16, + pub default_listing_type: i16, + pub lang: String, + pub show_avatars: bool, + pub send_notifications_to_email: bool, + pub matrix_user_id: Option, + pub actor_id: DbUrl, + pub bio: Option, + pub local: bool, + pub private_key: Option, + pub public_key: Option, + pub last_refreshed_at: chrono::NaiveDateTime, + pub banner: Option, + pub deleted: bool, + pub inbox_url: DbUrl, + pub shared_inbox_url: Option, +} + +/// A safe representation of user, without the sensitive info +#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize)] +#[table_name = "user_"] +pub struct UserSafe { + pub id: i32, + pub name: String, + pub preferred_username: Option, + pub avatar: Option, + pub admin: bool, + pub banned: bool, + pub published: chrono::NaiveDateTime, + pub updated: Option, + pub matrix_user_id: Option, + pub actor_id: DbUrl, + pub bio: Option, + pub local: bool, + pub banner: Option, + pub deleted: bool, + pub inbox_url: DbUrl, + pub shared_inbox_url: Option, +} + +/// A safe user view with only settings +#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize)] +#[table_name = "user_"] +pub struct UserSafeSettings { + pub id: i32, + pub name: String, + pub preferred_username: Option, + pub email: Option, + pub avatar: Option, + pub admin: bool, + pub banned: bool, + pub published: chrono::NaiveDateTime, + pub updated: Option, + pub show_nsfw: bool, + pub theme: String, + pub default_sort_type: i16, + pub default_listing_type: i16, + pub lang: String, + pub show_avatars: bool, + pub send_notifications_to_email: bool, + pub matrix_user_id: Option, + pub actor_id: DbUrl, + pub bio: Option, + pub local: bool, + pub last_refreshed_at: chrono::NaiveDateTime, + pub banner: Option, + pub deleted: bool, +} + +#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize)] +#[table_name = "user_alias_1"] +pub struct UserAlias1 { + pub id: i32, + pub name: String, + pub preferred_username: Option, + pub password_encrypted: String, + pub email: Option, + pub avatar: Option, + pub admin: bool, + pub banned: bool, + pub published: chrono::NaiveDateTime, + pub updated: Option, + pub show_nsfw: bool, + pub theme: String, + pub default_sort_type: i16, + pub default_listing_type: i16, + pub lang: String, + pub show_avatars: bool, + pub send_notifications_to_email: bool, + pub matrix_user_id: Option, + pub actor_id: DbUrl, + pub bio: Option, + pub local: bool, + pub private_key: Option, + pub public_key: Option, + pub last_refreshed_at: chrono::NaiveDateTime, + pub banner: Option, + pub deleted: bool, +} + +#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize)] +#[table_name = "user_alias_1"] +pub struct UserSafeAlias1 { + pub id: i32, + pub name: String, + pub preferred_username: Option, + pub avatar: Option, + pub admin: bool, + pub banned: bool, + pub published: chrono::NaiveDateTime, + pub updated: Option, + pub matrix_user_id: Option, + pub actor_id: DbUrl, + pub bio: Option, + pub local: bool, + pub banner: Option, + pub deleted: bool, +} + +#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize)] +#[table_name = "user_alias_2"] +pub struct UserAlias2 { + pub id: i32, + pub name: String, + pub preferred_username: Option, + pub password_encrypted: String, + pub email: Option, + pub avatar: Option, + pub admin: bool, + pub banned: bool, + pub published: chrono::NaiveDateTime, + pub updated: Option, + pub show_nsfw: bool, + pub theme: String, + pub default_sort_type: i16, + pub default_listing_type: i16, + pub lang: String, + pub show_avatars: bool, + pub send_notifications_to_email: bool, + pub matrix_user_id: Option, + pub actor_id: DbUrl, + pub bio: Option, + pub local: bool, + pub private_key: Option, + pub public_key: Option, + pub last_refreshed_at: chrono::NaiveDateTime, + pub banner: Option, + pub deleted: bool, +} + +#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize)] +#[table_name = "user_alias_2"] +pub struct UserSafeAlias2 { + pub id: i32, + pub name: String, + pub preferred_username: Option, + pub avatar: Option, + pub admin: bool, + pub banned: bool, + pub published: chrono::NaiveDateTime, + pub updated: Option, + pub matrix_user_id: Option, + pub actor_id: DbUrl, + pub bio: Option, + pub local: bool, + pub banner: Option, + pub deleted: bool, +} + +#[derive(Insertable, AsChangeset, Clone)] +#[table_name = "user_"] +pub struct UserForm { + pub name: String, + pub preferred_username: Option>, + pub password_encrypted: String, + pub admin: bool, + pub banned: Option, + pub email: Option>, + pub avatar: Option>, + pub published: Option, + pub updated: Option, + pub show_nsfw: bool, + pub theme: String, + pub default_sort_type: i16, + pub default_listing_type: i16, + pub lang: String, + pub show_avatars: bool, + pub send_notifications_to_email: bool, + pub matrix_user_id: Option>, + pub actor_id: Option, + pub bio: Option>, + pub local: bool, + pub private_key: Option, + pub public_key: Option, + pub last_refreshed_at: Option, + pub banner: Option>, + pub inbox_url: Option, + pub shared_inbox_url: Option>, +} diff --git a/crates/db_views/Cargo.toml b/crates/db_views/Cargo.toml index 175e6eae6..42a942b40 100644 --- a/crates/db_views/Cargo.toml +++ b/crates/db_views/Cargo.toml @@ -3,10 +3,16 @@ name = "lemmy_db_views" version = "0.1.0" edition = "2018" +[lib] +doctest = false + [dependencies] lemmy_db_queries = { path = "../db_queries" } lemmy_db_schema = { path = "../db_schema" } diesel = { version = "1.4.5", features = ["postgres","chrono","r2d2","serde_json"] } serde = { version = "1.0.123", features = ["derive"] } log = "0.4.14" -url = "2.2.0" +url = "2.2.1" + +[dev-dependencies] +serial_test = "0.5.1" \ No newline at end of file diff --git a/crates/db_views/src/comment_report_view.rs b/crates/db_views/src/comment_report_view.rs index 2863f6259..eb10bffbe 100644 --- a/crates/db_views/src/comment_report_view.rs +++ b/crates/db_views/src/comment_report_view.rs @@ -1,13 +1,13 @@ use diesel::{result::Error, *}; use lemmy_db_queries::{limit_and_offset, MaybeOptional, ToSafe, ViewToVec}; use lemmy_db_schema::{ - schema::{comment, comment_report, community, post, user_, user_alias_1, user_alias_2}, + schema::{comment, comment_report, community, post, person, person_alias_1, person_alias_2}, source::{ comment::Comment, comment_report::CommentReport, community::{Community, CommunitySafe}, post::Post, - user::{UserAlias1, UserAlias2, UserSafe, UserSafeAlias1, UserSafeAlias2, User_}, + person::{PersonAlias1, PersonAlias2, PersonSafe, PersonSafeAlias1, PersonSafeAlias2, Person}, }, }; use serde::Serialize; @@ -18,9 +18,9 @@ pub struct CommentReportView { pub comment: Comment, pub post: Post, pub community: CommunitySafe, - pub creator: UserSafe, - pub comment_creator: UserSafeAlias1, - pub resolver: Option, + pub creator: PersonSafe, + pub comment_creator: PersonSafeAlias1, + pub resolver: Option, } type CommentReportViewTuple = ( @@ -28,9 +28,9 @@ type CommentReportViewTuple = ( Comment, Post, CommunitySafe, - UserSafe, - UserSafeAlias1, - Option, + PersonSafe, + PersonSafeAlias1, + Option, ); impl CommentReportView { @@ -44,19 +44,19 @@ impl CommentReportView { .inner_join(comment::table) .inner_join(post::table.on(comment::post_id.eq(post::id))) .inner_join(community::table.on(post::community_id.eq(community::id))) - .inner_join(user_::table.on(comment_report::creator_id.eq(user_::id))) - .inner_join(user_alias_1::table.on(post::creator_id.eq(user_alias_1::id))) + .inner_join(person::table.on(comment_report::creator_id.eq(person::id))) + .inner_join(person_alias_1::table.on(post::creator_id.eq(person_alias_1::id))) .left_join( - user_alias_2::table.on(comment_report::resolver_id.eq(user_alias_2::id.nullable())), + person_alias_2::table.on(comment_report::resolver_id.eq(person_alias_2::id.nullable())), ) .select(( comment_report::all_columns, comment::all_columns, post::all_columns, Community::safe_columns_tuple(), - User_::safe_columns_tuple(), - UserAlias1::safe_columns_tuple(), - UserAlias2::safe_columns_tuple().nullable(), + Person::safe_columns_tuple(), + PersonAlias1::safe_columns_tuple(), + PersonAlias2::safe_columns_tuple().nullable(), )) .first::(conn)?; @@ -75,7 +75,7 @@ impl CommentReportView { /// /// * `community_ids` - a Vec of community_ids to get a count for /// TODO this eq_any is a bad way to do this, would be better to join to communitymoderator - /// for a user id + /// for a person id pub fn get_report_count(conn: &PgConnection, community_ids: &[i32]) -> Result { use diesel::dsl::*; comment_report::table @@ -135,19 +135,19 @@ impl<'a> CommentReportQueryBuilder<'a> { .inner_join(comment::table) .inner_join(post::table.on(comment::post_id.eq(post::id))) .inner_join(community::table.on(post::community_id.eq(community::id))) - .inner_join(user_::table.on(comment_report::creator_id.eq(user_::id))) - .inner_join(user_alias_1::table.on(post::creator_id.eq(user_alias_1::id))) + .inner_join(person::table.on(comment_report::creator_id.eq(person::id))) + .inner_join(person_alias_1::table.on(post::creator_id.eq(person_alias_1::id))) .left_join( - user_alias_2::table.on(comment_report::resolver_id.eq(user_alias_2::id.nullable())), + person_alias_2::table.on(comment_report::resolver_id.eq(person_alias_2::id.nullable())), ) .select(( comment_report::all_columns, comment::all_columns, post::all_columns, Community::safe_columns_tuple(), - User_::safe_columns_tuple(), - UserAlias1::safe_columns_tuple(), - UserAlias2::safe_columns_tuple().nullable(), + Person::safe_columns_tuple(), + PersonAlias1::safe_columns_tuple(), + PersonAlias2::safe_columns_tuple().nullable(), )) .into_boxed(); diff --git a/crates/db_views/src/comment_view.rs b/crates/db_views/src/comment_view.rs index 0db27794b..eb95a2ccd 100644 --- a/crates/db_views/src/comment_view.rs +++ b/crates/db_views/src/comment_view.rs @@ -19,16 +19,16 @@ use lemmy_db_schema::{ comment_saved, community, community_follower, - community_user_ban, + community_person_ban, post, - user_, - user_alias_1, + person, + person_alias_1, }, source::{ comment::{Comment, CommentAlias1, CommentSaved}, community::{Community, CommunityFollower, CommunitySafe, CommunityPersonBan}, post::Post, - user::{UserAlias1, UserSafe, UserSafeAlias1, User_}, + person::{PersonAlias1, PersonSafe, PersonSafeAlias1, Person}, }, }; use serde::Serialize; @@ -36,12 +36,12 @@ use serde::Serialize; #[derive(Debug, PartialEq, Serialize, Clone)] pub struct CommentView { pub comment: Comment, - pub creator: UserSafe, - pub recipient: Option, // Left joins to comment and user + pub creator: PersonSafe, + pub recipient: Option, // Left joins to comment and person pub post: Post, pub community: CommunitySafe, pub counts: CommentAggregates, - pub creator_banned_from_community: bool, // Left Join to CommunityUserBan + pub creator_banned_from_community: bool, // Left Join to CommunityPersonBan pub subscribed: bool, // Left join to CommunityFollower pub saved: bool, // Left join to CommentSaved pub my_vote: Option, // Left join to CommentLike @@ -49,9 +49,9 @@ pub struct CommentView { type CommentViewTuple = ( Comment, - UserSafe, + PersonSafe, Option, - Option, + Option, Post, CommunitySafe, CommentAggregates, @@ -65,10 +65,10 @@ impl CommentView { pub fn read( conn: &PgConnection, comment_id: i32, - my_user_id: Option, + my_person_id: Option, ) -> Result { // The left join below will return None in this case - let user_id_join = my_user_id.unwrap_or(-1); + let person_id_join = my_person_id.unwrap_or(-1); let ( comment, @@ -84,59 +84,59 @@ impl CommentView { comment_like, ) = comment::table .find(comment_id) - .inner_join(user_::table) + .inner_join(person::table) // recipient here .left_join(comment_alias_1::table.on(comment_alias_1::id.nullable().eq(comment::parent_id))) - .left_join(user_alias_1::table.on(user_alias_1::id.eq(comment_alias_1::creator_id))) + .left_join(person_alias_1::table.on(person_alias_1::id.eq(comment_alias_1::creator_id))) .inner_join(post::table) .inner_join(community::table.on(post::community_id.eq(community::id))) .inner_join(comment_aggregates::table) .left_join( - community_user_ban::table.on( + community_person_ban::table.on( community::id - .eq(community_user_ban::community_id) - .and(community_user_ban::user_id.eq(comment::creator_id)), + .eq(community_person_ban::community_id) + .and(community_person_ban::person_id.eq(comment::creator_id)), ), ) .left_join( community_follower::table.on( post::community_id .eq(community_follower::community_id) - .and(community_follower::user_id.eq(user_id_join)), + .and(community_follower::person_id.eq(person_id_join)), ), ) .left_join( comment_saved::table.on( comment::id .eq(comment_saved::comment_id) - .and(comment_saved::user_id.eq(user_id_join)), + .and(comment_saved::person_id.eq(person_id_join)), ), ) .left_join( comment_like::table.on( comment::id .eq(comment_like::comment_id) - .and(comment_like::user_id.eq(user_id_join)), + .and(comment_like::person_id.eq(person_id_join)), ), ) .select(( comment::all_columns, - User_::safe_columns_tuple(), + Person::safe_columns_tuple(), comment_alias_1::all_columns.nullable(), - UserAlias1::safe_columns_tuple().nullable(), + PersonAlias1::safe_columns_tuple().nullable(), post::all_columns, Community::safe_columns_tuple(), comment_aggregates::all_columns, - community_user_ban::all_columns.nullable(), + community_person_ban::all_columns.nullable(), community_follower::all_columns.nullable(), comment_saved::all_columns.nullable(), comment_like::score.nullable(), )) .first::(conn)?; - // If a user is given, then my_vote, if None, should be 0, not null - // Necessary to differentiate between other user's votes - let my_vote = if my_user_id.is_some() && comment_like.is_none() { + // If a person is given, then my_vote, if None, should be 0, not null + // Necessary to differentiate between other person's votes + let my_vote = if my_person_id.is_some() && comment_like.is_none() { Some(0) } else { comment_like @@ -156,7 +156,7 @@ impl CommentView { }) } - /// Gets the recipient user id. + /// Gets the recipient person id. /// If there is no parent comment, its the post creator pub fn get_recipient_id(&self) -> i32 { match &self.recipient { @@ -175,7 +175,7 @@ pub struct CommentQueryBuilder<'a> { post_id: Option, creator_id: Option, recipient_id: Option, - my_user_id: Option, + my_person_id: Option, search_term: Option, saved_only: bool, unread_only: bool, @@ -194,7 +194,7 @@ impl<'a> CommentQueryBuilder<'a> { post_id: None, creator_id: None, recipient_id: None, - my_user_id: None, + my_person_id: None, search_term: None, saved_only: false, unread_only: false, @@ -233,8 +233,8 @@ impl<'a> CommentQueryBuilder<'a> { self } - pub fn my_user_id>(mut self, my_user_id: T) -> Self { - self.my_user_id = my_user_id.get_optional(); + pub fn my_person_id>(mut self, my_person_id: T) -> Self { + self.my_person_id = my_person_id.get_optional(); self } @@ -272,53 +272,53 @@ impl<'a> CommentQueryBuilder<'a> { use diesel::dsl::*; // The left join below will return None in this case - let user_id_join = self.my_user_id.unwrap_or(-1); + let person_id_join = self.my_person_id.unwrap_or(-1); let mut query = comment::table - .inner_join(user_::table) + .inner_join(person::table) // recipient here .left_join(comment_alias_1::table.on(comment_alias_1::id.nullable().eq(comment::parent_id))) - .left_join(user_alias_1::table.on(user_alias_1::id.eq(comment_alias_1::creator_id))) + .left_join(person_alias_1::table.on(person_alias_1::id.eq(comment_alias_1::creator_id))) .inner_join(post::table) .inner_join(community::table.on(post::community_id.eq(community::id))) .inner_join(comment_aggregates::table) .left_join( - community_user_ban::table.on( + community_person_ban::table.on( community::id - .eq(community_user_ban::community_id) - .and(community_user_ban::user_id.eq(comment::creator_id)), + .eq(community_person_ban::community_id) + .and(community_person_ban::person_id.eq(comment::creator_id)), ), ) .left_join( community_follower::table.on( post::community_id .eq(community_follower::community_id) - .and(community_follower::user_id.eq(user_id_join)), + .and(community_follower::person_id.eq(person_id_join)), ), ) .left_join( comment_saved::table.on( comment::id .eq(comment_saved::comment_id) - .and(comment_saved::user_id.eq(user_id_join)), + .and(comment_saved::person_id.eq(person_id_join)), ), ) .left_join( comment_like::table.on( comment::id .eq(comment_like::comment_id) - .and(comment_like::user_id.eq(user_id_join)), + .and(comment_like::person_id.eq(person_id_join)), ), ) .select(( comment::all_columns, - User_::safe_columns_tuple(), + Person::safe_columns_tuple(), comment_alias_1::all_columns.nullable(), - UserAlias1::safe_columns_tuple().nullable(), + PersonAlias1::safe_columns_tuple().nullable(), post::all_columns, Community::safe_columns_tuple(), comment_aggregates::all_columns, - community_user_ban::all_columns.nullable(), + community_person_ban::all_columns.nullable(), community_follower::all_columns.nullable(), comment_saved::all_columns.nullable(), comment_like::score.nullable(), @@ -329,7 +329,7 @@ impl<'a> CommentQueryBuilder<'a> { if let Some(recipient_id) = self.recipient_id { query = query // TODO needs lots of testing - .filter(user_alias_1::id.eq(recipient_id)) // Gets the comment replies + .filter(person_alias_1::id.eq(recipient_id)) // Gets the comment replies .or_filter( comment::parent_id .is_null() @@ -367,7 +367,7 @@ impl<'a> CommentQueryBuilder<'a> { query = match self.listing_type { // ListingType::Subscribed => query.filter(community_follower::subscribed.eq(true)), - ListingType::Subscribed => query.filter(community_follower::user_id.is_not_null()), // TODO could be this: and(community_follower::user_id.eq(user_id_join)), + ListingType::Subscribed => query.filter(community_follower::person_id.is_not_null()), // TODO could be this: and(community_follower::user_id.eq(user_id_join)), ListingType::Local => query.filter(community::local.eq(true)), _ => query, }; @@ -439,37 +439,27 @@ mod tests { establish_unpooled_connection, Crud, Likeable, - ListingType, - SortType, }; - use lemmy_db_schema::source::{comment::*, community::*, post::*, user::*}; + use lemmy_db_schema::source::{comment::*, community::*, post::*, person::*}; + use serial_test::serial; #[test] + #[serial] fn test_crud() { let conn = establish_unpooled_connection(); - let new_user = UserForm { - name: "timmy".into(), + let new_person = PersonForm { + name: "thommy".into(), preferred_username: None, - password_encrypted: "nope".into(), - email: None, - matrix_user_id: None, avatar: None, banner: None, - admin: false, - banned: Some(false), + banned: None, + deleted: None, published: None, updated: None, - show_nsfw: false, - theme: "browser".into(), - default_sort_type: SortType::Hot as i16, - default_listing_type: ListingType::Subscribed as i16, - lang: "browser".into(), - show_avatars: true, - send_notifications_to_email: false, actor_id: None, bio: None, - local: true, + local: None, private_key: None, public_key: None, last_refreshed_at: None, @@ -477,13 +467,13 @@ mod tests { shared_inbox_url: None, }; - let inserted_user = User_::create(&conn, &new_user).unwrap(); + let inserted_person = Person::create(&conn, &new_person).unwrap(); let new_community = CommunityForm { name: "test community 5".to_string(), title: "nada".to_owned(), description: None, - creator_id: inserted_user.id, + creator_id: inserted_person.id, removed: None, deleted: None, updated: None, @@ -505,7 +495,7 @@ mod tests { let new_post = PostForm { name: "A test post 2".into(), - creator_id: inserted_user.id, + creator_id: inserted_person.id, url: None, body: None, community_id: inserted_community.id, @@ -528,7 +518,7 @@ mod tests { let comment_form = CommentForm { content: "A test comment 32".into(), - creator_id: inserted_user.id, + creator_id: inserted_person.id, post_id: inserted_post.id, parent_id: None, removed: None, @@ -545,7 +535,7 @@ mod tests { let comment_like_form = CommentLikeForm { comment_id: inserted_comment.id, post_id: inserted_post.id, - person_id: inserted_user.id, + person_id: inserted_person.id, score: 1, }; @@ -553,7 +543,7 @@ mod tests { let agg = CommentAggregates::read(&conn, inserted_comment.id).unwrap(); - let expected_comment_view_no_user = CommentView { + let expected_comment_view_no_person = CommentView { creator_banned_from_community: false, my_vote: None, subscribed: false, @@ -561,7 +551,7 @@ mod tests { comment: Comment { id: inserted_comment.id, content: "A test comment 32".into(), - creator_id: inserted_user.id, + creator_id: inserted_person.id, post_id: inserted_post.id, parent_id: None, removed: false, @@ -572,29 +562,27 @@ mod tests { updated: None, local: true, }, - creator: UserSafe { - id: inserted_user.id, + creator: PersonSafe { + id: inserted_person.id, name: "timmy".into(), preferred_username: None, - published: inserted_user.published, + published: inserted_person.published, avatar: None, - actor_id: inserted_user.actor_id.to_owned(), + actor_id: inserted_person.actor_id.to_owned(), local: true, banned: false, deleted: false, bio: None, banner: None, - admin: false, updated: None, - matrix_user_id: None, - inbox_url: inserted_user.inbox_url.to_owned(), + inbox_url: inserted_person.inbox_url.to_owned(), shared_inbox_url: None, }, recipient: None, post: Post { id: inserted_post.id, name: inserted_post.name.to_owned(), - creator_id: inserted_user.id, + creator_id: inserted_person.id, url: None, body: None, published: inserted_post.published, @@ -623,7 +611,7 @@ mod tests { local: true, title: "nada".to_owned(), description: None, - creator_id: inserted_user.id, + creator_id: inserted_person.id, updated: None, banner: None, published: inserted_community.published, @@ -638,30 +626,30 @@ mod tests { }, }; - let mut expected_comment_view_with_user = expected_comment_view_no_user.to_owned(); - expected_comment_view_with_user.my_vote = Some(1); + let mut expected_comment_view_with_person = expected_comment_view_no_person.to_owned(); + expected_comment_view_with_person.my_vote = Some(1); - let read_comment_views_no_user = CommentQueryBuilder::create(&conn) + let read_comment_views_no_person = CommentQueryBuilder::create(&conn) .post_id(inserted_post.id) .list() .unwrap(); - let read_comment_views_with_user = CommentQueryBuilder::create(&conn) + let read_comment_views_with_person = CommentQueryBuilder::create(&conn) .post_id(inserted_post.id) - .my_user_id(inserted_user.id) + .my_person_id(inserted_person.id) .list() .unwrap(); - let like_removed = CommentLike::remove(&conn, inserted_user.id, inserted_comment.id).unwrap(); + let like_removed = CommentLike::remove(&conn, inserted_person.id, inserted_comment.id).unwrap(); let num_deleted = Comment::delete(&conn, inserted_comment.id).unwrap(); Post::delete(&conn, inserted_post.id).unwrap(); Community::delete(&conn, inserted_community.id).unwrap(); - User_::delete(&conn, inserted_user.id).unwrap(); + Person::delete(&conn, inserted_person.id).unwrap(); - assert_eq!(expected_comment_view_no_user, read_comment_views_no_user[0]); + assert_eq!(expected_comment_view_no_person, read_comment_views_no_person[0]); assert_eq!( - expected_comment_view_with_user, - read_comment_views_with_user[0] + expected_comment_view_with_person, + read_comment_views_with_person[0] ); assert_eq!(1, num_deleted); assert_eq!(1, like_removed); diff --git a/crates/db_views/src/lib.rs b/crates/db_views/src/lib.rs index b46ec5a46..d37a1d3ed 100644 --- a/crates/db_views/src/lib.rs +++ b/crates/db_views/src/lib.rs @@ -1,6 +1,10 @@ +#[cfg(test)] +extern crate serial_test; + pub mod comment_report_view; pub mod comment_view; pub mod post_report_view; pub mod post_view; pub mod private_message_view; pub mod site_view; +pub mod local_user_view; diff --git a/crates/db_views/src/local_user_view.rs b/crates/db_views/src/local_user_view.rs new file mode 100644 index 000000000..384bf9007 --- /dev/null +++ b/crates/db_views/src/local_user_view.rs @@ -0,0 +1,78 @@ +use diesel::{result::Error, *}; +use lemmy_db_queries::{ + aggregates::person_aggregates::PersonAggregates, + ToSafe, + ToSafeSettings, +}; +use lemmy_db_schema::{ + schema::{person, person_aggregates, local_user}, + source::person::{PersonSafe, Person}, + source::local_user::{LocalUser, LocalUserSettings}, +}; +use serde::Serialize; + +#[derive(Debug, Serialize, Clone)] +pub struct LocalUserView { + pub person: Person, + pub counts: PersonAggregates, + pub local_user: LocalUser, +} + +type LocalUserViewTuple = (Person, PersonAggregates, LocalUser); + +impl LocalUserView { + pub fn read(conn: &PgConnection, person_id: i32) -> Result { + let (person, counts, local_user) = person::table + .find(person_id) + .inner_join(person_aggregates::table) + .inner_join(local_user::table) + .select((person::all_columns, person_aggregates::all_columns, local_user::all_columns)) + .first::(conn)?; + Ok(Self { person, counts, local_user }) + } + + // TODO check where this is used + pub fn read_from_name(conn: &PgConnection, name: &str) -> Result { + let (person, counts, local_user) = person::table + .filter(person::name.eq(name)) + .inner_join(person_aggregates::table) + .inner_join(local_user::table) + .select((person::all_columns, person_aggregates::all_columns, local_user::all_columns)) + .first::(conn)?; + Ok(Self { person, counts, local_user }) + } + + pub fn find_by_email_or_name( + conn: &PgConnection, + name_or_email: &str, + ) -> Result { + let (person, counts, local_user) = person::table + .inner_join(person_aggregates::table) + .inner_join(local_user::table) + .filter(person::name.ilike(name_or_email).or(local_user::email.ilike(name_or_email))) + .select((person::all_columns, person_aggregates::all_columns, local_user::all_columns)) + .first::(conn)?; + Ok(Self { person, counts, local_user }) + } +} + +#[derive(Debug, Serialize, Clone)] +pub struct LocalUserSettingsView { + pub person: PersonSafe, + pub counts: PersonAggregates, + pub local_user: LocalUserSettings, +} + +type LocalUserSettingsViewTuple = (PersonSafe, PersonAggregates, LocalUserSettings); + +impl LocalUserSettingsView { + pub fn read(conn: &PgConnection, person_id: i32) -> Result { + let (person, counts, local_user) = person::table + .find(person_id) + .inner_join(person_aggregates::table) + .inner_join(local_user::table) + .select((Person::safe_columns_tuple(), person_aggregates::all_columns, LocalUser::safe_settings_columns_tuple())) + .first::(conn)?; + Ok(Self { person, counts, local_user }) + } +} diff --git a/crates/db_views/src/post_report_view.rs b/crates/db_views/src/post_report_view.rs index 741162e3e..192a3d7b1 100644 --- a/crates/db_views/src/post_report_view.rs +++ b/crates/db_views/src/post_report_view.rs @@ -1,12 +1,12 @@ use diesel::{result::Error, *}; use lemmy_db_queries::{limit_and_offset, MaybeOptional, ToSafe, ViewToVec}; use lemmy_db_schema::{ - schema::{community, post, post_report, user_, user_alias_1, user_alias_2}, + schema::{community, post, post_report, person, person_alias_1, person_alias_2}, source::{ community::{Community, CommunitySafe}, post::Post, post_report::PostReport, - user::{UserAlias1, UserAlias2, UserSafe, UserSafeAlias1, UserSafeAlias2, User_}, + person::{PersonAlias1, PersonAlias2, PersonSafe, PersonSafeAlias1, PersonSafeAlias2, Person}, }, }; use serde::Serialize; @@ -16,18 +16,18 @@ pub struct PostReportView { pub post_report: PostReport, pub post: Post, pub community: CommunitySafe, - pub creator: UserSafe, - pub post_creator: UserSafeAlias1, - pub resolver: Option, + pub creator: PersonSafe, + pub post_creator: PersonSafeAlias1, + pub resolver: Option, } type PostReportViewTuple = ( PostReport, Post, CommunitySafe, - UserSafe, - UserSafeAlias1, - Option, + PersonSafe, + PersonSafeAlias1, + Option, ); impl PostReportView { @@ -39,16 +39,16 @@ impl PostReportView { .find(report_id) .inner_join(post::table) .inner_join(community::table.on(post::community_id.eq(community::id))) - .inner_join(user_::table.on(post_report::creator_id.eq(user_::id))) - .inner_join(user_alias_1::table.on(post::creator_id.eq(user_alias_1::id))) - .left_join(user_alias_2::table.on(post_report::resolver_id.eq(user_alias_2::id.nullable()))) + .inner_join(person::table.on(post_report::creator_id.eq(person::id))) + .inner_join(person_alias_1::table.on(post::creator_id.eq(person_alias_1::id))) + .left_join(person_alias_2::table.on(post_report::resolver_id.eq(person_alias_2::id.nullable()))) .select(( post_report::all_columns, post::all_columns, Community::safe_columns_tuple(), - User_::safe_columns_tuple(), - UserAlias1::safe_columns_tuple(), - UserAlias2::safe_columns_tuple().nullable(), + Person::safe_columns_tuple(), + PersonAlias1::safe_columns_tuple(), + PersonAlias2::safe_columns_tuple().nullable(), )) .first::(conn)?; @@ -66,7 +66,7 @@ impl PostReportView { /// /// * `community_ids` - a Vec of community_ids to get a count for /// TODO this eq_any is a bad way to do this, would be better to join to communitymoderator - /// for a user id + /// for a person id pub fn get_report_count(conn: &PgConnection, community_ids: &[i32]) -> Result { use diesel::dsl::*; post_report::table @@ -124,16 +124,16 @@ impl<'a> PostReportQueryBuilder<'a> { let mut query = post_report::table .inner_join(post::table) .inner_join(community::table.on(post::community_id.eq(community::id))) - .inner_join(user_::table.on(post_report::creator_id.eq(user_::id))) - .inner_join(user_alias_1::table.on(post::creator_id.eq(user_alias_1::id))) - .left_join(user_alias_2::table.on(post_report::resolver_id.eq(user_alias_2::id.nullable()))) + .inner_join(person::table.on(post_report::creator_id.eq(person::id))) + .inner_join(person_alias_1::table.on(post::creator_id.eq(person_alias_1::id))) + .left_join(person_alias_2::table.on(post_report::resolver_id.eq(person_alias_2::id.nullable()))) .select(( post_report::all_columns, post::all_columns, Community::safe_columns_tuple(), - User_::safe_columns_tuple(), - UserAlias1::safe_columns_tuple(), - UserAlias2::safe_columns_tuple().nullable(), + Person::safe_columns_tuple(), + PersonAlias1::safe_columns_tuple(), + PersonAlias2::safe_columns_tuple().nullable(), )) .into_boxed(); diff --git a/crates/db_views/src/post_view.rs b/crates/db_views/src/post_view.rs index f56c2f9be..4aca33286 100644 --- a/crates/db_views/src/post_view.rs +++ b/crates/db_views/src/post_view.rs @@ -14,18 +14,18 @@ use lemmy_db_schema::{ schema::{ community, community_follower, - community_user_ban, + community_person_ban, post, post_aggregates, post_like, post_read, post_saved, - user_, + person, }, source::{ community::{Community, CommunityFollower, CommunitySafe, CommunityPersonBan}, post::{Post, PostRead, PostSaved}, - user::{UserSafe, User_}, + person::{PersonSafe, Person}, }, }; use log::debug; @@ -34,9 +34,9 @@ use serde::Serialize; #[derive(Debug, PartialEq, Serialize, Clone)] pub struct PostView { pub post: Post, - pub creator: UserSafe, + pub creator: PersonSafe, pub community: CommunitySafe, - pub creator_banned_from_community: bool, // Left Join to CommunityUserBan + pub creator_banned_from_community: bool, // Left Join to CommunityPersonBan pub counts: PostAggregates, pub subscribed: bool, // Left join to CommunityFollower pub saved: bool, // Left join to PostSaved @@ -46,7 +46,7 @@ pub struct PostView { type PostViewTuple = ( Post, - UserSafe, + PersonSafe, CommunitySafe, Option, PostAggregates, @@ -57,9 +57,9 @@ type PostViewTuple = ( ); impl PostView { - pub fn read(conn: &PgConnection, post_id: i32, my_user_id: Option) -> Result { + pub fn read(conn: &PgConnection, post_id: i32, my_person_id: Option) -> Result { // The left join below will return None in this case - let user_id_join = my_user_id.unwrap_or(-1); + let person_id_join = my_person_id.unwrap_or(-1); let ( post, @@ -73,13 +73,13 @@ impl PostView { post_like, ) = post::table .find(post_id) - .inner_join(user_::table) + .inner_join(person::table) .inner_join(community::table) .left_join( - community_user_ban::table.on( + community_person_ban::table.on( post::community_id - .eq(community_user_ban::community_id) - .and(community_user_ban::user_id.eq(post::creator_id)), + .eq(community_person_ban::community_id) + .and(community_person_ban::person_id.eq(post::creator_id)), ), ) .inner_join(post_aggregates::table) @@ -87,35 +87,35 @@ impl PostView { community_follower::table.on( post::community_id .eq(community_follower::community_id) - .and(community_follower::user_id.eq(user_id_join)), + .and(community_follower::person_id.eq(person_id_join)), ), ) .left_join( post_saved::table.on( post::id .eq(post_saved::post_id) - .and(post_saved::user_id.eq(user_id_join)), + .and(post_saved::person_id.eq(person_id_join)), ), ) .left_join( post_read::table.on( post::id .eq(post_read::post_id) - .and(post_read::user_id.eq(user_id_join)), + .and(post_read::person_id.eq(person_id_join)), ), ) .left_join( post_like::table.on( post::id .eq(post_like::post_id) - .and(post_like::user_id.eq(user_id_join)), + .and(post_like::person_id.eq(person_id_join)), ), ) .select(( post::all_columns, - User_::safe_columns_tuple(), + Person::safe_columns_tuple(), Community::safe_columns_tuple(), - community_user_ban::all_columns.nullable(), + community_person_ban::all_columns.nullable(), post_aggregates::all_columns, community_follower::all_columns.nullable(), post_saved::all_columns.nullable(), @@ -124,9 +124,9 @@ impl PostView { )) .first::(conn)?; - // If a user is given, then my_vote, if None, should be 0, not null - // Necessary to differentiate between other user's votes - let my_vote = if my_user_id.is_some() && post_like.is_none() { + // If a person is given, then my_vote, if None, should be 0, not null + // Necessary to differentiate between other person's votes + let my_vote = if my_person_id.is_some() && post_like.is_none() { Some(0) } else { post_like @@ -153,7 +153,7 @@ pub struct PostQueryBuilder<'a> { creator_id: Option, community_id: Option, community_name: Option, - my_user_id: Option, + my_person_id: Option, search_term: Option, url_search: Option, show_nsfw: bool, @@ -172,7 +172,7 @@ impl<'a> PostQueryBuilder<'a> { creator_id: None, community_id: None, community_name: None, - my_user_id: None, + my_person_id: None, search_term: None, url_search: None, show_nsfw: true, @@ -198,8 +198,8 @@ impl<'a> PostQueryBuilder<'a> { self } - pub fn my_user_id>(mut self, my_user_id: T) -> Self { - self.my_user_id = my_user_id.get_optional(); + pub fn my_person_id>(mut self, my_person_id: T) -> Self { + self.my_person_id = my_person_id.get_optional(); self } @@ -247,16 +247,16 @@ impl<'a> PostQueryBuilder<'a> { use diesel::dsl::*; // The left join below will return None in this case - let user_id_join = self.my_user_id.unwrap_or(-1); + let person_id_join = self.my_person_id.unwrap_or(-1); let mut query = post::table - .inner_join(user_::table) + .inner_join(person::table) .inner_join(community::table) .left_join( - community_user_ban::table.on( + community_person_ban::table.on( post::community_id - .eq(community_user_ban::community_id) - .and(community_user_ban::user_id.eq(community::creator_id)), + .eq(community_person_ban::community_id) + .and(community_person_ban::person_id.eq(community::creator_id)), ), ) .inner_join(post_aggregates::table) @@ -264,35 +264,35 @@ impl<'a> PostQueryBuilder<'a> { community_follower::table.on( post::community_id .eq(community_follower::community_id) - .and(community_follower::user_id.eq(user_id_join)), + .and(community_follower::person_id.eq(person_id_join)), ), ) .left_join( post_saved::table.on( post::id .eq(post_saved::post_id) - .and(post_saved::user_id.eq(user_id_join)), + .and(post_saved::person_id.eq(person_id_join)), ), ) .left_join( post_read::table.on( post::id .eq(post_read::post_id) - .and(post_read::user_id.eq(user_id_join)), + .and(post_read::person_id.eq(person_id_join)), ), ) .left_join( post_like::table.on( post::id .eq(post_like::post_id) - .and(post_like::user_id.eq(user_id_join)), + .and(post_like::person_id.eq(person_id_join)), ), ) .select(( post::all_columns, - User_::safe_columns_tuple(), + Person::safe_columns_tuple(), Community::safe_columns_tuple(), - community_user_ban::all_columns.nullable(), + community_person_ban::all_columns.nullable(), post_aggregates::all_columns, community_follower::all_columns.nullable(), post_saved::all_columns.nullable(), @@ -302,7 +302,7 @@ impl<'a> PostQueryBuilder<'a> { .into_boxed(); query = match self.listing_type { - ListingType::Subscribed => query.filter(community_follower::user_id.is_not_null()), // TODO could be this: and(community_follower::user_id.eq(user_id_join)), + ListingType::Subscribed => query.filter(community_follower::person_id.is_not_null()), // TODO could be this: and(community_follower::person_id.eq(person_id_join)), ListingType::Local => query.filter(community::local.eq(true)), _ => query, }; @@ -333,7 +333,7 @@ impl<'a> PostQueryBuilder<'a> { ); } - // If its for a specific user, show the removed / deleted + // If its for a specific person, show the removed / deleted if let Some(creator_id) = self.creator_id { query = query.filter(post::creator_id.eq(creator_id)); } @@ -433,38 +433,30 @@ mod tests { ListingType, SortType, }; - use lemmy_db_schema::source::{community::*, post::*, user::*}; + use lemmy_db_schema::source::{community::*, post::*, person::*}; + use serial_test::serial; #[test] + #[serial] fn test_crud() { let conn = establish_unpooled_connection(); - let user_name = "tegan".to_string(); + let person_name = "tegan".to_string(); let community_name = "test_community_3".to_string(); let post_name = "test post 3".to_string(); - let new_user = UserForm { - name: user_name.to_owned(), + let new_person = PersonForm { + name: person_name.to_owned(), preferred_username: None, - password_encrypted: "nope".into(), - email: None, - matrix_user_id: None, avatar: None, banner: None, + banned: None, + deleted: None, published: None, updated: None, - admin: false, - banned: Some(false), - show_nsfw: false, - theme: "browser".into(), - default_sort_type: SortType::Hot as i16, - default_listing_type: ListingType::Subscribed as i16, - lang: "browser".into(), - show_avatars: true, - send_notifications_to_email: false, actor_id: None, bio: None, - local: true, + local: None, private_key: None, public_key: None, last_refreshed_at: None, @@ -472,13 +464,13 @@ mod tests { shared_inbox_url: None, }; - let inserted_user = User_::create(&conn, &new_user).unwrap(); + let inserted_person = Person::create(&conn, &new_person).unwrap(); let new_community = CommunityForm { name: community_name.to_owned(), title: "nada".to_owned(), description: None, - creator_id: inserted_user.id, + creator_id: inserted_person.id, removed: None, deleted: None, updated: None, @@ -502,7 +494,7 @@ mod tests { name: post_name.to_owned(), url: None, body: None, - creator_id: inserted_user.id, + creator_id: inserted_person.id, community_id: inserted_community.id, removed: None, deleted: None, @@ -523,7 +515,7 @@ mod tests { let post_like_form = PostLikeForm { post_id: inserted_post.id, - person_id: inserted_user.id, + person_id: inserted_person.id, score: 1, }; @@ -532,38 +524,38 @@ mod tests { let expected_post_like = PostLike { id: inserted_post_like.id, post_id: inserted_post.id, - person_id: inserted_user.id, + person_id: inserted_person.id, published: inserted_post_like.published, score: 1, }; - let read_post_listings_with_user = PostQueryBuilder::create(&conn) + let read_post_listings_with_person = PostQueryBuilder::create(&conn) .listing_type(&ListingType::Community) .sort(&SortType::New) .community_id(inserted_community.id) - .my_user_id(inserted_user.id) + .my_person_id(inserted_person.id) .list() .unwrap(); - let read_post_listings_no_user = PostQueryBuilder::create(&conn) + let read_post_listings_no_person = PostQueryBuilder::create(&conn) .listing_type(&ListingType::Community) .sort(&SortType::New) .community_id(inserted_community.id) .list() .unwrap(); - let read_post_listing_no_user = PostView::read(&conn, inserted_post.id, None).unwrap(); - let read_post_listing_with_user = - PostView::read(&conn, inserted_post.id, Some(inserted_user.id)).unwrap(); + let read_post_listing_no_person = PostView::read(&conn, inserted_post.id, None).unwrap(); + let read_post_listing_with_person = + PostView::read(&conn, inserted_post.id, Some(inserted_person.id)).unwrap(); let agg = PostAggregates::read(&conn, inserted_post.id).unwrap(); - // the non user version - let expected_post_listing_no_user = PostView { + // the non person version + let expected_post_listing_no_person = PostView { post: Post { id: inserted_post.id, name: post_name, - creator_id: inserted_user.id, + creator_id: inserted_person.id, url: None, body: None, published: inserted_post.published, @@ -582,22 +574,20 @@ mod tests { local: true, }, my_vote: None, - creator: UserSafe { - id: inserted_user.id, - name: user_name, + creator: PersonSafe { + id: inserted_person.id, + name: person_name, preferred_username: None, - published: inserted_user.published, + published: inserted_person.published, avatar: None, - actor_id: inserted_user.actor_id.to_owned(), + actor_id: inserted_person.actor_id.to_owned(), local: true, banned: false, deleted: false, bio: None, banner: None, - admin: false, updated: None, - matrix_user_id: None, - inbox_url: inserted_user.inbox_url.to_owned(), + inbox_url: inserted_person.inbox_url.to_owned(), shared_inbox_url: None, }, creator_banned_from_community: false, @@ -612,7 +602,7 @@ mod tests { local: true, title: "nada".to_owned(), description: None, - creator_id: inserted_user.id, + creator_id: inserted_person.id, updated: None, banner: None, published: inserted_community.published, @@ -635,26 +625,26 @@ mod tests { }; // TODO More needs to be added here - let mut expected_post_listing_with_user = expected_post_listing_no_user.to_owned(); + let mut expected_post_listing_with_user = expected_post_listing_no_person.to_owned(); expected_post_listing_with_user.my_vote = Some(1); - let like_removed = PostLike::remove(&conn, inserted_user.id, inserted_post.id).unwrap(); + let like_removed = PostLike::remove(&conn, inserted_person.id, inserted_post.id).unwrap(); let num_deleted = Post::delete(&conn, inserted_post.id).unwrap(); Community::delete(&conn, inserted_community.id).unwrap(); - User_::delete(&conn, inserted_user.id).unwrap(); + Person::delete(&conn, inserted_person.id).unwrap(); // The with user assert_eq!( expected_post_listing_with_user, - read_post_listings_with_user[0] + read_post_listings_with_person[0] ); - assert_eq!(expected_post_listing_with_user, read_post_listing_with_user); - assert_eq!(1, read_post_listings_with_user.len()); + assert_eq!(expected_post_listing_with_user, read_post_listing_with_person); + assert_eq!(1, read_post_listings_with_person.len()); // Without the user - assert_eq!(expected_post_listing_no_user, read_post_listings_no_user[0]); - assert_eq!(expected_post_listing_no_user, read_post_listing_no_user); - assert_eq!(1, read_post_listings_no_user.len()); + assert_eq!(expected_post_listing_no_person, read_post_listings_no_person[0]); + assert_eq!(expected_post_listing_no_person, read_post_listing_no_person); + assert_eq!(1, read_post_listings_no_person.len()); // assert_eq!(expected_post, inserted_post); // assert_eq!(expected_post, updated_post); diff --git a/crates/db_views/src/private_message_view.rs b/crates/db_views/src/private_message_view.rs index 578af80e9..29b1e4644 100644 --- a/crates/db_views/src/private_message_view.rs +++ b/crates/db_views/src/private_message_view.rs @@ -1,10 +1,10 @@ use diesel::{pg::Pg, result::Error, *}; use lemmy_db_queries::{limit_and_offset, MaybeOptional, ToSafe, ViewToVec}; use lemmy_db_schema::{ - schema::{private_message, user_, user_alias_1}, + schema::{private_message, person, person_alias_1}, source::{ private_message::PrivateMessage, - user::{UserAlias1, UserSafe, UserSafeAlias1, User_}, + person::{PersonAlias1, PersonSafe, PersonSafeAlias1, Person}, }, }; use log::debug; @@ -13,23 +13,23 @@ use serde::Serialize; #[derive(Debug, PartialEq, Serialize, Clone)] pub struct PrivateMessageView { pub private_message: PrivateMessage, - pub creator: UserSafe, - pub recipient: UserSafeAlias1, + pub creator: PersonSafe, + pub recipient: PersonSafeAlias1, } -type PrivateMessageViewTuple = (PrivateMessage, UserSafe, UserSafeAlias1); +type PrivateMessageViewTuple = (PrivateMessage, PersonSafe, PersonSafeAlias1); impl PrivateMessageView { pub fn read(conn: &PgConnection, private_message_id: i32) -> Result { let (private_message, creator, recipient) = private_message::table .find(private_message_id) - .inner_join(user_::table.on(private_message::creator_id.eq(user_::id))) - .inner_join(user_alias_1::table.on(private_message::recipient_id.eq(user_alias_1::id))) + .inner_join(person::table.on(private_message::creator_id.eq(person::id))) + .inner_join(person_alias_1::table.on(private_message::recipient_id.eq(person_alias_1::id))) .order_by(private_message::published.desc()) .select(( private_message::all_columns, - User_::safe_columns_tuple(), - UserAlias1::safe_columns_tuple(), + Person::safe_columns_tuple(), + PersonAlias1::safe_columns_tuple(), )) .first::(conn)?; @@ -77,12 +77,12 @@ impl<'a> PrivateMessageQueryBuilder<'a> { pub fn list(self) -> Result, Error> { let mut query = private_message::table - .inner_join(user_::table.on(private_message::creator_id.eq(user_::id))) - .inner_join(user_alias_1::table.on(private_message::recipient_id.eq(user_alias_1::id))) + .inner_join(person::table.on(private_message::creator_id.eq(person::id))) + .inner_join(person_alias_1::table.on(private_message::recipient_id.eq(person_alias_1::id))) .select(( private_message::all_columns, - User_::safe_columns_tuple(), - UserAlias1::safe_columns_tuple(), + Person::safe_columns_tuple(), + PersonAlias1::safe_columns_tuple(), )) .into_boxed(); diff --git a/crates/db_views/src/site_view.rs b/crates/db_views/src/site_view.rs index c04e85e9c..391cf84b1 100644 --- a/crates/db_views/src/site_view.rs +++ b/crates/db_views/src/site_view.rs @@ -1,10 +1,10 @@ use diesel::{result::Error, *}; use lemmy_db_queries::{aggregates::site_aggregates::SiteAggregates, ToSafe}; use lemmy_db_schema::{ - schema::{site, site_aggregates, user_}, + schema::{site, site_aggregates, person}, source::{ site::Site, - user::{UserSafe, User_}, + person::{PersonSafe, Person}, }, }; use serde::Serialize; @@ -12,21 +12,21 @@ use serde::Serialize; #[derive(Debug, Serialize, Clone)] pub struct SiteView { pub site: Site, - pub creator: UserSafe, + pub creator: PersonSafe, pub counts: SiteAggregates, } impl SiteView { pub fn read(conn: &PgConnection) -> Result { let (site, creator, counts) = site::table - .inner_join(user_::table) + .inner_join(person::table) .inner_join(site_aggregates::table) .select(( site::all_columns, - User_::safe_columns_tuple(), + Person::safe_columns_tuple(), site_aggregates::all_columns, )) - .first::<(Site, UserSafe, SiteAggregates)>(conn)?; + .first::<(Site, PersonSafe, SiteAggregates)>(conn)?; Ok(SiteView { site, diff --git a/crates/db_views_actor/Cargo.toml b/crates/db_views_actor/Cargo.toml index 8e86d4c0a..e237941e1 100644 --- a/crates/db_views_actor/Cargo.toml +++ b/crates/db_views_actor/Cargo.toml @@ -3,6 +3,9 @@ name = "lemmy_db_views_actor" version = "0.1.0" edition = "2018" +[lib] +doctest = false + [dependencies] lemmy_db_queries = { path = "../db_queries" } lemmy_db_schema = { path = "../db_schema" } diff --git a/crates/db_views_actor/src/community_follower_view.rs b/crates/db_views_actor/src/community_follower_view.rs index a4f2b20dc..6673acb53 100644 --- a/crates/db_views_actor/src/community_follower_view.rs +++ b/crates/db_views_actor/src/community_follower_view.rs @@ -1,10 +1,10 @@ use diesel::{result::Error, *}; use lemmy_db_queries::{ToSafe, ViewToVec}; use lemmy_db_schema::{ - schema::{community, community_follower, user_}, + schema::{community, community_follower, person}, source::{ community::{Community, CommunitySafe}, - user::{UserSafe, User_}, + person::{PersonSafe, Person}, }, }; use serde::Serialize; @@ -12,17 +12,17 @@ use serde::Serialize; #[derive(Debug, Serialize, Clone)] pub struct CommunityFollowerView { pub community: CommunitySafe, - pub follower: UserSafe, + pub follower: PersonSafe, } -type CommunityFollowerViewTuple = (CommunitySafe, UserSafe); +type CommunityFollowerViewTuple = (CommunitySafe, PersonSafe); impl CommunityFollowerView { pub fn for_community(conn: &PgConnection, community_id: i32) -> Result, Error> { let res = community_follower::table .inner_join(community::table) - .inner_join(user_::table) - .select((Community::safe_columns_tuple(), User_::safe_columns_tuple())) + .inner_join(person::table) + .select((Community::safe_columns_tuple(), Person::safe_columns_tuple())) .filter(community_follower::community_id.eq(community_id)) .order_by(community_follower::published) .load::(conn)?; @@ -30,12 +30,12 @@ impl CommunityFollowerView { Ok(Self::from_tuple_to_vec(res)) } - pub fn for_user(conn: &PgConnection, user_id: i32) -> Result, Error> { + pub fn for_person(conn: &PgConnection, person_id: i32) -> Result, Error> { let res = community_follower::table .inner_join(community::table) - .inner_join(user_::table) - .select((Community::safe_columns_tuple(), User_::safe_columns_tuple())) - .filter(community_follower::user_id.eq(user_id)) + .inner_join(person::table) + .select((Community::safe_columns_tuple(), Person::safe_columns_tuple())) + .filter(community_follower::person_id.eq(person_id)) .order_by(community_follower::published) .load::(conn)?; diff --git a/crates/db_views_actor/src/community_moderator_view.rs b/crates/db_views_actor/src/community_moderator_view.rs index fe8b3c222..7cc208472 100644 --- a/crates/db_views_actor/src/community_moderator_view.rs +++ b/crates/db_views_actor/src/community_moderator_view.rs @@ -1,10 +1,10 @@ use diesel::{result::Error, *}; use lemmy_db_queries::{ToSafe, ViewToVec}; use lemmy_db_schema::{ - schema::{community, community_moderator, user_}, + schema::{community, community_moderator, person}, source::{ community::{Community, CommunitySafe}, - user::{UserSafe, User_}, + person::{PersonSafe, Person}, }, }; use serde::Serialize; @@ -12,17 +12,17 @@ use serde::Serialize; #[derive(Debug, Serialize, Clone)] pub struct CommunityModeratorView { pub community: CommunitySafe, - pub moderator: UserSafe, + pub moderator: PersonSafe, } -type CommunityModeratorViewTuple = (CommunitySafe, UserSafe); +type CommunityModeratorViewTuple = (CommunitySafe, PersonSafe); impl CommunityModeratorView { pub fn for_community(conn: &PgConnection, community_id: i32) -> Result, Error> { let res = community_moderator::table .inner_join(community::table) - .inner_join(user_::table) - .select((Community::safe_columns_tuple(), User_::safe_columns_tuple())) + .inner_join(person::table) + .select((Community::safe_columns_tuple(), Person::safe_columns_tuple())) .filter(community_moderator::community_id.eq(community_id)) .order_by(community_moderator::published) .load::(conn)?; @@ -30,12 +30,12 @@ impl CommunityModeratorView { Ok(Self::from_tuple_to_vec(res)) } - pub fn for_user(conn: &PgConnection, user_id: i32) -> Result, Error> { + pub fn for_person(conn: &PgConnection, person_id: i32) -> Result, Error> { let res = community_moderator::table .inner_join(community::table) - .inner_join(user_::table) - .select((Community::safe_columns_tuple(), User_::safe_columns_tuple())) - .filter(community_moderator::user_id.eq(user_id)) + .inner_join(person::table) + .select((Community::safe_columns_tuple(), Person::safe_columns_tuple())) + .filter(community_moderator::person_id.eq(person_id)) .order_by(community_moderator::published) .load::(conn)?; diff --git a/crates/db_views_actor/src/community_person_ban_view.rs b/crates/db_views_actor/src/community_person_ban_view.rs new file mode 100644 index 000000000..651fcbf8e --- /dev/null +++ b/crates/db_views_actor/src/community_person_ban_view.rs @@ -0,0 +1,35 @@ +use diesel::{result::Error, *}; +use lemmy_db_queries::ToSafe; +use lemmy_db_schema::{ + schema::{community, community_person_ban, person}, + source::{ + community::{Community, CommunitySafe}, + person::{PersonSafe, Person}, + }, +}; +use serde::Serialize; + +#[derive(Debug, Serialize, Clone)] +pub struct CommunityPersonBanView { + pub community: CommunitySafe, + pub person: PersonSafe, +} + +impl CommunityPersonBanView { + pub fn get( + conn: &PgConnection, + from_person_id: i32, + from_community_id: i32, + ) -> Result { + let (community, person) = community_person_ban::table + .inner_join(community::table) + .inner_join(person::table) + .select((Community::safe_columns_tuple(), Person::safe_columns_tuple())) + .filter(community_person_ban::community_id.eq(from_community_id)) + .filter(community_person_ban::person_id.eq(from_person_id)) + .order_by(community_person_ban::published) + .first::<(CommunitySafe, PersonSafe)>(conn)?; + + Ok(CommunityPersonBanView { community, person }) + } +} diff --git a/crates/db_views_actor/src/community_user_ban_view.rs b/crates/db_views_actor/src/community_user_ban_view.rs deleted file mode 100644 index d0a925848..000000000 --- a/crates/db_views_actor/src/community_user_ban_view.rs +++ /dev/null @@ -1,35 +0,0 @@ -use diesel::{result::Error, *}; -use lemmy_db_queries::ToSafe; -use lemmy_db_schema::{ - schema::{community, community_user_ban, user_}, - source::{ - community::{Community, CommunitySafe}, - user::{UserSafe, User_}, - }, -}; -use serde::Serialize; - -#[derive(Debug, Serialize, Clone)] -pub struct CommunityUserBanView { - pub community: CommunitySafe, - pub user: UserSafe, -} - -impl CommunityUserBanView { - pub fn get( - conn: &PgConnection, - from_user_id: i32, - from_community_id: i32, - ) -> Result { - let (community, user) = community_user_ban::table - .inner_join(community::table) - .inner_join(user_::table) - .select((Community::safe_columns_tuple(), User_::safe_columns_tuple())) - .filter(community_user_ban::community_id.eq(from_community_id)) - .filter(community_user_ban::user_id.eq(from_user_id)) - .order_by(community_user_ban::published) - .first::<(CommunitySafe, UserSafe)>(conn)?; - - Ok(CommunityUserBanView { community, user }) - } -} diff --git a/crates/db_views_actor/src/community_view.rs b/crates/db_views_actor/src/community_view.rs index 9187696db..47d0b1e22 100644 --- a/crates/db_views_actor/src/community_view.rs +++ b/crates/db_views_actor/src/community_view.rs @@ -1,4 +1,4 @@ -use crate::{community_moderator_view::CommunityModeratorView, user_view::UserViewSafe}; +use crate::{community_moderator_view::CommunityModeratorView, person_view::PersonViewSafe}; use diesel::{result::Error, *}; use lemmy_db_queries::{ aggregates::community_aggregates::CommunityAggregates, @@ -12,10 +12,10 @@ use lemmy_db_queries::{ ViewToVec, }; use lemmy_db_schema::{ - schema::{community, community_aggregates, community_follower, user_}, + schema::{community, community_aggregates, community_follower, person}, source::{ community::{Community, CommunityFollower, CommunitySafe}, - user::{UserSafe, User_}, + person::{PersonSafe, Person}, }, }; use serde::Serialize; @@ -23,14 +23,14 @@ use serde::Serialize; #[derive(Debug, Serialize, Clone)] pub struct CommunityView { pub community: CommunitySafe, - pub creator: UserSafe, + pub creator: PersonSafe, pub subscribed: bool, pub counts: CommunityAggregates, } type CommunityViewTuple = ( CommunitySafe, - UserSafe, + PersonSafe, CommunityAggregates, Option, ); @@ -39,25 +39,25 @@ impl CommunityView { pub fn read( conn: &PgConnection, community_id: i32, - my_user_id: Option, + my_person_id: Option, ) -> Result { // The left join below will return None in this case - let user_id_join = my_user_id.unwrap_or(-1); + let person_id_join = my_person_id.unwrap_or(-1); let (community, creator, counts, follower) = community::table .find(community_id) - .inner_join(user_::table) + .inner_join(person::table) .inner_join(community_aggregates::table) .left_join( community_follower::table.on( community::id .eq(community_follower::community_id) - .and(community_follower::user_id.eq(user_id_join)), + .and(community_follower::person_id.eq(person_id_join)), ), ) .select(( Community::safe_columns_tuple(), - User_::safe_columns_tuple(), + Person::safe_columns_tuple(), community_aggregates::all_columns, community_follower::all_columns.nullable(), )) @@ -79,14 +79,14 @@ impl CommunityView { .map(|v| v.into_iter().map(|m| m.moderator.id).collect())?, ); mods_and_admins - .append(&mut UserViewSafe::admins(conn).map(|v| v.into_iter().map(|a| a.user.id).collect())?); + .append(&mut PersonViewSafe::admins(conn).map(|v| v.into_iter().map(|a| a.person.id).collect())?); Ok(mods_and_admins) } - pub fn is_mod_or_admin(conn: &PgConnection, user_id: i32, community_id: i32) -> bool { + pub fn is_mod_or_admin(conn: &PgConnection, person_id: i32, community_id: i32) -> bool { Self::community_mods_and_admins(conn, community_id) .unwrap_or_default() - .contains(&user_id) + .contains(&person_id) } } @@ -94,7 +94,7 @@ pub struct CommunityQueryBuilder<'a> { conn: &'a PgConnection, listing_type: &'a ListingType, sort: &'a SortType, - my_user_id: Option, + my_person_id: Option, show_nsfw: bool, search_term: Option, page: Option, @@ -105,7 +105,7 @@ impl<'a> CommunityQueryBuilder<'a> { pub fn create(conn: &'a PgConnection) -> Self { CommunityQueryBuilder { conn, - my_user_id: None, + my_person_id: None, listing_type: &ListingType::All, sort: &SortType::Hot, show_nsfw: true, @@ -135,8 +135,8 @@ impl<'a> CommunityQueryBuilder<'a> { self } - pub fn my_user_id>(mut self, my_user_id: T) -> Self { - self.my_user_id = my_user_id.get_optional(); + pub fn my_person_id>(mut self, my_person_id: T) -> Self { + self.my_person_id = my_person_id.get_optional(); self } @@ -152,21 +152,21 @@ impl<'a> CommunityQueryBuilder<'a> { pub fn list(self) -> Result, Error> { // The left join below will return None in this case - let user_id_join = self.my_user_id.unwrap_or(-1); + let person_id_join = self.my_person_id.unwrap_or(-1); let mut query = community::table - .inner_join(user_::table) + .inner_join(person::table) .inner_join(community_aggregates::table) .left_join( community_follower::table.on( community::id .eq(community_follower::community_id) - .and(community_follower::user_id.eq(user_id_join)), + .and(community_follower::person_id.eq(person_id_join)), ), ) .select(( Community::safe_columns_tuple(), - User_::safe_columns_tuple(), + Person::safe_columns_tuple(), community_aggregates::all_columns, community_follower::all_columns.nullable(), )) @@ -202,7 +202,7 @@ impl<'a> CommunityQueryBuilder<'a> { }; query = match self.listing_type { - ListingType::Subscribed => query.filter(community_follower::user_id.is_not_null()), // TODO could be this: and(community_follower::user_id.eq(user_id_join)), + ListingType::Subscribed => query.filter(community_follower::person_id.is_not_null()), // TODO could be this: and(community_follower::person_id.eq(person_id_join)), ListingType::Local => query.filter(community::local.eq(true)), _ => query, }; diff --git a/crates/db_views_actor/src/lib.rs b/crates/db_views_actor/src/lib.rs index a2ac31937..5d5203c56 100644 --- a/crates/db_views_actor/src/lib.rs +++ b/crates/db_views_actor/src/lib.rs @@ -1,6 +1,6 @@ pub mod community_follower_view; pub mod community_moderator_view; -pub mod community_user_ban_view; +pub mod community_person_ban_view; pub mod community_view; -pub mod user_mention_view; -pub mod user_view; +pub mod person_mention_view; +pub mod person_view; diff --git a/crates/db_views_actor/src/user_mention_view.rs b/crates/db_views_actor/src/person_mention_view.rs similarity index 70% rename from crates/db_views_actor/src/user_mention_view.rs rename to crates/db_views_actor/src/person_mention_view.rs index dc37a8804..5d7ee9833 100644 --- a/crates/db_views_actor/src/user_mention_view.rs +++ b/crates/db_views_actor/src/person_mention_view.rs @@ -16,44 +16,44 @@ use lemmy_db_schema::{ comment_saved, community, community_follower, - community_user_ban, + community_person_ban, post, - user_, - user_alias_1, - user_mention, + person, + person_alias_1, + person_mention, }, source::{ comment::{Comment, CommentSaved}, community::{Community, CommunityFollower, CommunitySafe, CommunityPersonBan}, post::Post, - user::{UserAlias1, UserSafe, UserSafeAlias1, User_}, - user_mention::UserMention, + person::{PersonAlias1, PersonSafe, PersonSafeAlias1, Person}, + person_mention::PersonMention, }, }; use serde::Serialize; #[derive(Debug, PartialEq, Serialize, Clone)] -pub struct UserMentionView { - pub user_mention: UserMention, +pub struct PersonMentionView { + pub person_mention: PersonMention, pub comment: Comment, - pub creator: UserSafe, + pub creator: PersonSafe, pub post: Post, pub community: CommunitySafe, - pub recipient: UserSafeAlias1, + pub recipient: PersonSafeAlias1, pub counts: CommentAggregates, - pub creator_banned_from_community: bool, // Left Join to CommunityUserBan + pub creator_banned_from_community: bool, // Left Join to CommunityPersonBan pub subscribed: bool, // Left join to CommunityFollower pub saved: bool, // Left join to CommentSaved pub my_vote: Option, // Left join to CommentLike } -type UserMentionViewTuple = ( - UserMention, +type PersonMentionViewTuple = ( + PersonMention, Comment, - UserSafe, + PersonSafe, Post, CommunitySafe, - UserSafeAlias1, + PersonSafeAlias1, CommentAggregates, Option, Option, @@ -61,17 +61,17 @@ type UserMentionViewTuple = ( Option, ); -impl UserMentionView { +impl PersonMentionView { pub fn read( conn: &PgConnection, - user_mention_id: i32, - my_user_id: Option, + person_mention_id: i32, + my_person_id: Option, ) -> Result { // The left join below will return None in this case - let user_id_join = my_user_id.unwrap_or(-1); + let person_id_join = my_person_id.unwrap_or(-1); let ( - user_mention, + person_mention, comment, creator, post, @@ -82,59 +82,59 @@ impl UserMentionView { subscribed, saved, my_vote, - ) = user_mention::table - .find(user_mention_id) + ) = person_mention::table + .find(person_mention_id) .inner_join(comment::table) - .inner_join(user_::table.on(comment::creator_id.eq(user_::id))) + .inner_join(person::table.on(comment::creator_id.eq(person::id))) .inner_join(post::table.on(comment::post_id.eq(post::id))) .inner_join(community::table.on(post::community_id.eq(community::id))) - .inner_join(user_alias_1::table) + .inner_join(person_alias_1::table) .inner_join(comment_aggregates::table.on(comment::id.eq(comment_aggregates::comment_id))) .left_join( - community_user_ban::table.on( + community_person_ban::table.on( community::id - .eq(community_user_ban::community_id) - .and(community_user_ban::user_id.eq(comment::creator_id)), + .eq(community_person_ban::community_id) + .and(community_person_ban::person_id.eq(comment::creator_id)), ), ) .left_join( community_follower::table.on( post::community_id .eq(community_follower::community_id) - .and(community_follower::user_id.eq(user_id_join)), + .and(community_follower::person_id.eq(person_id_join)), ), ) .left_join( comment_saved::table.on( comment::id .eq(comment_saved::comment_id) - .and(comment_saved::user_id.eq(user_id_join)), + .and(comment_saved::person_id.eq(person_id_join)), ), ) .left_join( comment_like::table.on( comment::id .eq(comment_like::comment_id) - .and(comment_like::user_id.eq(user_id_join)), + .and(comment_like::person_id.eq(person_id_join)), ), ) .select(( - user_mention::all_columns, + person_mention::all_columns, comment::all_columns, - User_::safe_columns_tuple(), + Person::safe_columns_tuple(), post::all_columns, Community::safe_columns_tuple(), - UserAlias1::safe_columns_tuple(), + PersonAlias1::safe_columns_tuple(), comment_aggregates::all_columns, - community_user_ban::all_columns.nullable(), + community_person_ban::all_columns.nullable(), community_follower::all_columns.nullable(), comment_saved::all_columns.nullable(), comment_like::score.nullable(), )) - .first::(conn)?; + .first::(conn)?; - Ok(UserMentionView { - user_mention, + Ok(PersonMentionView { + person_mention, comment, creator, post, @@ -149,9 +149,9 @@ impl UserMentionView { } } -pub struct UserMentionQueryBuilder<'a> { +pub struct PersonMentionQueryBuilder<'a> { conn: &'a PgConnection, - my_user_id: Option, + my_person_id: Option, recipient_id: Option, sort: &'a SortType, unread_only: bool, @@ -159,11 +159,11 @@ pub struct UserMentionQueryBuilder<'a> { limit: Option, } -impl<'a> UserMentionQueryBuilder<'a> { +impl<'a> PersonMentionQueryBuilder<'a> { pub fn create(conn: &'a PgConnection) -> Self { - UserMentionQueryBuilder { + PersonMentionQueryBuilder { conn, - my_user_id: None, + my_person_id: None, recipient_id: None, sort: &SortType::New, unread_only: false, @@ -187,8 +187,8 @@ impl<'a> UserMentionQueryBuilder<'a> { self } - pub fn my_user_id>(mut self, my_user_id: T) -> Self { - self.my_user_id = my_user_id.get_optional(); + pub fn my_person_id>(mut self, my_person_id: T) -> Self { + self.my_person_id = my_person_id.get_optional(); self } @@ -202,56 +202,56 @@ impl<'a> UserMentionQueryBuilder<'a> { self } - pub fn list(self) -> Result, Error> { + pub fn list(self) -> Result, Error> { use diesel::dsl::*; // The left join below will return None in this case - let user_id_join = self.my_user_id.unwrap_or(-1); + let person_id_join = self.my_person_id.unwrap_or(-1); - let mut query = user_mention::table + let mut query = person_mention::table .inner_join(comment::table) - .inner_join(user_::table.on(comment::creator_id.eq(user_::id))) + .inner_join(person::table.on(comment::creator_id.eq(person::id))) .inner_join(post::table.on(comment::post_id.eq(post::id))) .inner_join(community::table.on(post::community_id.eq(community::id))) - .inner_join(user_alias_1::table) + .inner_join(person_alias_1::table) .inner_join(comment_aggregates::table.on(comment::id.eq(comment_aggregates::comment_id))) .left_join( - community_user_ban::table.on( + community_person_ban::table.on( community::id - .eq(community_user_ban::community_id) - .and(community_user_ban::user_id.eq(comment::creator_id)), + .eq(community_person_ban::community_id) + .and(community_person_ban::person_id.eq(comment::creator_id)), ), ) .left_join( community_follower::table.on( post::community_id .eq(community_follower::community_id) - .and(community_follower::user_id.eq(user_id_join)), + .and(community_follower::person_id.eq(person_id_join)), ), ) .left_join( comment_saved::table.on( comment::id .eq(comment_saved::comment_id) - .and(comment_saved::user_id.eq(user_id_join)), + .and(comment_saved::person_id.eq(person_id_join)), ), ) .left_join( comment_like::table.on( comment::id .eq(comment_like::comment_id) - .and(comment_like::user_id.eq(user_id_join)), + .and(comment_like::person_id.eq(person_id_join)), ), ) .select(( - user_mention::all_columns, + person_mention::all_columns, comment::all_columns, - User_::safe_columns_tuple(), + Person::safe_columns_tuple(), post::all_columns, Community::safe_columns_tuple(), - UserAlias1::safe_columns_tuple(), + PersonAlias1::safe_columns_tuple(), comment_aggregates::all_columns, - community_user_ban::all_columns.nullable(), + community_person_ban::all_columns.nullable(), community_follower::all_columns.nullable(), comment_saved::all_columns.nullable(), comment_like::score.nullable(), @@ -259,11 +259,11 @@ impl<'a> UserMentionQueryBuilder<'a> { .into_boxed(); if let Some(recipient_id) = self.recipient_id { - query = query.filter(user_mention::recipient_id.eq(recipient_id)); + query = query.filter(person_mention::recipient_id.eq(recipient_id)); } if self.unread_only { - query = query.filter(user_mention::read.eq(false)); + query = query.filter(person_mention::read.eq(false)); } query = match self.sort { @@ -293,19 +293,19 @@ impl<'a> UserMentionQueryBuilder<'a> { let res = query .limit(limit) .offset(offset) - .load::(self.conn)?; + .load::(self.conn)?; - Ok(UserMentionView::from_tuple_to_vec(res)) + Ok(PersonMentionView::from_tuple_to_vec(res)) } } -impl ViewToVec for UserMentionView { - type DbTuple = UserMentionViewTuple; +impl ViewToVec for PersonMentionView { + type DbTuple = PersonMentionViewTuple; fn from_tuple_to_vec(items: Vec) -> Vec { items .iter() .map(|a| Self { - user_mention: a.0.to_owned(), + person_mention: a.0.to_owned(), comment: a.1.to_owned(), creator: a.2.to_owned(), post: a.3.to_owned(), diff --git a/crates/db_views_actor/src/person_view.rs b/crates/db_views_actor/src/person_view.rs new file mode 100644 index 000000000..ff936d6de --- /dev/null +++ b/crates/db_views_actor/src/person_view.rs @@ -0,0 +1,152 @@ +use diesel::{dsl::*, result::Error, *}; +use lemmy_db_queries::{ + aggregates::person_aggregates::PersonAggregates, + fuzzy_search, + limit_and_offset, + MaybeOptional, + SortType, + ToSafe, + ViewToVec, +}; +use lemmy_db_schema::{ + schema::{person, person_aggregates, local_user}, + source::person::{PersonSafe, Person}, +}; +use serde::Serialize; + +#[derive(Debug, Serialize, Clone)] +pub struct PersonViewSafe { + pub person: PersonSafe, + pub counts: PersonAggregates, +} + +type PersonViewSafeTuple = (PersonSafe, PersonAggregates); + +impl PersonViewSafe { + pub fn read(conn: &PgConnection, id: i32) -> Result { + let (person, counts) = person::table + .find(id) + .inner_join(person_aggregates::table) + .select((Person::safe_columns_tuple(), person_aggregates::all_columns)) + .first::(conn)?; + Ok(Self { person, counts }) + } + + pub fn admins(conn: &PgConnection) -> Result, Error> { + let admins = person::table + .inner_join(person_aggregates::table) + .inner_join(local_user::table) + .select((Person::safe_columns_tuple(), person_aggregates::all_columns)) + .filter(local_user::admin.eq(true)) + .order_by(person::published) + .load::(conn)?; + + Ok(Self::from_tuple_to_vec(admins)) + } + + pub fn banned(conn: &PgConnection) -> Result, Error> { + let banned = person::table + .inner_join(person_aggregates::table) + .select((Person::safe_columns_tuple(), person_aggregates::all_columns)) + .filter(person::banned.eq(true)) + .load::(conn)?; + + Ok(Self::from_tuple_to_vec(banned)) + } +} + +pub struct PersonQueryBuilder<'a> { + conn: &'a PgConnection, + sort: &'a SortType, + search_term: Option, + page: Option, + limit: Option, +} + +impl<'a> PersonQueryBuilder<'a> { + pub fn create(conn: &'a PgConnection) -> Self { + PersonQueryBuilder { + conn, + search_term: None, + sort: &SortType::Hot, + page: None, + limit: None, + } + } + + pub fn sort(mut self, sort: &'a SortType) -> Self { + self.sort = sort; + self + } + + pub fn search_term>(mut self, search_term: T) -> Self { + self.search_term = search_term.get_optional(); + self + } + + pub fn page>(mut self, page: T) -> Self { + self.page = page.get_optional(); + self + } + + pub fn limit>(mut self, limit: T) -> Self { + self.limit = limit.get_optional(); + self + } + + pub fn list(self) -> Result, Error> { + let mut query = person::table + .inner_join(person_aggregates::table) + .select((Person::safe_columns_tuple(), person_aggregates::all_columns)) + .into_boxed(); + + if let Some(search_term) = self.search_term { + query = query.filter(person::name.ilike(fuzzy_search(&search_term))); + } + + query = match self.sort { + SortType::Hot => query + .order_by(person_aggregates::comment_score.desc()) + .then_order_by(person::published.desc()), + SortType::Active => query + .order_by(person_aggregates::comment_score.desc()) + .then_order_by(person::published.desc()), + SortType::New | SortType::MostComments | SortType::NewComments => { + query.order_by(person::published.desc()) + } + SortType::TopAll => query.order_by(person_aggregates::comment_score.desc()), + SortType::TopYear => query + .filter(person::published.gt(now - 1.years())) + .order_by(person_aggregates::comment_score.desc()), + SortType::TopMonth => query + .filter(person::published.gt(now - 1.months())) + .order_by(person_aggregates::comment_score.desc()), + SortType::TopWeek => query + .filter(person::published.gt(now - 1.weeks())) + .order_by(person_aggregates::comment_score.desc()), + SortType::TopDay => query + .filter(person::published.gt(now - 1.days())) + .order_by(person_aggregates::comment_score.desc()), + }; + + let (limit, offset) = limit_and_offset(self.page, self.limit); + query = query.limit(limit).offset(offset); + + let res = query.load::(self.conn)?; + + Ok(PersonViewSafe::from_tuple_to_vec(res)) + } +} + +impl ViewToVec for PersonViewSafe { + type DbTuple = PersonViewSafeTuple; + fn from_tuple_to_vec(items: Vec) -> Vec { + items + .iter() + .map(|a| Self { + person: a.0.to_owned(), + counts: a.1.to_owned(), + }) + .collect::>() + } +} diff --git a/crates/db_views_actor/src/user_view.rs b/crates/db_views_actor/src/user_view.rs deleted file mode 100644 index bbe889a25..000000000 --- a/crates/db_views_actor/src/user_view.rs +++ /dev/null @@ -1,151 +0,0 @@ -use diesel::{dsl::*, result::Error, *}; -use lemmy_db_queries::{ - aggregates::user_aggregates::UserAggregates, - fuzzy_search, - limit_and_offset, - MaybeOptional, - SortType, - ToSafe, - ViewToVec, -}; -use lemmy_db_schema::{ - schema::{user_, user_aggregates}, - source::user::{UserSafe, User_}, -}; -use serde::Serialize; - -#[derive(Debug, Serialize, Clone)] -pub struct UserViewSafe { - pub user: UserSafe, - pub counts: UserAggregates, -} - -type UserViewSafeTuple = (UserSafe, UserAggregates); - -impl UserViewSafe { - pub fn read(conn: &PgConnection, id: i32) -> Result { - let (user, counts) = user_::table - .find(id) - .inner_join(user_aggregates::table) - .select((User_::safe_columns_tuple(), user_aggregates::all_columns)) - .first::(conn)?; - Ok(Self { user, counts }) - } - - pub fn admins(conn: &PgConnection) -> Result, Error> { - let admins = user_::table - .inner_join(user_aggregates::table) - .select((User_::safe_columns_tuple(), user_aggregates::all_columns)) - .filter(user_::admin.eq(true)) - .order_by(user_::published) - .load::(conn)?; - - Ok(Self::from_tuple_to_vec(admins)) - } - - pub fn banned(conn: &PgConnection) -> Result, Error> { - let banned = user_::table - .inner_join(user_aggregates::table) - .select((User_::safe_columns_tuple(), user_aggregates::all_columns)) - .filter(user_::banned.eq(true)) - .load::(conn)?; - - Ok(Self::from_tuple_to_vec(banned)) - } -} - -pub struct UserQueryBuilder<'a> { - conn: &'a PgConnection, - sort: &'a SortType, - search_term: Option, - page: Option, - limit: Option, -} - -impl<'a> UserQueryBuilder<'a> { - pub fn create(conn: &'a PgConnection) -> Self { - UserQueryBuilder { - conn, - search_term: None, - sort: &SortType::Hot, - page: None, - limit: None, - } - } - - pub fn sort(mut self, sort: &'a SortType) -> Self { - self.sort = sort; - self - } - - pub fn search_term>(mut self, search_term: T) -> Self { - self.search_term = search_term.get_optional(); - self - } - - pub fn page>(mut self, page: T) -> Self { - self.page = page.get_optional(); - self - } - - pub fn limit>(mut self, limit: T) -> Self { - self.limit = limit.get_optional(); - self - } - - pub fn list(self) -> Result, Error> { - let mut query = user_::table - .inner_join(user_aggregates::table) - .select((User_::safe_columns_tuple(), user_aggregates::all_columns)) - .into_boxed(); - - if let Some(search_term) = self.search_term { - query = query.filter(user_::name.ilike(fuzzy_search(&search_term))); - } - - query = match self.sort { - SortType::Hot => query - .order_by(user_aggregates::comment_score.desc()) - .then_order_by(user_::published.desc()), - SortType::Active => query - .order_by(user_aggregates::comment_score.desc()) - .then_order_by(user_::published.desc()), - SortType::New | SortType::MostComments | SortType::NewComments => { - query.order_by(user_::published.desc()) - } - SortType::TopAll => query.order_by(user_aggregates::comment_score.desc()), - SortType::TopYear => query - .filter(user_::published.gt(now - 1.years())) - .order_by(user_aggregates::comment_score.desc()), - SortType::TopMonth => query - .filter(user_::published.gt(now - 1.months())) - .order_by(user_aggregates::comment_score.desc()), - SortType::TopWeek => query - .filter(user_::published.gt(now - 1.weeks())) - .order_by(user_aggregates::comment_score.desc()), - SortType::TopDay => query - .filter(user_::published.gt(now - 1.days())) - .order_by(user_aggregates::comment_score.desc()), - }; - - let (limit, offset) = limit_and_offset(self.page, self.limit); - query = query.limit(limit).offset(offset); - - let res = query.load::(self.conn)?; - - Ok(UserViewSafe::from_tuple_to_vec(res)) - } -} - -impl ViewToVec for UserViewSafe { - type DbTuple = UserViewSafeTuple; - fn from_tuple_to_vec(items: Vec) -> Vec { - items - .iter() - .map(|a| Self { - user: a.0.to_owned(), - counts: a.1.to_owned(), - }) - .collect::>() - } -} diff --git a/crates/db_views_moderator/Cargo.toml b/crates/db_views_moderator/Cargo.toml index aef6abdc3..9df01522d 100644 --- a/crates/db_views_moderator/Cargo.toml +++ b/crates/db_views_moderator/Cargo.toml @@ -3,6 +3,9 @@ name = "lemmy_db_views_moderator" version = "0.1.0" edition = "2018" +[lib] +doctest = false + [dependencies] lemmy_db_queries = { path = "../db_queries" } lemmy_db_schema = { path = "../db_schema" } diff --git a/crates/db_views_moderator/src/mod_add_community_view.rs b/crates/db_views_moderator/src/mod_add_community_view.rs index dfb7de7e6..32988c190 100644 --- a/crates/db_views_moderator/src/mod_add_community_view.rs +++ b/crates/db_views_moderator/src/mod_add_community_view.rs @@ -1,11 +1,11 @@ use diesel::{result::Error, *}; use lemmy_db_queries::{limit_and_offset, ToSafe, ViewToVec}; use lemmy_db_schema::{ - schema::{community, mod_add_community, user_, user_alias_1}, + schema::{community, mod_add_community, person, person_alias_1}, source::{ community::{Community, CommunitySafe}, moderator::ModAddCommunity, - user::{UserAlias1, UserSafe, UserSafeAlias1, User_}, + person::{PersonAlias1, PersonSafe, PersonSafeAlias1, Person}, }, }; use serde::Serialize; @@ -13,35 +13,35 @@ use serde::Serialize; #[derive(Debug, Serialize, Clone)] pub struct ModAddCommunityView { pub mod_add_community: ModAddCommunity, - pub moderator: UserSafe, + pub moderator: PersonSafe, pub community: CommunitySafe, - pub modded_user: UserSafeAlias1, + pub modded_person: PersonSafeAlias1, } -type ModAddCommunityViewTuple = (ModAddCommunity, UserSafe, CommunitySafe, UserSafeAlias1); +type ModAddCommunityViewTuple = (ModAddCommunity, PersonSafe, CommunitySafe, PersonSafeAlias1); impl ModAddCommunityView { pub fn list( conn: &PgConnection, community_id: Option, - mod_user_id: Option, + mod_person_id: Option, page: Option, limit: Option, ) -> Result, Error> { let mut query = mod_add_community::table - .inner_join(user_::table.on(mod_add_community::mod_user_id.eq(user_::id))) + .inner_join(person::table.on(mod_add_community::mod_person_id.eq(person::id))) .inner_join(community::table) - .inner_join(user_alias_1::table.on(mod_add_community::other_user_id.eq(user_alias_1::id))) + .inner_join(person_alias_1::table.on(mod_add_community::other_person_id.eq(person_alias_1::id))) .select(( mod_add_community::all_columns, - User_::safe_columns_tuple(), + Person::safe_columns_tuple(), Community::safe_columns_tuple(), - UserAlias1::safe_columns_tuple(), + PersonAlias1::safe_columns_tuple(), )) .into_boxed(); - if let Some(mod_user_id) = mod_user_id { - query = query.filter(mod_add_community::mod_user_id.eq(mod_user_id)); + if let Some(mod_person_id) = mod_person_id { + query = query.filter(mod_add_community::mod_person_id.eq(mod_person_id)); }; if let Some(community_id) = community_id { @@ -69,7 +69,7 @@ impl ViewToVec for ModAddCommunityView { mod_add_community: a.0.to_owned(), moderator: a.1.to_owned(), community: a.2.to_owned(), - modded_user: a.3.to_owned(), + modded_person: a.3.to_owned(), }) .collect::>() } diff --git a/crates/db_views_moderator/src/mod_add_view.rs b/crates/db_views_moderator/src/mod_add_view.rs index 06c7091cc..e4a665c5e 100644 --- a/crates/db_views_moderator/src/mod_add_view.rs +++ b/crates/db_views_moderator/src/mod_add_view.rs @@ -1,10 +1,10 @@ use diesel::{result::Error, *}; use lemmy_db_queries::{limit_and_offset, ToSafe, ViewToVec}; use lemmy_db_schema::{ - schema::{mod_add, user_, user_alias_1}, + schema::{mod_add, person, person_alias_1}, source::{ moderator::ModAdd, - user::{UserAlias1, UserSafe, UserSafeAlias1, User_}, + person::{PersonAlias1, PersonSafe, PersonSafeAlias1, Person}, }, }; use serde::Serialize; @@ -12,31 +12,31 @@ use serde::Serialize; #[derive(Debug, Serialize, Clone)] pub struct ModAddView { pub mod_add: ModAdd, - pub moderator: UserSafe, - pub modded_user: UserSafeAlias1, + pub moderator: PersonSafe, + pub modded_person: PersonSafeAlias1, } -type ModAddViewTuple = (ModAdd, UserSafe, UserSafeAlias1); +type ModAddViewTuple = (ModAdd, PersonSafe, PersonSafeAlias1); impl ModAddView { pub fn list( conn: &PgConnection, - mod_user_id: Option, + mod_person_id: Option, page: Option, limit: Option, ) -> Result, Error> { let mut query = mod_add::table - .inner_join(user_::table.on(mod_add::mod_user_id.eq(user_::id))) - .inner_join(user_alias_1::table.on(mod_add::other_user_id.eq(user_alias_1::id))) + .inner_join(person::table.on(mod_add::mod_person_id.eq(person::id))) + .inner_join(person_alias_1::table.on(mod_add::other_person_id.eq(person_alias_1::id))) .select(( mod_add::all_columns, - User_::safe_columns_tuple(), - UserAlias1::safe_columns_tuple(), + Person::safe_columns_tuple(), + PersonAlias1::safe_columns_tuple(), )) .into_boxed(); - if let Some(mod_user_id) = mod_user_id { - query = query.filter(mod_add::mod_user_id.eq(mod_user_id)); + if let Some(mod_person_id) = mod_person_id { + query = query.filter(mod_add::mod_person_id.eq(mod_person_id)); }; let (limit, offset) = limit_and_offset(page, limit); @@ -59,7 +59,7 @@ impl ViewToVec for ModAddView { .map(|a| Self { mod_add: a.0.to_owned(), moderator: a.1.to_owned(), - modded_user: a.2.to_owned(), + modded_person: a.2.to_owned(), }) .collect::>() } diff --git a/crates/db_views_moderator/src/mod_ban_from_community_view.rs b/crates/db_views_moderator/src/mod_ban_from_community_view.rs index 1d9b1fafd..a60ede61b 100644 --- a/crates/db_views_moderator/src/mod_ban_from_community_view.rs +++ b/crates/db_views_moderator/src/mod_ban_from_community_view.rs @@ -1,11 +1,11 @@ use diesel::{result::Error, *}; use lemmy_db_queries::{limit_and_offset, ToSafe, ViewToVec}; use lemmy_db_schema::{ - schema::{community, mod_ban_from_community, user_, user_alias_1}, + schema::{community, mod_ban_from_community, person, person_alias_1}, source::{ community::{Community, CommunitySafe}, moderator::ModBanFromCommunity, - user::{UserAlias1, UserSafe, UserSafeAlias1, User_}, + person::{PersonAlias1, PersonSafe, PersonSafeAlias1, Person}, }, }; use serde::Serialize; @@ -13,37 +13,37 @@ use serde::Serialize; #[derive(Debug, Serialize, Clone)] pub struct ModBanFromCommunityView { pub mod_ban_from_community: ModBanFromCommunity, - pub moderator: UserSafe, + pub moderator: PersonSafe, pub community: CommunitySafe, - pub banned_user: UserSafeAlias1, + pub banned_person: PersonSafeAlias1, } -type ModBanFromCommunityViewTuple = (ModBanFromCommunity, UserSafe, CommunitySafe, UserSafeAlias1); +type ModBanFromCommunityViewTuple = (ModBanFromCommunity, PersonSafe, CommunitySafe, PersonSafeAlias1); impl ModBanFromCommunityView { pub fn list( conn: &PgConnection, community_id: Option, - mod_user_id: Option, + mod_person_id: Option, page: Option, limit: Option, ) -> Result, Error> { let mut query = mod_ban_from_community::table - .inner_join(user_::table.on(mod_ban_from_community::mod_user_id.eq(user_::id))) + .inner_join(person::table.on(mod_ban_from_community::mod_person_id.eq(person::id))) .inner_join(community::table) .inner_join( - user_alias_1::table.on(mod_ban_from_community::other_user_id.eq(user_alias_1::id)), + person_alias_1::table.on(mod_ban_from_community::other_person_id.eq(person_alias_1::id)), ) .select(( mod_ban_from_community::all_columns, - User_::safe_columns_tuple(), + Person::safe_columns_tuple(), Community::safe_columns_tuple(), - UserAlias1::safe_columns_tuple(), + PersonAlias1::safe_columns_tuple(), )) .into_boxed(); - if let Some(mod_user_id) = mod_user_id { - query = query.filter(mod_ban_from_community::mod_user_id.eq(mod_user_id)); + if let Some(mod_person_id) = mod_person_id { + query = query.filter(mod_ban_from_community::mod_person_id.eq(mod_person_id)); }; if let Some(community_id) = community_id { @@ -71,7 +71,7 @@ impl ViewToVec for ModBanFromCommunityView { mod_ban_from_community: a.0.to_owned(), moderator: a.1.to_owned(), community: a.2.to_owned(), - banned_user: a.3.to_owned(), + banned_person: a.3.to_owned(), }) .collect::>() } diff --git a/crates/db_views_moderator/src/mod_ban_view.rs b/crates/db_views_moderator/src/mod_ban_view.rs index ff599e187..2c55d5149 100644 --- a/crates/db_views_moderator/src/mod_ban_view.rs +++ b/crates/db_views_moderator/src/mod_ban_view.rs @@ -1,10 +1,10 @@ use diesel::{result::Error, *}; use lemmy_db_queries::{limit_and_offset, ToSafe, ViewToVec}; use lemmy_db_schema::{ - schema::{mod_ban, user_, user_alias_1}, + schema::{mod_ban, person, person_alias_1}, source::{ moderator::ModBan, - user::{UserAlias1, UserSafe, UserSafeAlias1, User_}, + person::{PersonAlias1, PersonSafe, PersonSafeAlias1, Person}, }, }; use serde::Serialize; @@ -12,31 +12,31 @@ use serde::Serialize; #[derive(Debug, Serialize, Clone)] pub struct ModBanView { pub mod_ban: ModBan, - pub moderator: UserSafe, - pub banned_user: UserSafeAlias1, + pub moderator: PersonSafe, + pub banned_person: PersonSafeAlias1, } -type ModBanViewTuple = (ModBan, UserSafe, UserSafeAlias1); +type ModBanViewTuple = (ModBan, PersonSafe, PersonSafeAlias1); impl ModBanView { pub fn list( conn: &PgConnection, - mod_user_id: Option, + mod_person_id: Option, page: Option, limit: Option, ) -> Result, Error> { let mut query = mod_ban::table - .inner_join(user_::table.on(mod_ban::mod_user_id.eq(user_::id))) - .inner_join(user_alias_1::table.on(mod_ban::other_user_id.eq(user_alias_1::id))) + .inner_join(person::table.on(mod_ban::mod_person_id.eq(person::id))) + .inner_join(person_alias_1::table.on(mod_ban::other_person_id.eq(person_alias_1::id))) .select(( mod_ban::all_columns, - User_::safe_columns_tuple(), - UserAlias1::safe_columns_tuple(), + Person::safe_columns_tuple(), + PersonAlias1::safe_columns_tuple(), )) .into_boxed(); - if let Some(mod_user_id) = mod_user_id { - query = query.filter(mod_ban::mod_user_id.eq(mod_user_id)); + if let Some(mod_person_id) = mod_person_id { + query = query.filter(mod_ban::mod_person_id.eq(mod_person_id)); }; let (limit, offset) = limit_and_offset(page, limit); @@ -59,7 +59,7 @@ impl ViewToVec for ModBanView { .map(|a| Self { mod_ban: a.0.to_owned(), moderator: a.1.to_owned(), - banned_user: a.2.to_owned(), + banned_person: a.2.to_owned(), }) .collect::>() } diff --git a/crates/db_views_moderator/src/mod_lock_post_view.rs b/crates/db_views_moderator/src/mod_lock_post_view.rs index e6c697af7..9369ba99b 100644 --- a/crates/db_views_moderator/src/mod_lock_post_view.rs +++ b/crates/db_views_moderator/src/mod_lock_post_view.rs @@ -1,12 +1,12 @@ use diesel::{result::Error, *}; use lemmy_db_queries::{limit_and_offset, ToSafe, ViewToVec}; use lemmy_db_schema::{ - schema::{community, mod_lock_post, post, user_}, + schema::{community, mod_lock_post, post, person}, source::{ community::{Community, CommunitySafe}, moderator::ModLockPost, post::Post, - user::{UserSafe, User_}, + person::{PersonSafe, Person}, }, }; use serde::Serialize; @@ -14,28 +14,28 @@ use serde::Serialize; #[derive(Debug, Serialize, Clone)] pub struct ModLockPostView { pub mod_lock_post: ModLockPost, - pub moderator: UserSafe, + pub moderator: PersonSafe, pub post: Post, pub community: CommunitySafe, } -type ModLockPostViewTuple = (ModLockPost, UserSafe, Post, CommunitySafe); +type ModLockPostViewTuple = (ModLockPost, PersonSafe, Post, CommunitySafe); impl ModLockPostView { pub fn list( conn: &PgConnection, community_id: Option, - mod_user_id: Option, + mod_person_id: Option, page: Option, limit: Option, ) -> Result, Error> { let mut query = mod_lock_post::table - .inner_join(user_::table) + .inner_join(person::table) .inner_join(post::table) .inner_join(community::table.on(post::community_id.eq(community::id))) .select(( mod_lock_post::all_columns, - User_::safe_columns_tuple(), + Person::safe_columns_tuple(), post::all_columns, Community::safe_columns_tuple(), )) @@ -45,8 +45,8 @@ impl ModLockPostView { query = query.filter(post::community_id.eq(community_id)); }; - if let Some(mod_user_id) = mod_user_id { - query = query.filter(mod_lock_post::mod_user_id.eq(mod_user_id)); + if let Some(mod_person_id) = mod_person_id { + query = query.filter(mod_lock_post::mod_person_id.eq(mod_person_id)); }; let (limit, offset) = limit_and_offset(page, limit); diff --git a/crates/db_views_moderator/src/mod_remove_comment_view.rs b/crates/db_views_moderator/src/mod_remove_comment_view.rs index 082703532..9633f2009 100644 --- a/crates/db_views_moderator/src/mod_remove_comment_view.rs +++ b/crates/db_views_moderator/src/mod_remove_comment_view.rs @@ -1,13 +1,13 @@ use diesel::{result::Error, *}; use lemmy_db_queries::{limit_and_offset, ToSafe, ViewToVec}; use lemmy_db_schema::{ - schema::{comment, community, mod_remove_comment, post, user_, user_alias_1}, + schema::{comment, community, mod_remove_comment, post, person, person_alias_1}, source::{ comment::Comment, community::{Community, CommunitySafe}, moderator::ModRemoveComment, post::Post, - user::{UserAlias1, UserSafe, UserSafeAlias1, User_}, + person::{PersonAlias1, PersonSafe, PersonSafeAlias1, Person}, }, }; use serde::Serialize; @@ -15,18 +15,18 @@ use serde::Serialize; #[derive(Debug, Serialize, Clone)] pub struct ModRemoveCommentView { pub mod_remove_comment: ModRemoveComment, - pub moderator: UserSafe, + pub moderator: PersonSafe, pub comment: Comment, - pub commenter: UserSafeAlias1, + pub commenter: PersonSafeAlias1, pub post: Post, pub community: CommunitySafe, } type ModRemoveCommentViewTuple = ( ModRemoveComment, - UserSafe, + PersonSafe, Comment, - UserSafeAlias1, + PersonSafeAlias1, Post, CommunitySafe, ); @@ -35,21 +35,21 @@ impl ModRemoveCommentView { pub fn list( conn: &PgConnection, community_id: Option, - mod_user_id: Option, + mod_person_id: Option, page: Option, limit: Option, ) -> Result, Error> { let mut query = mod_remove_comment::table - .inner_join(user_::table) + .inner_join(person::table) .inner_join(comment::table) - .inner_join(user_alias_1::table.on(comment::creator_id.eq(user_alias_1::id))) + .inner_join(person_alias_1::table.on(comment::creator_id.eq(person_alias_1::id))) .inner_join(post::table.on(comment::post_id.eq(post::id))) .inner_join(community::table.on(post::community_id.eq(community::id))) .select(( mod_remove_comment::all_columns, - User_::safe_columns_tuple(), + Person::safe_columns_tuple(), comment::all_columns, - UserAlias1::safe_columns_tuple(), + PersonAlias1::safe_columns_tuple(), post::all_columns, Community::safe_columns_tuple(), )) @@ -59,8 +59,8 @@ impl ModRemoveCommentView { query = query.filter(post::community_id.eq(community_id)); }; - if let Some(mod_user_id) = mod_user_id { - query = query.filter(mod_remove_comment::mod_user_id.eq(mod_user_id)); + if let Some(mod_person_id) = mod_person_id { + query = query.filter(mod_remove_comment::mod_person_id.eq(mod_person_id)); }; let (limit, offset) = limit_and_offset(page, limit); diff --git a/crates/db_views_moderator/src/mod_remove_community_view.rs b/crates/db_views_moderator/src/mod_remove_community_view.rs index ff62ac15f..6d49acbe5 100644 --- a/crates/db_views_moderator/src/mod_remove_community_view.rs +++ b/crates/db_views_moderator/src/mod_remove_community_view.rs @@ -1,11 +1,11 @@ use diesel::{result::Error, *}; use lemmy_db_queries::{limit_and_offset, ToSafe, ViewToVec}; use lemmy_db_schema::{ - schema::{community, mod_remove_community, user_}, + schema::{community, mod_remove_community, person}, source::{ community::{Community, CommunitySafe}, moderator::ModRemoveCommunity, - user::{UserSafe, User_}, + person::{PersonSafe, Person}, }, }; use serde::Serialize; @@ -13,31 +13,31 @@ use serde::Serialize; #[derive(Debug, Serialize, Clone)] pub struct ModRemoveCommunityView { pub mod_remove_community: ModRemoveCommunity, - pub moderator: UserSafe, + pub moderator: PersonSafe, pub community: CommunitySafe, } -type ModRemoveCommunityTuple = (ModRemoveCommunity, UserSafe, CommunitySafe); +type ModRemoveCommunityTuple = (ModRemoveCommunity, PersonSafe, CommunitySafe); impl ModRemoveCommunityView { pub fn list( conn: &PgConnection, - mod_user_id: Option, + mod_person_id: Option, page: Option, limit: Option, ) -> Result, Error> { let mut query = mod_remove_community::table - .inner_join(user_::table) + .inner_join(person::table) .inner_join(community::table) .select(( mod_remove_community::all_columns, - User_::safe_columns_tuple(), + Person::safe_columns_tuple(), Community::safe_columns_tuple(), )) .into_boxed(); - if let Some(mod_user_id) = mod_user_id { - query = query.filter(mod_remove_community::mod_user_id.eq(mod_user_id)); + if let Some(mod_person_id) = mod_person_id { + query = query.filter(mod_remove_community::mod_person_id.eq(mod_person_id)); }; let (limit, offset) = limit_and_offset(page, limit); diff --git a/crates/db_views_moderator/src/mod_remove_post_view.rs b/crates/db_views_moderator/src/mod_remove_post_view.rs index 530ae0396..8530656cc 100644 --- a/crates/db_views_moderator/src/mod_remove_post_view.rs +++ b/crates/db_views_moderator/src/mod_remove_post_view.rs @@ -1,12 +1,12 @@ use diesel::{result::Error, *}; use lemmy_db_queries::{limit_and_offset, ToSafe, ViewToVec}; use lemmy_db_schema::{ - schema::{community, mod_remove_post, post, user_}, + schema::{community, mod_remove_post, post, person}, source::{ community::{Community, CommunitySafe}, moderator::ModRemovePost, post::Post, - user::{UserSafe, User_}, + person::{PersonSafe, Person}, }, }; use serde::Serialize; @@ -14,28 +14,28 @@ use serde::Serialize; #[derive(Debug, Serialize, Clone)] pub struct ModRemovePostView { pub mod_remove_post: ModRemovePost, - pub moderator: UserSafe, + pub moderator: PersonSafe, pub post: Post, pub community: CommunitySafe, } -type ModRemovePostViewTuple = (ModRemovePost, UserSafe, Post, CommunitySafe); +type ModRemovePostViewTuple = (ModRemovePost, PersonSafe, Post, CommunitySafe); impl ModRemovePostView { pub fn list( conn: &PgConnection, community_id: Option, - mod_user_id: Option, + mod_person_id: Option, page: Option, limit: Option, ) -> Result, Error> { let mut query = mod_remove_post::table - .inner_join(user_::table) + .inner_join(person::table) .inner_join(post::table) .inner_join(community::table.on(post::community_id.eq(community::id))) .select(( mod_remove_post::all_columns, - User_::safe_columns_tuple(), + Person::safe_columns_tuple(), post::all_columns, Community::safe_columns_tuple(), )) @@ -45,8 +45,8 @@ impl ModRemovePostView { query = query.filter(post::community_id.eq(community_id)); }; - if let Some(mod_user_id) = mod_user_id { - query = query.filter(mod_remove_post::mod_user_id.eq(mod_user_id)); + if let Some(mod_person_id) = mod_person_id { + query = query.filter(mod_remove_post::mod_person_id.eq(mod_person_id)); }; let (limit, offset) = limit_and_offset(page, limit); diff --git a/crates/db_views_moderator/src/mod_sticky_post_view.rs b/crates/db_views_moderator/src/mod_sticky_post_view.rs index 1d726ca7c..9f4ea4af6 100644 --- a/crates/db_views_moderator/src/mod_sticky_post_view.rs +++ b/crates/db_views_moderator/src/mod_sticky_post_view.rs @@ -1,12 +1,12 @@ use diesel::{result::Error, *}; use lemmy_db_queries::{limit_and_offset, ToSafe, ViewToVec}; use lemmy_db_schema::{ - schema::{community, mod_sticky_post, post, user_}, + schema::{community, mod_sticky_post, post, person}, source::{ community::{Community, CommunitySafe}, moderator::ModStickyPost, post::Post, - user::{UserSafe, User_}, + person::{PersonSafe, Person}, }, }; use serde::Serialize; @@ -14,28 +14,28 @@ use serde::Serialize; #[derive(Debug, Serialize, Clone)] pub struct ModStickyPostView { pub mod_sticky_post: ModStickyPost, - pub moderator: UserSafe, + pub moderator: PersonSafe, pub post: Post, pub community: CommunitySafe, } -type ModStickyPostViewTuple = (ModStickyPost, UserSafe, Post, CommunitySafe); +type ModStickyPostViewTuple = (ModStickyPost, PersonSafe, Post, CommunitySafe); impl ModStickyPostView { pub fn list( conn: &PgConnection, community_id: Option, - mod_user_id: Option, + mod_person_id: Option, page: Option, limit: Option, ) -> Result, Error> { let mut query = mod_sticky_post::table - .inner_join(user_::table) + .inner_join(person::table) .inner_join(post::table) .inner_join(community::table.on(post::community_id.eq(community::id))) .select(( mod_sticky_post::all_columns, - User_::safe_columns_tuple(), + Person::safe_columns_tuple(), post::all_columns, Community::safe_columns_tuple(), )) @@ -45,8 +45,8 @@ impl ModStickyPostView { query = query.filter(post::community_id.eq(community_id)); }; - if let Some(mod_user_id) = mod_user_id { - query = query.filter(mod_sticky_post::mod_user_id.eq(mod_user_id)); + if let Some(mod_person_id) = mod_person_id { + query = query.filter(mod_sticky_post::mod_person_id.eq(mod_person_id)); }; let (limit, offset) = limit_and_offset(page, limit); diff --git a/crates/routes/Cargo.toml b/crates/routes/Cargo.toml index 0c5eac665..b6b464c33 100644 --- a/crates/routes/Cargo.toml +++ b/crates/routes/Cargo.toml @@ -3,6 +3,9 @@ name = "lemmy_routes" version = "0.1.0" edition = "2018" +[lib] +doctest = false + [dependencies] lemmy_utils = { path = "../utils" } lemmy_websocket = { path = "../websocket" } @@ -10,7 +13,7 @@ lemmy_db_queries = { path = "../db_queries" } lemmy_db_views = { path = "../db_views" } lemmy_db_views_actor = { path = "../db_views_actor" } lemmy_db_schema = { path = "../db_schema" } -lemmy_structs = { path = "../structs" } +lemmy_api_structs = { path = "../api_structs" } diesel = "1.4.5" actix = "0.10.0" actix-web = { version = "3.3.2", default-features = false, features = ["rustls"] } @@ -22,6 +25,6 @@ chrono = { version = "0.4.19", features = ["serde"] } rss = "1.10.0" serde = { version = "1.0.123", features = ["derive"] } awc = { version = "2.0.3", default-features = false } -url = { version = "2.2.0", features = ["serde"] } +url = { version = "2.2.1", features = ["serde"] } strum = "0.20.0" lazy_static = "1.4.0" diff --git a/crates/routes/src/feeds.rs b/crates/routes/src/feeds.rs index 837e1489a..568107984 100644 --- a/crates/routes/src/feeds.rs +++ b/crates/routes/src/feeds.rs @@ -2,20 +2,25 @@ use actix_web::{error::ErrorBadRequest, *}; use anyhow::anyhow; use chrono::{DateTime, NaiveDateTime, Utc}; use diesel::PgConnection; +use lemmy_api_structs::blocking; use lemmy_db_queries::{ - source::{community::Community_, user::User}, + source::{community::Community_, person::Person_}, ListingType, SortType, }; -use lemmy_db_schema::source::{community::Community, user::User_}; +use lemmy_db_schema::source::{community::Community, person::Person}; use lemmy_db_views::{ comment_view::{CommentQueryBuilder, CommentView}, post_view::{PostQueryBuilder, PostView}, site_view::SiteView, }; -use lemmy_db_views_actor::user_mention_view::{UserMentionQueryBuilder, UserMentionView}; -use lemmy_structs::blocking; -use lemmy_utils::{claims::Claims, settings::Settings, utils::markdown_to_html, LemmyError}; +use lemmy_db_views_actor::person_mention_view::{PersonMentionQueryBuilder, PersonMentionView}; +use lemmy_utils::{ + claims::Claims, + settings::structs::Settings, + utils::markdown_to_html, + LemmyError, +}; use lemmy_websocket::LemmyContext; use rss::{ extension::dublincore::DublinCoreExtensionBuilder, @@ -162,13 +167,12 @@ fn get_feed_user( user_name: String, ) -> Result { let site_view = SiteView::read(&conn)?; - let user = User_::find_by_username(&conn, &user_name)?; - let user_url = user.get_profile_url(&Settings::get().hostname); + let person = Person::find_by_name(&conn, &user_name)?; let posts = PostQueryBuilder::create(&conn) .listing_type(&ListingType::All) .sort(sort_type) - .creator_id(user.id) + .creator_id(person.id) .list()?; let items = create_post_items(posts)?; @@ -176,8 +180,8 @@ fn get_feed_user( let mut channel_builder = ChannelBuilder::default(); channel_builder .namespaces(RSS_NAMESPACE.to_owned()) - .title(&format!("{} - {}", site_view.site.name, user.name)) - .link(user_url) + .title(&format!("{} - {}", site_view.site.name, person.name)) + .link(person.actor_id.to_string()) .items(items); Ok(channel_builder) @@ -219,11 +223,11 @@ fn get_feed_front( jwt: String, ) -> Result { let site_view = SiteView::read(&conn)?; - let user_id = Claims::decode(&jwt)?.claims.id; + let person_id = Claims::decode(&jwt)?.claims.id; let posts = PostQueryBuilder::create(&conn) .listing_type(&ListingType::Subscribed) - .my_user_id(user_id) + .my_person_id(person_id) .sort(sort_type) .list()?; @@ -245,19 +249,19 @@ fn get_feed_front( fn get_feed_inbox(conn: &PgConnection, jwt: String) -> Result { let site_view = SiteView::read(&conn)?; - let user_id = Claims::decode(&jwt)?.claims.id; + let person_id = Claims::decode(&jwt)?.claims.id; let sort = SortType::New; let replies = CommentQueryBuilder::create(&conn) - .recipient_id(user_id) - .my_user_id(user_id) + .recipient_id(person_id) + .my_person_id(person_id) .sort(&sort) .list()?; - let mentions = UserMentionQueryBuilder::create(&conn) - .recipient_id(user_id) - .my_user_id(user_id) + let mentions = PersonMentionQueryBuilder::create(&conn) + .recipient_id(person_id) + .my_person_id(person_id) .sort(&sort) .list()?; @@ -282,7 +286,7 @@ fn get_feed_inbox(conn: &PgConnection, jwt: String) -> Result, - mentions: Vec, + mentions: Vec, ) -> Result, LemmyError> { let mut reply_items: Vec = replies .iter() @@ -391,9 +395,6 @@ fn create_post_items(posts: Vec) -> Result, LemmyError> { p.community.name ); - // TODO: for category we should just put the name of the category, but then we would have - // to read each community from the db - // TODO add images let mut description = format!("submitted by {} to {}
{} points | {} comments", p.creator.actor_id, diff --git a/crates/routes/src/images.rs b/crates/routes/src/images.rs index 4d7656e1b..fe23fe029 100644 --- a/crates/routes/src/images.rs +++ b/crates/routes/src/images.rs @@ -1,7 +1,7 @@ use actix::clock::Duration; use actix_web::{body::BodyStream, http::StatusCode, *}; use awc::Client; -use lemmy_utils::{claims::Claims, rate_limit::RateLimit, settings::Settings}; +use lemmy_utils::{claims::Claims, rate_limit::RateLimit, settings::structs::Settings}; use serde::{Deserialize, Serialize}; pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) { @@ -54,8 +54,10 @@ async fn upload( return Ok(HttpResponse::Unauthorized().finish()); }; - let mut client_req = - client.request_from(format!("{}/image", Settings::get().pictrs_url), req.head()); + let mut client_req = client.request_from( + format!("{}/image", Settings::get().pictrs_url()), + req.head(), + ); if let Some(addr) = req.head().peer_addr { client_req = client_req.header("X-Forwarded-For", addr.to_string()) @@ -78,14 +80,14 @@ async fn full_res( // If there are no query params, the URL is original let url = if params.format.is_none() && params.thumbnail.is_none() { - format!("{}/image/original/{}", Settings::get().pictrs_url, name,) + format!("{}/image/original/{}", Settings::get().pictrs_url(), name,) } else { // Use jpg as a default when none is given let format = params.format.unwrap_or_else(|| "jpg".to_string()); let mut url = format!( "{}/image/process.{}?src={}", - Settings::get().pictrs_url, + Settings::get().pictrs_url(), format, name, ); @@ -134,7 +136,7 @@ async fn delete( let url = format!( "{}/image/delete/{}/{}", - Settings::get().pictrs_url, + Settings::get().pictrs_url(), &token, &file ); diff --git a/crates/routes/src/nodeinfo.rs b/crates/routes/src/nodeinfo.rs index 46ef7ce4d..1333279cc 100644 --- a/crates/routes/src/nodeinfo.rs +++ b/crates/routes/src/nodeinfo.rs @@ -1,8 +1,8 @@ use actix_web::{body::Body, error::ErrorBadRequest, *}; use anyhow::anyhow; +use lemmy_api_structs::blocking; use lemmy_db_views::site_view::SiteView; -use lemmy_structs::blocking; -use lemmy_utils::{settings::Settings, version, LemmyError}; +use lemmy_utils::{settings::structs::Settings, version, LemmyError}; use lemmy_websocket::LemmyContext; use serde::{Deserialize, Serialize}; use url::Url; @@ -31,7 +31,7 @@ async fn node_info(context: web::Data) -> Result( &jwt, - &DecodingKey::from_secret(Settings::get().jwt_secret.as_ref()), + &DecodingKey::from_secret(Settings::get().jwt_secret().as_ref()), &v, ) } @@ -31,7 +31,7 @@ impl Claims { encode( &Header::default(), &my_claims, - &EncodingKey::from_secret(Settings::get().jwt_secret.as_ref()), + &EncodingKey::from_secret(Settings::get().jwt_secret().as_ref()), ) } } diff --git a/crates/utils/src/email.rs b/crates/utils/src/email.rs index 8e61500c0..ead534924 100644 --- a/crates/utils/src/email.rs +++ b/crates/utils/src/email.rs @@ -1,4 +1,4 @@ -use crate::settings::Settings; +use crate::settings::structs::Settings; use lettre::{ message::{header, Mailbox, MultiPart, SinglePart}, transport::smtp::{ @@ -19,8 +19,8 @@ pub fn send_email( to_username: &str, html: &str, ) -> Result<(), String> { - let email_config = Settings::get().email.ok_or("no_email_setup")?; - let domain = Settings::get().hostname; + let email_config = Settings::get().email().ok_or("no_email_setup")?; + let domain = Settings::get().hostname(); let (smtp_server, smtp_port) = { let email_and_port = email_config.smtp_server.split(':').collect::>(); diff --git a/crates/utils/src/lib.rs b/crates/utils/src/lib.rs index e64271568..bd2b56844 100644 --- a/crates/utils/src/lib.rs +++ b/crates/utils/src/lib.rs @@ -9,12 +9,13 @@ pub mod email; pub mod rate_limit; pub mod request; pub mod settings; + #[cfg(test)] mod test; pub mod utils; pub mod version; -use crate::settings::Settings; +use crate::settings::structs::Settings; use http::StatusCode; use regex::Regex; use thiserror::Error; @@ -83,12 +84,12 @@ impl actix_web::error::ResponseError for LemmyError { lazy_static! { pub static ref WEBFINGER_COMMUNITY_REGEX: Regex = Regex::new(&format!( "^group:([a-z0-9_]{{3, 20}})@{}$", - Settings::get().hostname + Settings::get().hostname() )) - .unwrap(); + .expect("compile webfinger regex"); pub static ref WEBFINGER_USER_REGEX: Regex = Regex::new(&format!( "^acct:([a-z0-9_]{{3, 20}})@{}$", - Settings::get().hostname + Settings::get().hostname() )) - .unwrap(); + .expect("compile webfinger regex"); } diff --git a/crates/utils/src/rate_limit/mod.rs b/crates/utils/src/rate_limit/mod.rs index 5a18ffd54..d3e74ed5b 100644 --- a/crates/utils/src/rate_limit/mod.rs +++ b/crates/utils/src/rate_limit/mod.rs @@ -1,5 +1,5 @@ use crate::{ - settings::{RateLimitConfig, Settings}, + settings::structs::{RateLimitConfig, Settings}, utils::get_ip, LemmyError, }; @@ -70,7 +70,7 @@ impl RateLimited { { // Does not need to be blocking because the RwLock in settings never held across await points, // and the operation here locks only long enough to clone - let rate_limit: RateLimitConfig = Settings::get().rate_limit; + let rate_limit: RateLimitConfig = Settings::get().rate_limit(); // before { diff --git a/crates/utils/src/request.rs b/crates/utils/src/request.rs index c3207dddd..66d0b11d1 100644 --- a/crates/utils/src/request.rs +++ b/crates/utils/src/request.rs @@ -1,4 +1,4 @@ -use crate::{settings::Settings, LemmyError}; +use crate::{settings::structs::Settings, LemmyError}; use anyhow::anyhow; use log::error; use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC}; @@ -6,6 +6,7 @@ use reqwest::Client; use serde::Deserialize; use std::future::Future; use thiserror::Error; +use url::Url; #[derive(Clone, Debug, Error)] #[error("Error sending request, {0}")] @@ -43,22 +44,22 @@ where } } - response.unwrap() + response.expect("retry http request") } #[derive(Deserialize, Debug)] pub(crate) struct IframelyResponse { title: Option, description: Option, - thumbnail_url: Option, + thumbnail_url: Option, html: Option, } pub(crate) async fn fetch_iframely( client: &Client, - url: &str, + url: &Url, ) -> Result { - let fetch_url = format!("{}/oembed?url={}", Settings::get().iframely_url, url); + let fetch_url = format!("{}/oembed?url={}", Settings::get().iframely_url(), url); let response = retry(|| client.get(&fetch_url).send()).await?; @@ -83,14 +84,14 @@ pub(crate) struct PictrsFile { pub(crate) async fn fetch_pictrs( client: &Client, - image_url: &str, + image_url: &Url, ) -> Result { is_image_content_type(client, image_url).await?; let fetch_url = format!( "{}/image/download?url={}", - Settings::get().pictrs_url, - utf8_percent_encode(image_url, NON_ALPHANUMERIC) // TODO this might not be needed + Settings::get().pictrs_url(), + utf8_percent_encode(image_url.as_str(), NON_ALPHANUMERIC) // TODO this might not be needed ); let response = retry(|| client.get(&fetch_url).send()).await?; @@ -109,13 +110,8 @@ pub(crate) async fn fetch_pictrs( pub async fn fetch_iframely_and_pictrs_data( client: &Client, - url: Option, -) -> ( - Option, - Option, - Option, - Option, -) { + url: Option<&Url>, +) -> (Option, Option, Option, Option) { match &url { Some(url) => { // Fetch iframely data @@ -149,11 +145,19 @@ pub async fn fetch_iframely_and_pictrs_data( // The full urls are necessary for federation let pictrs_thumbnail = if let Some(pictrs_hash) = pictrs_hash { - Some(format!( + let url = Url::parse(&format!( "{}/pictrs/image/{}", Settings::get().get_protocol_and_hostname(), pictrs_hash - )) + )); + match url { + Ok(parsed_url) => Some(parsed_url), + Err(e) => { + // This really shouldn't happen unless the settings or hash are malformed + error!("Unexpected error constructing pictrs thumbnail URL: {}", e); + None + } + } } else { None }; @@ -169,9 +173,8 @@ pub async fn fetch_iframely_and_pictrs_data( } } -async fn is_image_content_type(client: &Client, test: &str) -> Result<(), LemmyError> { - let response = retry(|| client.get(test).send()).await?; - +async fn is_image_content_type(client: &Client, test: &Url) -> Result<(), LemmyError> { + let response = retry(|| client.get(test.to_owned()).send()).await?; if response .headers() .get("Content-Type") diff --git a/crates/utils/src/settings.rs b/crates/utils/src/settings.rs deleted file mode 100644 index 8301dcee4..000000000 --- a/crates/utils/src/settings.rs +++ /dev/null @@ -1,210 +0,0 @@ -use crate::location_info; -use anyhow::Context; -use config::{Config, ConfigError, Environment, File}; -use serde::Deserialize; -use std::{env, fs, io::Error, net::IpAddr, sync::RwLock}; - -static CONFIG_FILE_DEFAULTS: &str = "config/defaults.hjson"; -static CONFIG_FILE: &str = "config/config.hjson"; - -#[derive(Debug, Deserialize, Clone)] -pub struct Settings { - pub setup: Option, - pub database: DatabaseConfig, - pub hostname: String, - pub bind: IpAddr, - pub port: u16, - pub tls_enabled: bool, - pub jwt_secret: String, - pub pictrs_url: String, - pub iframely_url: String, - pub rate_limit: RateLimitConfig, - pub email: Option, - pub federation: FederationConfig, - pub captcha: CaptchaConfig, -} - -#[derive(Debug, Deserialize, Clone)] -pub struct Setup { - pub admin_username: String, - pub admin_password: String, - pub admin_email: Option, - pub site_name: String, -} - -#[derive(Debug, Deserialize, Clone)] -pub struct RateLimitConfig { - pub message: i32, - pub message_per_second: i32, - pub post: i32, - pub post_per_second: i32, - pub register: i32, - pub register_per_second: i32, - pub image: i32, - pub image_per_second: i32, -} - -#[derive(Debug, Deserialize, Clone)] -pub struct EmailConfig { - pub smtp_server: String, - pub smtp_login: Option, - pub smtp_password: Option, - pub smtp_from_address: String, - pub use_tls: bool, -} - -#[derive(Debug, Deserialize, Clone)] -pub struct CaptchaConfig { - pub enabled: bool, - pub difficulty: String, // easy, medium, or hard -} - -#[derive(Debug, Deserialize, Clone)] -pub struct DatabaseConfig { - pub user: String, - pub password: String, - pub host: String, - pub port: i32, - pub database: String, - pub pool_size: u32, -} - -#[derive(Debug, Deserialize, Clone)] -pub struct FederationConfig { - pub enabled: bool, - pub allowed_instances: String, - pub blocked_instances: String, -} - -lazy_static! { - static ref SETTINGS: RwLock = RwLock::new(match Settings::init() { - Ok(c) => c, - Err(e) => panic!("{}", e), - }); -} - -impl Settings { - /// Reads config from the files and environment. - /// First, defaults are loaded from CONFIG_FILE_DEFAULTS, then these values can be overwritten - /// from CONFIG_FILE (optional). Finally, values from the environment (with prefix LEMMY) are - /// added to the config. - /// - /// Note: The env var `LEMMY_DATABASE_URL` is parsed in - /// `lemmy_db_queries/src/lib.rs::get_database_url_from_env()` - fn init() -> Result { - let mut s = Config::new(); - - s.merge(File::with_name(&Self::get_config_defaults_location()))?; - - s.merge(File::with_name(&Self::get_config_location()).required(false))?; - - // Add in settings from the environment (with a prefix of LEMMY) - // Eg.. `LEMMY_DEBUG=1 ./target/app` would set the `debug` key - // Note: we need to use double underscore here, because otherwise variables containing - // underscore cant be set from environmnet. - // https://github.com/mehcode/config-rs/issues/73 - s.merge(Environment::with_prefix("LEMMY").separator("__"))?; - - s.try_into() - } - - /// Returns the config as a struct. - pub fn get() -> Self { - SETTINGS.read().unwrap().to_owned() - } - - pub fn get_database_url(&self) -> String { - format!( - "postgres://{}:{}@{}:{}/{}", - self.database.user, - self.database.password, - self.database.host, - self.database.port, - self.database.database - ) - } - - pub fn get_config_defaults_location() -> String { - env::var("LEMMY_CONFIG_DEFAULTS_LOCATION").unwrap_or_else(|_| CONFIG_FILE_DEFAULTS.to_string()) - } - - pub fn get_config_location() -> String { - env::var("LEMMY_CONFIG_LOCATION").unwrap_or_else(|_| CONFIG_FILE.to_string()) - } - - pub fn read_config_file() -> Result { - fs::read_to_string(Self::get_config_location()) - } - - pub fn get_allowed_instances(&self) -> Vec { - let mut allowed_instances: Vec = self - .federation - .allowed_instances - .split(',') - .map(|d| d.trim().to_string()) - .collect(); - - // The defaults.hjson config always returns a [""] - allowed_instances.retain(|d| !d.eq("")); - - allowed_instances - } - - pub fn get_blocked_instances(&self) -> Vec { - let mut blocked_instances: Vec = self - .federation - .blocked_instances - .split(',') - .map(|d| d.trim().to_string()) - .collect(); - - // The defaults.hjson config always returns a [""] - blocked_instances.retain(|d| !d.eq("")); - - blocked_instances - } - - /// Returns either "http" or "https", depending on tls_enabled setting - pub fn get_protocol_string(&self) -> &'static str { - if self.tls_enabled { - "https" - } else { - "http" - } - } - - /// Returns something like `http://localhost` or `https://lemmy.ml`, - /// with the correct protocol and hostname. - pub fn get_protocol_and_hostname(&self) -> String { - format!("{}://{}", self.get_protocol_string(), self.hostname) - } - - /// When running the federation test setup in `api_tests/` or `docker/federation`, the `hostname` - /// variable will be like `lemmy-alpha:8541`. This method removes the port and returns - /// `lemmy-alpha` instead. It has no effect in production. - pub fn get_hostname_without_port(&self) -> Result { - Ok( - self - .hostname - .split(':') - .collect::>() - .first() - .context(location_info!())? - .to_string(), - ) - } - - pub fn save_config_file(data: &str) -> Result { - fs::write(CONFIG_FILE, data)?; - - // Reload the new settings - // From https://stackoverflow.com/questions/29654927/how-do-i-assign-a-string-to-a-mutable-static-variable/47181804#47181804 - let mut new_settings = SETTINGS.write().unwrap(); - *new_settings = match Settings::init() { - Ok(c) => c, - Err(e) => panic!("{}", e), - }; - - Self::read_config_file() - } -} diff --git a/crates/utils/src/settings/defaults.rs b/crates/utils/src/settings/defaults.rs new file mode 100644 index 000000000..56d24c7fb --- /dev/null +++ b/crates/utils/src/settings/defaults.rs @@ -0,0 +1,69 @@ +use crate::settings::{CaptchaConfig, DatabaseConfig, FederationConfig, RateLimitConfig, Settings}; +use std::net::{IpAddr, Ipv4Addr}; + +impl Default for Settings { + fn default() -> Self { + Self { + database: Some(DatabaseConfig::default()), + rate_limit: Some(RateLimitConfig::default()), + federation: Some(FederationConfig::default()), + captcha: Some(CaptchaConfig::default()), + email: None, + setup: None, + hostname: None, + bind: Some(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0))), + port: Some(8536), + tls_enabled: Some(true), + jwt_secret: Some("changeme".into()), + pictrs_url: Some("http://pictrs:8080".into()), + iframely_url: Some("http://iframely".into()), + } + } +} + +impl Default for DatabaseConfig { + fn default() -> Self { + Self { + user: "lemmy".into(), + password: "password".into(), + host: "localhost".into(), + port: 5432, + database: "lemmy".into(), + pool_size: 5, + } + } +} + +impl Default for CaptchaConfig { + fn default() -> Self { + Self { + enabled: true, + difficulty: "medium".into(), + } + } +} + +impl Default for FederationConfig { + fn default() -> Self { + Self { + enabled: false, + allowed_instances: None, + blocked_instances: None, + } + } +} + +impl Default for RateLimitConfig { + fn default() -> Self { + Self { + message: 180, + message_per_second: 60, + post: 6, + post_per_second: 600, + register: 3, + register_per_second: 3600, + image: 6, + image_per_second: 3600, + } + } +} diff --git a/crates/utils/src/settings/mod.rs b/crates/utils/src/settings/mod.rs new file mode 100644 index 000000000..3911a18f9 --- /dev/null +++ b/crates/utils/src/settings/mod.rs @@ -0,0 +1,172 @@ +use crate::{ + location_info, + settings::structs::{ + CaptchaConfig, + DatabaseConfig, + EmailConfig, + FederationConfig, + RateLimitConfig, + Settings, + SetupConfig, + }, + LemmyError, +}; +use anyhow::{anyhow, Context}; +use deser_hjson::from_str; +use merge::Merge; +use std::{env, fs, io::Error, net::IpAddr, sync::RwLock}; + +pub(crate) mod defaults; +pub mod structs; + +static CONFIG_FILE: &str = "config/config.hjson"; + +lazy_static! { + static ref SETTINGS: RwLock = RwLock::new(match Settings::init() { + Ok(c) => c, + Err(e) => panic!("{}", e), + }); +} + +impl Settings { + /// Reads config from the files and environment. + /// First, defaults are loaded from CONFIG_FILE_DEFAULTS, then these values can be overwritten + /// from CONFIG_FILE (optional). Finally, values from the environment (with prefix LEMMY) are + /// added to the config. + /// + /// Note: The env var `LEMMY_DATABASE_URL` is parsed in + /// `lemmy_db_queries/src/lib.rs::get_database_url_from_env()` + fn init() -> Result { + // Read the config file + let mut custom_config = from_str::(&Self::read_config_file()?)?; + + // Merge with env vars + custom_config.merge(envy::prefixed("LEMMY_").from_env::()?); + + // Merge with default + custom_config.merge(Settings::default()); + + if custom_config.hostname == Settings::default().hostname { + return Err(anyhow!("Hostname variable is not set!").into()); + } + + Ok(custom_config) + } + + /// Returns the config as a struct. + pub fn get() -> Self { + SETTINGS.read().expect("read config").to_owned() + } + + pub fn get_database_url(&self) -> String { + let conf = self.database(); + format!( + "postgres://{}:{}@{}:{}/{}", + conf.user, conf.password, conf.host, conf.port, conf.database, + ) + } + + pub fn get_config_location() -> String { + env::var("LEMMY_CONFIG_LOCATION").unwrap_or_else(|_| CONFIG_FILE.to_string()) + } + + pub fn read_config_file() -> Result { + fs::read_to_string(Self::get_config_location()) + } + + pub fn get_allowed_instances(&self) -> Option> { + self.federation().allowed_instances + } + + pub fn get_blocked_instances(&self) -> Option> { + self.federation().blocked_instances + } + + /// Returns either "http" or "https", depending on tls_enabled setting + pub fn get_protocol_string(&self) -> &'static str { + if let Some(tls_enabled) = self.tls_enabled { + if tls_enabled { + "https" + } else { + "http" + } + } else { + "http" + } + } + + /// Returns something like `http://localhost` or `https://lemmy.ml`, + /// with the correct protocol and hostname. + pub fn get_protocol_and_hostname(&self) -> String { + format!("{}://{}", self.get_protocol_string(), self.hostname()) + } + + /// When running the federation test setup in `api_tests/` or `docker/federation`, the `hostname` + /// variable will be like `lemmy-alpha:8541`. This method removes the port and returns + /// `lemmy-alpha` instead. It has no effect in production. + pub fn get_hostname_without_port(&self) -> Result { + Ok( + self + .hostname() + .split(':') + .collect::>() + .first() + .context(location_info!())? + .to_string(), + ) + } + + pub fn save_config_file(data: &str) -> Result { + fs::write(CONFIG_FILE, data)?; + + // Reload the new settings + // From https://stackoverflow.com/questions/29654927/how-do-i-assign-a-string-to-a-mutable-static-variable/47181804#47181804 + let mut new_settings = SETTINGS.write().expect("write config"); + *new_settings = match Settings::init() { + Ok(c) => c, + Err(e) => panic!("{}", e), + }; + + Ok(Self::read_config_file()?) + } + + pub fn database(&self) -> DatabaseConfig { + self.database.to_owned().unwrap_or_default() + } + pub fn hostname(&self) -> String { + self.hostname.to_owned().unwrap_or_default() + } + pub fn bind(&self) -> IpAddr { + self.bind.expect("return bind address") + } + pub fn port(&self) -> u16 { + self.port.unwrap_or_default() + } + pub fn tls_enabled(&self) -> bool { + self.tls_enabled.unwrap_or_default() + } + pub fn jwt_secret(&self) -> String { + self.jwt_secret.to_owned().unwrap_or_default() + } + pub fn pictrs_url(&self) -> String { + self.pictrs_url.to_owned().unwrap_or_default() + } + pub fn iframely_url(&self) -> String { + self.iframely_url.to_owned().unwrap_or_default() + } + pub fn rate_limit(&self) -> RateLimitConfig { + self.rate_limit.to_owned().unwrap_or_default() + } + pub fn federation(&self) -> FederationConfig { + self.federation.to_owned().unwrap_or_default() + } + pub fn captcha(&self) -> CaptchaConfig { + self.captcha.to_owned().unwrap_or_default() + } + pub fn email(&self) -> Option { + self.email.to_owned() + } + pub fn setup(&self) -> Option { + self.setup.to_owned() + } +} diff --git a/crates/utils/src/settings/structs.rs b/crates/utils/src/settings/structs.rs new file mode 100644 index 000000000..21d89b98a --- /dev/null +++ b/crates/utils/src/settings/structs.rs @@ -0,0 +1,72 @@ +use merge::Merge; +use serde::Deserialize; +use std::net::IpAddr; + +#[derive(Debug, Deserialize, Clone, Merge)] +pub struct Settings { + pub(crate) database: Option, + pub(crate) rate_limit: Option, + pub(crate) federation: Option, + pub(crate) hostname: Option, + pub(crate) bind: Option, + pub(crate) port: Option, + pub(crate) tls_enabled: Option, + pub(crate) jwt_secret: Option, + pub(crate) pictrs_url: Option, + pub(crate) iframely_url: Option, + pub(crate) captcha: Option, + pub(crate) email: Option, + pub(crate) setup: Option, +} + +#[derive(Debug, Deserialize, Clone)] +pub struct CaptchaConfig { + pub enabled: bool, + pub difficulty: String, +} + +#[derive(Debug, Deserialize, Clone)] +pub struct DatabaseConfig { + pub user: String, + pub password: String, + pub host: String, + pub port: i32, + pub database: String, + pub pool_size: u32, +} + +#[derive(Debug, Deserialize, Clone)] +pub struct EmailConfig { + pub smtp_server: String, + pub smtp_login: Option, + pub smtp_password: Option, + pub smtp_from_address: String, + pub use_tls: bool, +} + +#[derive(Debug, Deserialize, Clone)] +pub struct FederationConfig { + pub enabled: bool, + pub allowed_instances: Option>, + pub blocked_instances: Option>, +} + +#[derive(Debug, Deserialize, Clone)] +pub struct RateLimitConfig { + pub message: i32, + pub message_per_second: i32, + pub post: i32, + pub post_per_second: i32, + pub register: i32, + pub register_per_second: i32, + pub image: i32, + pub image_per_second: i32, +} + +#[derive(Debug, Deserialize, Clone)] +pub struct SetupConfig { + pub admin_username: String, + pub admin_password: String, + pub admin_email: Option, + pub site_name: String, +} diff --git a/crates/utils/src/utils.rs b/crates/utils/src/utils.rs index e0bbb88e7..33ea833d5 100644 --- a/crates/utils/src/utils.rs +++ b/crates/utils/src/utils.rs @@ -1,4 +1,4 @@ -use crate::{settings::Settings, ApiError}; +use crate::{settings::structs::Settings, ApiError}; use actix_web::dev::ConnectionInfo; use chrono::{DateTime, FixedOffset, NaiveDateTime}; use itertools::Itertools; @@ -6,15 +6,15 @@ use rand::{distributions::Alphanumeric, thread_rng, Rng}; use regex::{Regex, RegexBuilder}; lazy_static! { -static ref EMAIL_REGEX: Regex = Regex::new(r"^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$").unwrap(); -static ref SLUR_REGEX: Regex = RegexBuilder::new(r"(fag(g|got|tard)?\b|cock\s?sucker(s|ing)?|\bn(i|1)g(\b|g?(a|er)?(s|z)?)\b|mudslime?s?|kikes?|\bspi(c|k)s?\b|\bchinks?|gooks?|bitch(es|ing|y)?|whor(es?|ing)|\btr(a|@)nn?(y|ies?)|\b(b|re|r)tard(ed)?s?)").case_insensitive(true).build().unwrap(); -static ref USERNAME_MATCHES_REGEX: Regex = Regex::new(r"/u/[a-zA-Z][0-9a-zA-Z_]*").unwrap(); -// TODO keep this old one, it didn't work with port well tho -// static ref MENTIONS_REGEX: Regex = Regex::new(r"@(?P[\w.]+)@(?P[a-zA-Z0-9._-]+\.[a-zA-Z0-9_-]+)").unwrap(); -static ref MENTIONS_REGEX: Regex = Regex::new(r"@(?P[\w.]+)@(?P[a-zA-Z0-9._:-]+)").unwrap(); -static ref VALID_USERNAME_REGEX: Regex = Regex::new(r"^[a-zA-Z0-9_]{3,20}$").unwrap(); -static ref VALID_COMMUNITY_NAME_REGEX: Regex = Regex::new(r"^[a-z0-9_]{3,20}$").unwrap(); -static ref VALID_POST_TITLE_REGEX: Regex = Regex::new(r".*\S.*").unwrap(); + static ref EMAIL_REGEX: Regex = Regex::new(r"^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$").expect("compile regex"); + static ref SLUR_REGEX: Regex = RegexBuilder::new(r"(fag(g|got|tard)?\b|cock\s?sucker(s|ing)?|\bn(i|1)g(\b|g?(a|er)?(s|z)?)\b|mudslime?s?|kikes?|\bspi(c|k)s?\b|\bchinks?|gooks?|bitch(es|ing|y)?|whor(es?|ing)|\btr(a|@)nn?(y|ies?)|\b(b|re|r)tard(ed)?s?)").case_insensitive(true).build().expect("compile regex"); + static ref USERNAME_MATCHES_REGEX: Regex = Regex::new(r"/u/[a-zA-Z][0-9a-zA-Z_]*").expect("compile regex"); + // TODO keep this old one, it didn't work with port well tho + // static ref MENTIONS_REGEX: Regex = Regex::new(r"@(?P[\w.]+)@(?P[a-zA-Z0-9._-]+\.[a-zA-Z0-9_-]+)").expect("compile regex"); + static ref MENTIONS_REGEX: Regex = Regex::new(r"@(?P[\w.]+)@(?P[a-zA-Z0-9._:-]+)").expect("compile regex"); + static ref VALID_USERNAME_REGEX: Regex = Regex::new(r"^[a-zA-Z0-9_]{3,20}$").expect("compile regex"); + static ref VALID_COMMUNITY_NAME_REGEX: Regex = Regex::new(r"^[a-z0-9_]{3,20}$").expect("compile regex"); + static ref VALID_POST_TITLE_REGEX: Regex = Regex::new(r".*\S.*").expect("compile regex"); } pub fn naive_from_unix(time: i64) -> NaiveDateTime { @@ -85,7 +85,7 @@ pub struct MentionData { impl MentionData { pub fn is_local(&self) -> bool { - Settings::get().hostname.eq(&self.domain) + Settings::get().hostname().eq(&self.domain) } pub fn full_name(&self) -> String { format!("@{}@{}", &self.name, &self.domain) diff --git a/crates/websocket/Cargo.toml b/crates/websocket/Cargo.toml index 1cb71ea1d..b957e9446 100644 --- a/crates/websocket/Cargo.toml +++ b/crates/websocket/Cargo.toml @@ -1,16 +1,16 @@ [package] name = "lemmy_websocket" version = "0.1.0" -authors = ["Felix Ableitner "] edition = "2018" [lib] name = "lemmy_websocket" path = "src/lib.rs" +doctest = false [dependencies] lemmy_utils = { path = "../utils" } -lemmy_structs = { path = "../structs" } +lemmy_api_structs = { path = "../api_structs" } lemmy_db_queries = { path = "../db_queries" } lemmy_db_schema = { path = "../db_schema" } reqwest = { version = "0.10.10", features = ["json"] } diff --git a/crates/websocket/src/chat_server.rs b/crates/websocket/src/chat_server.rs index fa1d90185..9978d1ec6 100644 --- a/crates/websocket/src/chat_server.rs +++ b/crates/websocket/src/chat_server.rs @@ -6,7 +6,7 @@ use diesel::{ r2d2::{ConnectionManager, Pool}, PgConnection, }; -use lemmy_structs::{comment::*, post::*}; +use lemmy_api_structs::{comment::*, post::*}; use lemmy_utils::{ location_info, rate_limit::RateLimit, diff --git a/crates/websocket/src/lib.rs b/crates/websocket/src/lib.rs index 4723c7141..56b18a179 100644 --- a/crates/websocket/src/lib.rs +++ b/crates/websocket/src/lib.rs @@ -117,10 +117,10 @@ pub enum UserOperation { RemoveCommunity, FollowCommunity, GetFollowedCommunities, - GetUserDetails, + GetPersonDetails, GetReplies, - GetUserMentions, - MarkUserMentionAsRead, + GetPersonMentions, + MarkPersonMentionAsRead, GetModlog, BanFromCommunity, AddModToCommunity, @@ -128,7 +128,7 @@ pub enum UserOperation { EditSite, GetSite, AddAdmin, - BanUser, + BanPerson, Search, MarkAllAsRead, SaveUserSettings, diff --git a/crates/websocket/src/messages.rs b/crates/websocket/src/messages.rs index 4349b01b6..89f3f2b3e 100644 --- a/crates/websocket/src/messages.rs +++ b/crates/websocket/src/messages.rs @@ -1,6 +1,6 @@ use crate::UserOperation; use actix::{prelude::*, Recipient}; -use lemmy_structs::{comment::CommentResponse, post::PostResponse}; +use lemmy_api_structs::{comment::CommentResponse, post::PostResponse}; use lemmy_utils::{CommunityId, ConnectionId, IpAddr, PostId, UserId}; use serde::{Deserialize, Serialize}; diff --git a/docker/dev/Dockerfile b/docker/dev/Dockerfile index 3e3963d29..954c85c84 100644 --- a/docker/dev/Dockerfile +++ b/docker/dev/Dockerfile @@ -1,4 +1,4 @@ -ARG RUST_BUILDER_IMAGE=ekidd/rust-musl-builder:1.47.0 +ARG RUST_BUILDER_IMAGE=ekidd/rust-musl-builder:1.50.0 # Cargo chef plan FROM $RUST_BUILDER_IMAGE as planner @@ -56,7 +56,6 @@ RUN addgroup -g 1000 lemmy RUN adduser -D -s /bin/sh -u 1000 -G lemmy lemmy # Copy resources -COPY --chown=lemmy:lemmy config/defaults.hjson /config/defaults.hjson COPY --chown=lemmy:lemmy --from=builder /app/lemmy_server /app/lemmy RUN chown lemmy:lemmy /app/lemmy diff --git a/docker/dev/docker-compose.yml b/docker/dev/docker-compose.yml index da6eef533..a23f1e0ed 100644 --- a/docker/dev/docker-compose.yml +++ b/docker/dev/docker-compose.yml @@ -57,3 +57,4 @@ services: volumes: - ../iframely.config.local.js:/iframely/config.local.js:ro restart: always + mem_limit: 200m diff --git a/docker/dev/volume_mount.dockerfile b/docker/dev/volume_mount.dockerfile index 3bb0b81d5..0cb036247 100644 --- a/docker/dev/volume_mount.dockerfile +++ b/docker/dev/volume_mount.dockerfile @@ -1,5 +1,7 @@ # syntax=docker/dockerfile:experimental -FROM rust:1.47-buster as rust + +# Warning: this will not pick up migrations unless there are code changes +FROM rust:1.50-buster as rust ENV HOME=/home/root diff --git a/docker/federation/docker-compose.yml b/docker/federation/docker-compose.yml index b2b5ef7ea..c40de9022 100644 --- a/docker/federation/docker-compose.yml +++ b/docker/federation/docker-compose.yml @@ -38,20 +38,9 @@ services: - lemmy-alpha lemmy-alpha: image: lemmy-federation:latest + volumes: + - ./lemmy_alpha.hjson:/config/config.hjson environment: - - LEMMY_HOSTNAME=lemmy-alpha:8541 - - LEMMY_DATABASE_URL=postgres://lemmy:password@postgres_alpha:5432/lemmy - - LEMMY_JWT_SECRET=changeme - - LEMMY_FEDERATION__ENABLED=true - - LEMMY_TLS_ENABLED=false - - LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-beta,lemmy-gamma,lemmy-delta,lemmy-epsilon - - LEMMY_PORT=8541 - - LEMMY_SETUP__ADMIN_USERNAME=lemmy_alpha - - LEMMY_SETUP__ADMIN_PASSWORD=lemmy - - LEMMY_SETUP__SITE_NAME=lemmy-alpha - - LEMMY_RATE_LIMIT__POST=99999 - - LEMMY_RATE_LIMIT__REGISTER=99999 - - LEMMY_CAPTCHA__ENABLED=false - LEMMY_TEST_SEND_SYNC=1 - RUST_BACKTRACE=1 - RUST_LOG=debug @@ -78,20 +67,9 @@ services: - lemmy-beta lemmy-beta: image: lemmy-federation:latest + volumes: + - ./lemmy_beta.hjson:/config/config.hjson environment: - - LEMMY_HOSTNAME=lemmy-beta:8551 - - LEMMY_DATABASE_URL=postgres://lemmy:password@postgres_beta:5432/lemmy - - LEMMY_JWT_SECRET=changeme - - LEMMY_FEDERATION__ENABLED=true - - LEMMY_TLS_ENABLED=false - - LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-alpha,lemmy-gamma,lemmy-delta,lemmy-epsilon - - LEMMY_PORT=8551 - - LEMMY_SETUP__ADMIN_USERNAME=lemmy_beta - - LEMMY_SETUP__ADMIN_PASSWORD=lemmy - - LEMMY_SETUP__SITE_NAME=lemmy-beta - - LEMMY_RATE_LIMIT__POST=99999 - - LEMMY_RATE_LIMIT__REGISTER=99999 - - LEMMY_CAPTCHA__ENABLED=false - LEMMY_TEST_SEND_SYNC=1 - RUST_BACKTRACE=1 - RUST_LOG=debug @@ -118,20 +96,9 @@ services: - lemmy-gamma lemmy-gamma: image: lemmy-federation:latest + volumes: + - ./lemmy_gamma.hjson:/config/config.hjson environment: - - LEMMY_HOSTNAME=lemmy-gamma:8561 - - LEMMY_DATABASE_URL=postgres://lemmy:password@postgres_gamma:5432/lemmy - - LEMMY_JWT_SECRET=changeme - - LEMMY_FEDERATION__ENABLED=true - - LEMMY_TLS_ENABLED=false - - LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-alpha,lemmy-beta,lemmy-delta,lemmy-epsilon - - LEMMY_PORT=8561 - - LEMMY_SETUP__ADMIN_USERNAME=lemmy_gamma - - LEMMY_SETUP__ADMIN_PASSWORD=lemmy - - LEMMY_SETUP__SITE_NAME=lemmy-gamma - - LEMMY_RATE_LIMIT__POST=99999 - - LEMMY_RATE_LIMIT__REGISTER=99999 - - LEMMY_CAPTCHA__ENABLED=false - LEMMY_TEST_SEND_SYNC=1 - RUST_BACKTRACE=1 - RUST_LOG=debug @@ -159,20 +126,9 @@ services: - lemmy-delta lemmy-delta: image: lemmy-federation:latest + volumes: + - ./lemmy_delta.hjson:/config/config.hjson environment: - - LEMMY_HOSTNAME=lemmy-delta:8571 - - LEMMY_DATABASE_URL=postgres://lemmy:password@postgres_delta:5432/lemmy - - LEMMY_JWT_SECRET=changeme - - LEMMY_FEDERATION__ENABLED=true - - LEMMY_TLS_ENABLED=false - - LEMMY_FEDERATION__ALLOWED_INSTANCES=lemmy-beta - - LEMMY_PORT=8571 - - LEMMY_SETUP__ADMIN_USERNAME=lemmy_delta - - LEMMY_SETUP__ADMIN_PASSWORD=lemmy - - LEMMY_SETUP__SITE_NAME=lemmy-delta - - LEMMY_RATE_LIMIT__POST=99999 - - LEMMY_RATE_LIMIT__REGISTER=99999 - - LEMMY_CAPTCHA__ENABLED=false - LEMMY_TEST_SEND_SYNC=1 - RUST_BACKTRACE=1 - RUST_LOG=debug @@ -200,20 +156,9 @@ services: - lemmy-epsilon lemmy-epsilon: image: lemmy-federation:latest + volumes: + - ./lemmy_epsilon.hjson:/config/config.hjson environment: - - LEMMY_HOSTNAME=lemmy-epsilon:8581 - - LEMMY_DATABASE_URL=postgres://lemmy:password@postgres_epsilon:5432/lemmy - - LEMMY_JWT_SECRET=changeme - - LEMMY_FEDERATION__ENABLED=true - - LEMMY_TLS_ENABLED=false - - LEMMY_FEDERATION__BLOCKED_INSTANCES=lemmy-alpha - - LEMMY_PORT=8581 - - LEMMY_SETUP__ADMIN_USERNAME=lemmy_epsilon - - LEMMY_SETUP__ADMIN_PASSWORD=lemmy - - LEMMY_SETUP__SITE_NAME=lemmy-epsilon - - LEMMY_RATE_LIMIT__POST=99999 - - LEMMY_RATE_LIMIT__REGISTER=99999 - - LEMMY_CAPTCHA__ENABLED=false - LEMMY_TEST_SEND_SYNC=1 - RUST_BACKTRACE=1 - RUST_LOG=debug diff --git a/docker/federation/lemmy_alpha.hjson b/docker/federation/lemmy_alpha.hjson new file mode 100644 index 000000000..e806397a8 --- /dev/null +++ b/docker/federation/lemmy_alpha.hjson @@ -0,0 +1,36 @@ +{ + port: 8541 + tls_enabled: false + jwt_secret: changeme + setup: { + admin_username: lemmy_alpha + admin_password: lemmy + site_name: lemmy-alpha + } + database: { + database: lemmy + user: lemmy + password: password + host: postgres_alpha + port: 5432 + pool_size: 5 + } + federation: { + enabled: true + allowed_instances: ["lemmy-beta","lemmy-gamma","lemmy-delta","lemmy-epsilon"] + } + captcha: { + enabled: false + difficulty: medium + } + rate_limit: { + message: 180 + message_per_second: 60 + post: 99999 + post_per_second: 600 + register: 99999 + register_per_second: 3600 + image: 6 + image_per_second: 3600 + } +} diff --git a/docker/federation/lemmy_beta.hjson b/docker/federation/lemmy_beta.hjson new file mode 100644 index 000000000..e16ecd53b --- /dev/null +++ b/docker/federation/lemmy_beta.hjson @@ -0,0 +1,37 @@ +{ + hostname: lemmy-beta:8551 + port: 8551 + tls_enabled: false + jwt_secret: changeme + setup: { + admin_username: lemmy_beta + admin_password: lemmy + site_name: lemmy-beta + } + database: { + database: lemmy + user: lemmy + password: password + host: postgres_beta + port: 5432 + pool_size: 5 + } + federation: { + enabled: true + allowed_instances: ["lemmy-alpha","lemmy-gamma","lemmy-delta","lemmy-epsilon"] + } + captcha: { + enabled: false + difficulty: medium + } + rate_limit: { + message: 180 + message_per_second: 60 + post: 99999 + post_per_second: 600 + register: 99999 + register_per_second: 3600 + image: 6 + image_per_second: 3600 + } +} diff --git a/docker/federation/lemmy_delta.hjson b/docker/federation/lemmy_delta.hjson new file mode 100644 index 000000000..321775fb5 --- /dev/null +++ b/docker/federation/lemmy_delta.hjson @@ -0,0 +1,37 @@ +{ + hostname: lemmy-delta:8571 + port: 8571 + tls_enabled: false + jwt_secret: changeme + setup: { + admin_username: lemmy_delta + admin_password: lemmy + site_name: lemmy-delta + } + database: { + database: lemmy + user: lemmy + password: password + host: postgres_delta + port: 5432 + pool_size: 5 + } + federation: { + enabled: true + allowed_instances: ["lemmy-beta"] + } + captcha: { + enabled: false + difficulty: medium + } + rate_limit: { + message: 180 + message_per_second: 60 + post: 99999 + post_per_second: 600 + register: 99999 + register_per_second: 3600 + image: 6 + image_per_second: 3600 + } +} diff --git a/docker/federation/lemmy_epsilon.hjson b/docker/federation/lemmy_epsilon.hjson new file mode 100644 index 000000000..20fb2c353 --- /dev/null +++ b/docker/federation/lemmy_epsilon.hjson @@ -0,0 +1,37 @@ +{ + hostname: lemmy-epsilon:8581 + port: 8581 + tls_enabled: false + jwt_secret: changeme + setup: { + admin_username: lemmy_epsilon + admin_password: lemmy + site_name: lemmy-epsilon + } + database: { + database: lemmy + user: lemmy + password: password + host: postgres_epsilon + port: 5432 + pool_size: 5 + } + federation: { + enabled: true + blocked_instances: ["lemmy-alpha"] + } + captcha: { + enabled: false + difficulty: medium + } + rate_limit: { + message: 180 + message_per_second: 60 + post: 99999 + post_per_second: 600 + register: 99999 + register_per_second: 3600 + image: 6 + image_per_second: 3600 + } +} diff --git a/docker/federation/lemmy_gamma.hjson b/docker/federation/lemmy_gamma.hjson new file mode 100644 index 000000000..784f98eb7 --- /dev/null +++ b/docker/federation/lemmy_gamma.hjson @@ -0,0 +1,37 @@ +{ + hostname: lemmy-gamma:8561 + port: 8561 + tls_enabled: false + jwt_secret: changeme + setup: { + admin_username: lemmy_gamma + admin_password: lemmy + site_name: lemmy-gamma + } + database: { + database: lemmy + user: lemmy + password: password + host: postgres_gamma + port: 5432 + pool_size: 5 + } + federation: { + enabled: true + allowed_instances: ["lemmy-alpha","lemmy-beta","lemmy-delta","lemmy-epsilon"] + } + captcha: { + enabled: false + difficulty: medium + } + rate_limit: { + message: 180 + message_per_second: 60 + post: 99999 + post_per_second: 600 + register: 99999 + register_per_second: 3600 + image: 6 + image_per_second: 3600 + } +} diff --git a/docker/lemmy.hjson b/docker/lemmy.hjson index bea65d8f9..bceb5f6cd 100644 --- a/docker/lemmy.hjson +++ b/docker/lemmy.hjson @@ -29,6 +29,10 @@ password: "password" # host where postgres is running host: "postgres" + # port where postgres can be accessed + port: 5432 + # maximum number of active sql connections + pool_size: 5 } # # optional: email sending configuration # email: { diff --git a/docker/prod/Dockerfile b/docker/prod/Dockerfile index 66e8217fe..2ad601aec 100644 --- a/docker/prod/Dockerfile +++ b/docker/prod/Dockerfile @@ -1,4 +1,4 @@ -ARG RUST_BUILDER_IMAGE=ekidd/rust-musl-builder:1.47.0 +ARG RUST_BUILDER_IMAGE=ekidd/rust-musl-builder:1.50.0 # Cargo chef plan FROM $RUST_BUILDER_IMAGE as planner @@ -56,7 +56,6 @@ RUN addgroup -g 1000 lemmy RUN adduser -D -s /bin/sh -u 1000 -G lemmy lemmy # Copy resources -COPY --chown=lemmy:lemmy config/defaults.hjson /config/defaults.hjson COPY --chown=lemmy:lemmy --from=builder /app/lemmy_server /app/lemmy RUN chown lemmy:lemmy /app/lemmy diff --git a/docker/prod/Dockerfile.arm b/docker/prod/Dockerfile.arm index bcf590034..61d1f86c9 100644 --- a/docker/prod/Dockerfile.arm +++ b/docker/prod/Dockerfile.arm @@ -1,4 +1,4 @@ -ARG RUST_BUILDER_IMAGE=rust:1.47-slim-buster +ARG RUST_BUILDER_IMAGE=rust:1.50-slim-buster # Build Lemmy FROM $RUST_BUILDER_IMAGE as builder @@ -31,7 +31,6 @@ RUN addgroup --gid 1000 lemmy RUN adduser --no-create-home --shell /bin/sh --uid 1000 --gid 1000 lemmy # Copy resources -COPY --chown=lemmy:lemmy config/defaults.hjson /config/defaults.hjson COPY --chown=lemmy:lemmy --from=builder /app/lemmy_server /app/lemmy RUN chown lemmy:lemmy /app/lemmy diff --git a/docker/prod/docker-compose.yml b/docker/prod/docker-compose.yml index 5cbdc8d29..e219bdef8 100644 --- a/docker/prod/docker-compose.yml +++ b/docker/prod/docker-compose.yml @@ -53,4 +53,4 @@ services: volumes: - ./iframely.config.local.js:/iframely/config.local.js:ro restart: always - mem_limit: 100m + mem_limit: 200m diff --git a/migrations/2021-02-28-162616_clean_empty_post_urls/down.sql b/migrations/2021-02-28-162616_clean_empty_post_urls/down.sql new file mode 100644 index 000000000..7195601c9 --- /dev/null +++ b/migrations/2021-02-28-162616_clean_empty_post_urls/down.sql @@ -0,0 +1,4 @@ +-- This is a clean-up migration that cannot be undone, +-- but Diesel requires a non-empty script so run a no-op. +SELECT 1; + diff --git a/migrations/2021-02-28-162616_clean_empty_post_urls/up.sql b/migrations/2021-02-28-162616_clean_empty_post_urls/up.sql new file mode 100644 index 000000000..24e2d16b8 --- /dev/null +++ b/migrations/2021-02-28-162616_clean_empty_post_urls/up.sql @@ -0,0 +1 @@ +UPDATE post SET url = NULL where url = ''; diff --git a/migrations/2021-03-04-040229_clean_icon_urls/down.sql b/migrations/2021-03-04-040229_clean_icon_urls/down.sql new file mode 100644 index 000000000..f866b155c --- /dev/null +++ b/migrations/2021-03-04-040229_clean_icon_urls/down.sql @@ -0,0 +1,3 @@ +-- This is a clean-up migration that cannot be undone, +-- but Diesel requires a non-empty script so run a no-op. +SELECT 1; diff --git a/migrations/2021-03-04-040229_clean_icon_urls/up.sql b/migrations/2021-03-04-040229_clean_icon_urls/up.sql new file mode 100644 index 000000000..8b22b33fc --- /dev/null +++ b/migrations/2021-03-04-040229_clean_icon_urls/up.sql @@ -0,0 +1,5 @@ +-- If these are not urls, it will crash the server +update user_ set avatar = NULL where avatar not like 'http%'; +update user_ set banner = NULL where banner not like 'http%'; +update community set icon = NULL where icon not like 'http%'; +update community set banner = NULL where banner not like 'http%'; diff --git a/migrations/2021-02-25-173454_split_user_table_1/down.sql b/migrations/2021-03-09-171136_split_user_table_2/down.sql similarity index 100% rename from migrations/2021-02-25-173454_split_user_table_1/down.sql rename to migrations/2021-03-09-171136_split_user_table_2/down.sql diff --git a/migrations/2021-02-25-173454_split_user_table_1/up.sql b/migrations/2021-03-09-171136_split_user_table_2/up.sql similarity index 99% rename from migrations/2021-02-25-173454_split_user_table_1/up.sql rename to migrations/2021-03-09-171136_split_user_table_2/up.sql index d20bf0213..db3547e5f 100644 --- a/migrations/2021-02-25-173454_split_user_table_1/up.sql +++ b/migrations/2021-03-09-171136_split_user_table_2/up.sql @@ -11,7 +11,7 @@ create table local_user ( id serial primary key, person_id int references person on update cascade on delete cascade not null, password_encrypted text not null, - email text, + email text unique, admin boolean default false not null, show_nsfw boolean default false not null, theme character varying(20) default 'darkly'::character varying not null, diff --git a/restore_db.sh b/restore_db.sh new file mode 100755 index 000000000..318b99099 --- /dev/null +++ b/restore_db.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +psql -U lemmy -c "DROP SCHEMA public CASCADE; CREATE SCHEMA public;" +cat docker/dev/lemmy_dump_2021-01-29_16_13_40.sqldump | psql -U lemmy +psql -U lemmy -c "alter user lemmy with password 'password'" diff --git a/scripts/compilation_benchmark.sh b/scripts/compilation_benchmark.sh index 760037980..6d454795d 100755 --- a/scripts/compilation_benchmark.sh +++ b/scripts/compilation_benchmark.sh @@ -12,7 +12,7 @@ for ((i=0; i < times; i++)) ; do cargo clean echo "cargo build" start=$(date +%s.%N) - RUSTC_WRAPPER='' cargo +1.47.0 build -q + RUSTC_WRAPPER='' cargo build -q end=$(date +%s.%N) echo "Finished iteration $i after $(bc <<< "scale=0; $end - $start") seconds" duration=$(bc <<< "$duration + $end - $start") diff --git a/scripts/test.sh b/scripts/test.sh index b47f09fae..251e6a74a 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -5,9 +5,5 @@ psql -U lemmy -d postgres -c "DROP DATABASE lemmy;" psql -U lemmy -d postgres -c "CREATE DATABASE lemmy;" export LEMMY_DATABASE_URL=postgres://lemmy:password@localhost:5432/lemmy -# Commenting since this will overwrite schema.rs, which will break things now -# diesel migration run -# Integration tests only work on stable due to a bug in config-rs -# https://github.com/mehcode/config-rs/issues/158 -RUST_BACKTRACE=1 RUST_TEST_THREADS=1 \ - cargo +1.47.0 test --workspace --no-fail-fast +RUST_BACKTRACE=1 \ + cargo test --workspace --no-fail-fast diff --git a/src/code_migrations.rs b/src/code_migrations.rs index ea11e32d3..009b7afb6 100644 --- a/src/code_migrations.rs +++ b/src/code_migrations.rs @@ -24,7 +24,7 @@ use lemmy_db_schema::{ user::{UserForm, User_}, }, }; -use lemmy_utils::{apub::generate_actor_keypair, settings::Settings, LemmyError}; +use lemmy_utils::{apub::generate_actor_keypair, settings::structs::Settings, LemmyError}; use log::info; pub fn run_advanced_migrations(conn: &PgConnection) -> Result<(), LemmyError> { @@ -72,7 +72,7 @@ fn user_updates_2020_04_02(conn: &PgConnection) -> Result<(), LemmyError> { lang: cuser.lang.to_owned(), show_avatars: cuser.show_avatars, send_notifications_to_email: cuser.send_notifications_to_email, - actor_id: Some(generate_apub_endpoint(EndpointType::User, &cuser.name)?), + actor_id: Some(generate_apub_endpoint(EndpointType::Person, &cuser.name)?), bio: Some(cuser.bio.to_owned()), local: cuser.local, private_key: Some(keypair.private_key), diff --git a/src/main.rs b/src/main.rs index 4ebedb4f8..fa110b51e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,14 +8,14 @@ use diesel::{ PgConnection, }; use lemmy_api::match_websocket_operation; +use lemmy_api_structs::blocking; use lemmy_apub::activity_queue::create_activity_queue; use lemmy_db_queries::get_database_url_from_env; use lemmy_routes::{feeds, images, nodeinfo, webfinger}; use lemmy_server::{code_migrations::run_advanced_migrations, scheduled_tasks}; -use lemmy_structs::blocking; use lemmy_utils::{ rate_limit::{rate_limiter::RateLimiter, RateLimit}, - settings::Settings, + settings::structs::Settings, LemmyError, }; use lemmy_websocket::{chat_server::ChatServer, LemmyContext}; @@ -37,7 +37,7 @@ async fn main() -> Result<(), LemmyError> { }; let manager = ConnectionManager::::new(&db_url); let pool = Pool::builder() - .max_size(settings.database.pool_size) + .max_size(settings.database().pool_size) .build(manager) .unwrap_or_else(|_| panic!("Error connecting to {}", db_url)); @@ -61,7 +61,8 @@ async fn main() -> Result<(), LemmyError> { println!( "Starting http server at {}:{}", - settings.bind, settings.port + settings.bind(), + settings.port() ); let activity_queue = create_activity_queue(); @@ -94,7 +95,7 @@ async fn main() -> Result<(), LemmyError> { .configure(nodeinfo::config) .configure(webfinger::config) }) - .bind((settings.bind, settings.port))? + .bind((settings.bind(), settings.port()))? .run() .await?; diff --git a/src/scheduled_tasks.rs b/src/scheduled_tasks.rs index 53dfd6bf3..4751e9ea2 100644 --- a/src/scheduled_tasks.rs +++ b/src/scheduled_tasks.rs @@ -48,14 +48,14 @@ fn reindex_aggregates_tables(conn: &PgConnection) { fn reindex_table(conn: &PgConnection, table_name: &str) { info!("Reindexing table {} ...", table_name); let query = format!("reindex table concurrently {}", table_name); - sql_query(query).execute(conn).unwrap(); + sql_query(query).execute(conn).expect("reindex table"); info!("Done."); } /// Clear old activities (this table gets very large) fn clear_old_activities(conn: &PgConnection) { info!("Clearing old activities..."); - Activity::delete_olds(&conn).unwrap(); + Activity::delete_olds(&conn).expect("clear old activities"); info!("Done."); } @@ -75,10 +75,14 @@ fn active_counts(conn: &PgConnection) { "update site_aggregates set users_active_{} = (select * from site_aggregates_activity('{}'))", i.1, i.0 ); - sql_query(update_site_stmt).execute(conn).unwrap(); + sql_query(update_site_stmt) + .execute(conn) + .expect("update site stats"); let update_community_stmt = format!("update community_aggregates ca set users_active_{} = mv.count_ from community_aggregates_activity('{}') mv where ca.community_id = mv.community_id_", i.1, i.0); - sql_query(update_community_stmt).execute(conn).unwrap(); + sql_query(update_community_stmt) + .execute(conn) + .expect("update community stats"); } info!("Done.");