mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-11-29 07:41:20 +00:00
Addressing PR comments.
This commit is contained in:
commit
3eae5b9d9b
52 changed files with 652 additions and 206 deletions
4
.github/CODEOWNERS
vendored
4
.github/CODEOWNERS
vendored
|
@ -1,3 +1,3 @@
|
||||||
* @Nutomic @dessalines @phiresky
|
* @Nutomic @dessalines @phiresky @dullbananas
|
||||||
crates/apub/ @Nutomic
|
crates/apub/ @Nutomic
|
||||||
migrations/ @dessalines @phiresky
|
migrations/ @dessalines @phiresky @dullbananas
|
||||||
|
|
2
.github/ISSUE_TEMPLATE/BUG_REPORT.yml
vendored
2
.github/ISSUE_TEMPLATE/BUG_REPORT.yml
vendored
|
@ -20,6 +20,8 @@ body:
|
||||||
required: true
|
required: true
|
||||||
- label: Is this only a single bug? Do not put multiple bugs in one issue.
|
- label: Is this only a single bug? Do not put multiple bugs in one issue.
|
||||||
required: true
|
required: true
|
||||||
|
- label: Do you agree to follow the rules in our [Code of Conduct](https://join-lemmy.org/docs/code_of_conduct.html)?
|
||||||
|
required: true
|
||||||
- label: Is this a backend issue? Use the [lemmy-ui](https://github.com/LemmyNet/lemmy-ui) repo for UI / frontend issues.
|
- label: Is this a backend issue? Use the [lemmy-ui](https://github.com/LemmyNet/lemmy-ui) repo for UI / frontend issues.
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
|
|
2
.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml
vendored
2
.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml
vendored
|
@ -20,6 +20,8 @@ body:
|
||||||
required: true
|
required: true
|
||||||
- label: Is this a backend issue? Use the [lemmy-ui](https://github.com/LemmyNet/lemmy-ui) repo for UI / frontend issues.
|
- label: Is this a backend issue? Use the [lemmy-ui](https://github.com/LemmyNet/lemmy-ui) repo for UI / frontend issues.
|
||||||
required: true
|
required: true
|
||||||
|
- label: Do you agree to follow the rules in our [Code of Conduct](https://join-lemmy.org/docs/code_of_conduct.html)?
|
||||||
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: problem
|
id: problem
|
||||||
attributes:
|
attributes:
|
||||||
|
|
100
Cargo.lock
generated
100
Cargo.lock
generated
|
@ -16,9 +16,9 @@ checksum = "8f27d075294830fcab6f66e320dab524bc6d048f4a151698e153205559113772"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "activitypub_federation"
|
name = "activitypub_federation"
|
||||||
version = "0.5.1-beta.1"
|
version = "0.5.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "866db431760d14a7360f12e75ad48f3265b5b89cd2303e548a02bcc8983e4fcd"
|
checksum = "a028034c642d3ed16b535f98f48b3df30397833c183d68852d79de16650d5ed5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"activitystreams-kinds",
|
"activitystreams-kinds",
|
||||||
"actix-web",
|
"actix-web",
|
||||||
|
@ -35,7 +35,7 @@ dependencies = [
|
||||||
"http-signature-normalization",
|
"http-signature-normalization",
|
||||||
"http-signature-normalization-reqwest",
|
"http-signature-normalization-reqwest",
|
||||||
"httpdate",
|
"httpdate",
|
||||||
"itertools 0.12.0",
|
"itertools 0.12.1",
|
||||||
"moka",
|
"moka",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"openssl",
|
"openssl",
|
||||||
|
@ -112,9 +112,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "actix-http"
|
name = "actix-http"
|
||||||
version = "3.5.1"
|
version = "3.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "129d4c88e98860e1758c5de288d1632b07970a16d59bdf7b8d66053d582bb71f"
|
checksum = "d223b13fd481fc0d1f83bb12659ae774d9e3601814c68a0bc539731698cca743"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-codec",
|
"actix-codec",
|
||||||
"actix-rt",
|
"actix-rt",
|
||||||
|
@ -236,9 +236,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "actix-tls"
|
name = "actix-tls"
|
||||||
version = "3.2.0"
|
version = "3.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "929e47cc23865cdb856e59673cfba2d28f00b3bbd060dfc80e33a00a3cea8317"
|
checksum = "d4cce60a2f2b477bc72e5cde0af1812a6e82d8fd85b5570a5dcf2a5bf2c5be5f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-rt",
|
"actix-rt",
|
||||||
"actix-service",
|
"actix-service",
|
||||||
|
@ -265,9 +265,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "actix-web"
|
name = "actix-web"
|
||||||
version = "4.4.1"
|
version = "4.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e43428f3bf11dee6d166b00ec2df4e3aa8cc1606aaa0b7433c146852e2f4e03b"
|
checksum = "43a6556ddebb638c2358714d853257ed226ece6023ef9364f23f0c70737ea984"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-codec",
|
"actix-codec",
|
||||||
"actix-http",
|
"actix-http",
|
||||||
|
@ -851,9 +851,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chrono"
|
name = "chrono"
|
||||||
version = "0.4.32"
|
version = "0.4.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "41daef31d7a747c5c847246f36de49ced6f7403b4cdabc807a97b5cc184cda7a"
|
checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"android-tzdata",
|
"android-tzdata",
|
||||||
"iana-time-zone",
|
"iana-time-zone",
|
||||||
|
@ -1564,9 +1564,9 @@ checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dyn-clone"
|
name = "dyn-clone"
|
||||||
version = "1.0.16"
|
version = "1.0.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d"
|
checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
|
@ -2026,7 +2026,7 @@ dependencies = [
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http",
|
"http",
|
||||||
"indexmap 2.1.0",
|
"indexmap 2.2.5",
|
||||||
"slab",
|
"slab",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
|
@ -2401,9 +2401,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.1.0"
|
version = "2.2.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
|
checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown 0.14.3",
|
"hashbrown 0.14.3",
|
||||||
|
@ -2465,9 +2465,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.12.0"
|
version = "0.12.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
|
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"either",
|
"either",
|
||||||
]
|
]
|
||||||
|
@ -2577,8 +2577,6 @@ version = "0.19.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"activitypub_federation",
|
"activitypub_federation",
|
||||||
"actix-web",
|
"actix-web",
|
||||||
"anyhow",
|
|
||||||
"async-trait",
|
|
||||||
"chrono",
|
"chrono",
|
||||||
"encoding",
|
"encoding",
|
||||||
"enum-map",
|
"enum-map",
|
||||||
|
@ -2600,7 +2598,6 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_with",
|
"serde_with",
|
||||||
"serial_test",
|
"serial_test",
|
||||||
"task-local-extensions",
|
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
"ts-rs",
|
"ts-rs",
|
||||||
|
@ -2649,7 +2646,7 @@ dependencies = [
|
||||||
"html2md",
|
"html2md",
|
||||||
"html2text",
|
"html2text",
|
||||||
"http",
|
"http",
|
||||||
"itertools 0.12.0",
|
"itertools 0.12.1",
|
||||||
"lemmy_api_common",
|
"lemmy_api_common",
|
||||||
"lemmy_db_schema",
|
"lemmy_db_schema",
|
||||||
"lemmy_db_views",
|
"lemmy_db_views",
|
||||||
|
@ -2884,7 +2881,7 @@ dependencies = [
|
||||||
"futures",
|
"futures",
|
||||||
"html2text",
|
"html2text",
|
||||||
"http",
|
"http",
|
||||||
"itertools 0.12.0",
|
"itertools 0.12.1",
|
||||||
"lettre",
|
"lettre",
|
||||||
"markdown-it",
|
"markdown-it",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
@ -3236,9 +3233,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "moka"
|
name = "moka"
|
||||||
version = "0.12.4"
|
version = "0.12.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ad9dc9808102655926a6086abd0b9965ebefd4a39ef0d184f074c34ba5049ec6"
|
checksum = "b1911e88d5831f748a4097a43862d129e3c6fca831eecac9b8db6d01d93c9de2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-lock",
|
"async-lock",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
@ -3380,9 +3377,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl"
|
name = "openssl"
|
||||||
version = "0.10.63"
|
version = "0.10.64"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "15c9d69dd87a29568d4d017cfe8ec518706046a05184e5aea92d0af890b803c8"
|
checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.4.2",
|
"bitflags 2.4.2",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
@ -3412,9 +3409,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-sys"
|
name = "openssl-sys"
|
||||||
version = "0.9.99"
|
version = "0.9.101"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "22e1bf214306098e4832460f797824c05d25aacdf896f64a985fb0fd992454ae"
|
checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"libc",
|
"libc",
|
||||||
|
@ -3457,7 +3454,7 @@ checksum = "1e32339a5dc40459130b3bd269e9892439f55b33e772d2a9d402a789baaf4e8a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"indexmap 2.1.0",
|
"indexmap 2.2.5",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
|
@ -3854,7 +3851,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e5699cc8a63d1aa2b1ee8e12b9ad70ac790d65788cd36101fa37f87ea46c4cef"
|
checksum = "e5699cc8a63d1aa2b1ee8e12b9ad70ac790d65788cd36101fa37f87ea46c4cef"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.21.7",
|
"base64 0.21.7",
|
||||||
"indexmap 2.1.0",
|
"indexmap 2.2.5",
|
||||||
"line-wrap",
|
"line-wrap",
|
||||||
"quick-xml 0.31.0",
|
"quick-xml 0.31.0",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -4308,9 +4305,9 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest"
|
name = "reqwest"
|
||||||
version = "0.11.23"
|
version = "0.11.24"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41"
|
checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-compression",
|
"async-compression",
|
||||||
"base64 0.21.7",
|
"base64 0.21.7",
|
||||||
|
@ -4338,6 +4335,7 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_urlencoded",
|
"serde_urlencoded",
|
||||||
|
"sync_wrapper",
|
||||||
"system-configuration",
|
"system-configuration",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-native-tls",
|
"tokio-native-tls",
|
||||||
|
@ -4690,9 +4688,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.195"
|
version = "1.0.197"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02"
|
checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
@ -4708,9 +4706,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.195"
|
version = "1.0.197"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c"
|
checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -4719,11 +4717,11 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.111"
|
version = "1.0.114"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4"
|
checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.1.0",
|
"indexmap 2.2.5",
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -4769,7 +4767,7 @@ dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"hex",
|
"hex",
|
||||||
"indexmap 1.9.3",
|
"indexmap 1.9.3",
|
||||||
"indexmap 2.1.0",
|
"indexmap 2.2.5",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_with_macros",
|
"serde_with_macros",
|
||||||
|
@ -5204,18 +5202,18 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.56"
|
version = "1.0.57"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad"
|
checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "1.0.56"
|
version = "1.0.57"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471"
|
checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -5284,9 +5282,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.35.1"
|
version = "1.36.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104"
|
checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
@ -5467,7 +5465,7 @@ version = "0.19.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
|
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.1.0",
|
"indexmap 2.2.5",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_spanned",
|
"serde_spanned",
|
||||||
"toml_datetime",
|
"toml_datetime",
|
||||||
|
@ -5480,7 +5478,7 @@ version = "0.21.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03"
|
checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.1.0",
|
"indexmap 2.2.5",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_spanned",
|
"serde_spanned",
|
||||||
"toml_datetime",
|
"toml_datetime",
|
||||||
|
@ -6068,9 +6066,9 @@ checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-streams"
|
name = "wasm-streams"
|
||||||
version = "0.3.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b4609d447824375f43e1ffbc051b50ad8f4b3ae8219680c94452ea05eb240ac7"
|
checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
|
|
|
@ -96,7 +96,7 @@ lemmy_routes = { version = "=0.19.3", path = "./crates/routes" }
|
||||||
lemmy_db_views = { version = "=0.19.3", path = "./crates/db_views" }
|
lemmy_db_views = { version = "=0.19.3", path = "./crates/db_views" }
|
||||||
lemmy_db_views_actor = { version = "=0.19.3", path = "./crates/db_views_actor" }
|
lemmy_db_views_actor = { version = "=0.19.3", path = "./crates/db_views_actor" }
|
||||||
lemmy_db_views_moderator = { version = "=0.19.3", path = "./crates/db_views_moderator" }
|
lemmy_db_views_moderator = { version = "=0.19.3", path = "./crates/db_views_moderator" }
|
||||||
activitypub_federation = { version = "0.5.1-beta.1", default-features = false, features = [
|
activitypub_federation = { version = "0.5.2", default-features = false, features = [
|
||||||
"actix-web",
|
"actix-web",
|
||||||
] }
|
] }
|
||||||
diesel = "2.1.4"
|
diesel = "2.1.4"
|
||||||
|
|
|
@ -68,6 +68,10 @@ test("Upload image and delete it", async () => {
|
||||||
// ensure that image is deleted
|
// ensure that image is deleted
|
||||||
const content2 = downloadFileSync(upload.url);
|
const content2 = downloadFileSync(upload.url);
|
||||||
expect(content2).toBe("");
|
expect(content2).toBe("");
|
||||||
|
|
||||||
|
// Ensure that it shows the image is deleted
|
||||||
|
const deletedListMediaRes = await alphaImage.listMedia({});
|
||||||
|
expect(deletedListMediaRes.images.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Purge user, uploaded image removed", async () => {
|
test("Purge user, uploaded image removed", async () => {
|
||||||
|
|
86
cliff.toml
Normal file
86
cliff.toml
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
# git-cliff ~ configuration file
|
||||||
|
# https://git-cliff.org/docs/configuration
|
||||||
|
|
||||||
|
[remote.github]
|
||||||
|
owner = "LemmyNet"
|
||||||
|
repo = "lemmy"
|
||||||
|
# token = ""
|
||||||
|
|
||||||
|
[changelog]
|
||||||
|
# template for the changelog body
|
||||||
|
# https://keats.github.io/tera/docs/#introduction
|
||||||
|
body = """
|
||||||
|
## What's Changed
|
||||||
|
|
||||||
|
{%- if version %} in {{ version }}{%- endif -%}
|
||||||
|
{% for commit in commits %}
|
||||||
|
{% if commit.github.pr_title -%}
|
||||||
|
{%- set commit_message = commit.github.pr_title -%}
|
||||||
|
{%- else -%}
|
||||||
|
{%- set commit_message = commit.message -%}
|
||||||
|
{%- endif -%}
|
||||||
|
* {{ commit_message | split(pat="\n") | first | trim }}\
|
||||||
|
{% if commit.github.username %} by @{{ commit.github.username }}{%- endif -%}
|
||||||
|
{% if commit.github.pr_number %} in \
|
||||||
|
[#{{ commit.github.pr_number }}]({{ self::remote_url() }}/pull/{{ commit.github.pr_number }}) \
|
||||||
|
{%- endif %}
|
||||||
|
{%- endfor -%}
|
||||||
|
|
||||||
|
{% if github.contributors | filter(attribute="is_first_time", value=true) | length != 0 %}
|
||||||
|
{% raw %}\n{% endraw -%}
|
||||||
|
## New Contributors
|
||||||
|
{%- endif %}\
|
||||||
|
{% for contributor in github.contributors | filter(attribute="is_first_time", value=true) %}
|
||||||
|
* @{{ contributor.username }} made their first contribution
|
||||||
|
{%- if contributor.pr_number %} in \
|
||||||
|
[#{{ contributor.pr_number }}]({{ self::remote_url() }}/pull/{{ contributor.pr_number }}) \
|
||||||
|
{%- endif %}
|
||||||
|
{%- endfor -%}
|
||||||
|
|
||||||
|
{% if version %}
|
||||||
|
{% if previous.version %}
|
||||||
|
**Full Changelog**: {{ self::remote_url() }}/compare/{{ previous.version }}...{{ version }}
|
||||||
|
{% endif %}
|
||||||
|
{% else -%}
|
||||||
|
{% raw %}\n{% endraw %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{%- macro remote_url() -%}
|
||||||
|
https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}
|
||||||
|
{%- endmacro -%}
|
||||||
|
"""
|
||||||
|
# remove the leading and trailing whitespace from the template
|
||||||
|
trim = true
|
||||||
|
# changelog footer
|
||||||
|
footer = """
|
||||||
|
<!-- generated by git-cliff -->
|
||||||
|
"""
|
||||||
|
# postprocessors
|
||||||
|
postprocessors = []
|
||||||
|
|
||||||
|
[git]
|
||||||
|
# parse the commits based on https://www.conventionalcommits.org
|
||||||
|
conventional_commits = false
|
||||||
|
# filter out the commits that are not conventional
|
||||||
|
filter_unconventional = true
|
||||||
|
# process each line of a commit as an individual commit
|
||||||
|
split_commits = false
|
||||||
|
# regex for preprocessing the commit messages
|
||||||
|
commit_preprocessors = [
|
||||||
|
# remove issue numbers from commits
|
||||||
|
{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "" },
|
||||||
|
]
|
||||||
|
# protect breaking changes from being skipped due to matching a skipping commit_parser
|
||||||
|
protect_breaking_commits = false
|
||||||
|
# filter out the commits that are not matched by commit parsers
|
||||||
|
filter_commits = false
|
||||||
|
# regex for matching git tags
|
||||||
|
tag_pattern = "[0-9].*"
|
||||||
|
# regex for skipping tags
|
||||||
|
skip_tags = "beta|alpha"
|
||||||
|
# regex for ignoring tags
|
||||||
|
ignore_tags = "rc"
|
||||||
|
# sort the tags topologically
|
||||||
|
topo_order = false
|
||||||
|
# sort the commits inside sections by oldest/newest order
|
||||||
|
sort_commits = "newest"
|
|
@ -135,11 +135,7 @@ pub(crate) fn generate_totp_2fa_secret() -> String {
|
||||||
Secret::generate_secret().to_string()
|
Secret::generate_secret().to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn build_totp_2fa(
|
fn build_totp_2fa(hostname: &str, username: &str, secret: &str) -> Result<TOTP, LemmyError> {
|
||||||
site_name: &str,
|
|
||||||
username: &str,
|
|
||||||
secret: &str,
|
|
||||||
) -> Result<TOTP, LemmyError> {
|
|
||||||
let sec = Secret::Raw(secret.as_bytes().to_vec());
|
let sec = Secret::Raw(secret.as_bytes().to_vec());
|
||||||
let sec_bytes = sec
|
let sec_bytes = sec
|
||||||
.to_bytes()
|
.to_bytes()
|
||||||
|
@ -151,7 +147,7 @@ pub(crate) fn build_totp_2fa(
|
||||||
1,
|
1,
|
||||||
30,
|
30,
|
||||||
sec_bytes,
|
sec_bytes,
|
||||||
Some(site_name.to_string()),
|
Some(hostname.to_string()),
|
||||||
username.to_string(),
|
username.to_string(),
|
||||||
)
|
)
|
||||||
.with_lemmy_type(LemmyErrorType::CouldntGenerateTotp)
|
.with_lemmy_type(LemmyErrorType::CouldntGenerateTotp)
|
||||||
|
@ -272,7 +268,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_build_totp() {
|
fn test_build_totp() {
|
||||||
let generated_secret = generate_totp_2fa_secret();
|
let generated_secret = generate_totp_2fa_secret();
|
||||||
let totp = build_totp_2fa("lemmy", "my_name", &generated_secret);
|
let totp = build_totp_2fa("lemmy.ml", "my_name", &generated_secret);
|
||||||
assert!(totp.is_ok());
|
assert!(totp.is_ok());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,11 +17,12 @@ pub async fn list_media(
|
||||||
) -> Result<Json<ListMediaResponse>, LemmyError> {
|
) -> Result<Json<ListMediaResponse>, LemmyError> {
|
||||||
let page = data.page;
|
let page = data.page;
|
||||||
let limit = data.limit;
|
let limit = data.limit;
|
||||||
let images = LocalImage::get_all_paged_by_local_user_id(
|
let images = LocalImage::get_all_by_local_user_id(
|
||||||
&mut context.pool(),
|
&mut context.pool(),
|
||||||
local_user_view.local_user.id,
|
local_user_view.local_user.id,
|
||||||
page,
|
page,
|
||||||
limit,
|
limit,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(Json(ListMediaResponse { images }))
|
Ok(Json(ListMediaResponse { images }))
|
||||||
|
|
|
@ -50,7 +50,11 @@ pub async fn login(
|
||||||
|
|
||||||
// Check the totp if enabled
|
// Check the totp if enabled
|
||||||
if local_user_view.local_user.totp_2fa_enabled {
|
if local_user_view.local_user.totp_2fa_enabled {
|
||||||
check_totp_2fa_valid(&local_user_view, &data.totp_2fa_token, &site_view.site.name)?;
|
check_totp_2fa_valid(
|
||||||
|
&local_user_view,
|
||||||
|
&data.totp_2fa_token,
|
||||||
|
&context.settings().hostname,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let jwt = Claims::generate(local_user_view.local_user.id, req, &context).await?;
|
let jwt = Claims::generate(local_user_view.local_user.id, req, &context).await?;
|
||||||
|
|
|
@ -14,6 +14,7 @@ use lemmy_db_schema::{
|
||||||
source::{
|
source::{
|
||||||
actor_language::LocalUserLanguage,
|
actor_language::LocalUserLanguage,
|
||||||
local_user::{LocalUser, LocalUserUpdateForm},
|
local_user::{LocalUser, LocalUserUpdateForm},
|
||||||
|
local_user_vote_display_mode::{LocalUserVoteDisplayMode, LocalUserVoteDisplayModeUpdateForm},
|
||||||
person::{Person, PersonUpdateForm},
|
person::{Person, PersonUpdateForm},
|
||||||
},
|
},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
|
@ -136,5 +137,15 @@ pub async fn save_user_settings(
|
||||||
.await
|
.await
|
||||||
.ok();
|
.ok();
|
||||||
|
|
||||||
|
// Update the vote display modes
|
||||||
|
let vote_display_modes_form = LocalUserVoteDisplayModeUpdateForm {
|
||||||
|
score: data.show_scores,
|
||||||
|
upvotes: data.show_upvotes,
|
||||||
|
downvotes: data.show_downvotes,
|
||||||
|
upvote_percentage: data.show_upvote_percentage,
|
||||||
|
};
|
||||||
|
LocalUserVoteDisplayMode::update(&mut context.pool(), local_user_id, &vote_display_modes_form)
|
||||||
|
.await?;
|
||||||
|
|
||||||
Ok(Json(SuccessResponse::default()))
|
Ok(Json(SuccessResponse::default()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use lemmy_db_schema::{
|
||||||
source::local_user::{LocalUser, LocalUserUpdateForm},
|
source::local_user::{LocalUser, LocalUserUpdateForm},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
};
|
};
|
||||||
use lemmy_db_views::structs::{LocalUserView, SiteView};
|
use lemmy_db_views::structs::LocalUserView;
|
||||||
use lemmy_utils::error::LemmyError;
|
use lemmy_utils::error::LemmyError;
|
||||||
|
|
||||||
/// Enable or disable two-factor-authentication. The current setting is determined from
|
/// Enable or disable two-factor-authentication. The current setting is determined from
|
||||||
|
@ -25,12 +25,10 @@ pub async fn update_totp(
|
||||||
local_user_view: LocalUserView,
|
local_user_view: LocalUserView,
|
||||||
context: Data<LemmyContext>,
|
context: Data<LemmyContext>,
|
||||||
) -> Result<Json<UpdateTotpResponse>, LemmyError> {
|
) -> Result<Json<UpdateTotpResponse>, LemmyError> {
|
||||||
let site_view = SiteView::read_local(&mut context.pool()).await?;
|
|
||||||
|
|
||||||
check_totp_2fa_valid(
|
check_totp_2fa_valid(
|
||||||
&local_user_view,
|
&local_user_view,
|
||||||
&Some(data.totp_token.clone()),
|
&Some(data.totp_token.clone()),
|
||||||
&site_view.site.name,
|
&context.settings().hostname,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// toggle the 2fa setting
|
// toggle the 2fa setting
|
||||||
|
|
|
@ -31,8 +31,14 @@ pub async fn purge_person(
|
||||||
|
|
||||||
// Read the local user to get their images, and delete them
|
// Read the local user to get their images, and delete them
|
||||||
if let Ok(local_user) = LocalUserView::read_person(&mut context.pool(), data.person_id).await {
|
if let Ok(local_user) = LocalUserView::read_person(&mut context.pool(), data.person_id).await {
|
||||||
let pictrs_uploads =
|
let pictrs_uploads = LocalImage::get_all_by_local_user_id(
|
||||||
LocalImage::get_all_by_local_user_id(&mut context.pool(), local_user.local_user.id).await?;
|
&mut context.pool(),
|
||||||
|
local_user.local_user.id,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
for upload in pictrs_uploads {
|
for upload in pictrs_uploads {
|
||||||
delete_image_from_pictrs(&upload.pictrs_alias, &upload.pictrs_delete_token, &context)
|
delete_image_from_pictrs(&upload.pictrs_alias, &upload.pictrs_delete_token, &context)
|
||||||
|
|
|
@ -54,7 +54,6 @@ tracing = { workspace = true, optional = true }
|
||||||
reqwest-middleware = { workspace = true, optional = true }
|
reqwest-middleware = { workspace = true, optional = true }
|
||||||
regex = { workspace = true }
|
regex = { workspace = true }
|
||||||
rosetta-i18n = { workspace = true, optional = true }
|
rosetta-i18n = { workspace = true, optional = true }
|
||||||
anyhow = { workspace = true }
|
|
||||||
futures = { workspace = true, optional = true }
|
futures = { workspace = true, optional = true }
|
||||||
uuid = { workspace = true, optional = true }
|
uuid = { workspace = true, optional = true }
|
||||||
tokio = { workspace = true, optional = true }
|
tokio = { workspace = true, optional = true }
|
||||||
|
@ -64,7 +63,6 @@ once_cell = { workspace = true, optional = true }
|
||||||
actix-web = { workspace = true, optional = true }
|
actix-web = { workspace = true, optional = true }
|
||||||
enum-map = { workspace = true }
|
enum-map = { workspace = true }
|
||||||
urlencoding = { workspace = true }
|
urlencoding = { workspace = true }
|
||||||
async-trait = { workspace = true }
|
|
||||||
mime = { version = "0.3.17", optional = true }
|
mime = { version = "0.3.17", optional = true }
|
||||||
webpage = { version = "1.6", default-features = false, features = [
|
webpage = { version = "1.6", default-features = false, features = [
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -73,7 +71,6 @@ encoding = { version = "0.2.33", optional = true }
|
||||||
jsonwebtoken = { version = "8.3.0", optional = true }
|
jsonwebtoken = { version = "8.3.0", optional = true }
|
||||||
# necessary for wasmt compilation
|
# necessary for wasmt compilation
|
||||||
getrandom = { version = "0.2.12", features = ["js"] }
|
getrandom = { version = "0.2.12", features = ["js"] }
|
||||||
task-local-extensions = "0.1.4"
|
|
||||||
|
|
||||||
[package.metadata.cargo-machete]
|
[package.metadata.cargo-machete]
|
||||||
ignored = ["getrandom"]
|
ignored = ["getrandom"]
|
||||||
|
|
|
@ -87,7 +87,7 @@ pub async fn build_post_response(
|
||||||
Ok(Json(PostResponse { post_view }))
|
Ok(Json(PostResponse { post_view }))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this function is a mess and should be split up to handle email seperately
|
// TODO: this function is a mess and should be split up to handle email separately
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub async fn send_local_notifs(
|
pub async fn send_local_notifs(
|
||||||
mentions: Vec<MentionData>,
|
mentions: Vec<MentionData>,
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::request::client_builder;
|
use crate::request::client_builder;
|
||||||
use activitypub_federation::config::{Data, FederationConfig};
|
use activitypub_federation::config::{Data, FederationConfig};
|
||||||
use anyhow::anyhow;
|
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
source::secret::Secret,
|
source::secret::Secret,
|
||||||
utils::{build_db_pool_for_tests, ActualDbPool, DbPool},
|
utils::{build_db_pool_for_tests, ActualDbPool, DbPool},
|
||||||
|
@ -9,10 +8,8 @@ use lemmy_utils::{
|
||||||
rate_limit::RateLimitCell,
|
rate_limit::RateLimitCell,
|
||||||
settings::{structs::Settings, SETTINGS},
|
settings::{structs::Settings, SETTINGS},
|
||||||
};
|
};
|
||||||
use reqwest::{Request, Response};
|
use reqwest_middleware::{ClientBuilder, ClientWithMiddleware};
|
||||||
use reqwest_middleware::{ClientBuilder, ClientWithMiddleware, Middleware, Next};
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use task_local_extensions::Extensions;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct LemmyContext {
|
pub struct LemmyContext {
|
||||||
|
@ -55,32 +52,16 @@ impl LemmyContext {
|
||||||
&self.rate_limit_cell
|
&self.rate_limit_cell
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize a context for use in tests, optionally blocks network requests.
|
/// Initialize a context for use in tests which blocks federation network calls.
|
||||||
///
|
///
|
||||||
/// Do not use this in production code.
|
/// Do not use this in production code.
|
||||||
pub async fn init_test_context() -> Data<LemmyContext> {
|
pub async fn init_test_context() -> Data<LemmyContext> {
|
||||||
Self::build_test_context(true).await
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initialize a context for use in tests, with network requests allowed.
|
|
||||||
/// TODO: get rid of this if possible.
|
|
||||||
///
|
|
||||||
/// Do not use this in production code.
|
|
||||||
pub async fn init_test_context_with_networking() -> Data<LemmyContext> {
|
|
||||||
Self::build_test_context(false).await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn build_test_context(block_networking: bool) -> Data<LemmyContext> {
|
|
||||||
// call this to run migrations
|
// call this to run migrations
|
||||||
let pool = build_db_pool_for_tests().await;
|
let pool = build_db_pool_for_tests().await;
|
||||||
|
|
||||||
let client = client_builder(&SETTINGS).build().expect("build client");
|
let client = client_builder(&SETTINGS).build().expect("build client");
|
||||||
|
|
||||||
let mut client = ClientBuilder::new(client);
|
let client = ClientBuilder::new(client).build();
|
||||||
if block_networking {
|
|
||||||
client = client.with(BlockedMiddleware);
|
|
||||||
}
|
|
||||||
let client = client.build();
|
|
||||||
let secret = Secret {
|
let secret = Secret {
|
||||||
id: 0,
|
id: 0,
|
||||||
jwt_secret: String::new(),
|
jwt_secret: String::new(),
|
||||||
|
@ -92,24 +73,11 @@ impl LemmyContext {
|
||||||
let config = FederationConfig::builder()
|
let config = FederationConfig::builder()
|
||||||
.domain(context.settings().hostname.clone())
|
.domain(context.settings().hostname.clone())
|
||||||
.app_data(context)
|
.app_data(context)
|
||||||
|
// Dont allow any network fetches
|
||||||
|
.http_fetch_limit(0)
|
||||||
.build()
|
.build()
|
||||||
.await
|
.await
|
||||||
.expect("build federation config");
|
.expect("build federation config");
|
||||||
config.to_request_data()
|
config.to_request_data()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BlockedMiddleware;
|
|
||||||
|
|
||||||
/// A reqwest middleware which blocks all requests
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl Middleware for BlockedMiddleware {
|
|
||||||
async fn handle(
|
|
||||||
&self,
|
|
||||||
_req: Request,
|
|
||||||
_extensions: &mut Extensions,
|
|
||||||
_next: Next<'_>,
|
|
||||||
) -> reqwest_middleware::Result<Response> {
|
|
||||||
Err(anyhow!("Network requests not allowed").into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -86,8 +86,6 @@ pub struct SaveUserSettings {
|
||||||
pub show_nsfw: Option<bool>,
|
pub show_nsfw: Option<bool>,
|
||||||
pub blur_nsfw: Option<bool>,
|
pub blur_nsfw: Option<bool>,
|
||||||
pub auto_expand: Option<bool>,
|
pub auto_expand: Option<bool>,
|
||||||
/// Show post and comment scores.
|
|
||||||
pub show_scores: Option<bool>,
|
|
||||||
/// Your user's theme.
|
/// Your user's theme.
|
||||||
pub theme: Option<String>,
|
pub theme: Option<String>,
|
||||||
pub default_sort_type: Option<SortType>,
|
pub default_sort_type: Option<SortType>,
|
||||||
|
@ -122,6 +120,7 @@ pub struct SaveUserSettings {
|
||||||
pub open_links_in_new_tab: Option<bool>,
|
pub open_links_in_new_tab: Option<bool>,
|
||||||
/// Enable infinite scroll
|
/// Enable infinite scroll
|
||||||
pub infinite_scroll_enabled: Option<bool>,
|
pub infinite_scroll_enabled: Option<bool>,
|
||||||
|
/// A post-view mode that changes how multiple post listings look.
|
||||||
pub post_listing_mode: Option<PostListingMode>,
|
pub post_listing_mode: Option<PostListingMode>,
|
||||||
/// Whether to allow keyboard navigation (for browsing and interacting with posts and comments).
|
/// Whether to allow keyboard navigation (for browsing and interacting with posts and comments).
|
||||||
pub enable_keyboard_navigation: Option<bool>,
|
pub enable_keyboard_navigation: Option<bool>,
|
||||||
|
@ -129,6 +128,11 @@ pub struct SaveUserSettings {
|
||||||
pub enable_animated_images: Option<bool>,
|
pub enable_animated_images: Option<bool>,
|
||||||
/// Whether to auto-collapse bot comments.
|
/// Whether to auto-collapse bot comments.
|
||||||
pub collapse_bot_comments: Option<bool>,
|
pub collapse_bot_comments: Option<bool>,
|
||||||
|
/// Some vote display mode settings
|
||||||
|
pub show_scores: Option<bool>,
|
||||||
|
pub show_upvotes: Option<bool>,
|
||||||
|
pub show_downvotes: Option<bool>,
|
||||||
|
pub show_upvote_percentage: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
|
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]
|
||||||
|
|
|
@ -4,7 +4,10 @@ use crate::{
|
||||||
utils::proxy_image_link,
|
utils::proxy_image_link,
|
||||||
};
|
};
|
||||||
use encoding::{all::encodings, DecoderTrap};
|
use encoding::{all::encodings, DecoderTrap};
|
||||||
use lemmy_db_schema::newtypes::DbUrl;
|
use lemmy_db_schema::{
|
||||||
|
newtypes::DbUrl,
|
||||||
|
source::images::{LocalImage, LocalImageForm},
|
||||||
|
};
|
||||||
use lemmy_utils::{
|
use lemmy_utils::{
|
||||||
error::{LemmyError, LemmyErrorType},
|
error::{LemmyError, LemmyErrorType},
|
||||||
settings::structs::{PictrsImageMode, Settings},
|
settings::structs::{PictrsImageMode, Settings},
|
||||||
|
@ -184,7 +187,6 @@ struct PictrsResponse {
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
struct PictrsFile {
|
struct PictrsFile {
|
||||||
file: String,
|
file: String,
|
||||||
#[allow(dead_code)]
|
|
||||||
delete_token: String,
|
delete_token: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,6 +289,14 @@ async fn generate_pictrs_thumbnail(
|
||||||
context.settings().get_protocol_and_hostname(),
|
context.settings().get_protocol_and_hostname(),
|
||||||
response.files.first().expect("missing pictrs file").file
|
response.files.first().expect("missing pictrs file").file
|
||||||
))?;
|
))?;
|
||||||
|
for uploaded_image in response.files {
|
||||||
|
let form = LocalImageForm {
|
||||||
|
local_user_id: None,
|
||||||
|
pictrs_alias: uploaded_image.file.to_string(),
|
||||||
|
pictrs_delete_token: uploaded_image.delete_token.to_string(),
|
||||||
|
};
|
||||||
|
LocalImage::create(&mut context.pool(), &form).await?;
|
||||||
|
}
|
||||||
Ok(thumbnail_url)
|
Ok(thumbnail_url)
|
||||||
} else {
|
} else {
|
||||||
Err(LemmyErrorType::PictrsResponseError(response.msg))?
|
Err(LemmyErrorType::PictrsResponseError(response.msg))?
|
||||||
|
@ -327,7 +337,7 @@ mod tests {
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[serial]
|
#[serial]
|
||||||
async fn test_link_metadata() {
|
async fn test_link_metadata() {
|
||||||
let context = LemmyContext::init_test_context_with_networking().await;
|
let context = LemmyContext::init_test_context().await;
|
||||||
let sample_url = Url::parse("https://gitlab.com/IzzyOnDroid/repo/-/wikis/FAQ").unwrap();
|
let sample_url = Url::parse("https://gitlab.com/IzzyOnDroid/repo/-/wikis/FAQ").unwrap();
|
||||||
let sample_res = fetch_link_metadata(&sample_url, false, &context)
|
let sample_res = fetch_link_metadata(&sample_url, false, &context)
|
||||||
.await
|
.await
|
||||||
|
|
|
@ -21,6 +21,7 @@ use lemmy_db_schema::{
|
||||||
source::{
|
source::{
|
||||||
captcha_answer::{CaptchaAnswer, CheckCaptchaAnswer},
|
captcha_answer::{CaptchaAnswer, CheckCaptchaAnswer},
|
||||||
local_user::{LocalUser, LocalUserInsertForm},
|
local_user::{LocalUser, LocalUserInsertForm},
|
||||||
|
local_user_vote_display_mode::LocalUserVoteDisplayMode,
|
||||||
person::{Person, PersonInsertForm},
|
person::{Person, PersonInsertForm},
|
||||||
registration_application::{RegistrationApplication, RegistrationApplicationInsertForm},
|
registration_application::{RegistrationApplication, RegistrationApplicationInsertForm},
|
||||||
},
|
},
|
||||||
|
@ -183,6 +184,7 @@ pub async fn register(
|
||||||
if local_site.require_email_verification {
|
if local_site.require_email_verification {
|
||||||
let local_user_view = LocalUserView {
|
let local_user_view = LocalUserView {
|
||||||
local_user: inserted_local_user,
|
local_user: inserted_local_user,
|
||||||
|
local_user_vote_display_mode: LocalUserVoteDisplayMode::default(),
|
||||||
person: inserted_person,
|
person: inserted_person,
|
||||||
counts: PersonAggregates::default(),
|
counts: PersonAggregates::default(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
"type": "Application",
|
"type": "Application",
|
||||||
"id": "https://enterprise.lemmy.ml/",
|
"id": "https://enterprise.lemmy.ml/",
|
||||||
"name": "Enterprise",
|
"name": "Enterprise",
|
||||||
|
"preferredUsername": "enterprise.lemmy.ml",
|
||||||
"summary": "A test instance",
|
"summary": "A test instance",
|
||||||
"content": "<p>Enterprise sidebar</p>\\n",
|
"content": "<p>Enterprise sidebar</p>\\n",
|
||||||
"mediaType": "text/html",
|
"mediaType": "text/html",
|
||||||
|
|
|
@ -11,21 +11,21 @@
|
||||||
"votersCount": "toot:votersCount"
|
"votersCount": "toot:votersCount"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"id": "https://dice.camp/users/thekernelinyellow/statuses/110830743680706519",
|
"id": "https://masto.qa.urbanwildlife.biz/users/mastodon/statuses/110830743680706519",
|
||||||
"type": "Note",
|
"type": "Note",
|
||||||
"summary": null,
|
"summary": null,
|
||||||
"inReplyTo": null,
|
"inReplyTo": null,
|
||||||
"published": "2023-08-04T09:55:39Z",
|
"published": "2023-08-04T09:55:39Z",
|
||||||
"url": "https://dice.camp/@thekernelinyellow/110830743680706519",
|
"url": "https://masto.qa.urbanwildlife.biz/110830743680706519",
|
||||||
"attributedTo": "https://dice.camp/users/thekernelinyellow",
|
"attributedTo": "https://masto.qa.urbanwildlife.biz/users/mastodon",
|
||||||
"to": ["https://www.w3.org/ns/activitystreams#Public"],
|
"to": ["https://www.w3.org/ns/activitystreams#Public"],
|
||||||
"cc": [
|
"cc": [
|
||||||
"https://dice.camp/users/thekernelinyellow/followers",
|
"https://masto.qa.urbanwildlife.biz/users/mastodon/followers",
|
||||||
"https://enterprise.lemmy.ml/c/tenforward",
|
"https://enterprise.lemmy.ml/c/tenforward",
|
||||||
"https://enterprise.lemmy.ml/c/tenforward/followers"
|
"https://enterprise.lemmy.ml/c/tenforward/followers"
|
||||||
],
|
],
|
||||||
"sensitive": false,
|
"sensitive": false,
|
||||||
"atomUri": "https://dice.camp/users/thekernelinyellow/statuses/110830743680706519",
|
"atomUri": "https://masto.qa.urbanwildlife.biz/statuses/110830743680706519",
|
||||||
"inReplyToAtomUri": null,
|
"inReplyToAtomUri": null,
|
||||||
"conversation": "tag:dice.camp,2023-08-04:objectId=29969291:objectType=Conversation",
|
"conversation": "tag:dice.camp,2023-08-04:objectId=29969291:objectType=Conversation",
|
||||||
"content": "<p><span class=\"h-card\" translate=\"no\"><a href=\"https://enterprise.lemmy.ml/c/tenforward\" class=\"u-url mention\">@<span>tenforward</span></a></span> Variable never resetting at refresh</p><p>Hi! I'm using a variable to count elements in my generator but every time I generate a new character, the counter's value carries on from the previous one. Is there a function to reset it (I set it to 0 at the beginning of the file)</p>",
|
"content": "<p><span class=\"h-card\" translate=\"no\"><a href=\"https://enterprise.lemmy.ml/c/tenforward\" class=\"u-url mention\">@<span>tenforward</span></a></span> Variable never resetting at refresh</p><p>Hi! I'm using a variable to count elements in my generator but every time I generate a new character, the counter's value carries on from the previous one. Is there a function to reset it (I set it to 0 at the beginning of the file)</p>",
|
||||||
|
@ -41,12 +41,12 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"replies": {
|
"replies": {
|
||||||
"id": "https://dice.camp/users/thekernelinyellow/statuses/110830743680706519/replies",
|
"id": "https://masto.qa.urbanwildlife.biz/users/mastodon/statuses/110830743680706519/replies",
|
||||||
"type": "Collection",
|
"type": "Collection",
|
||||||
"first": {
|
"first": {
|
||||||
"type": "CollectionPage",
|
"type": "CollectionPage",
|
||||||
"next": "https://dice.camp/users/thekernelinyellow/statuses/110830743680706519/replies?only_other_accounts=true&page=true",
|
"next": "https://masto.qa.urbanwildlife.biz/users/mastodon/statuses/110830743680706519/replies?only_other_accounts=true&page=true",
|
||||||
"partOf": "https://dice.camp/users/thekernelinyellow/statuses/110830743680706519/replies",
|
"partOf": "https://masto.qa.urbanwildlife.biz/users/mastodon/statuses/110830743680706519/replies",
|
||||||
"items": []
|
"items": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ use lemmy_db_schema::{
|
||||||
instance::Instance,
|
instance::Instance,
|
||||||
instance_block::{InstanceBlock, InstanceBlockForm},
|
instance_block::{InstanceBlock, InstanceBlockForm},
|
||||||
local_user::{LocalUser, LocalUserUpdateForm},
|
local_user::{LocalUser, LocalUserUpdateForm},
|
||||||
|
local_user_vote_display_mode::{LocalUserVoteDisplayMode, LocalUserVoteDisplayModeUpdateForm},
|
||||||
person::{Person, PersonUpdateForm},
|
person::{Person, PersonUpdateForm},
|
||||||
person_block::{PersonBlock, PersonBlockForm},
|
person_block::{PersonBlock, PersonBlockForm},
|
||||||
post::{PostSaved, PostSavedForm},
|
post::{PostSaved, PostSavedForm},
|
||||||
|
@ -50,6 +51,7 @@ pub struct UserSettingsBackup {
|
||||||
// TODO: might be worth making a separate struct for settings backup, to avoid breakage in case
|
// TODO: might be worth making a separate struct for settings backup, to avoid breakage in case
|
||||||
// fields are renamed, and to avoid storing unnecessary fields like person_id or email
|
// fields are renamed, and to avoid storing unnecessary fields like person_id or email
|
||||||
pub settings: Option<LocalUser>,
|
pub settings: Option<LocalUser>,
|
||||||
|
pub vote_display_mode_settings: Option<LocalUserVoteDisplayMode>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub followed_communities: Vec<ObjectId<ApubCommunity>>,
|
pub followed_communities: Vec<ObjectId<ApubCommunity>>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
@ -80,6 +82,7 @@ pub async fn export_settings(
|
||||||
matrix_id: local_user_view.person.matrix_user_id,
|
matrix_id: local_user_view.person.matrix_user_id,
|
||||||
bot_account: local_user_view.person.bot_account.into(),
|
bot_account: local_user_view.person.bot_account.into(),
|
||||||
settings: Some(local_user_view.local_user),
|
settings: Some(local_user_view.local_user),
|
||||||
|
vote_display_mode_settings: Some(local_user_view.local_user_vote_display_mode),
|
||||||
followed_communities: vec_into(lists.followed_communities),
|
followed_communities: vec_into(lists.followed_communities),
|
||||||
blocked_communities: vec_into(lists.blocked_communities),
|
blocked_communities: vec_into(lists.blocked_communities),
|
||||||
blocked_instances: lists.blocked_instances,
|
blocked_instances: lists.blocked_instances,
|
||||||
|
@ -132,6 +135,27 @@ pub async fn import_settings(
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
// Update the vote display mode settings
|
||||||
|
let vote_display_mode_form = LocalUserVoteDisplayModeUpdateForm {
|
||||||
|
score: data.vote_display_mode_settings.as_ref().map(|s| s.score),
|
||||||
|
upvotes: data.vote_display_mode_settings.as_ref().map(|s| s.upvotes),
|
||||||
|
downvotes: data
|
||||||
|
.vote_display_mode_settings
|
||||||
|
.as_ref()
|
||||||
|
.map(|s| s.downvotes),
|
||||||
|
upvote_percentage: data
|
||||||
|
.vote_display_mode_settings
|
||||||
|
.as_ref()
|
||||||
|
.map(|s| s.upvote_percentage),
|
||||||
|
};
|
||||||
|
|
||||||
|
LocalUserVoteDisplayMode::update(
|
||||||
|
&mut context.pool(),
|
||||||
|
local_user_view.local_user.id,
|
||||||
|
&vote_display_mode_form,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
let url_count = data.followed_communities.len()
|
let url_count = data.followed_communities.len()
|
||||||
+ data.blocked_communities.len()
|
+ data.blocked_communities.len()
|
||||||
+ data.blocked_users.len()
|
+ data.blocked_users.len()
|
||||||
|
|
|
@ -72,7 +72,7 @@ pub(crate) async fn get_apub_community_followers(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the community outbox, which is populated by a maximum of 20 posts (but no other
|
/// Returns the community outbox, which is populated by a maximum of 20 posts (but no other
|
||||||
/// activites like votes or comments).
|
/// activities like votes or comments).
|
||||||
pub(crate) async fn get_apub_community_outbox(
|
pub(crate) async fn get_apub_community_outbox(
|
||||||
info: web::Path<CommunityQuery>,
|
info: web::Path<CommunityQuery>,
|
||||||
context: Data<LemmyContext>,
|
context: Data<LemmyContext>,
|
||||||
|
|
|
@ -96,6 +96,7 @@ impl Object for ApubSite {
|
||||||
kind: ApplicationType::Application,
|
kind: ApplicationType::Application,
|
||||||
id: self.id().into(),
|
id: self.id().into(),
|
||||||
name: self.name.clone(),
|
name: self.name.clone(),
|
||||||
|
preferred_username: data.domain().to_string(),
|
||||||
content: self.sidebar.as_ref().map(|d| markdown_to_html(d)),
|
content: self.sidebar.as_ref().map(|d| markdown_to_html(d)),
|
||||||
source: self.sidebar.clone().map(Source::new),
|
source: self.sidebar.clone().map(Source::new),
|
||||||
summary: self.description.clone(),
|
summary: self.description.clone(),
|
||||||
|
|
|
@ -302,8 +302,7 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
objects::{
|
objects::{
|
||||||
community::{tests::parse_lemmy_community, ApubCommunity},
|
community::tests::parse_lemmy_community,
|
||||||
instance::ApubSite,
|
|
||||||
person::{tests::parse_lemmy_person, ApubPerson},
|
person::{tests::parse_lemmy_person, ApubPerson},
|
||||||
},
|
},
|
||||||
protocol::tests::file_to_json_object,
|
protocol::tests::file_to_json_object,
|
||||||
|
@ -333,7 +332,10 @@ mod tests {
|
||||||
assert!(!post.featured_community);
|
assert!(!post.featured_community);
|
||||||
assert_eq!(context.request_count(), 0);
|
assert_eq!(context.request_count(), 0);
|
||||||
|
|
||||||
cleanup(&context, person, site, community, post).await?;
|
Post::delete(&mut context.pool(), post.id).await?;
|
||||||
|
Person::delete(&mut context.pool(), person.id).await?;
|
||||||
|
Community::delete(&mut context.pool(), community.id).await?;
|
||||||
|
Site::delete(&mut context.pool(), site.id).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,29 +343,19 @@ mod tests {
|
||||||
#[serial]
|
#[serial]
|
||||||
async fn test_convert_mastodon_post_title() -> LemmyResult<()> {
|
async fn test_convert_mastodon_post_title() -> LemmyResult<()> {
|
||||||
let context = LemmyContext::init_test_context().await;
|
let context = LemmyContext::init_test_context().await;
|
||||||
let (person, site) = parse_lemmy_person(&context).await?;
|
|
||||||
let community = parse_lemmy_community(&context).await?;
|
let community = parse_lemmy_community(&context).await?;
|
||||||
|
|
||||||
|
let json = file_to_json_object("assets/mastodon/objects/person.json")?;
|
||||||
|
let person = ApubPerson::from_json(json, &context).await?;
|
||||||
|
|
||||||
let json = file_to_json_object("assets/mastodon/objects/page.json")?;
|
let json = file_to_json_object("assets/mastodon/objects/page.json")?;
|
||||||
let post = ApubPost::from_json(json, &context).await?;
|
let post = ApubPost::from_json(json, &context).await?;
|
||||||
|
|
||||||
assert_eq!(post.name, "Variable never resetting at refresh");
|
assert_eq!(post.name, "Variable never resetting at refresh");
|
||||||
|
|
||||||
cleanup(&context, person, site, community, post).await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn cleanup(
|
|
||||||
context: &Data<LemmyContext>,
|
|
||||||
person: ApubPerson,
|
|
||||||
site: ApubSite,
|
|
||||||
community: ApubCommunity,
|
|
||||||
post: ApubPost,
|
|
||||||
) -> LemmyResult<()> {
|
|
||||||
Post::delete(&mut context.pool(), post.id).await?;
|
Post::delete(&mut context.pool(), post.id).await?;
|
||||||
Person::delete(&mut context.pool(), person.id).await?;
|
Person::delete(&mut context.pool(), person.id).await?;
|
||||||
Community::delete(&mut context.pool(), community.id).await?;
|
Community::delete(&mut context.pool(), community.id).await?;
|
||||||
Site::delete(&mut context.pool(), site.id).await?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,10 @@ pub struct Instance {
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
pub(crate) kind: ApplicationType,
|
pub(crate) kind: ApplicationType,
|
||||||
pub(crate) id: ObjectId<ApubSite>,
|
pub(crate) id: ObjectId<ApubSite>,
|
||||||
// site name
|
/// site name
|
||||||
pub(crate) name: String,
|
pub(crate) name: String,
|
||||||
|
/// instance domain, necessary for mastodon authorized fetch
|
||||||
|
pub(crate) preferred_username: String,
|
||||||
pub(crate) inbox: Url,
|
pub(crate) inbox: Url,
|
||||||
/// mandatory field in activitypub, lemmy currently serves an empty outbox
|
/// mandatory field in activitypub, lemmy currently serves an empty outbox
|
||||||
pub(crate) outbox: Url,
|
pub(crate) outbox: Url,
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::{
|
||||||
newtypes::{DbUrl, LocalUserId},
|
newtypes::{DbUrl, LocalUserId},
|
||||||
schema::{local_image, remote_image},
|
schema::{local_image, remote_image},
|
||||||
source::images::{LocalImage, LocalImageForm, RemoteImage, RemoteImageForm},
|
source::images::{LocalImage, LocalImageForm, RemoteImage, RemoteImageForm},
|
||||||
utils::{get_conn, limit_and_offset, DbPool},
|
utils::{get_conn, limit_and_offset, limit_and_offset_unlimited, DbPool},
|
||||||
};
|
};
|
||||||
use diesel::{
|
use diesel::{
|
||||||
dsl::exists,
|
dsl::exists,
|
||||||
|
@ -25,28 +25,19 @@ impl LocalImage {
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This should only be used in the internal API, since it has no page and limit
|
|
||||||
pub async fn get_all_by_local_user_id(
|
pub async fn get_all_by_local_user_id(
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
user_id: LocalUserId,
|
user_id: LocalUserId,
|
||||||
) -> Result<Vec<Self>, Error> {
|
|
||||||
let conn = &mut get_conn(pool).await?;
|
|
||||||
local_image::table
|
|
||||||
.filter(local_image::local_user_id.eq(user_id))
|
|
||||||
.select(local_image::all_columns)
|
|
||||||
.load::<LocalImage>(conn)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This is okay for API use.
|
|
||||||
pub async fn get_all_paged_by_local_user_id(
|
|
||||||
pool: &mut DbPool<'_>,
|
|
||||||
user_id: LocalUserId,
|
|
||||||
page: Option<i64>,
|
page: Option<i64>,
|
||||||
limit: Option<i64>,
|
limit: Option<i64>,
|
||||||
|
ignore_page_limits: bool,
|
||||||
) -> Result<Vec<Self>, Error> {
|
) -> Result<Vec<Self>, Error> {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
let (limit, offset) = limit_and_offset(page, limit)?;
|
let (limit, offset) = if ignore_page_limits {
|
||||||
|
limit_and_offset_unlimited(page, limit)
|
||||||
|
} else {
|
||||||
|
limit_and_offset(page, limit)?
|
||||||
|
};
|
||||||
|
|
||||||
local_image::table
|
local_image::table
|
||||||
.filter(local_image::local_user_id.eq(user_id))
|
.filter(local_image::local_user_id.eq(user_id))
|
||||||
|
|
|
@ -4,6 +4,7 @@ use crate::{
|
||||||
source::{
|
source::{
|
||||||
actor_language::{LocalUserLanguage, SiteLanguage},
|
actor_language::{LocalUserLanguage, SiteLanguage},
|
||||||
local_user::{LocalUser, LocalUserInsertForm, LocalUserUpdateForm},
|
local_user::{LocalUser, LocalUserInsertForm, LocalUserUpdateForm},
|
||||||
|
local_user_vote_display_mode::{LocalUserVoteDisplayMode, LocalUserVoteDisplayModeInsertForm},
|
||||||
},
|
},
|
||||||
traits::Crud,
|
traits::Crud,
|
||||||
utils::{
|
utils::{
|
||||||
|
@ -211,6 +212,12 @@ impl Crud for LocalUser {
|
||||||
LocalUserLanguage::update(pool, vec![], local_user_.id).await?;
|
LocalUserLanguage::update(pool, vec![], local_user_.id).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create their vote_display_modes
|
||||||
|
let vote_display_mode_form = LocalUserVoteDisplayModeInsertForm::builder()
|
||||||
|
.local_user_id(local_user_.id)
|
||||||
|
.build();
|
||||||
|
LocalUserVoteDisplayMode::create(pool, &vote_display_mode_form).await?;
|
||||||
|
|
||||||
Ok(local_user_)
|
Ok(local_user_)
|
||||||
}
|
}
|
||||||
async fn update(
|
async fn update(
|
||||||
|
|
57
crates/db_schema/src/impls/local_user_vote_display_mode.rs
Normal file
57
crates/db_schema/src/impls/local_user_vote_display_mode.rs
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
use crate::{
|
||||||
|
newtypes::LocalUserId,
|
||||||
|
schema::local_user_vote_display_mode,
|
||||||
|
source::local_user_vote_display_mode::{
|
||||||
|
LocalUserVoteDisplayMode,
|
||||||
|
LocalUserVoteDisplayModeInsertForm,
|
||||||
|
LocalUserVoteDisplayModeUpdateForm,
|
||||||
|
},
|
||||||
|
utils::{get_conn, DbPool},
|
||||||
|
};
|
||||||
|
use diesel::{dsl::insert_into, result::Error, QueryDsl};
|
||||||
|
use diesel_async::RunQueryDsl;
|
||||||
|
|
||||||
|
impl LocalUserVoteDisplayMode {
|
||||||
|
pub async fn read(pool: &mut DbPool<'_>) -> Result<Self, Error> {
|
||||||
|
let conn = &mut get_conn(pool).await?;
|
||||||
|
local_user_vote_display_mode::table
|
||||||
|
.first::<Self>(conn)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn create(
|
||||||
|
pool: &mut DbPool<'_>,
|
||||||
|
form: &LocalUserVoteDisplayModeInsertForm,
|
||||||
|
) -> Result<Self, Error> {
|
||||||
|
let conn = &mut get_conn(pool).await?;
|
||||||
|
insert_into(local_user_vote_display_mode::table)
|
||||||
|
.values(form)
|
||||||
|
.get_result::<Self>(conn)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
pub async fn update(
|
||||||
|
pool: &mut DbPool<'_>,
|
||||||
|
local_user_id: LocalUserId,
|
||||||
|
form: &LocalUserVoteDisplayModeUpdateForm,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
// avoid error "There are no changes to save. This query cannot be built"
|
||||||
|
if form.is_empty() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let conn = &mut get_conn(pool).await?;
|
||||||
|
diesel::update(local_user_vote_display_mode::table.find(local_user_id))
|
||||||
|
.set(form)
|
||||||
|
.get_result::<Self>(conn)
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LocalUserVoteDisplayModeUpdateForm {
|
||||||
|
fn is_empty(&self) -> bool {
|
||||||
|
self.score.is_none()
|
||||||
|
&& self.upvotes.is_none()
|
||||||
|
&& self.downvotes.is_none()
|
||||||
|
&& self.upvote_percentage.is_none()
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,6 +18,7 @@ pub mod language;
|
||||||
pub mod local_site;
|
pub mod local_site;
|
||||||
pub mod local_site_rate_limit;
|
pub mod local_site_rate_limit;
|
||||||
pub mod local_user;
|
pub mod local_user;
|
||||||
|
pub mod local_user_vote_display_mode;
|
||||||
pub mod login_token;
|
pub mod login_token;
|
||||||
pub mod moderator;
|
pub mod moderator;
|
||||||
pub mod password_reset_request;
|
pub mod password_reset_request;
|
||||||
|
|
|
@ -342,7 +342,7 @@ diesel::table! {
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
local_image (pictrs_alias) {
|
local_image (pictrs_alias) {
|
||||||
local_user_id -> Int4,
|
local_user_id -> Nullable<Int4>,
|
||||||
pictrs_alias -> Text,
|
pictrs_alias -> Text,
|
||||||
pictrs_delete_token -> Text,
|
pictrs_delete_token -> Text,
|
||||||
published -> Timestamptz,
|
published -> Timestamptz,
|
||||||
|
@ -454,6 +454,16 @@ diesel::table! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
diesel::table! {
|
||||||
|
local_user_vote_display_mode (local_user_id) {
|
||||||
|
local_user_id -> Int4,
|
||||||
|
score -> Bool,
|
||||||
|
upvotes -> Bool,
|
||||||
|
downvotes -> Bool,
|
||||||
|
upvote_percentage -> Bool,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
diesel::table! {
|
diesel::table! {
|
||||||
login_token (token) {
|
login_token (token) {
|
||||||
token -> Text,
|
token -> Text,
|
||||||
|
@ -961,6 +971,7 @@ diesel::joinable!(local_site_rate_limit -> local_site (local_site_id));
|
||||||
diesel::joinable!(local_user -> person (person_id));
|
diesel::joinable!(local_user -> person (person_id));
|
||||||
diesel::joinable!(local_user_language -> language (language_id));
|
diesel::joinable!(local_user_language -> language (language_id));
|
||||||
diesel::joinable!(local_user_language -> local_user (local_user_id));
|
diesel::joinable!(local_user_language -> local_user (local_user_id));
|
||||||
|
diesel::joinable!(local_user_vote_display_mode -> local_user (local_user_id));
|
||||||
diesel::joinable!(login_token -> local_user (user_id));
|
diesel::joinable!(login_token -> local_user (user_id));
|
||||||
diesel::joinable!(mod_add_community -> community (community_id));
|
diesel::joinable!(mod_add_community -> community (community_id));
|
||||||
diesel::joinable!(mod_ban_from_community -> community (community_id));
|
diesel::joinable!(mod_ban_from_community -> community (community_id));
|
||||||
|
@ -1043,6 +1054,7 @@ diesel::allow_tables_to_appear_in_same_query!(
|
||||||
local_site_rate_limit,
|
local_site_rate_limit,
|
||||||
local_user,
|
local_user,
|
||||||
local_user_language,
|
local_user_language,
|
||||||
|
local_user_vote_display_mode,
|
||||||
login_token,
|
login_token,
|
||||||
mod_add,
|
mod_add,
|
||||||
mod_add_community,
|
mod_add_community,
|
||||||
|
|
|
@ -24,7 +24,7 @@ use typed_builder::TypedBuilder;
|
||||||
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||||
#[cfg_attr(feature = "full", diesel(primary_key(local_user_id)))]
|
#[cfg_attr(feature = "full", diesel(primary_key(local_user_id)))]
|
||||||
pub struct LocalImage {
|
pub struct LocalImage {
|
||||||
pub local_user_id: LocalUserId,
|
pub local_user_id: Option<LocalUserId>,
|
||||||
pub pictrs_alias: String,
|
pub pictrs_alias: String,
|
||||||
pub pictrs_delete_token: String,
|
pub pictrs_delete_token: String,
|
||||||
pub published: DateTime<Utc>,
|
pub published: DateTime<Utc>,
|
||||||
|
@ -34,14 +34,13 @@ pub struct LocalImage {
|
||||||
#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
|
#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
|
||||||
#[cfg_attr(feature = "full", diesel(table_name = local_image))]
|
#[cfg_attr(feature = "full", diesel(table_name = local_image))]
|
||||||
pub struct LocalImageForm {
|
pub struct LocalImageForm {
|
||||||
pub local_user_id: LocalUserId,
|
pub local_user_id: Option<LocalUserId>,
|
||||||
pub pictrs_alias: String,
|
pub pictrs_alias: String,
|
||||||
pub pictrs_delete_token: String,
|
pub pictrs_delete_token: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores all images which are hosted on remote domains. When attempting to proxy an image, it
|
/// Stores all images which are hosted on remote domains. When attempting to proxy an image, it
|
||||||
/// is checked against this table to avoid Lemmy being used as a general purpose proxy.
|
/// is checked against this table to avoid Lemmy being used as a general purpose proxy.
|
||||||
#[skip_serializing_none]
|
|
||||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||||
#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
|
#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
|
||||||
#[cfg_attr(feature = "full", diesel(table_name = remote_image))]
|
#[cfg_attr(feature = "full", diesel(table_name = remote_image))]
|
||||||
|
|
|
@ -36,6 +36,7 @@ pub struct LocalUser {
|
||||||
pub show_avatars: bool,
|
pub show_avatars: bool,
|
||||||
pub send_notifications_to_email: bool,
|
pub send_notifications_to_email: bool,
|
||||||
/// Whether to show comment / post scores.
|
/// Whether to show comment / post scores.
|
||||||
|
// TODO now that there is a vote_display_mode, this can be gotten rid of in future releases.
|
||||||
pub show_scores: bool,
|
pub show_scores: bool,
|
||||||
/// Whether to show bot accounts.
|
/// Whether to show bot accounts.
|
||||||
pub show_bot_accounts: bool,
|
pub show_bot_accounts: bool,
|
||||||
|
@ -55,6 +56,7 @@ pub struct LocalUser {
|
||||||
pub infinite_scroll_enabled: bool,
|
pub infinite_scroll_enabled: bool,
|
||||||
/// Whether the person is an admin.
|
/// Whether the person is an admin.
|
||||||
pub admin: bool,
|
pub admin: bool,
|
||||||
|
/// A post-view mode that changes how multiple post listings look.
|
||||||
pub post_listing_mode: PostListingMode,
|
pub post_listing_mode: PostListingMode,
|
||||||
pub totp_2fa_enabled: bool,
|
pub totp_2fa_enabled: bool,
|
||||||
/// Whether to allow keyboard navigation (for browsing and interacting with posts and comments).
|
/// Whether to allow keyboard navigation (for browsing and interacting with posts and comments).
|
||||||
|
|
51
crates/db_schema/src/source/local_user_vote_display_mode.rs
Normal file
51
crates/db_schema/src/source/local_user_vote_display_mode.rs
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
use crate::newtypes::LocalUserId;
|
||||||
|
#[cfg(feature = "full")]
|
||||||
|
use crate::schema::local_user_vote_display_mode;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_with::skip_serializing_none;
|
||||||
|
#[cfg(feature = "full")]
|
||||||
|
use ts_rs::TS;
|
||||||
|
use typed_builder::TypedBuilder;
|
||||||
|
|
||||||
|
#[skip_serializing_none]
|
||||||
|
#[derive(PartialEq, Eq, Debug, Clone, Default, Serialize, Deserialize)]
|
||||||
|
#[cfg_attr(feature = "full", derive(Queryable, Selectable, Identifiable, TS))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(table_name = local_user_vote_display_mode))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(primary_key(local_user_id)))]
|
||||||
|
#[cfg_attr(
|
||||||
|
feature = "full",
|
||||||
|
diesel(belongs_to(crate::source::local_site::LocalUser))
|
||||||
|
)]
|
||||||
|
#[cfg_attr(feature = "full", diesel(check_for_backend(diesel::pg::Pg)))]
|
||||||
|
#[cfg_attr(feature = "full", ts(export))]
|
||||||
|
/// The vote display settings for your user.
|
||||||
|
pub struct LocalUserVoteDisplayMode {
|
||||||
|
pub local_user_id: LocalUserId,
|
||||||
|
pub score: bool,
|
||||||
|
pub upvotes: bool,
|
||||||
|
pub downvotes: bool,
|
||||||
|
pub upvote_percentage: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, TypedBuilder)]
|
||||||
|
#[builder(field_defaults(default))]
|
||||||
|
#[cfg_attr(feature = "full", derive(Insertable))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(table_name = local_user_vote_display_mode))]
|
||||||
|
pub struct LocalUserVoteDisplayModeInsertForm {
|
||||||
|
#[builder(!default)]
|
||||||
|
pub local_user_id: LocalUserId,
|
||||||
|
pub score: Option<bool>,
|
||||||
|
pub upvotes: Option<bool>,
|
||||||
|
pub downvotes: Option<bool>,
|
||||||
|
pub upvote_percentage: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
#[cfg_attr(feature = "full", derive(AsChangeset))]
|
||||||
|
#[cfg_attr(feature = "full", diesel(table_name = local_user_vote_display_mode))]
|
||||||
|
pub struct LocalUserVoteDisplayModeUpdateForm {
|
||||||
|
pub score: Option<bool>,
|
||||||
|
pub upvotes: Option<bool>,
|
||||||
|
pub downvotes: Option<bool>,
|
||||||
|
pub upvote_percentage: Option<bool>,
|
||||||
|
}
|
|
@ -23,6 +23,7 @@ pub mod language;
|
||||||
pub mod local_site;
|
pub mod local_site;
|
||||||
pub mod local_site_rate_limit;
|
pub mod local_site_rate_limit;
|
||||||
pub mod local_user;
|
pub mod local_user;
|
||||||
|
pub mod local_user_vote_display_mode;
|
||||||
pub mod login_token;
|
pub mod login_token;
|
||||||
pub mod moderator;
|
pub mod moderator;
|
||||||
pub mod password_reset_request;
|
pub mod password_reset_request;
|
||||||
|
@ -44,6 +45,6 @@ pub mod tagline;
|
||||||
/// value is not sent by Lemmy. Necessary for crates which rely on Rust API such as lemmy-stats-crawler.
|
/// value is not sent by Lemmy. Necessary for crates which rely on Rust API such as lemmy-stats-crawler.
|
||||||
fn placeholder_apub_url() -> DbUrl {
|
fn placeholder_apub_url() -> DbUrl {
|
||||||
DbUrl(Box::new(
|
DbUrl(Box::new(
|
||||||
Url::parse("http://example.com").expect("parse placeholer url"),
|
Url::parse("http://example.com").expect("parse placeholder url"),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,9 @@ pub struct Site {
|
||||||
pub last_refreshed_at: DateTime<Utc>,
|
pub last_refreshed_at: DateTime<Utc>,
|
||||||
/// The site inbox
|
/// The site inbox
|
||||||
pub inbox_url: DbUrl,
|
pub inbox_url: DbUrl,
|
||||||
|
#[serde(skip)]
|
||||||
pub private_key: Option<String>,
|
pub private_key: Option<String>,
|
||||||
|
#[serde(skip)]
|
||||||
pub public_key: String,
|
pub public_key: String,
|
||||||
pub instance_id: InstanceId,
|
pub instance_id: InstanceId,
|
||||||
/// If present, nsfw content is visible by default. Should be displayed by frontends/clients
|
/// If present, nsfw content is visible by default. Should be displayed by frontends/clients
|
||||||
|
|
|
@ -18,10 +18,14 @@ use lemmy_db_schema::{
|
||||||
comment_aggregates,
|
comment_aggregates,
|
||||||
comment_like,
|
comment_like,
|
||||||
comment_report,
|
comment_report,
|
||||||
|
comment_saved,
|
||||||
community,
|
community,
|
||||||
|
community_follower,
|
||||||
community_moderator,
|
community_moderator,
|
||||||
community_person_ban,
|
community_person_ban,
|
||||||
|
local_user,
|
||||||
person,
|
person,
|
||||||
|
person_block,
|
||||||
post,
|
post,
|
||||||
},
|
},
|
||||||
utils::{get_conn, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn},
|
utils::{get_conn, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn},
|
||||||
|
@ -64,6 +68,45 @@ fn queries<'a>() -> Queries<
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
.left_join(
|
||||||
|
aliases::community_moderator1.on(
|
||||||
|
community::id
|
||||||
|
.eq(aliases::community_moderator1.field(community_moderator::community_id))
|
||||||
|
.and(
|
||||||
|
aliases::community_moderator1
|
||||||
|
.field(community_moderator::person_id)
|
||||||
|
.eq(comment::creator_id),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.left_join(
|
||||||
|
local_user::table.on(
|
||||||
|
comment::creator_id
|
||||||
|
.eq(local_user::person_id)
|
||||||
|
.and(local_user::admin.eq(true)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.left_join(
|
||||||
|
person_block::table.on(
|
||||||
|
comment::creator_id
|
||||||
|
.eq(person_block::target_id)
|
||||||
|
.and(person_block::person_id.eq(my_person_id)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.left_join(
|
||||||
|
community_follower::table.on(
|
||||||
|
post::community_id
|
||||||
|
.eq(community_follower::community_id)
|
||||||
|
.and(community_follower::person_id.eq(my_person_id)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.left_join(
|
||||||
|
comment_saved::table.on(
|
||||||
|
comment::id
|
||||||
|
.eq(comment_saved::comment_id)
|
||||||
|
.and(comment_saved::person_id.eq(my_person_id)),
|
||||||
|
),
|
||||||
|
)
|
||||||
.select((
|
.select((
|
||||||
comment_report::all_columns,
|
comment_report::all_columns,
|
||||||
comment::all_columns,
|
comment::all_columns,
|
||||||
|
@ -73,6 +116,14 @@ fn queries<'a>() -> Queries<
|
||||||
aliases::person1.fields(person::all_columns),
|
aliases::person1.fields(person::all_columns),
|
||||||
comment_aggregates::all_columns,
|
comment_aggregates::all_columns,
|
||||||
community_person_ban::community_id.nullable().is_not_null(),
|
community_person_ban::community_id.nullable().is_not_null(),
|
||||||
|
aliases::community_moderator1
|
||||||
|
.field(community_moderator::community_id)
|
||||||
|
.nullable()
|
||||||
|
.is_not_null(),
|
||||||
|
local_user::admin.nullable().is_not_null(),
|
||||||
|
person_block::target_id.nullable().is_not_null(),
|
||||||
|
community_follower::pending.nullable(),
|
||||||
|
comment_saved::published.nullable().is_not_null(),
|
||||||
comment_like::score.nullable(),
|
comment_like::score.nullable(),
|
||||||
aliases::person2.fields(person::all_columns).nullable(),
|
aliases::person2.fields(person::all_columns).nullable(),
|
||||||
))
|
))
|
||||||
|
@ -223,12 +274,14 @@ mod tests {
|
||||||
community::{Community, CommunityInsertForm, CommunityModerator, CommunityModeratorForm},
|
community::{Community, CommunityInsertForm, CommunityModerator, CommunityModeratorForm},
|
||||||
instance::Instance,
|
instance::Instance,
|
||||||
local_user::{LocalUser, LocalUserInsertForm},
|
local_user::{LocalUser, LocalUserInsertForm},
|
||||||
|
local_user_vote_display_mode::LocalUserVoteDisplayMode,
|
||||||
person::{Person, PersonInsertForm},
|
person::{Person, PersonInsertForm},
|
||||||
post::{Post, PostInsertForm},
|
post::{Post, PostInsertForm},
|
||||||
},
|
},
|
||||||
traits::{Crud, Joinable, Reportable},
|
traits::{Crud, Joinable, Reportable},
|
||||||
utils::{build_db_pool_for_tests, RANK_DEFAULT},
|
utils::{build_db_pool_for_tests, RANK_DEFAULT},
|
||||||
CommunityVisibility,
|
CommunityVisibility,
|
||||||
|
SubscribedType,
|
||||||
};
|
};
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
@ -258,6 +311,7 @@ mod tests {
|
||||||
let timmy_local_user = LocalUser::create(pool, &new_local_user).await.unwrap();
|
let timmy_local_user = LocalUser::create(pool, &new_local_user).await.unwrap();
|
||||||
let timmy_view = LocalUserView {
|
let timmy_view = LocalUserView {
|
||||||
local_user: timmy_local_user,
|
local_user: timmy_local_user,
|
||||||
|
local_user_vote_display_mode: LocalUserVoteDisplayMode::default(),
|
||||||
person: inserted_timmy.clone(),
|
person: inserted_timmy.clone(),
|
||||||
counts: Default::default(),
|
counts: Default::default(),
|
||||||
};
|
};
|
||||||
|
@ -350,6 +404,11 @@ mod tests {
|
||||||
comment_report: inserted_jessica_report.clone(),
|
comment_report: inserted_jessica_report.clone(),
|
||||||
comment: inserted_comment.clone(),
|
comment: inserted_comment.clone(),
|
||||||
post: inserted_post,
|
post: inserted_post,
|
||||||
|
creator_is_moderator: true,
|
||||||
|
creator_is_admin: false,
|
||||||
|
creator_blocked: false,
|
||||||
|
subscribed: SubscribedType::NotSubscribed,
|
||||||
|
saved: false,
|
||||||
community: Community {
|
community: Community {
|
||||||
id: inserted_community.id,
|
id: inserted_community.id,
|
||||||
name: inserted_community.name,
|
name: inserted_community.name,
|
||||||
|
|
|
@ -441,6 +441,7 @@ mod tests {
|
||||||
instance::Instance,
|
instance::Instance,
|
||||||
language::Language,
|
language::Language,
|
||||||
local_user::{LocalUser, LocalUserInsertForm},
|
local_user::{LocalUser, LocalUserInsertForm},
|
||||||
|
local_user_vote_display_mode::LocalUserVoteDisplayMode,
|
||||||
person::{Person, PersonInsertForm},
|
person::{Person, PersonInsertForm},
|
||||||
person_block::{PersonBlock, PersonBlockForm},
|
person_block::{PersonBlock, PersonBlockForm},
|
||||||
post::{Post, PostInsertForm},
|
post::{Post, PostInsertForm},
|
||||||
|
@ -614,6 +615,7 @@ mod tests {
|
||||||
|
|
||||||
let timmy_local_user_view = LocalUserView {
|
let timmy_local_user_view = LocalUserView {
|
||||||
local_user: inserted_timmy_local_user.clone(),
|
local_user: inserted_timmy_local_user.clone(),
|
||||||
|
local_user_vote_display_mode: LocalUserVoteDisplayMode::default(),
|
||||||
person: inserted_timmy_person.clone(),
|
person: inserted_timmy_person.clone(),
|
||||||
counts: Default::default(),
|
counts: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,7 +4,7 @@ use diesel::{result::Error, BoolExpressionMethods, ExpressionMethods, JoinOnDsl,
|
||||||
use diesel_async::RunQueryDsl;
|
use diesel_async::RunQueryDsl;
|
||||||
use lemmy_db_schema::{
|
use lemmy_db_schema::{
|
||||||
newtypes::{LocalUserId, PersonId},
|
newtypes::{LocalUserId, PersonId},
|
||||||
schema::{local_user, person, person_aggregates},
|
schema::{local_user, local_user_vote_display_mode, person, person_aggregates},
|
||||||
utils::{
|
utils::{
|
||||||
functions::{coalesce, lower},
|
functions::{coalesce, lower},
|
||||||
DbConn,
|
DbConn,
|
||||||
|
@ -33,6 +33,7 @@ fn queries<'a>(
|
||||||
) -> Queries<impl ReadFn<'a, LocalUserView, ReadBy<'a>>, impl ListFn<'a, LocalUserView, ListMode>> {
|
) -> Queries<impl ReadFn<'a, LocalUserView, ReadBy<'a>>, impl ListFn<'a, LocalUserView, ListMode>> {
|
||||||
let selection = (
|
let selection = (
|
||||||
local_user::all_columns,
|
local_user::all_columns,
|
||||||
|
local_user_vote_display_mode::all_columns,
|
||||||
person::all_columns,
|
person::all_columns,
|
||||||
person_aggregates::all_columns,
|
person_aggregates::all_columns,
|
||||||
);
|
);
|
||||||
|
@ -58,6 +59,7 @@ fn queries<'a>(
|
||||||
_ => query,
|
_ => query,
|
||||||
};
|
};
|
||||||
query
|
query
|
||||||
|
.inner_join(local_user_vote_display_mode::table)
|
||||||
.inner_join(person_aggregates::table.on(person::id.eq(person_aggregates::person_id)))
|
.inner_join(person_aggregates::table.on(person::id.eq(person_aggregates::person_id)))
|
||||||
.select(selection)
|
.select(selection)
|
||||||
.first::<LocalUserView>(&mut conn)
|
.first::<LocalUserView>(&mut conn)
|
||||||
|
@ -68,10 +70,11 @@ fn queries<'a>(
|
||||||
match mode {
|
match mode {
|
||||||
ListMode::AdminsWithEmails => {
|
ListMode::AdminsWithEmails => {
|
||||||
local_user::table
|
local_user::table
|
||||||
.filter(local_user::email.is_not_null())
|
.inner_join(local_user_vote_display_mode::table)
|
||||||
.filter(local_user::admin.eq(true))
|
|
||||||
.inner_join(person::table)
|
.inner_join(person::table)
|
||||||
.inner_join(person_aggregates::table.on(person::id.eq(person_aggregates::person_id)))
|
.inner_join(person_aggregates::table.on(person::id.eq(person_aggregates::person_id)))
|
||||||
|
.filter(local_user::email.is_not_null())
|
||||||
|
.filter(local_user::admin.eq(true))
|
||||||
.select(selection)
|
.select(selection)
|
||||||
.load::<LocalUserView>(&mut conn)
|
.load::<LocalUserView>(&mut conn)
|
||||||
.await
|
.await
|
||||||
|
|
|
@ -14,15 +14,31 @@ use lemmy_db_schema::{
|
||||||
newtypes::{CommunityId, PersonId, PostId, PostReportId},
|
newtypes::{CommunityId, PersonId, PostId, PostReportId},
|
||||||
schema::{
|
schema::{
|
||||||
community,
|
community,
|
||||||
|
community_follower,
|
||||||
community_moderator,
|
community_moderator,
|
||||||
community_person_ban,
|
community_person_ban,
|
||||||
|
local_user,
|
||||||
person,
|
person,
|
||||||
|
person_block,
|
||||||
|
person_post_aggregates,
|
||||||
post,
|
post,
|
||||||
post_aggregates,
|
post_aggregates,
|
||||||
|
post_hide,
|
||||||
post_like,
|
post_like,
|
||||||
|
post_read,
|
||||||
post_report,
|
post_report,
|
||||||
|
post_saved,
|
||||||
|
},
|
||||||
|
utils::{
|
||||||
|
functions::coalesce,
|
||||||
|
get_conn,
|
||||||
|
limit_and_offset,
|
||||||
|
DbConn,
|
||||||
|
DbPool,
|
||||||
|
ListFn,
|
||||||
|
Queries,
|
||||||
|
ReadFn,
|
||||||
},
|
},
|
||||||
utils::{get_conn, limit_and_offset, DbConn, DbPool, ListFn, Queries, ReadFn},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fn queries<'a>() -> Queries<
|
fn queries<'a>() -> Queries<
|
||||||
|
@ -42,6 +58,67 @@ fn queries<'a>() -> Queries<
|
||||||
.and(community_person_ban::person_id.eq(post::creator_id)),
|
.and(community_person_ban::person_id.eq(post::creator_id)),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
.left_join(
|
||||||
|
aliases::community_moderator1.on(
|
||||||
|
aliases::community_moderator1
|
||||||
|
.field(community_moderator::community_id)
|
||||||
|
.eq(post::community_id)
|
||||||
|
.and(
|
||||||
|
aliases::community_moderator1
|
||||||
|
.field(community_moderator::person_id)
|
||||||
|
.eq(my_person_id),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.left_join(
|
||||||
|
local_user::table.on(
|
||||||
|
post::creator_id
|
||||||
|
.eq(local_user::person_id)
|
||||||
|
.and(local_user::admin.eq(true)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.left_join(
|
||||||
|
post_saved::table.on(
|
||||||
|
post::id
|
||||||
|
.eq(post_saved::post_id)
|
||||||
|
.and(post_saved::person_id.eq(my_person_id)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.left_join(
|
||||||
|
post_read::table.on(
|
||||||
|
post::id
|
||||||
|
.eq(post_read::post_id)
|
||||||
|
.and(post_read::person_id.eq(my_person_id)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.left_join(
|
||||||
|
post_hide::table.on(
|
||||||
|
post::id
|
||||||
|
.eq(post_hide::post_id)
|
||||||
|
.and(post_hide::person_id.eq(my_person_id)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.left_join(
|
||||||
|
person_block::table.on(
|
||||||
|
post::creator_id
|
||||||
|
.eq(person_block::target_id)
|
||||||
|
.and(person_block::person_id.eq(my_person_id)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.left_join(
|
||||||
|
person_post_aggregates::table.on(
|
||||||
|
post::id
|
||||||
|
.eq(person_post_aggregates::post_id)
|
||||||
|
.and(person_post_aggregates::person_id.eq(my_person_id)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.left_join(
|
||||||
|
community_follower::table.on(
|
||||||
|
post::community_id
|
||||||
|
.eq(community_follower::community_id)
|
||||||
|
.and(community_follower::person_id.eq(my_person_id)),
|
||||||
|
),
|
||||||
|
)
|
||||||
.left_join(
|
.left_join(
|
||||||
post_like::table.on(
|
post_like::table.on(
|
||||||
post::id
|
post::id
|
||||||
|
@ -61,7 +138,21 @@ fn queries<'a>() -> Queries<
|
||||||
person::all_columns,
|
person::all_columns,
|
||||||
aliases::person1.fields(person::all_columns),
|
aliases::person1.fields(person::all_columns),
|
||||||
community_person_ban::community_id.nullable().is_not_null(),
|
community_person_ban::community_id.nullable().is_not_null(),
|
||||||
|
aliases::community_moderator1
|
||||||
|
.field(community_moderator::community_id)
|
||||||
|
.nullable()
|
||||||
|
.is_not_null(),
|
||||||
|
local_user::admin.nullable().is_not_null(),
|
||||||
|
community_follower::pending.nullable(),
|
||||||
|
post_saved::post_id.nullable().is_not_null(),
|
||||||
|
post_read::post_id.nullable().is_not_null(),
|
||||||
|
post_hide::post_id.nullable().is_not_null(),
|
||||||
|
person_block::target_id.nullable().is_not_null(),
|
||||||
post_like::score.nullable(),
|
post_like::score.nullable(),
|
||||||
|
coalesce(
|
||||||
|
post_aggregates::comments.nullable() - person_post_aggregates::read_comments.nullable(),
|
||||||
|
post_aggregates::comments,
|
||||||
|
),
|
||||||
post_aggregates::all_columns,
|
post_aggregates::all_columns,
|
||||||
aliases::person2.fields(person::all_columns.nullable()),
|
aliases::person2.fields(person::all_columns.nullable()),
|
||||||
))
|
))
|
||||||
|
@ -206,6 +297,7 @@ mod tests {
|
||||||
community::{Community, CommunityInsertForm, CommunityModerator, CommunityModeratorForm},
|
community::{Community, CommunityInsertForm, CommunityModerator, CommunityModeratorForm},
|
||||||
instance::Instance,
|
instance::Instance,
|
||||||
local_user::{LocalUser, LocalUserInsertForm},
|
local_user::{LocalUser, LocalUserInsertForm},
|
||||||
|
local_user_vote_display_mode::LocalUserVoteDisplayMode,
|
||||||
person::{Person, PersonInsertForm},
|
person::{Person, PersonInsertForm},
|
||||||
post::{Post, PostInsertForm},
|
post::{Post, PostInsertForm},
|
||||||
post_report::{PostReport, PostReportForm},
|
post_report::{PostReport, PostReportForm},
|
||||||
|
@ -241,6 +333,7 @@ mod tests {
|
||||||
let timmy_local_user = LocalUser::create(pool, &new_local_user).await.unwrap();
|
let timmy_local_user = LocalUser::create(pool, &new_local_user).await.unwrap();
|
||||||
let timmy_view = LocalUserView {
|
let timmy_view = LocalUserView {
|
||||||
local_user: timmy_local_user,
|
local_user: timmy_local_user,
|
||||||
|
local_user_vote_display_mode: LocalUserVoteDisplayMode::default(),
|
||||||
person: inserted_timmy.clone(),
|
person: inserted_timmy.clone(),
|
||||||
counts: Default::default(),
|
counts: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -749,6 +749,7 @@ mod tests {
|
||||||
instance_block::{InstanceBlock, InstanceBlockForm},
|
instance_block::{InstanceBlock, InstanceBlockForm},
|
||||||
language::Language,
|
language::Language,
|
||||||
local_user::{LocalUser, LocalUserInsertForm, LocalUserUpdateForm},
|
local_user::{LocalUser, LocalUserInsertForm, LocalUserUpdateForm},
|
||||||
|
local_user_vote_display_mode::LocalUserVoteDisplayMode,
|
||||||
person::{Person, PersonInsertForm},
|
person::{Person, PersonInsertForm},
|
||||||
person_block::{PersonBlock, PersonBlockForm},
|
person_block::{PersonBlock, PersonBlockForm},
|
||||||
post::{Post, PostHide, PostInsertForm, PostLike, PostLikeForm, PostRead, PostUpdateForm},
|
post::{Post, PostHide, PostInsertForm, PostLike, PostLikeForm, PostRead, PostUpdateForm},
|
||||||
|
@ -871,11 +872,13 @@ mod tests {
|
||||||
let inserted_bot_post = Post::create(pool, &new_bot_post).await?;
|
let inserted_bot_post = Post::create(pool, &new_bot_post).await?;
|
||||||
let local_user_view = LocalUserView {
|
let local_user_view = LocalUserView {
|
||||||
local_user: inserted_local_user,
|
local_user: inserted_local_user,
|
||||||
|
local_user_vote_display_mode: LocalUserVoteDisplayMode::default(),
|
||||||
person: inserted_person,
|
person: inserted_person,
|
||||||
counts: Default::default(),
|
counts: Default::default(),
|
||||||
};
|
};
|
||||||
let blocked_local_user_view = LocalUserView {
|
let blocked_local_user_view = LocalUserView {
|
||||||
local_user: inserted_blocked_local_user,
|
local_user: inserted_blocked_local_user,
|
||||||
|
local_user_vote_display_mode: LocalUserVoteDisplayMode::default(),
|
||||||
person: inserted_blocked_person,
|
person: inserted_blocked_person,
|
||||||
counts: Default::default(),
|
counts: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,7 +9,7 @@ use lemmy_db_schema::{
|
||||||
impl SiteView {
|
impl SiteView {
|
||||||
pub async fn read_local(pool: &mut DbPool<'_>) -> Result<Self, Error> {
|
pub async fn read_local(pool: &mut DbPool<'_>) -> Result<Self, Error> {
|
||||||
let conn = &mut get_conn(pool).await?;
|
let conn = &mut get_conn(pool).await?;
|
||||||
let mut res = site::table
|
site::table
|
||||||
.inner_join(local_site::table)
|
.inner_join(local_site::table)
|
||||||
.inner_join(
|
.inner_join(
|
||||||
local_site_rate_limit::table.on(local_site::id.eq(local_site_rate_limit::local_site_id)),
|
local_site_rate_limit::table.on(local_site::id.eq(local_site_rate_limit::local_site_id)),
|
||||||
|
@ -22,9 +22,6 @@ impl SiteView {
|
||||||
site_aggregates::all_columns,
|
site_aggregates::all_columns,
|
||||||
))
|
))
|
||||||
.first::<SiteView>(conn)
|
.first::<SiteView>(conn)
|
||||||
.await?;
|
.await
|
||||||
|
|
||||||
res.site.private_key = None;
|
|
||||||
Ok(res)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ use lemmy_db_schema::{
|
||||||
local_site::LocalSite,
|
local_site::LocalSite,
|
||||||
local_site_rate_limit::LocalSiteRateLimit,
|
local_site_rate_limit::LocalSiteRateLimit,
|
||||||
local_user::LocalUser,
|
local_user::LocalUser,
|
||||||
|
local_user_vote_display_mode::LocalUserVoteDisplayMode,
|
||||||
person::Person,
|
person::Person,
|
||||||
post::Post,
|
post::Post,
|
||||||
post_report::PostReport,
|
post_report::PostReport,
|
||||||
|
@ -41,6 +42,11 @@ pub struct CommentReportView {
|
||||||
pub comment_creator: Person,
|
pub comment_creator: Person,
|
||||||
pub counts: CommentAggregates,
|
pub counts: CommentAggregates,
|
||||||
pub creator_banned_from_community: bool,
|
pub creator_banned_from_community: bool,
|
||||||
|
pub creator_is_moderator: bool,
|
||||||
|
pub creator_is_admin: bool,
|
||||||
|
pub creator_blocked: bool,
|
||||||
|
pub subscribed: SubscribedType,
|
||||||
|
pub saved: bool,
|
||||||
pub my_vote: Option<i16>,
|
pub my_vote: Option<i16>,
|
||||||
pub resolver: Option<Person>,
|
pub resolver: Option<Person>,
|
||||||
}
|
}
|
||||||
|
@ -73,6 +79,7 @@ pub struct CommentView {
|
||||||
/// A local user view.
|
/// A local user view.
|
||||||
pub struct LocalUserView {
|
pub struct LocalUserView {
|
||||||
pub local_user: LocalUser,
|
pub local_user: LocalUser,
|
||||||
|
pub local_user_vote_display_mode: LocalUserVoteDisplayMode,
|
||||||
pub person: Person,
|
pub person: Person,
|
||||||
pub counts: PersonAggregates,
|
pub counts: PersonAggregates,
|
||||||
}
|
}
|
||||||
|
@ -90,7 +97,15 @@ pub struct PostReportView {
|
||||||
pub creator: Person,
|
pub creator: Person,
|
||||||
pub post_creator: Person,
|
pub post_creator: Person,
|
||||||
pub creator_banned_from_community: bool,
|
pub creator_banned_from_community: bool,
|
||||||
|
pub creator_is_moderator: bool,
|
||||||
|
pub creator_is_admin: bool,
|
||||||
|
pub subscribed: SubscribedType,
|
||||||
|
pub saved: bool,
|
||||||
|
pub read: bool,
|
||||||
|
pub hidden: bool,
|
||||||
|
pub creator_blocked: bool,
|
||||||
pub my_vote: Option<i16>,
|
pub my_vote: Option<i16>,
|
||||||
|
pub unread_comments: i64,
|
||||||
pub counts: PostAggregates,
|
pub counts: PostAggregates,
|
||||||
pub resolver: Option<Person>,
|
pub resolver: Option<Person>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,7 +114,7 @@ async fn upload(
|
||||||
if let Some(images) = &images.files {
|
if let Some(images) = &images.files {
|
||||||
for uploaded_image in images {
|
for uploaded_image in images {
|
||||||
let form = LocalImageForm {
|
let form = LocalImageForm {
|
||||||
local_user_id: local_user_view.local_user.id,
|
local_user_id: Some(local_user_view.local_user.id),
|
||||||
pictrs_alias: uploaded_image.file.to_string(),
|
pictrs_alias: uploaded_image.file.to_string(),
|
||||||
pictrs_delete_token: uploaded_image.delete_token.to_string(),
|
pictrs_delete_token: uploaded_image.delete_token.to_string(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use activitypub_federation::{
|
use activitypub_federation::{
|
||||||
config::Data,
|
config::Data,
|
||||||
fetch::webfinger::{extract_webfinger_name, Webfinger, WebfingerLink},
|
fetch::webfinger::{extract_webfinger_name, Webfinger, WebfingerLink, WEBFINGER_CONTENT_TYPE},
|
||||||
};
|
};
|
||||||
use actix_web::{web, web::Query, HttpResponse};
|
use actix_web::{web, web::Query, HttpResponse};
|
||||||
use lemmy_api_common::context::LemmyContext;
|
use lemmy_api_common::context::LemmyContext;
|
||||||
|
@ -38,6 +38,12 @@ async fn get_webfinger_response(
|
||||||
) -> Result<HttpResponse, LemmyError> {
|
) -> Result<HttpResponse, LemmyError> {
|
||||||
let name = extract_webfinger_name(&info.resource, &context)?;
|
let name = extract_webfinger_name(&info.resource, &context)?;
|
||||||
|
|
||||||
|
let links = if name == context.settings().hostname {
|
||||||
|
// webfinger response for instance actor (required for mastodon authorized fetch)
|
||||||
|
let url = Url::parse(&context.settings().get_protocol_and_hostname())?;
|
||||||
|
vec![webfinger_link_for_actor(Some(url), "none", &context)]
|
||||||
|
} else {
|
||||||
|
// webfinger response for user/community
|
||||||
let user_id: Option<Url> = Person::read_from_name(&mut context.pool(), name, false)
|
let user_id: Option<Url> = Person::read_from_name(&mut context.pool(), name, false)
|
||||||
.await
|
.await
|
||||||
.ok()
|
.ok()
|
||||||
|
@ -56,21 +62,30 @@ async fn get_webfinger_response(
|
||||||
|
|
||||||
// Mastodon seems to prioritize the last webfinger item in case of duplicates. Put
|
// Mastodon seems to prioritize the last webfinger item in case of duplicates. Put
|
||||||
// community last so that it gets prioritized. For Lemmy the order doesnt matter.
|
// community last so that it gets prioritized. For Lemmy the order doesnt matter.
|
||||||
let links = vec![
|
vec![
|
||||||
webfinger_link_for_actor(user_id, "Person", &context),
|
webfinger_link_for_actor(user_id, "Person", &context),
|
||||||
webfinger_link_for_actor(community_id, "Group", &context),
|
webfinger_link_for_actor(community_id, "Group", &context),
|
||||||
]
|
]
|
||||||
|
}
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flatten()
|
.flatten()
|
||||||
.collect();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
if links.is_empty() {
|
||||||
|
Ok(HttpResponse::NotFound().finish())
|
||||||
|
} else {
|
||||||
let json = Webfinger {
|
let json = Webfinger {
|
||||||
subject: info.resource.clone(),
|
subject: info.resource.clone(),
|
||||||
links,
|
links,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(json))
|
Ok(
|
||||||
|
HttpResponse::Ok()
|
||||||
|
.content_type(&WEBFINGER_CONTENT_TYPE)
|
||||||
|
.json(json),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn webfinger_link_for_actor(
|
fn webfinger_link_for_actor(
|
||||||
|
|
|
@ -212,7 +212,7 @@ impl<C: Default> RateLimitedGroup<C> {
|
||||||
now: InstantSecs,
|
now: InstantSecs,
|
||||||
config: BucketConfig,
|
config: BucketConfig,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
#[allow(clippy::indexing_slicing)] // `EnumMap` has no `get` funciton
|
#[allow(clippy::indexing_slicing)] // `EnumMap` has no `get` function
|
||||||
let bucket = &mut self.total[action_type];
|
let bucket = &mut self.total[action_type];
|
||||||
|
|
||||||
let new_bucket = bucket.update(now, config);
|
let new_bucket = bucket.update(now, config);
|
||||||
|
|
|
@ -204,7 +204,7 @@ pub fn site_description_length_check(description: &str) -> LemmyResult<()> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check minumum and maximum length of input string. If the string is too short or too long, the
|
/// Check minimum and maximum length of input string. If the string is too short or too long, the
|
||||||
/// corresponding error is returned.
|
/// corresponding error is returned.
|
||||||
///
|
///
|
||||||
/// HTML frontends specify maximum input length using `maxlength` attribute.
|
/// HTML frontends specify maximum input length using `maxlength` attribute.
|
||||||
|
|
|
@ -75,18 +75,19 @@ RUN --mount=type=cache,target=./target,uid=10001,gid=10001 set -ex; \
|
||||||
mv "./target/$CARGO_BUILD_TARGET/$RUST_RELEASE_MODE/lemmy_server" /home/lemmy/lemmy_server; \
|
mv "./target/$CARGO_BUILD_TARGET/$RUST_RELEASE_MODE/lemmy_server" /home/lemmy/lemmy_server; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
# amd64 base runner
|
# amd64 base runner
|
||||||
FROM ${AMD_RUNNER_IMAGE} AS runner-linux-amd64
|
FROM ${AMD_RUNNER_IMAGE} AS runner-linux-amd64
|
||||||
|
|
||||||
# Federation needs CA certificates
|
# Add system packages that are needed: federation needs CA certificates, curl can be used for healthchecks
|
||||||
RUN apt update && apt install -y libssl-dev libpq-dev ca-certificates
|
RUN apt update && apt install -y libssl-dev libpq-dev ca-certificates curl
|
||||||
|
|
||||||
COPY --from=build-amd64 --chmod=0755 /lemmy/lemmy_server /usr/local/bin
|
COPY --from=build-amd64 --chmod=0755 /lemmy/lemmy_server /usr/local/bin
|
||||||
|
|
||||||
# arm base runner
|
# arm base runner
|
||||||
FROM ${ARM_RUNNER_IMAGE} AS runner-linux-arm64
|
FROM ${ARM_RUNNER_IMAGE} AS runner-linux-arm64
|
||||||
|
|
||||||
RUN apt update && apt install -y ca-certificates libssl-dev libpq-dev
|
RUN apt update && apt install -y libssl-dev libpq-dev ca-certificates curl
|
||||||
|
|
||||||
COPY --from=build-arm64 --chmod=0755 /home/lemmy/lemmy_server /usr/local/bin
|
COPY --from=build-arm64 --chmod=0755 /home/lemmy/lemmy_server /usr/local/bin
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
DROP TABLE local_user_vote_display_mode;
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
-- Create an extra table to hold local user vote display settings
|
||||||
|
-- Score and Upvote percentage are turned on by default.
|
||||||
|
CREATE TABLE local_user_vote_display_mode (
|
||||||
|
local_user_id int REFERENCES local_user ON UPDATE CASCADE ON DELETE CASCADE NOT NULL,
|
||||||
|
score boolean DEFAULT TRUE NOT NULL,
|
||||||
|
upvotes boolean DEFAULT FALSE NOT NULL,
|
||||||
|
downvotes boolean DEFAULT FALSE NOT NULL,
|
||||||
|
upvote_percentage boolean DEFAULT TRUE NOT NULL,
|
||||||
|
PRIMARY KEY (local_user_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Insert rows for every local user
|
||||||
|
INSERT INTO local_user_vote_display_mode (local_user_id)
|
||||||
|
SELECT
|
||||||
|
id
|
||||||
|
FROM
|
||||||
|
local_user;
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
ALTER TABLE local_image
|
||||||
|
ALTER COLUMN local_user_id SET NOT NULL;
|
||||||
|
|
3
migrations/2024-03-06-104706_local_image_user_opt/up.sql
Normal file
3
migrations/2024-03-06-104706_local_image_user_opt/up.sql
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
ALTER TABLE local_image
|
||||||
|
ALTER COLUMN local_user_id DROP NOT NULL;
|
||||||
|
|
Loading…
Reference in a new issue