Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f0ca7ccde8 | |||
| 7fd1fe6d52 | |||
| 54c6d21fc5 | |||
| c031804464 | |||
| 5289fe872a |
Generated
+155
@@ -1308,6 +1308,40 @@ name = "lazycell"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lber"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nom 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ldap3"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lber 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nom 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-tls 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-uds 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-uds-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lettre"
|
||||
version = "0.9.0"
|
||||
@@ -1642,6 +1676,11 @@ name = "nodrop"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "4.2.3"
|
||||
@@ -1879,6 +1918,7 @@ dependencies = [
|
||||
"askama_escape 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"atom_syndication 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ctrlc 3.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"diesel 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -1993,6 +2033,7 @@ dependencies = [
|
||||
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ldap3 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"migrations_internals 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"openssl 0.10.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"plume-api 0.3.0",
|
||||
@@ -2581,6 +2622,11 @@ dependencies = [
|
||||
"variance 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scoped-tls"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "0.1.2"
|
||||
@@ -2694,11 +2740,21 @@ name = "siphasher"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "0.6.9"
|
||||
@@ -2879,6 +2935,11 @@ dependencies = [
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "take"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "tantivy"
|
||||
version = "0.9.1"
|
||||
@@ -3050,6 +3111,24 @@ dependencies = [
|
||||
"tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-core"
|
||||
version = "0.1.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-current-thread"
|
||||
version = "0.1.6"
|
||||
@@ -3088,6 +3167,23 @@ dependencies = [
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-proto"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-reactor"
|
||||
version = "0.1.9"
|
||||
@@ -3106,6 +3202,14 @@ dependencies = [
|
||||
"tokio-sync 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-service"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-sync"
|
||||
version = "0.1.5"
|
||||
@@ -3155,6 +3259,16 @@ dependencies = [
|
||||
"tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-tls"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-trace-core"
|
||||
version = "0.2.0"
|
||||
@@ -3177,6 +3291,22 @@ dependencies = [
|
||||
"tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-uds"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-uds"
|
||||
version = "0.2.5"
|
||||
@@ -3194,6 +3324,18 @@ dependencies = [
|
||||
"tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-uds-proto"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"futures 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-uds 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.4.10"
|
||||
@@ -3658,6 +3800,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
|
||||
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
|
||||
"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
|
||||
"checksum lber 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aa172a35dd26774593b503d085735a189e322d16a2049b2739eb7f914b141b36"
|
||||
"checksum ldap3 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dae98945f9023ddb484ec9cd9faffddabf18174e1f08bab360848a36ab4f8a80"
|
||||
"checksum lettre 0.9.0 (git+https://github.com/lettre/lettre?rev=c988b1760ad8179d9e7f3fb8594d2b86cf2a0a49)" = "<none>"
|
||||
"checksum lettre_email 0.9.0 (git+https://github.com/lettre/lettre?rev=c988b1760ad8179d9e7f3fb8594d2b86cf2a0a49)" = "<none>"
|
||||
"checksum levenshtein_automata 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73a004f877f468548d8d0ac4977456a249d8fabbdb8416c36db163dfc8f2e8ca"
|
||||
@@ -3693,6 +3837,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum new_debug_unreachable 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f40f005c60db6e03bae699e414c58bf9aa7ea02a2d0b9bfbcf19286cc4c82b30"
|
||||
"checksum nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce"
|
||||
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
|
||||
"checksum nom 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf51a729ecf40266a2368ad335a5fdde43471f545a967109cd62146ecf8b66ff"
|
||||
"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
|
||||
"checksum notify 4.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "ceb1a496a81dd6125f68ce772b41b83efe89a54d21768ed6d0c33c95832604e6"
|
||||
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
|
||||
@@ -3780,6 +3925,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum schannel 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f6abf258d99c3c1c5c2131d99d064e94b7b3dd5f416483057f308fea253339"
|
||||
"checksum scheduled-thread-pool 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a2ff3fc5223829be817806c6441279c676e454cc7da608faf03b0ccc09d3889"
|
||||
"checksum scoped-pool 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "817a3a15e704545ce59ed2b5c60a5d32bda4d7869befb8b36667b658a6c00b43"
|
||||
"checksum scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28"
|
||||
"checksum scopeguard 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "59a076157c1e2dc561d8de585151ee6965d910dd4dcb5dabb7ae3e83981a6c57"
|
||||
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
|
||||
"checksum security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eee63d0f4a9ec776eeb30e220f0bc1e092c3ad744b2a379e3993070364d3adc2"
|
||||
@@ -3794,7 +3940,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
|
||||
"checksum shrinkwraprs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7d5f047b90b2ca2d1526ff73d67cba61f86f4cf9a8afddc99dd96702ded8e684"
|
||||
"checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac"
|
||||
"checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23"
|
||||
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||
"checksum smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c8cbcd6df1e117c2210e13ab5109635ad68a929fcbb8964dc965b76cb5ee013"
|
||||
"checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be"
|
||||
"checksum snap 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "95d697d63d44ad8b78b8d235bf85b34022a78af292c8918527c5f0cffdde7f43"
|
||||
"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
|
||||
@@ -3815,6 +3963,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)" = "a1393e4a97a19c01e900df2aec855a29f71cf02c402e2f443b8d2747c25c5dbe"
|
||||
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
|
||||
"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f"
|
||||
"checksum take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b157868d8ac1f56b64604539990685fa7611d8fa9e5476cf0c02cf34d32917c5"
|
||||
"checksum tantivy 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "67a63475a55950ad47573f881d912b8fab7f1f53a9cc2e036185efc92b471402"
|
||||
"checksum tantivy-fst 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "16b22af5ff09b8897093287642a5aaee6f30eb496526ef83a8dd0f4c636ac367"
|
||||
"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
|
||||
@@ -3827,18 +3976,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum tokio 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "ec2ffcf4bcfc641413fa0f1427bf8f91dfc78f56a6559cbf50e04837ae442a87"
|
||||
"checksum tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46"
|
||||
"checksum tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f"
|
||||
"checksum tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71"
|
||||
"checksum tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d16217cad7f1b840c5a97dfb3c43b0c871fef423a6e8d2118c604e843662a443"
|
||||
"checksum tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "83ea44c6c0773cc034771693711c35c677b4b5a4b21b9e7071704c54de7d555e"
|
||||
"checksum tokio-fs 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe6dc22b08d6993916647d108a1a7d15b9cd29c4f4496c62b92c45b5041b7af"
|
||||
"checksum tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5090db468dad16e1a7a54c8c67280c5e4b544f3d3e018f0b913b400261f85926"
|
||||
"checksum tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fbb47ae81353c63c487030659494b295f6cb6576242f907f203473b191b0389"
|
||||
"checksum tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6af16bfac7e112bea8b0442542161bfc41cbfa4466b580bdda7d18cb88b911ce"
|
||||
"checksum tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162"
|
||||
"checksum tokio-sync 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "5b2f843ffdf8d6e1f90bddd48da43f99ab071660cd92b7ec560ef3cdfd7a409a"
|
||||
"checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119"
|
||||
"checksum tokio-threadpool 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72558af20be886ea124595ea0f806dd5703b8958e4705429dd58b3d8231f72f2"
|
||||
"checksum tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f2106812d500ed25a4f38235b9cae8f78a09edf43203e16e59c3b769a342a60e"
|
||||
"checksum tokio-tls 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "354b8cd83825b3c20217a9dc174d6a0c67441a2fae5c41bcb1ea6679f6ae0f7c"
|
||||
"checksum tokio-trace-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9c8a256d6956f7cb5e2bdfe8b1e8022f1a09206c6c2b1ba00f3b746b260c613"
|
||||
"checksum tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "66268575b80f4a4a710ef83d087fdfeeabdce9b74c797535fbac18a2cb906e92"
|
||||
"checksum tokio-uds 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "65ae5d255ce739e8537221ed2942e0445f4b3b813daebac1c0050ddaaa3587f9"
|
||||
"checksum tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "037ffc3ba0e12a0ab4aca92e5234e0dedeb48fddf6ccd260f1f150a36a9f2445"
|
||||
"checksum tokio-uds-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "93842f83f760d2a48eb54225f819d05549e69c481f56be4a1b1f51decf99da5b"
|
||||
"checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f"
|
||||
"checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079"
|
||||
"checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382"
|
||||
|
||||
@@ -8,6 +8,7 @@ repository = "https://github.com/Plume-org/Plume"
|
||||
activitypub = "0.1.3"
|
||||
askama_escape = "0.1"
|
||||
atom_syndication = "0.6"
|
||||
clap = "2.33"
|
||||
colored = "1.8"
|
||||
dotenv = "0.14"
|
||||
gettext = { git = "https://github.com/Plume-org/gettext/", rev = "294c54d74c699fbc66502b480a37cc66c1daa7f3" }
|
||||
|
||||
@@ -25,7 +25,11 @@ fn main() {
|
||||
.subcommand(users::command());
|
||||
let matches = app.clone().get_matches();
|
||||
|
||||
dotenv::dotenv().ok();
|
||||
match dotenv::dotenv() {
|
||||
Ok(path) => println!("Configuration read from {}", path.display()),
|
||||
Err(ref e) if e.not_found() => eprintln!("no .env was found"),
|
||||
e => e.map(|_| ()).unwrap(),
|
||||
}
|
||||
let conn = Conn::establish(CONFIG.database_url.as_str());
|
||||
let _ = conn.as_ref().map(|conn| Instance::cache_local(conn));
|
||||
|
||||
|
||||
+2
-10
@@ -109,16 +109,8 @@ fn new<'a>(args: &ArgMatches<'a>, conn: &Connection) {
|
||||
rpassword::read_password().expect("Couldn't read your password.")
|
||||
});
|
||||
|
||||
NewUser::new_local(
|
||||
conn,
|
||||
username,
|
||||
display_name,
|
||||
admin,
|
||||
&bio,
|
||||
email,
|
||||
User::hash_pass(&password).expect("Couldn't hash password"),
|
||||
)
|
||||
.expect("Couldn't save new user");
|
||||
NewUser::new_local(conn, username, display_name, admin, &bio, email, &password)
|
||||
.expect("Couldn't save new user");
|
||||
}
|
||||
|
||||
fn reset_password<'a>(args: &ArgMatches<'a>, conn: &Connection) {
|
||||
|
||||
@@ -12,6 +12,7 @@ guid-create = "0.1"
|
||||
heck = "0.3.0"
|
||||
itertools = "0.8.0"
|
||||
lazy_static = "*"
|
||||
ldap3 = "0.6.1"
|
||||
migrations_internals= "1.4.0"
|
||||
openssl = "0.10.22"
|
||||
rocket = "0.4.0"
|
||||
|
||||
@@ -14,6 +14,7 @@ pub struct Config {
|
||||
pub search_index: String,
|
||||
pub rocket: Result<RocketConfig, RocketError>,
|
||||
pub logo: LogoConfig,
|
||||
pub ldap: LdapConfig,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -184,6 +185,27 @@ impl Default for LogoConfig {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct LdapConfig {
|
||||
pub url: Option<String>,
|
||||
pub bind_dn: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for LdapConfig {
|
||||
fn default() -> Self {
|
||||
let url = var("LDAP_URL").ok();
|
||||
let bind_dn = var("LDAP_BIND_DN").ok();
|
||||
if url.is_some() ^ bind_dn.is_some() {
|
||||
panic!(
|
||||
r#"Invalid configuration :
|
||||
You must provide both LDAP_URL and LDAP_BIND_DN, or neither"#
|
||||
);
|
||||
} else {
|
||||
LdapConfig { url, bind_dn }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref CONFIG: Config = Config {
|
||||
base_url: var("BASE_URL").unwrap_or_else(|_| format!(
|
||||
@@ -199,5 +221,6 @@ lazy_static! {
|
||||
search_index: var("SEARCH_INDEX").unwrap_or_else(|_| "search_index".to_owned()),
|
||||
rocket: get_rocket_config(),
|
||||
logo: LogoConfig::default(),
|
||||
ldap: LdapConfig::default(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
use crate::CONFIG;
|
||||
use ldap3::LdapConn;
|
||||
use std::io;
|
||||
use std::sync::{mpsc, Mutex};
|
||||
use std::thread;
|
||||
|
||||
type Message = (String, String, mpsc::Sender<io::Result<bool>>);
|
||||
pub struct Ldap {
|
||||
channel: mpsc::Sender<Message>,
|
||||
}
|
||||
|
||||
impl Ldap {
|
||||
pub fn get_shared() -> Self {
|
||||
Ldap {
|
||||
channel: CHANNEL.lock().unwrap().clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn connect(&self, username: String, password: String) -> LdapResult {
|
||||
let (s, r) = mpsc::channel();
|
||||
self.channel.send((username, password, s)).unwrap(); //we know the remote end was not closed
|
||||
LdapResult { channel: r }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LdapResult {
|
||||
channel: mpsc::Receiver<io::Result<bool>>,
|
||||
}
|
||||
|
||||
impl LdapResult {
|
||||
pub fn get(self) -> io::Result<bool> {
|
||||
self.channel.recv().unwrap() //we know some message must have been send, be it an error
|
||||
}
|
||||
}
|
||||
|
||||
/// This function loop indefinitelly, handling requests
|
||||
fn handle(url: &str, bind_dn: &str, channel: mpsc::Receiver<Message>) {
|
||||
let mut conn = LdapConn::new(url).expect("Error connecting to ldap server");
|
||||
for (user, password, channel) in channel.iter() {
|
||||
let res = conn
|
||||
.simple_bind(&format!("uid={},{}", user, bind_dn), &password)
|
||||
.map(|r| r.rc == 0);
|
||||
let err = res.is_err();
|
||||
channel.send(res).ok(); //we can't assume the other end did not drop it's handle
|
||||
let err = conn.unbind().is_err() || err;
|
||||
if err {
|
||||
if let Ok(c) = LdapConn::new(url) {
|
||||
conn = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn ignore(channel: mpsc::Receiver<Message>) {
|
||||
for (_user, _password, channel) in channel.iter() {
|
||||
channel.send(Ok(false)).ok();
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref CHANNEL: Mutex<mpsc::Sender<Message>> = {
|
||||
let (s, r) = mpsc::channel();
|
||||
|
||||
let builder = thread::Builder::new().name("ldap_handler".into());
|
||||
builder
|
||||
.spawn(move || {
|
||||
if CONFIG.ldap.url.is_some() && CONFIG.ldap.bind_dn.is_some() {
|
||||
handle(
|
||||
CONFIG.ldap.url.as_ref().unwrap(),
|
||||
CONFIG.ldap.bind_dn.as_ref().unwrap(),
|
||||
r,
|
||||
)
|
||||
} else {
|
||||
ignore(r);
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
Mutex::new(s)
|
||||
};
|
||||
}
|
||||
@@ -15,6 +15,7 @@ extern crate heck;
|
||||
extern crate itertools;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
extern crate ldap3;
|
||||
extern crate migrations_internals;
|
||||
extern crate openssl;
|
||||
extern crate plume_api;
|
||||
@@ -363,6 +364,7 @@ pub mod follows;
|
||||
pub mod headers;
|
||||
pub mod inbox;
|
||||
pub mod instance;
|
||||
pub mod ldap;
|
||||
pub mod likes;
|
||||
pub mod medias;
|
||||
pub mod mentions;
|
||||
|
||||
@@ -41,6 +41,7 @@ use blogs::Blog;
|
||||
use db_conn::DbConn;
|
||||
use follows::Follow;
|
||||
use instance::*;
|
||||
use ldap::Ldap;
|
||||
use medias::Media;
|
||||
use post_authors::PostAuthor;
|
||||
use posts::Post;
|
||||
@@ -333,17 +334,41 @@ impl User {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn hash_pass(pass: &str) -> Result<String> {
|
||||
fn hash_pass(pass: &str) -> Result<String> {
|
||||
bcrypt::hash(pass, 10).map_err(Error::from)
|
||||
}
|
||||
|
||||
pub fn auth(&self, pass: &str) -> bool {
|
||||
fn auth(&self, pass: &str) -> bool {
|
||||
self.hashed_password
|
||||
.clone()
|
||||
.map(|hashed| bcrypt::verify(pass, hashed.as_ref()).unwrap_or(false))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn connect(rocket: &PlumeRocket, name: &str, password: &str) -> Result<Self> {
|
||||
let user = User::find_by_email(&*rocket.conn, &name)
|
||||
.or_else(|_| User::find_by_fqn(&rocket, &name));
|
||||
match user {
|
||||
Ok(user) => {
|
||||
let ldap_conn = Ldap::get_shared().connect(name.to_owned(), password.to_owned());
|
||||
let local_conn = user.auth(password);
|
||||
let ldap_conn = ldap_conn.get().unwrap_or(false);
|
||||
if ldap_conn && local_conn {
|
||||
user.clear_password(&rocket.conn).ok();
|
||||
}
|
||||
if ldap_conn || local_conn {
|
||||
Ok(user)
|
||||
} else {
|
||||
Err(Error::NotFound)
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
User::get(&rocket.conn, 1)?.auth(password);
|
||||
Err(Error::NotFound)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset_password(&self, conn: &Connection, pass: &str) -> Result<()> {
|
||||
diesel::update(self)
|
||||
.set(users::hashed_password.eq(User::hash_pass(pass)?))
|
||||
@@ -351,6 +376,13 @@ impl User {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn clear_password(&self, conn: &Connection) -> Result<()> {
|
||||
diesel::update(self)
|
||||
.set(users::hashed_password.eq::<Option<String>>(None))
|
||||
.execute(conn)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_local_page(conn: &Connection, (min, max): (i32, i32)) -> Result<Vec<User>> {
|
||||
users::table
|
||||
.filter(users::instance_id.eq(Instance::get_local()?.id))
|
||||
@@ -923,7 +955,7 @@ impl NewUser {
|
||||
is_admin: bool,
|
||||
summary: &str,
|
||||
email: String,
|
||||
password: String,
|
||||
password: &str,
|
||||
) -> Result<User> {
|
||||
let (pub_key, priv_key) = gen_keypair();
|
||||
User::insert(
|
||||
@@ -935,7 +967,7 @@ impl NewUser {
|
||||
summary: summary.to_owned(),
|
||||
summary_html: SafeString::new(&utils::md_to_html(&summary, None, false, None).0),
|
||||
email: Some(email),
|
||||
hashed_password: Some(password),
|
||||
hashed_password: Some(User::hash_pass(password)?),
|
||||
instance_id: Instance::get_local()?.id,
|
||||
ap_url: String::new(),
|
||||
public_key: String::from_utf8(pub_key).or(Err(Error::Signature))?,
|
||||
@@ -964,7 +996,7 @@ pub(crate) mod tests {
|
||||
true,
|
||||
"Hello there, I'm the admin",
|
||||
"admin@example.com".to_owned(),
|
||||
"invalid_admin_password".to_owned(),
|
||||
"invalid_admin_password",
|
||||
)
|
||||
.unwrap();
|
||||
let user = NewUser::new_local(
|
||||
@@ -974,7 +1006,7 @@ pub(crate) mod tests {
|
||||
false,
|
||||
"Hello there, I'm no one",
|
||||
"user@example.com".to_owned(),
|
||||
"invalid_user_password".to_owned(),
|
||||
"invalid_user_password",
|
||||
)
|
||||
.unwrap();
|
||||
let other = NewUser::new_local(
|
||||
@@ -984,7 +1016,7 @@ pub(crate) mod tests {
|
||||
false,
|
||||
"Hello there, I'm someone else",
|
||||
"other@example.com".to_owned(),
|
||||
"invalid_other_password".to_owned(),
|
||||
"invalid_other_password",
|
||||
)
|
||||
.unwrap();
|
||||
vec![admin, user, other]
|
||||
@@ -1003,7 +1035,7 @@ pub(crate) mod tests {
|
||||
false,
|
||||
"Hello I'm a test",
|
||||
"test@example.com".to_owned(),
|
||||
User::hash_pass("test_password").unwrap(),
|
||||
"test_password",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -1109,7 +1141,7 @@ pub(crate) mod tests {
|
||||
false,
|
||||
"Hello I'm a test",
|
||||
"test@example.com".to_owned(),
|
||||
User::hash_pass("test_password").unwrap(),
|
||||
"test_password",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
||||
+468
-498
File diff suppressed because it is too large
Load Diff
+434
-461
File diff suppressed because it is too large
Load Diff
+446
-476
File diff suppressed because it is too large
Load Diff
+468
-498
File diff suppressed because it is too large
Load Diff
+472
-502
File diff suppressed because it is too large
Load Diff
+411
-438
File diff suppressed because it is too large
Load Diff
+416
-443
File diff suppressed because it is too large
Load Diff
+466
-496
File diff suppressed because it is too large
Load Diff
+486
-516
File diff suppressed because it is too large
Load Diff
+471
-501
File diff suppressed because it is too large
Load Diff
+447
-474
File diff suppressed because it is too large
Load Diff
+436
-463
File diff suppressed because it is too large
Load Diff
+465
-495
File diff suppressed because it is too large
Load Diff
+475
-505
File diff suppressed because it is too large
Load Diff
+488
-518
File diff suppressed because it is too large
Load Diff
+467
-497
File diff suppressed because it is too large
Load Diff
+397
-417
@@ -73,11 +73,11 @@ msgid "Your blog information have been updated."
|
||||
msgstr ""
|
||||
|
||||
# src/routes/comments.rs:97
|
||||
msgid "Your comment has been posted."
|
||||
msgid "Your comment have been posted."
|
||||
msgstr ""
|
||||
|
||||
# src/routes/comments.rs:172
|
||||
msgid "Your comment has been deleted."
|
||||
msgid "Your comment have been deleted."
|
||||
msgstr ""
|
||||
|
||||
# src/routes/instance.rs:134
|
||||
@@ -109,7 +109,7 @@ msgid "You are not allowed to delete this media."
|
||||
msgstr ""
|
||||
|
||||
# src/routes/medias.rs:163
|
||||
msgid "Your avatar has been updated."
|
||||
msgid "Your avatar have been updated."
|
||||
msgstr ""
|
||||
|
||||
# src/routes/medias.rs:168
|
||||
@@ -145,15 +145,11 @@ msgid "You are not allowed to publish on this blog."
|
||||
msgstr ""
|
||||
|
||||
# src/routes/posts.rs:350
|
||||
msgid "Your article has been updated."
|
||||
msgid "Your article have been updated."
|
||||
msgstr ""
|
||||
|
||||
# src/routes/posts.rs:532
|
||||
msgid "Your article has been saved."
|
||||
msgstr ""
|
||||
|
||||
# src/routes/posts.rs:538
|
||||
msgid "New article"
|
||||
msgid "Your post have been saved."
|
||||
msgstr ""
|
||||
|
||||
# src/routes/posts.rs:572
|
||||
@@ -161,7 +157,7 @@ msgid "You are not allowed to delete this article."
|
||||
msgstr ""
|
||||
|
||||
# src/routes/posts.rs:597
|
||||
msgid "Your article has been deleted."
|
||||
msgid "Your article have been deleted."
|
||||
msgstr ""
|
||||
|
||||
# src/routes/posts.rs:602
|
||||
@@ -212,152 +208,328 @@ msgstr ""
|
||||
msgid "You are now following {}."
|
||||
msgstr ""
|
||||
|
||||
# src/routes/user.rs:254
|
||||
# src/routes/user.rs:255
|
||||
msgid "To subscribe to someone, you need to be logged in"
|
||||
msgstr ""
|
||||
|
||||
# src/routes/user.rs:356
|
||||
# src/routes/user.rs:357
|
||||
msgid "To edit your profile, you need to be logged in"
|
||||
msgstr ""
|
||||
|
||||
# src/routes/user.rs:398
|
||||
msgid "Your profile has been updated."
|
||||
# src/routes/user.rs:399
|
||||
msgid "Your profile have been updated."
|
||||
msgstr ""
|
||||
|
||||
# src/routes/user.rs:425
|
||||
msgid "Your account has been deleted."
|
||||
# src/routes/user.rs:426
|
||||
msgid "Your account have been deleted."
|
||||
msgstr ""
|
||||
|
||||
# src/routes/user.rs:431
|
||||
# src/routes/user.rs:432
|
||||
msgid "You can't delete someone else's account."
|
||||
msgstr ""
|
||||
|
||||
# src/routes/user.rs:503
|
||||
# src/routes/user.rs:504
|
||||
msgid "Registrations are closed on this instance."
|
||||
msgstr ""
|
||||
|
||||
# src/routes/user.rs:527
|
||||
msgid "Your account has been created. Now you just need to log in, before you can use it."
|
||||
# src/routes/user.rs:528
|
||||
msgid "Your account have been created. You just need to login before you can use it."
|
||||
msgstr ""
|
||||
|
||||
msgid "Internal server error"
|
||||
msgid "Plume"
|
||||
msgstr ""
|
||||
|
||||
msgid "Something broke on our side."
|
||||
msgid "Menu"
|
||||
msgstr ""
|
||||
|
||||
msgid "Sorry about that. If you think this is a bug, please report it."
|
||||
msgid "Search"
|
||||
msgstr ""
|
||||
|
||||
msgid "You are not authorized."
|
||||
msgid "Dashboard"
|
||||
msgstr ""
|
||||
|
||||
msgid "Page not found"
|
||||
msgid "Notifications"
|
||||
msgstr ""
|
||||
|
||||
msgid "We couldn't find this page."
|
||||
msgid "Log Out"
|
||||
msgstr ""
|
||||
|
||||
msgid "The link that led you here may be broken."
|
||||
msgid "My account"
|
||||
msgstr ""
|
||||
|
||||
msgid "The content you sent can't be processed."
|
||||
msgid "Log In"
|
||||
msgstr ""
|
||||
|
||||
msgid "Maybe it was too long."
|
||||
msgid "Register"
|
||||
msgstr ""
|
||||
|
||||
msgid "Invalid CSRF token"
|
||||
msgid "About this instance"
|
||||
msgstr ""
|
||||
|
||||
msgid "Something is wrong with your CSRF token. Make sure cookies are enabled in you browser, and try reloading this page. If you continue to see this error message, please report it."
|
||||
msgid "Source code"
|
||||
msgstr ""
|
||||
|
||||
msgid "Articles tagged \"{0}\""
|
||||
msgid "Matrix room"
|
||||
msgstr ""
|
||||
|
||||
msgid "There are currently no articles with such a tag"
|
||||
msgid "Administration"
|
||||
msgstr ""
|
||||
|
||||
msgid "New Blog"
|
||||
msgid "Welcome to {}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Create a blog"
|
||||
msgid "Latest articles"
|
||||
msgstr ""
|
||||
|
||||
msgid "Your feed"
|
||||
msgstr ""
|
||||
|
||||
msgid "Federated feed"
|
||||
msgstr ""
|
||||
|
||||
msgid "Local feed"
|
||||
msgstr ""
|
||||
|
||||
msgid "Administration of {0}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Instances"
|
||||
msgstr ""
|
||||
|
||||
msgid "Configuration"
|
||||
msgstr ""
|
||||
|
||||
msgid "Users"
|
||||
msgstr ""
|
||||
|
||||
msgid "Unblock"
|
||||
msgstr ""
|
||||
|
||||
msgid "Block"
|
||||
msgstr ""
|
||||
|
||||
msgid "Ban"
|
||||
msgstr ""
|
||||
|
||||
msgid "All the articles of the Fediverse"
|
||||
msgstr ""
|
||||
|
||||
msgid "Articles from {}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Nothing to see here yet. Try subscribing to more people."
|
||||
msgstr ""
|
||||
|
||||
# src/template_utils.rs:251
|
||||
msgid "Title"
|
||||
msgid "Name"
|
||||
msgstr ""
|
||||
|
||||
# src/template_utils.rs:254
|
||||
msgid "Optional"
|
||||
msgstr ""
|
||||
|
||||
msgid "Create blog"
|
||||
msgid "Allow anyone to register here"
|
||||
msgstr ""
|
||||
|
||||
msgid "Edit \"{}\""
|
||||
msgstr ""
|
||||
|
||||
msgid "Description"
|
||||
msgid "Short description"
|
||||
msgstr ""
|
||||
|
||||
msgid "Markdown syntax is supported"
|
||||
msgstr ""
|
||||
|
||||
msgid "You can upload images to your gallery, to use them as blog icons, or banners."
|
||||
msgid "Long description"
|
||||
msgstr ""
|
||||
|
||||
msgid "Upload images"
|
||||
# src/template_utils.rs:251
|
||||
msgid "Default article license"
|
||||
msgstr ""
|
||||
|
||||
msgid "Blog icon"
|
||||
msgid "Save these settings"
|
||||
msgstr ""
|
||||
|
||||
msgid "Blog banner"
|
||||
msgid "About {0}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Update blog"
|
||||
msgid "Home to <em>{0}</em> people"
|
||||
msgstr ""
|
||||
|
||||
msgid "Who wrote <em>{0}</em> articles"
|
||||
msgstr ""
|
||||
|
||||
msgid "And are connected to <em>{0}</em> other instances"
|
||||
msgstr ""
|
||||
|
||||
msgid "Administred by"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runs Plume {0}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Follow {}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Log in to follow"
|
||||
msgstr ""
|
||||
|
||||
msgid "Enter your full username handle to follow"
|
||||
msgstr ""
|
||||
|
||||
msgid "Edit your account"
|
||||
msgstr ""
|
||||
|
||||
msgid "Your Profile"
|
||||
msgstr ""
|
||||
|
||||
msgid "To change your avatar, upload it to your gallery and then select from there."
|
||||
msgstr ""
|
||||
|
||||
msgid "Upload an avatar"
|
||||
msgstr ""
|
||||
|
||||
# src/template_utils.rs:251
|
||||
msgid "Display name"
|
||||
msgstr ""
|
||||
|
||||
# src/template_utils.rs:251
|
||||
msgid "Email"
|
||||
msgstr ""
|
||||
|
||||
msgid "Summary"
|
||||
msgstr ""
|
||||
|
||||
msgid "Update account"
|
||||
msgstr ""
|
||||
|
||||
msgid "Danger zone"
|
||||
msgstr ""
|
||||
|
||||
msgid "Be very careful, any action taken here can't be reversed."
|
||||
msgid "Be very careful, any action taken here can't be cancelled."
|
||||
msgstr ""
|
||||
|
||||
msgid "Permanently delete this blog"
|
||||
msgid "Delete your account"
|
||||
msgstr ""
|
||||
|
||||
msgid "{}'s icon"
|
||||
msgid "Sorry, but as an admin, you can't leave your own instance."
|
||||
msgstr ""
|
||||
|
||||
msgid "Edit"
|
||||
msgid "Your Dashboard"
|
||||
msgstr ""
|
||||
|
||||
msgid "There's one author on this blog: "
|
||||
msgid_plural "There are {0} authors on this blog: "
|
||||
msgstr[0] ""
|
||||
|
||||
msgid "Latest articles"
|
||||
msgid "Your Blogs"
|
||||
msgstr ""
|
||||
|
||||
msgid "No posts to see here yet."
|
||||
msgid "You don't have any blog yet. Create your own, or ask to join one."
|
||||
msgstr ""
|
||||
|
||||
msgid "Search result(s) for \"{0}\""
|
||||
msgid "Start a new blog"
|
||||
msgstr ""
|
||||
|
||||
msgid "Search result(s)"
|
||||
msgid "Your Drafts"
|
||||
msgstr ""
|
||||
|
||||
msgid "No results for your query"
|
||||
msgid "Your media"
|
||||
msgstr ""
|
||||
|
||||
msgid "No more results for your query"
|
||||
msgid "Go to your gallery"
|
||||
msgstr ""
|
||||
|
||||
msgid "Search"
|
||||
msgid "Create your account"
|
||||
msgstr ""
|
||||
|
||||
msgid "Create an account"
|
||||
msgstr ""
|
||||
|
||||
# src/template_utils.rs:251
|
||||
msgid "Username"
|
||||
msgstr ""
|
||||
|
||||
# src/template_utils.rs:251
|
||||
msgid "Password"
|
||||
msgstr ""
|
||||
|
||||
# src/template_utils.rs:251
|
||||
msgid "Password confirmation"
|
||||
msgstr ""
|
||||
|
||||
msgid "Apologies, but registrations are closed on this particular instance. You can, however, find a different one."
|
||||
msgstr ""
|
||||
|
||||
msgid "Articles"
|
||||
msgstr ""
|
||||
|
||||
msgid "Subscribers"
|
||||
msgstr ""
|
||||
|
||||
msgid "Subscriptions"
|
||||
msgstr ""
|
||||
|
||||
msgid "Atom feed"
|
||||
msgstr ""
|
||||
|
||||
msgid "Recently boosted"
|
||||
msgstr ""
|
||||
|
||||
msgid "Admin"
|
||||
msgstr ""
|
||||
|
||||
msgid "It is you"
|
||||
msgstr ""
|
||||
|
||||
msgid "Edit your profile"
|
||||
msgstr ""
|
||||
|
||||
msgid "Open on {0}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Unsubscribe"
|
||||
msgstr ""
|
||||
|
||||
msgid "Subscribe"
|
||||
msgstr ""
|
||||
|
||||
msgid "{0}'s subscriptions"
|
||||
msgstr ""
|
||||
|
||||
msgid "{0}'s subscribers"
|
||||
msgstr ""
|
||||
|
||||
msgid "Respond"
|
||||
msgstr ""
|
||||
|
||||
msgid "Are you sure?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Delete this comment"
|
||||
msgstr ""
|
||||
|
||||
msgid "What is Plume?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Plume is a decentralized blogging engine."
|
||||
msgstr ""
|
||||
|
||||
msgid "Authors can manage multiple blogs, each as its own website."
|
||||
msgstr ""
|
||||
|
||||
msgid "Articles are also visible on other Plume instances, and you can interact with them directly from other platforms like Mastodon."
|
||||
msgstr ""
|
||||
|
||||
msgid "Read the detailed rules"
|
||||
msgstr ""
|
||||
|
||||
msgid "None"
|
||||
msgstr ""
|
||||
|
||||
msgid "No description"
|
||||
msgstr ""
|
||||
|
||||
msgid "View all"
|
||||
msgstr ""
|
||||
|
||||
msgid "By {0}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Draft"
|
||||
msgstr ""
|
||||
|
||||
msgid "Your query"
|
||||
@@ -370,6 +542,9 @@ msgstr ""
|
||||
msgid "Article title matching these words"
|
||||
msgstr ""
|
||||
|
||||
msgid "Title"
|
||||
msgstr ""
|
||||
|
||||
# src/template_utils.rs:339
|
||||
msgid "Subtitle matching these words"
|
||||
msgstr ""
|
||||
@@ -434,6 +609,52 @@ msgstr ""
|
||||
msgid "Article license"
|
||||
msgstr ""
|
||||
|
||||
msgid "Search result(s) for \"{0}\""
|
||||
msgstr ""
|
||||
|
||||
msgid "Search result(s)"
|
||||
msgstr ""
|
||||
|
||||
msgid "No results for your query"
|
||||
msgstr ""
|
||||
|
||||
msgid "No more results for your query"
|
||||
msgstr ""
|
||||
|
||||
msgid "Reset your password"
|
||||
msgstr ""
|
||||
|
||||
# src/template_utils.rs:251
|
||||
msgid "New password"
|
||||
msgstr ""
|
||||
|
||||
# src/template_utils.rs:251
|
||||
msgid "Confirmation"
|
||||
msgstr ""
|
||||
|
||||
msgid "Update password"
|
||||
msgstr ""
|
||||
|
||||
msgid "Check your inbox!"
|
||||
msgstr ""
|
||||
|
||||
msgid "We sent a mail to the address you gave us, with a link to reset your password."
|
||||
msgstr ""
|
||||
|
||||
# src/template_utils.rs:251
|
||||
msgid "E-mail"
|
||||
msgstr ""
|
||||
|
||||
msgid "Send password reset link"
|
||||
msgstr ""
|
||||
|
||||
msgid "Log in"
|
||||
msgstr ""
|
||||
|
||||
# src/template_utils.rs:251
|
||||
msgid "Username, or email"
|
||||
msgstr ""
|
||||
|
||||
msgid "Interact with {}"
|
||||
msgstr ""
|
||||
|
||||
@@ -492,6 +713,12 @@ msgstr ""
|
||||
msgid "Written by {0}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Edit"
|
||||
msgstr ""
|
||||
|
||||
msgid "Delete this article"
|
||||
msgstr ""
|
||||
|
||||
msgid "All rights reserved."
|
||||
msgstr ""
|
||||
|
||||
@@ -521,12 +748,6 @@ msgstr ""
|
||||
msgid "{0}Log in{1}, or {2}use your Fediverse account{3} to interact with this article"
|
||||
msgstr ""
|
||||
|
||||
msgid "Unsubscribe"
|
||||
msgstr ""
|
||||
|
||||
msgid "Subscribe"
|
||||
msgstr ""
|
||||
|
||||
msgid "Comments"
|
||||
msgstr ""
|
||||
|
||||
@@ -543,16 +764,120 @@ msgstr ""
|
||||
msgid "No comments yet. Be the first to react!"
|
||||
msgstr ""
|
||||
|
||||
msgid "Are you sure?"
|
||||
msgid "Invalid CSRF token"
|
||||
msgstr ""
|
||||
|
||||
msgid "Something is wrong with your CSRF token. Make sure cookies are enabled in you browser, and try reloading this page. If you continue to see this error message, please report it."
|
||||
msgstr ""
|
||||
|
||||
msgid "Page not found"
|
||||
msgstr ""
|
||||
|
||||
msgid "We couldn't find this page."
|
||||
msgstr ""
|
||||
|
||||
msgid "The link that led you here may be broken."
|
||||
msgstr ""
|
||||
|
||||
msgid "The content you sent can't be processed."
|
||||
msgstr ""
|
||||
|
||||
msgid "Maybe it was too long."
|
||||
msgstr ""
|
||||
|
||||
msgid "You are not authorized."
|
||||
msgstr ""
|
||||
|
||||
msgid "Internal server error"
|
||||
msgstr ""
|
||||
|
||||
msgid "Something broke on our side."
|
||||
msgstr ""
|
||||
|
||||
msgid "Sorry about that. If you think this is a bug, please report it."
|
||||
msgstr ""
|
||||
|
||||
msgid "Edit \"{}\""
|
||||
msgstr ""
|
||||
|
||||
msgid "Description"
|
||||
msgstr ""
|
||||
|
||||
msgid "You can upload images to your gallery, to use them as blog icons, or banners."
|
||||
msgstr ""
|
||||
|
||||
msgid "Upload images"
|
||||
msgstr ""
|
||||
|
||||
msgid "Blog icon"
|
||||
msgstr ""
|
||||
|
||||
msgid "Blog banner"
|
||||
msgstr ""
|
||||
|
||||
msgid "Update blog"
|
||||
msgstr ""
|
||||
|
||||
msgid "Be very careful, any action taken here can't be reversed."
|
||||
msgstr ""
|
||||
|
||||
msgid "Permanently delete this blog"
|
||||
msgstr ""
|
||||
|
||||
msgid "New Blog"
|
||||
msgstr ""
|
||||
|
||||
msgid "Create a blog"
|
||||
msgstr ""
|
||||
|
||||
msgid "Create blog"
|
||||
msgstr ""
|
||||
|
||||
msgid "{}'s icon"
|
||||
msgstr ""
|
||||
|
||||
msgid "New article"
|
||||
msgstr ""
|
||||
|
||||
msgid "There's one author on this blog: "
|
||||
msgid_plural "There are {0} authors on this blog: "
|
||||
msgstr[0] ""
|
||||
|
||||
msgid "No posts to see here yet."
|
||||
msgstr ""
|
||||
|
||||
msgid "Articles tagged \"{0}\""
|
||||
msgstr ""
|
||||
|
||||
msgid "There are currently no articles with such a tag"
|
||||
msgstr ""
|
||||
|
||||
msgid "I'm from this instance"
|
||||
msgstr ""
|
||||
|
||||
msgid "I'm from another instance"
|
||||
msgstr ""
|
||||
|
||||
# src/template_utils.rs:259
|
||||
msgid "Example: user@plu.me"
|
||||
msgstr ""
|
||||
|
||||
msgid "Continue to your instance"
|
||||
msgstr ""
|
||||
|
||||
msgid "Upload"
|
||||
msgstr ""
|
||||
|
||||
msgid "You don't have any media yet."
|
||||
msgstr ""
|
||||
|
||||
msgid "Content warning: {0}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Delete"
|
||||
msgstr ""
|
||||
|
||||
msgid "This article is still a draft. Only you and other authors can see it."
|
||||
msgstr ""
|
||||
|
||||
msgid "Only you and other authors can edit this article."
|
||||
msgid "Details"
|
||||
msgstr ""
|
||||
|
||||
msgid "Media upload"
|
||||
@@ -570,21 +895,6 @@ msgstr ""
|
||||
msgid "Send"
|
||||
msgstr ""
|
||||
|
||||
msgid "Your media"
|
||||
msgstr ""
|
||||
|
||||
msgid "Upload"
|
||||
msgstr ""
|
||||
|
||||
msgid "You don't have any media yet."
|
||||
msgstr ""
|
||||
|
||||
msgid "Content warning: {0}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Details"
|
||||
msgstr ""
|
||||
|
||||
msgid "Media details"
|
||||
msgstr ""
|
||||
|
||||
@@ -599,333 +909,3 @@ msgstr ""
|
||||
|
||||
msgid "Use as an avatar"
|
||||
msgstr ""
|
||||
|
||||
msgid "Notifications"
|
||||
msgstr ""
|
||||
|
||||
msgid "Plume"
|
||||
msgstr ""
|
||||
|
||||
msgid "Menu"
|
||||
msgstr ""
|
||||
|
||||
msgid "Dashboard"
|
||||
msgstr ""
|
||||
|
||||
msgid "Log Out"
|
||||
msgstr ""
|
||||
|
||||
msgid "My account"
|
||||
msgstr ""
|
||||
|
||||
msgid "Log In"
|
||||
msgstr ""
|
||||
|
||||
msgid "Register"
|
||||
msgstr ""
|
||||
|
||||
msgid "About this instance"
|
||||
msgstr ""
|
||||
|
||||
msgid "Privacy policy"
|
||||
msgstr ""
|
||||
|
||||
msgid "Administration"
|
||||
msgstr ""
|
||||
|
||||
msgid "Documentation"
|
||||
msgstr ""
|
||||
|
||||
msgid "Source code"
|
||||
msgstr ""
|
||||
|
||||
msgid "Matrix room"
|
||||
msgstr ""
|
||||
|
||||
msgid "Your feed"
|
||||
msgstr ""
|
||||
|
||||
msgid "Federated feed"
|
||||
msgstr ""
|
||||
|
||||
msgid "Local feed"
|
||||
msgstr ""
|
||||
|
||||
msgid "Nothing to see here yet. Try subscribing to more people."
|
||||
msgstr ""
|
||||
|
||||
msgid "Articles from {}"
|
||||
msgstr ""
|
||||
|
||||
msgid "All the articles of the Fediverse"
|
||||
msgstr ""
|
||||
|
||||
msgid "Users"
|
||||
msgstr ""
|
||||
|
||||
msgid "Configuration"
|
||||
msgstr ""
|
||||
|
||||
msgid "Instances"
|
||||
msgstr ""
|
||||
|
||||
msgid "Ban"
|
||||
msgstr ""
|
||||
|
||||
msgid "Administration of {0}"
|
||||
msgstr ""
|
||||
|
||||
# src/template_utils.rs:251
|
||||
msgid "Name"
|
||||
msgstr ""
|
||||
|
||||
msgid "Allow anyone to register here"
|
||||
msgstr ""
|
||||
|
||||
msgid "Short description"
|
||||
msgstr ""
|
||||
|
||||
msgid "Long description"
|
||||
msgstr ""
|
||||
|
||||
# src/template_utils.rs:251
|
||||
msgid "Default article license"
|
||||
msgstr ""
|
||||
|
||||
msgid "Save these settings"
|
||||
msgstr ""
|
||||
|
||||
msgid "About {0}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Runs Plume {0}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Home to <em>{0}</em> people"
|
||||
msgstr ""
|
||||
|
||||
msgid "Who wrote <em>{0}</em> articles"
|
||||
msgstr ""
|
||||
|
||||
msgid "And are connected to <em>{0}</em> other instances"
|
||||
msgstr ""
|
||||
|
||||
msgid "Administred by"
|
||||
msgstr ""
|
||||
|
||||
msgid "If you are browsing this site as a visitor, no data about you is collected."
|
||||
msgstr ""
|
||||
|
||||
msgid "As a registered user, you have to provide your username (which does not have to be your real name), your functional email address and a password, in order to be able to log in, write articles and comment. The content you submit is stored until you delete it."
|
||||
msgstr ""
|
||||
|
||||
msgid "When you log in, we store two cookies, one to keep your session open, the second to prevent other people to act on your behalf. We don't store any other cookies."
|
||||
msgstr ""
|
||||
|
||||
msgid "Welcome to {}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Unblock"
|
||||
msgstr ""
|
||||
|
||||
msgid "Block"
|
||||
msgstr ""
|
||||
|
||||
msgid "Reset your password"
|
||||
msgstr ""
|
||||
|
||||
# src/template_utils.rs:251
|
||||
msgid "New password"
|
||||
msgstr ""
|
||||
|
||||
# src/template_utils.rs:251
|
||||
msgid "Confirmation"
|
||||
msgstr ""
|
||||
|
||||
msgid "Update password"
|
||||
msgstr ""
|
||||
|
||||
msgid "Log in"
|
||||
msgstr ""
|
||||
|
||||
# src/template_utils.rs:251
|
||||
msgid "Username, or email"
|
||||
msgstr ""
|
||||
|
||||
# src/template_utils.rs:251
|
||||
msgid "Password"
|
||||
msgstr ""
|
||||
|
||||
# src/template_utils.rs:251
|
||||
msgid "E-mail"
|
||||
msgstr ""
|
||||
|
||||
msgid "Send password reset link"
|
||||
msgstr ""
|
||||
|
||||
msgid "Check your inbox!"
|
||||
msgstr ""
|
||||
|
||||
msgid "We sent a mail to the address you gave us, with a link to reset your password."
|
||||
msgstr ""
|
||||
|
||||
msgid "Admin"
|
||||
msgstr ""
|
||||
|
||||
msgid "It is you"
|
||||
msgstr ""
|
||||
|
||||
msgid "Edit your profile"
|
||||
msgstr ""
|
||||
|
||||
msgid "Open on {0}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Follow {}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Log in to follow"
|
||||
msgstr ""
|
||||
|
||||
msgid "Enter your full username handle to follow"
|
||||
msgstr ""
|
||||
|
||||
msgid "{0}'s subscriptions"
|
||||
msgstr ""
|
||||
|
||||
msgid "Articles"
|
||||
msgstr ""
|
||||
|
||||
msgid "Subscribers"
|
||||
msgstr ""
|
||||
|
||||
msgid "Subscriptions"
|
||||
msgstr ""
|
||||
|
||||
msgid "Create your account"
|
||||
msgstr ""
|
||||
|
||||
msgid "Create an account"
|
||||
msgstr ""
|
||||
|
||||
# src/template_utils.rs:251
|
||||
msgid "Username"
|
||||
msgstr ""
|
||||
|
||||
# src/template_utils.rs:251
|
||||
msgid "Email"
|
||||
msgstr ""
|
||||
|
||||
# src/template_utils.rs:251
|
||||
msgid "Password confirmation"
|
||||
msgstr ""
|
||||
|
||||
msgid "Apologies, but registrations are closed on this particular instance. You can, however, find a different one."
|
||||
msgstr ""
|
||||
|
||||
msgid "{0}'s subscribers"
|
||||
msgstr ""
|
||||
|
||||
msgid "Edit your account"
|
||||
msgstr ""
|
||||
|
||||
msgid "Your Profile"
|
||||
msgstr ""
|
||||
|
||||
msgid "To change your avatar, upload it to your gallery and then select from there."
|
||||
msgstr ""
|
||||
|
||||
msgid "Upload an avatar"
|
||||
msgstr ""
|
||||
|
||||
# src/template_utils.rs:251
|
||||
msgid "Display name"
|
||||
msgstr ""
|
||||
|
||||
msgid "Summary"
|
||||
msgstr ""
|
||||
|
||||
msgid "Update account"
|
||||
msgstr ""
|
||||
|
||||
msgid "Be very careful, any action taken here can't be cancelled."
|
||||
msgstr ""
|
||||
|
||||
msgid "Delete your account"
|
||||
msgstr ""
|
||||
|
||||
msgid "Sorry, but as an admin, you can't leave your own instance."
|
||||
msgstr ""
|
||||
|
||||
msgid "Your Dashboard"
|
||||
msgstr ""
|
||||
|
||||
msgid "Your Blogs"
|
||||
msgstr ""
|
||||
|
||||
msgid "You don't have any blog yet. Create your own, or ask to join one."
|
||||
msgstr ""
|
||||
|
||||
msgid "Start a new blog"
|
||||
msgstr ""
|
||||
|
||||
msgid "Your Drafts"
|
||||
msgstr ""
|
||||
|
||||
msgid "Go to your gallery"
|
||||
msgstr ""
|
||||
|
||||
msgid "Atom feed"
|
||||
msgstr ""
|
||||
|
||||
msgid "Recently boosted"
|
||||
msgstr ""
|
||||
|
||||
msgid "What is Plume?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Plume is a decentralized blogging engine."
|
||||
msgstr ""
|
||||
|
||||
msgid "Authors can manage multiple blogs, each as its own website."
|
||||
msgstr ""
|
||||
|
||||
msgid "Articles are also visible on other Plume instances, and you can interact with them directly from other platforms like Mastodon."
|
||||
msgstr ""
|
||||
|
||||
msgid "Read the detailed rules"
|
||||
msgstr ""
|
||||
|
||||
msgid "View all"
|
||||
msgstr ""
|
||||
|
||||
msgid "None"
|
||||
msgstr ""
|
||||
|
||||
msgid "No description"
|
||||
msgstr ""
|
||||
|
||||
msgid "By {0}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Draft"
|
||||
msgstr ""
|
||||
|
||||
msgid "Respond"
|
||||
msgstr ""
|
||||
|
||||
msgid "Delete this comment"
|
||||
msgstr ""
|
||||
|
||||
msgid "I'm from this instance"
|
||||
msgstr ""
|
||||
|
||||
msgid "I'm from another instance"
|
||||
msgstr ""
|
||||
|
||||
# src/template_utils.rs:259
|
||||
msgid "Example: user@plu.me"
|
||||
msgstr ""
|
||||
|
||||
msgid "Continue to your instance"
|
||||
msgstr ""
|
||||
|
||||
+462
-492
File diff suppressed because it is too large
Load Diff
+436
-463
File diff suppressed because it is too large
Load Diff
+430
-460
File diff suppressed because it is too large
Load Diff
+469
-499
File diff suppressed because it is too large
Load Diff
+414
-441
File diff suppressed because it is too large
Load Diff
+411
-438
File diff suppressed because it is too large
Load Diff
+13
-23
@@ -62,30 +62,20 @@ pub fn oauth(
|
||||
let conn = &*rockets.conn;
|
||||
let app = App::find_by_client_id(conn, &query.client_id)?;
|
||||
if app.client_secret == query.client_secret {
|
||||
if let Ok(user) = User::find_by_fqn(&rockets, &query.username) {
|
||||
if user.auth(&query.password) {
|
||||
let token = ApiToken::insert(
|
||||
conn,
|
||||
NewApiToken {
|
||||
app_id: app.id,
|
||||
user_id: user.id,
|
||||
value: random_hex(),
|
||||
scopes: query.scopes.clone(),
|
||||
},
|
||||
)?;
|
||||
Ok(Json(json!({
|
||||
"token": token.value
|
||||
})))
|
||||
} else {
|
||||
Ok(Json(json!({
|
||||
"error": "Invalid credentials"
|
||||
})))
|
||||
}
|
||||
if let Ok(user) = User::connect(&rockets, &query.username, &query.password) {
|
||||
let token = ApiToken::insert(
|
||||
conn,
|
||||
NewApiToken {
|
||||
app_id: app.id,
|
||||
user_id: user.id,
|
||||
value: random_hex(),
|
||||
scopes: query.scopes.clone(),
|
||||
},
|
||||
)?;
|
||||
Ok(Json(json!({
|
||||
"token": token.value
|
||||
})))
|
||||
} else {
|
||||
// Making fake password verification to avoid different
|
||||
// response times that would make it possible to know
|
||||
// if a username is registered or not.
|
||||
User::get(conn, 1)?.auth(&query.password);
|
||||
Ok(Json(json!({
|
||||
"error": "Invalid credentials"
|
||||
})))
|
||||
|
||||
+22
-1
@@ -5,6 +5,7 @@ extern crate activitypub;
|
||||
extern crate askama_escape;
|
||||
extern crate atom_syndication;
|
||||
extern crate chrono;
|
||||
extern crate clap;
|
||||
extern crate colored;
|
||||
extern crate ctrlc;
|
||||
extern crate diesel;
|
||||
@@ -38,10 +39,12 @@ extern crate validator;
|
||||
extern crate validator_derive;
|
||||
extern crate webfinger;
|
||||
|
||||
use clap::App;
|
||||
use diesel::r2d2::ConnectionManager;
|
||||
use plume_models::{
|
||||
db_conn::{DbPool, PragmaForeignKey},
|
||||
instance::Instance,
|
||||
ldap::Ldap,
|
||||
migrations::IMPORTED_MIGRATIONS,
|
||||
search::{Searcher as UnmanagedSearcher, SearcherError},
|
||||
Connection, Error, CONFIG,
|
||||
@@ -73,8 +76,13 @@ compile_i18n!();
|
||||
|
||||
/// Initializes a database pool.
|
||||
fn init_pool() -> Option<DbPool> {
|
||||
dotenv::dotenv().ok();
|
||||
match dotenv::dotenv() {
|
||||
Ok(path) => println!("Configuration read from {}", path.display()),
|
||||
Err(ref e) if e.not_found() => eprintln!("no .env was found"),
|
||||
e => e.map(|_| ()).unwrap(),
|
||||
}
|
||||
|
||||
let _ = Ldap::get_shared(); // force initialization of lazy static
|
||||
let manager = ConnectionManager::<Connection>::new(CONFIG.database_url.as_str());
|
||||
let pool = DbPool::builder()
|
||||
.connection_customizer(Box::new(PragmaForeignKey))
|
||||
@@ -85,6 +93,19 @@ fn init_pool() -> Option<DbPool> {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
App::new("Plume")
|
||||
.bin_name("plume")
|
||||
.version(env!("CARGO_PKG_VERSION"))
|
||||
.about("Plume backend server")
|
||||
.after_help(
|
||||
r#"
|
||||
The plume command should be run inside the directory
|
||||
containing the `.env` configuration file and `static` directory.
|
||||
See https://docs.joinplu.me/installation/config
|
||||
and https://docs.joinplu.me/installation/init for more info.
|
||||
"#,
|
||||
)
|
||||
.get_matches();
|
||||
let dbpool = init_pool().expect("main: database pool initialization error");
|
||||
if IMPORTED_MIGRATIONS
|
||||
.is_pending(&dbpool.get().unwrap())
|
||||
|
||||
+7
-31
@@ -33,53 +33,29 @@ pub fn new(m: Option<String>, rockets: PlumeRocket) -> Ructe {
|
||||
))
|
||||
}
|
||||
|
||||
#[derive(Default, FromForm, Validate)]
|
||||
#[derive(Default, FromForm)]
|
||||
pub struct LoginForm {
|
||||
#[validate(length(min = "1", message = "We need an email, or a username to identify you"))]
|
||||
pub email_or_name: String,
|
||||
#[validate(length(min = "1", message = "Your password can't be empty"))]
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
#[post("/login", data = "<form>")]
|
||||
pub fn create(
|
||||
form: LenientForm<LoginForm>,
|
||||
mut cookies: Cookies,
|
||||
rockets: PlumeRocket,
|
||||
mut cookies: Cookies,
|
||||
) -> RespondOrRedirect {
|
||||
let conn = &*rockets.conn;
|
||||
let user = User::find_by_email(&*conn, &form.email_or_name)
|
||||
.or_else(|_| User::find_by_fqn(&rockets, &form.email_or_name));
|
||||
let mut errors = match form.validate() {
|
||||
Ok(_) => ValidationErrors::new(),
|
||||
Err(e) => e,
|
||||
};
|
||||
|
||||
let user_id = if let Ok(user) = user {
|
||||
if !user.auth(&form.password) {
|
||||
let mut err = ValidationError::new("invalid_login");
|
||||
err.message = Some(Cow::from("Invalid username, or password"));
|
||||
errors.add("email_or_name", err);
|
||||
String::new()
|
||||
} else {
|
||||
user.id.to_string()
|
||||
}
|
||||
let user_id = if let Ok(user) = User::connect(&rockets, &form.email_or_name, &form.password) {
|
||||
user.id.to_string()
|
||||
} else {
|
||||
// Fake password verification, only to avoid different login times
|
||||
// that could be used to see if an email adress is registered or not
|
||||
User::get(&*conn, 1)
|
||||
.map(|u| u.auth(&form.password))
|
||||
.expect("No user is registered");
|
||||
|
||||
let mut errors = ValidationErrors::new();
|
||||
let mut err = ValidationError::new("invalid_login");
|
||||
err.message = Some(Cow::from("Invalid username, or password"));
|
||||
errors.add("email_or_name", err);
|
||||
String::new()
|
||||
};
|
||||
|
||||
if !errors.is_empty() {
|
||||
return render!(session::login(&rockets.to_context(), None, &*form, errors)).into();
|
||||
}
|
||||
};
|
||||
|
||||
cookies.add_private(
|
||||
Cookie::build(AUTH_COOKIE, user_id)
|
||||
@@ -111,7 +87,7 @@ pub fn create(
|
||||
&(conn, &rockets.intl.catalog, None, None),
|
||||
None,
|
||||
&*form,
|
||||
errors
|
||||
ValidationErrors::new()
|
||||
))
|
||||
.into()
|
||||
}
|
||||
|
||||
+1
-1
@@ -520,7 +520,7 @@ pub fn create(
|
||||
false,
|
||||
"",
|
||||
form.email.to_string(),
|
||||
User::hash_pass(&form.password).map_err(to_validation)?,
|
||||
&form.password,
|
||||
)
|
||||
.map_err(to_validation)?;
|
||||
Ok(Flash::success(
|
||||
|
||||
@@ -146,7 +146,7 @@ pub fn avatar(
|
||||
pub fn tabs(links: &[(&str, String, bool)]) -> Html<String> {
|
||||
let mut res = String::from(r#"<div class="tabs">"#);
|
||||
for (url, title, selected) in links {
|
||||
res.push_str(r#"<a href=""#);
|
||||
res.push_str(r#"<a dir="auto" href=""#);
|
||||
res.push_str(url);
|
||||
if *selected {
|
||||
res.push_str(r#"" class="selected">"#);
|
||||
@@ -176,7 +176,7 @@ pub fn paginate_param(
|
||||
p
|
||||
})
|
||||
.unwrap_or_default();
|
||||
res.push_str(r#"<div class="pagination">"#);
|
||||
res.push_str(r#"<div class="pagination" dir="auto">"#);
|
||||
if page != 1 {
|
||||
res.push_str(
|
||||
format!(
|
||||
@@ -239,13 +239,13 @@ macro_rules! input {
|
||||
|
||||
Html(format!(
|
||||
r#"
|
||||
<label for="{name}">
|
||||
<label for="{name}" dir="auto">
|
||||
{label}
|
||||
{optional}
|
||||
{details}
|
||||
</label>
|
||||
{error}
|
||||
<input type="{kind}" id="{name}" name="{name}" value="{val}" {props}/>
|
||||
<input type="{kind}" id="{name}" name="{name}" value="{val}" {props} dir="auto"/>
|
||||
"#,
|
||||
name = stringify!($name),
|
||||
label = i18n!(cat, $label),
|
||||
@@ -264,7 +264,7 @@ macro_rules! input {
|
||||
$err.errors().get(stringify!($name))
|
||||
{
|
||||
format!(
|
||||
r#"<p class="error">{}</p>"#,
|
||||
r#"<p class="error" dir="auto">{}</p>"#,
|
||||
errs[0]
|
||||
.message
|
||||
.clone()
|
||||
@@ -332,8 +332,8 @@ macro_rules! input {
|
||||
let cat = $catalog;
|
||||
Html(format!(
|
||||
r#"
|
||||
<label for="{name}">{label}</label>
|
||||
<input type="{kind}" id="{name}" name="{name}" {props}/>
|
||||
<label for="{name}" dir="auto">{label}</label>
|
||||
<input type="{kind}" id="{name}" name="{name}" {props} dir="auto"/>
|
||||
"#,
|
||||
name = stringify!($name),
|
||||
label = i18n!(cat, $label),
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<link href='@Instance::get_local().unwrap().compute_box("~", &blog.fqn, "atom.xml")' rel='alternate' type='application/atom+xml'>
|
||||
<link href='@blog.ap_url' rel='alternate' type='application/activity+json'>
|
||||
}, {
|
||||
<a href="@uri!(blogs::details: name = &blog.fqn, page = _)">@blog.title</a>
|
||||
<a href="@uri!(blogs::details: name = &blog.fqn, page = _)" dir="auto">@blog.title</a>
|
||||
}, {
|
||||
<div class="hidden">
|
||||
@for author in authors {
|
||||
@@ -41,38 +41,38 @@
|
||||
}
|
||||
<div class="h-card">
|
||||
<div class="user">
|
||||
<div class="flex wrap">
|
||||
<div class="flex wrap" dir="auto">
|
||||
<div class="avatar medium" style="background-image: url('@blog.icon_url(ctx.0)');" aria-label="@i18n!(ctx.1, "{}'s icon"; &blog.title)"></div>
|
||||
<img class="hidden u-photo" src="@blog.icon_url(ctx.0)"/>
|
||||
|
||||
<h1 class="grow flex vertical">
|
||||
<span class="p-name">@blog.title</span>
|
||||
<small>~@blog.fqn</small>
|
||||
<small dir="auto">~@blog.fqn</small>
|
||||
</h1>
|
||||
|
||||
@if ctx.2.clone().and_then(|u| u.is_author_in(ctx.0, &blog).ok()).unwrap_or(false) {
|
||||
<a href="@uri!(posts::new: blog = &blog.fqn)" class="button">@i18n!(ctx.1, "New article")</a>
|
||||
<a href="@uri!(blogs::edit: name = &blog.fqn)" class="button">@i18n!(ctx.1, "Edit")</a>
|
||||
<a href="@uri!(posts::new: blog = &blog.fqn)" class="button" dir="auto">@i18n!(ctx.1, "New article")</a>
|
||||
<a href="@uri!(blogs::edit: name = &blog.fqn)" class="button" dir="auto">@i18n!(ctx.1, "Edit")</a>
|
||||
}
|
||||
</div>
|
||||
|
||||
<main class="user-summary">
|
||||
|
||||
<main class="user-summary" dir="auto">
|
||||
<p>
|
||||
@i18n!(ctx.1, "There's one author on this blog: ", "There are {0} authors on this blog: "; authors.len())
|
||||
@for (i, author) in authors.iter().enumerate() {@if i >= 1 {, }
|
||||
<a class="author p-author" href="@uri!(user::details: name = &author.fqn)">@author.name()</a>}
|
||||
<a class="author p-author" href="@uri!(user::details: name = &author.fqn)" dir="auto">@author.name()</a>}
|
||||
</p>
|
||||
@Html(blog.summary_html.clone())
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<section>
|
||||
<h2>
|
||||
<h2 dir="auto">
|
||||
@i18n!(ctx.1, "Latest articles")
|
||||
<small><a href="@uri!(blogs::atom_feed: name = &blog.fqn)" title="Atom feed">@icon!("rss")</a></small>
|
||||
</h2>
|
||||
@if posts.is_empty() {
|
||||
<p>@i18n!(ctx.1, "No posts to see here yet.")</p>
|
||||
<p dir="auto">@i18n!(ctx.1, "No posts to see here yet.")</p>
|
||||
}
|
||||
<div class="cards">
|
||||
@for article in posts {
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
@(ctx: BaseContext, form: &NewBlogForm, errors: ValidationErrors)
|
||||
|
||||
@:base(ctx, i18n!(ctx.1, "New Blog"), {}, {}, {
|
||||
<h1>@i18n!(ctx.1, "Create a blog")</h1>
|
||||
<h1 dir="auto">@i18n!(ctx.1, "Create a blog")</h1>
|
||||
<form method="post" action="@uri!(blogs::create)">
|
||||
@input!(ctx.1, title (text), "Title", form, errors, "required minlength=\"1\"")
|
||||
<input type="submit" value="@i18n!(ctx.1, "Create blog")"/>
|
||||
<input type="submit" value="@i18n!(ctx.1, "Create blog")" dir="auto"/>
|
||||
</form>
|
||||
})
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<div class="comment u-comment h-cite" id="comment-@comm.id">
|
||||
<main class="content">
|
||||
<header>
|
||||
<a class="author u-author h-card" href="@uri!(user::details: name = &author.fqn)">
|
||||
<a class="author u-author h-card" href="@uri!(user::details: name = &author.fqn)" dir="auto">
|
||||
@avatar(ctx.0, &author, Size::Small, true, ctx.1)
|
||||
<span class="display-name p-name">@author.name()</span>
|
||||
<small>@author.fqn</small>
|
||||
@@ -27,7 +27,7 @@
|
||||
<div class="text p-content">
|
||||
@if comm.sensitive {
|
||||
<details>
|
||||
<summary>@comm.spoiler_text</summary>
|
||||
<summary dir="auto">@comm.spoiler_text</summary>
|
||||
}
|
||||
@Html(&comm.content)
|
||||
@if comm.sensitive {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
@if !articles.is_empty() {
|
||||
<div class="h-feed">
|
||||
<h2><span class="p-name">@title</span> — <a href="@link">@i18n!(ctx.1, "View all")</a></h2>
|
||||
<h2 dir="auto"><span class="p-name">@title</span> — <a href="@link">@i18n!(ctx.1, "View all")</a></h2>
|
||||
<div class="cards">
|
||||
@for article in articles {
|
||||
@:post_card(ctx, article)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
@(ctx: BaseContext, id: &str, title: String, optional: bool, medias: Vec<Media>, selected: Option<i32>)
|
||||
|
||||
<label for="@id">
|
||||
<label for="@id" dir="auto">
|
||||
@title
|
||||
@if optional {
|
||||
<small>@i18n!(ctx.1, "Optional")</small>
|
||||
@@ -13,7 +13,7 @@
|
||||
<option value="none" @if selected.is_none() { selected }>@i18n!(ctx.1, "None")</option>
|
||||
@for media in medias {
|
||||
@if media.category() == MediaCategory::Image {
|
||||
<option value="@media.id" @if selected.map(|c| c == media.id).unwrap_or(false) { selected }>
|
||||
<option value="@media.id" @if selected.map(|c| c == media.id).unwrap_or(false) { selected } dir="auto">
|
||||
@if !media.alt_text.is_empty() {
|
||||
@media.alt_text
|
||||
} else {
|
||||
@@ -22,4 +22,4 @@
|
||||
</option>
|
||||
}
|
||||
}
|
||||
</select>
|
||||
</select>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
@(ctx: BaseContext, instance: Instance, n_users: i64, n_articles: i64)
|
||||
|
||||
<section class="split">
|
||||
<section class="split" dir="auto">
|
||||
<div class="presentation card">
|
||||
<h2>@i18n!(ctx.1, "What is Plume?")</h2>
|
||||
<main>
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
@if article.cover_id.is_some() {
|
||||
<div class="cover" style="background-image: url('@Html(article.cover_url(ctx.0).unwrap_or_default())')"></div>
|
||||
}
|
||||
<h3 class="p-name">
|
||||
<h3 class="p-name" dir="auto">
|
||||
<a class="u-url" href="@uri!(posts::details: blog = article.get_blog(ctx.0).unwrap().fqn, slug = &article.slug, responding_to = _)">
|
||||
@article.title
|
||||
</a>
|
||||
</h3>
|
||||
<main>
|
||||
<p class="p-summary">@article.subtitle</p>
|
||||
<p class="p-summary" dir="auto">@article.subtitle</p>
|
||||
</main>
|
||||
<footer class="authors">
|
||||
@Html(i18n!(ctx.1, "By {0}"; format!(
|
||||
|
||||
@@ -28,8 +28,8 @@
|
||||
@if article.cover_id.is_some() { style="background-image: url('@article.cover_url(ctx.0).unwrap_or_default()'" }
|
||||
>
|
||||
<div>
|
||||
<h1 class="article p-name">@article.title</h1>
|
||||
<div class="article-info">
|
||||
<h1 class="article p-name" dir="auto">@article.title</h1>
|
||||
<div class="article-info" dir="auto">
|
||||
<span class="author">
|
||||
@Html(i18n!(ctx.1, "Written by {0}"; format!("<a href=\"{}\">{}</a>",
|
||||
uri!(user::details: name = &author.fqn),
|
||||
@@ -38,7 +38,7 @@
|
||||
—
|
||||
<span class="date dt-published" datetime="@article.creation_date.format("%F %T")">@article.creation_date.format("%B %e, %Y")</span><a class="u-url" href="@article.ap_url"></a>
|
||||
</div>
|
||||
<h2 class="article p-summary">@article.subtitle</h2>
|
||||
<h2 class="article p-summary" dir="auto">@article.subtitle</h2>
|
||||
</div>
|
||||
@if article.cover_id.is_some() {
|
||||
<div class="shadow"></div>
|
||||
@@ -46,12 +46,12 @@
|
||||
}
|
||||
</header>
|
||||
|
||||
<article class="e-content">
|
||||
<article class="e-content" dir="auto">
|
||||
@Html(&article.content)
|
||||
</article>
|
||||
<div class="article-meta">
|
||||
<section class="split">
|
||||
<ul class="tags">
|
||||
<ul class="tags" dir="auto">
|
||||
@for tag in tags {
|
||||
@if !tag.is_hashtag {
|
||||
<li><a class="p-category" href="@uri!(tags::tag: name = &tag.tag, page = _)">@tag.tag</a></li>
|
||||
@@ -60,7 +60,7 @@
|
||||
}
|
||||
}
|
||||
</ul>
|
||||
<p class="right">
|
||||
<p class="right" dir="auto">
|
||||
@if article.license.is_empty() {
|
||||
@i18n!(ctx.1, "All rights reserved."; &article.license)
|
||||
} else {
|
||||
@@ -116,7 +116,7 @@
|
||||
</section>
|
||||
}
|
||||
<section class="banner">
|
||||
<div class="flex p-author h-card user">
|
||||
<div class="flex p-author h-card user" dir="auto">
|
||||
@avatar(ctx.0, &author, Size::Medium, true, ctx.1)
|
||||
<div class="grow">
|
||||
<h2 class="p-name">
|
||||
@@ -132,7 +132,7 @@
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
<section class="comments">
|
||||
<section class="comments" dir="auto">
|
||||
<h2>@i18n!(ctx.1, "Comments")</h2>
|
||||
|
||||
@if ctx.2.is_some() {
|
||||
@@ -143,7 +143,7 @@
|
||||
@if let Some(ref prev) = previous_comment {
|
||||
<input type="hidden" name="responding_to" value="@prev.id"/>
|
||||
}
|
||||
<textarea id="plume-editor" name="content">@comment_form.content</textarea>
|
||||
<textarea id="plume-editor" name="content" dir="auto">@comment_form.content</textarea>
|
||||
<input type="submit" value="@i18n!(ctx.1, "Submit comment")" />
|
||||
</form>
|
||||
}
|
||||
@@ -153,7 +153,7 @@
|
||||
@:comment(ctx, &comm, Some(&article.ap_url), &blog.fqn, &article.slug)
|
||||
}
|
||||
} else {
|
||||
<p class="center">@i18n!(ctx.1, "No comments yet. Be the first to react!")</p>
|
||||
<p class="center" dir="auto">@i18n!(ctx.1, "No comments yet. Be the first to react!")</p>
|
||||
}
|
||||
</section>
|
||||
</div>
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
@(ctx: BaseContext, title: String, blog: Blog, editing: bool, form: &NewPostForm, is_draft: bool, article: Option<Post>, errors: ValidationErrors, medias: Vec<Media>, content_len: u64)
|
||||
|
||||
@:base(ctx, title.clone(), {}, {}, {
|
||||
<h1 id="plume-editor-title">@title</h1>
|
||||
<div id="plume-editor" style="display: none;">
|
||||
<h1 id="plume-editor-title" dir="auto">@title</h1>
|
||||
<div id="plume-editor" style="display: none;" dir="auto">
|
||||
<header>
|
||||
<button id="publish" class="button">@i18n!(ctx.1, "Publish")</button>
|
||||
<p id="char-count">@content_len</p>
|
||||
@@ -32,10 +32,10 @@
|
||||
@format!(r#"<p class="error">{}</p>"#, errs[0].message.clone().unwrap_or_else(|| Cow::from("Unknown error")))
|
||||
}
|
||||
|
||||
<label for="editor-content">@i18n!(ctx.1, "Content")<small>@i18n!(ctx.1, "Markdown syntax is supported")</small></label>
|
||||
<textarea id="editor-content" name="content" rows="20">@Html(&form.content)</textarea>
|
||||
<small id="editor-left">@content_len</small>
|
||||
<p>
|
||||
<label for="editor-content" dir="auto">@i18n!(ctx.1, "Content")<small>@i18n!(ctx.1, "Markdown syntax is supported")</small></label>
|
||||
<textarea id="editor-content" name="content" rows="20" dir="auto">@Html(&form.content)</textarea>
|
||||
<small id="editor-left" dir="auto">@content_len</small>
|
||||
<p dir="auto">
|
||||
@i18n!(ctx.1, "You can upload media to your gallery, and then copy their Markdown code into your articles to insert them.")
|
||||
<a href="@uri!(medias::new)">@i18n!(ctx.1, "Upload media")</a>
|
||||
</p>
|
||||
@@ -47,7 +47,7 @@
|
||||
@:image_select(ctx, "cover", i18n!(ctx.1, "Illustration"), true, medias, form.cover)
|
||||
|
||||
@if is_draft {
|
||||
<label for="draft">
|
||||
<label for="draft" dir="auto">
|
||||
<input type="checkbox" name="draft" id="draft" checked>
|
||||
@i18n!(ctx.1, "This is a draft, don't publish it yet.")
|
||||
</label>
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
@(ctx: BaseContext, post: Post, login_form: LoginForm, login_errs: ValidationErrors, remote_form: RemoteForm, remote_errs: ValidationErrors)
|
||||
|
||||
@:remote_interact_base(ctx, i18n!(ctx.1, "Interact with {}"; post.title.clone()), i18n!(ctx.1, "Log in to interact"), i18n!(ctx.1, "Enter your full username to interact"), {
|
||||
<h1>@i18n!(ctx.1, "Interact with {}"; post.title.clone())</h1>
|
||||
<h1 dir="auto">@i18n!(ctx.1, "Interact with {}"; post.title.clone())</h1>
|
||||
@:post_card(ctx, post)
|
||||
}, login_form, login_errs, remote_form, remote_errs)
|
||||
|
||||
Reference in New Issue
Block a user