Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f0ca7ccde8 | |||
| 7fd1fe6d52 |
Generated
+176
-35
@@ -243,7 +243,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.1.0"
|
version = "1.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -370,7 +370,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -382,7 +382,7 @@ name = "cloudabi"
|
|||||||
version = "0.0.3"
|
version = "0.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -659,7 +659,7 @@ name = "devise_core"
|
|||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -670,7 +670,7 @@ name = "diesel"
|
|||||||
version = "1.4.2"
|
version = "1.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"diesel_derives 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"diesel_derives 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -923,7 +923,7 @@ name = "fsevent"
|
|||||||
version = "0.4.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"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -953,7 +953,7 @@ name = "fuchsia-zircon"
|
|||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1236,7 +1236,7 @@ name = "inotify"
|
|||||||
version = "0.6.1"
|
version = "0.6.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
@@ -1308,6 +1308,40 @@ name = "lazycell"
|
|||||||
version = "1.2.1"
|
version = "1.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "lettre"
|
name = "lettre"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
@@ -1630,7 +1664,7 @@ name = "nix"
|
|||||||
version = "0.14.1"
|
version = "0.14.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -1642,6 +1676,11 @@ name = "nodrop"
|
|||||||
version = "0.1.13"
|
version = "0.1.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "nom"
|
name = "nom"
|
||||||
version = "4.2.3"
|
version = "4.2.3"
|
||||||
@@ -1656,7 +1695,7 @@ name = "notify"
|
|||||||
version = "4.0.11"
|
version = "4.0.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"filetime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"filetime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"fsevent 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fsevent 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -1722,7 +1761,7 @@ name = "openssl"
|
|||||||
version = "0.10.22"
|
version = "0.10.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -1898,7 +1937,7 @@ dependencies = [
|
|||||||
"plume-models 0.3.0",
|
"plume-models 0.3.0",
|
||||||
"rocket 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rocket 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rocket_contrib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rocket_contrib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rocket_csrf 0.1.0 (git+https://github.com/Plume-org/rocket_csrf?rev=89ecb380266234f858c651354216bf5bf3cc09b2)",
|
"rocket_csrf 0.1.0 (git+https://github.com/fdb-hiroshima/rocket_csrf?rev=4a72ea2ec716cb0b26188fb00bccf2ef7d1e031c)",
|
||||||
"rocket_i18n 0.4.0 (git+https://github.com/Plume-org/rocket_i18n?rev=e922afa7c366038b3433278c03b1456b346074f2)",
|
"rocket_i18n 0.4.0 (git+https://github.com/Plume-org/rocket_i18n?rev=e922afa7c366038b3433278c03b1456b346074f2)",
|
||||||
"rpassword 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rpassword 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rsass 0.9.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rsass 0.9.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -1911,7 +1950,7 @@ dependencies = [
|
|||||||
"shrinkwraprs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"shrinkwraprs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"validator 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"validator 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"validator_derive 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"validator_derive 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"webfinger 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"webfinger 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1965,9 +2004,6 @@ dependencies = [
|
|||||||
"gettext-macros 0.4.0 (git+https://github.com/Plume-org/gettext-macros/?rev=a7c605f7edd6bfbfbfe7778026bfefd88d82db10)",
|
"gettext-macros 0.4.0 (git+https://github.com/Plume-org/gettext-macros/?rev=a7c605f7edd6bfbfbfe7778026bfefd88d82db10)",
|
||||||
"gettext-utils 0.1.0 (git+https://github.com/Plume-org/gettext-macros/?rev=a7c605f7edd6bfbfbfe7778026bfefd88d82db10)",
|
"gettext-utils 0.1.0 (git+https://github.com/Plume-org/gettext-macros/?rev=a7c605f7edd6bfbfbfe7778026bfefd88d82db10)",
|
||||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"plume-api 0.3.0",
|
|
||||||
"pulldown-cmark 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"stdweb 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"stdweb 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"stdweb-internal-runtime 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"stdweb-internal-runtime 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
@@ -1997,6 +2033,7 @@ dependencies = [
|
|||||||
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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)",
|
"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)",
|
"openssl 0.10.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"plume-api 0.3.0",
|
"plume-api 0.3.0",
|
||||||
@@ -2012,7 +2049,7 @@ dependencies = [
|
|||||||
"shrinkwraprs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"shrinkwraprs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"tantivy 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tantivy 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"webfinger 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"webfinger 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"whatlang 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"whatlang 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2083,17 +2120,7 @@ name = "pulldown-cmark"
|
|||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pulldown-cmark"
|
|
||||||
version = "0.5.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"unicase 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2449,7 +2476,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "rocket_csrf"
|
name = "rocket_csrf"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/Plume-org/rocket_csrf?rev=89ecb380266234f858c651354216bf5bf3cc09b2#89ecb380266234f858c651354216bf5bf3cc09b2"
|
source = "git+https://github.com/fdb-hiroshima/rocket_csrf?rev=4a72ea2ec716cb0b26188fb00bccf2ef7d1e031c#4a72ea2ec716cb0b26188fb00bccf2ef7d1e031c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -2595,6 +2622,11 @@ dependencies = [
|
|||||||
"variance 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
@@ -2697,7 +2729,7 @@ name = "shrinkwraprs"
|
|||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syn 0.12.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 0.12.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -2708,11 +2740,21 @@ name = "siphasher"
|
|||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "smallvec"
|
name = "smallvec"
|
||||||
version = "0.6.9"
|
version = "0.6.9"
|
||||||
@@ -2893,6 +2935,11 @@ dependencies = [
|
|||||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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]]
|
[[package]]
|
||||||
name = "tantivy"
|
name = "tantivy"
|
||||||
version = "0.9.1"
|
version = "0.9.1"
|
||||||
@@ -3064,6 +3111,24 @@ dependencies = [
|
|||||||
"tokio-io 0.1.12 (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-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]]
|
[[package]]
|
||||||
name = "tokio-current-thread"
|
name = "tokio-current-thread"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
@@ -3102,6 +3167,23 @@ dependencies = [
|
|||||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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]]
|
[[package]]
|
||||||
name = "tokio-reactor"
|
name = "tokio-reactor"
|
||||||
version = "0.1.9"
|
version = "0.1.9"
|
||||||
@@ -3120,6 +3202,14 @@ dependencies = [
|
|||||||
"tokio-sync 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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]]
|
[[package]]
|
||||||
name = "tokio-sync"
|
name = "tokio-sync"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
@@ -3169,6 +3259,16 @@ dependencies = [
|
|||||||
"tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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]]
|
[[package]]
|
||||||
name = "tokio-trace-core"
|
name = "tokio-trace-core"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@@ -3191,6 +3291,22 @@ dependencies = [
|
|||||||
"tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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]]
|
[[package]]
|
||||||
name = "tokio-uds"
|
name = "tokio-uds"
|
||||||
version = "0.2.5"
|
version = "0.2.5"
|
||||||
@@ -3208,6 +3324,18 @@ dependencies = [
|
|||||||
"tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.4.10"
|
version = "0.4.10"
|
||||||
@@ -3426,12 +3554,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "webfinger"
|
name = "webfinger"
|
||||||
version = "0.4.1"
|
version = "0.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"reqwest 0.9.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
"reqwest 0.9.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_derive 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_derive 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3547,7 +3676,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
"checksum bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e84c238982c4b1e1ee668d136c510c67a13465279c0cb367ea6baf6310620a80"
|
"checksum bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e84c238982c4b1e1ee668d136c510c67a13465279c0cb367ea6baf6310620a80"
|
||||||
"checksum bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f59bbe95d4e52a6398ec21238d31577f2b28a9d86807f06ca59d191d8440d0bb"
|
"checksum bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f59bbe95d4e52a6398ec21238d31577f2b28a9d86807f06ca59d191d8440d0bb"
|
||||||
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
|
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
|
||||||
"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
|
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
||||||
"checksum bitpacking 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "667f3f518358b2cf64891b46a6dd2eb794e9f80d39f7eb5974f4784bcda9a61b"
|
"checksum bitpacking 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "667f3f518358b2cf64891b46a6dd2eb794e9f80d39f7eb5974f4784bcda9a61b"
|
||||||
"checksum block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774"
|
"checksum block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774"
|
||||||
"checksum blowfish 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6aeb80d00f2688459b8542068abd974cfb101e7a82182414a99b5026c0d85cc3"
|
"checksum blowfish 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6aeb80d00f2688459b8542068abd974cfb101e7a82182414a99b5026c0d85cc3"
|
||||||
@@ -3671,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 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 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 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 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 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"
|
"checksum levenshtein_automata 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73a004f877f468548d8d0ac4977456a249d8fabbdb8416c36db163dfc8f2e8ca"
|
||||||
@@ -3706,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 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 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 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 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 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"
|
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
|
||||||
@@ -3741,7 +3873,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
|
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
|
||||||
"checksum publicsuffix 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5afecba86dcf1e4fd610246f89899d1924fe12e1e89f555eb7c7f710f3c5ad1d"
|
"checksum publicsuffix 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5afecba86dcf1e4fd610246f89899d1924fe12e1e89f555eb7c7f710f3c5ad1d"
|
||||||
"checksum pulldown-cmark 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eef52fac62d0ea7b9b4dc7da092aa64ea7ec3d90af6679422d3d7e0e14b6ee15"
|
"checksum pulldown-cmark 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eef52fac62d0ea7b9b4dc7da092aa64ea7ec3d90af6679422d3d7e0e14b6ee15"
|
||||||
"checksum pulldown-cmark 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "77043da1282374688ee212dc44b3f37ff929431de9c9adc3053bd3cee5630357"
|
|
||||||
"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
|
"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
|
||||||
"checksum quick-xml 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1d8065cbb01701c11cc195cde85cbf39d1c6a80705b67a157ebb3042e0e5777f"
|
"checksum quick-xml 0.12.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1d8065cbb01701c11cc195cde85cbf39d1c6a80705b67a157ebb3042e0e5777f"
|
||||||
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
|
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
|
||||||
@@ -3777,7 +3908,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
"checksum rocket 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "55b83fcf219c8b4980220231d5dd9eae167bdc63449fdab0a04b6c8b8cd361a8"
|
"checksum rocket 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "55b83fcf219c8b4980220231d5dd9eae167bdc63449fdab0a04b6c8b8cd361a8"
|
||||||
"checksum rocket_codegen 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5549dc59a729fbd0e6f5d5de33ba136340228871633485e4946664d36289ffd7"
|
"checksum rocket_codegen 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5549dc59a729fbd0e6f5d5de33ba136340228871633485e4946664d36289ffd7"
|
||||||
"checksum rocket_contrib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5af691b5f5c06c3a30213217696681d3d3bdc2f10428fa3ce6bbaeab156b6409"
|
"checksum rocket_contrib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5af691b5f5c06c3a30213217696681d3d3bdc2f10428fa3ce6bbaeab156b6409"
|
||||||
"checksum rocket_csrf 0.1.0 (git+https://github.com/Plume-org/rocket_csrf?rev=89ecb380266234f858c651354216bf5bf3cc09b2)" = "<none>"
|
"checksum rocket_csrf 0.1.0 (git+https://github.com/fdb-hiroshima/rocket_csrf?rev=4a72ea2ec716cb0b26188fb00bccf2ef7d1e031c)" = "<none>"
|
||||||
"checksum rocket_http 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "abec045da00893bd4eef6084307a4bec0742278a7635a6a8b943da023202a5f7"
|
"checksum rocket_http 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "abec045da00893bd4eef6084307a4bec0742278a7635a6a8b943da023202a5f7"
|
||||||
"checksum rocket_i18n 0.4.0 (git+https://github.com/Plume-org/rocket_i18n?rev=e922afa7c366038b3433278c03b1456b346074f2)" = "<none>"
|
"checksum rocket_i18n 0.4.0 (git+https://github.com/Plume-org/rocket_i18n?rev=e922afa7c366038b3433278c03b1456b346074f2)" = "<none>"
|
||||||
"checksum rpassword 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c34fa7bcae7fca3c8471e8417088bbc3ad9af8066b0ecf4f3c0d98a0d772716e"
|
"checksum rpassword 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c34fa7bcae7fca3c8471e8417088bbc3ad9af8066b0ecf4f3c0d98a0d772716e"
|
||||||
@@ -3794,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 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 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-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.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 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"
|
"checksum security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eee63d0f4a9ec776eeb30e220f0bc1e092c3ad744b2a379e3993070364d3adc2"
|
||||||
@@ -3808,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 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 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 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 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 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 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"
|
"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
|
||||||
@@ -3829,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 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 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 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 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 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"
|
"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
|
||||||
@@ -3841,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 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-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-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-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-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-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-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-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-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-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-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-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-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-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 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 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 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"
|
"checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382"
|
||||||
@@ -3884,7 +4025,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||||
"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1"
|
"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1"
|
||||||
"checksum want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "797464475f30ddb8830cc529aaaae648d581f99e2036a928877dfde027ddf6b3"
|
"checksum want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "797464475f30ddb8830cc529aaaae648d581f99e2036a928877dfde027ddf6b3"
|
||||||
"checksum webfinger 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ec24b1b0700d4b466d280228ed0f62274eedeaa80206820f071fdc8ed787b664"
|
"checksum webfinger 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "edc8f298f29f04bf5b6a85d7d448de4f16b7d45807d0a3ec422efcfbf1960519"
|
||||||
"checksum whatlang 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bf61042986b0f0612917b71609b861d695e76c55f9fc81b8a8f8cd363646816c"
|
"checksum whatlang 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bf61042986b0f0612917b71609b861d695e76c55f9fc81b8a8f8cd363646816c"
|
||||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||||
"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
|
"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
|
||||||
|
|||||||
+3
-3
@@ -31,7 +31,7 @@ serde_qs = "0.4"
|
|||||||
shrinkwraprs = "0.2.1"
|
shrinkwraprs = "0.2.1"
|
||||||
validator = "0.8"
|
validator = "0.8"
|
||||||
validator_derive = "0.8"
|
validator_derive = "0.8"
|
||||||
webfinger = "0.4.1"
|
webfinger = "0.3.1"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "plume"
|
name = "plume"
|
||||||
@@ -64,8 +64,8 @@ path = "plume-common"
|
|||||||
path = "plume-models"
|
path = "plume-models"
|
||||||
|
|
||||||
[dependencies.rocket_csrf]
|
[dependencies.rocket_csrf]
|
||||||
git = "https://github.com/Plume-org/rocket_csrf"
|
git = "https://github.com/fdb-hiroshima/rocket_csrf"
|
||||||
rev = "89ecb380266234f858c651354216bf5bf3cc09b2"
|
rev = "4a72ea2ec716cb0b26188fb00bccf2ef7d1e031c"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
ructe = "0.6.2"
|
ructe = "0.6.2"
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
-- This file should undo anything in `up.sql`
|
|
||||||
DELETE FROM apps WHERE name = 'Plume web interface';
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
-- Your SQL goes here
|
|
||||||
--#!|conn: &Connection, path: &Path| {
|
|
||||||
--#! use plume_common::utils::random_hex;
|
|
||||||
--#!
|
|
||||||
--#! let client_id = random_hex();
|
|
||||||
--#! let client_secret = random_hex();
|
|
||||||
--#! let app = crate::apps::App::insert(
|
|
||||||
--#! &*conn,
|
|
||||||
--#! crate::apps::NewApp {
|
|
||||||
--#! name: "Plume web interface".into(),
|
|
||||||
--#! client_id,
|
|
||||||
--#! client_secret,
|
|
||||||
--#! redirect_uri: None,
|
|
||||||
--#! website: Some("https://joinplu.me".into()),
|
|
||||||
--#! },
|
|
||||||
--#! ).unwrap();
|
|
||||||
--#!
|
|
||||||
--#! for i in 0..=(crate::users::User::count_local(conn).unwrap() as i32 / 20) {
|
|
||||||
--#! if let Ok(page) = crate::users::User::get_local_page(conn, (i * 20, (i + 1) * 20)) {
|
|
||||||
--#! for user in page {
|
|
||||||
--#! crate::api_tokens::ApiToken::insert(
|
|
||||||
--#! conn,
|
|
||||||
--#! crate::api_tokens::NewApiToken {
|
|
||||||
--#! app_id: app.id,
|
|
||||||
--#! user_id: user.id,
|
|
||||||
--#! value: random_hex(),
|
|
||||||
--#! scopes: "read+write".into(),
|
|
||||||
--#! },
|
|
||||||
--#! ).unwrap();
|
|
||||||
--#! }
|
|
||||||
--#! }
|
|
||||||
--#! }
|
|
||||||
--#!
|
|
||||||
--#! Ok(())
|
|
||||||
--#!}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
-- This file should undo anything in `up.sql`
|
|
||||||
DELETE FROM apps WHERE name = 'Plume web interface';
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
-- Your SQL goes here
|
|
||||||
--#!|conn: &Connection, path: &Path| {
|
|
||||||
--#! use plume_common::utils::random_hex;
|
|
||||||
--#!
|
|
||||||
--#! let client_id = random_hex();
|
|
||||||
--#! let client_secret = random_hex();
|
|
||||||
--#! let app = crate::apps::App::insert(
|
|
||||||
--#! &*conn,
|
|
||||||
--#! crate::apps::NewApp {
|
|
||||||
--#! name: "Plume web interface".into(),
|
|
||||||
--#! client_id,
|
|
||||||
--#! client_secret,
|
|
||||||
--#! redirect_uri: None,
|
|
||||||
--#! website: Some("https://joinplu.me".into()),
|
|
||||||
--#! },
|
|
||||||
--#! ).unwrap();
|
|
||||||
--#!
|
|
||||||
--#! for i in 0..=(crate::users::User::count_local(conn).unwrap() as i32 / 20) {
|
|
||||||
--#! if let Ok(page) = crate::users::User::get_local_page(conn, (i * 20, (i + 1) * 20)) {
|
|
||||||
--#! for user in page {
|
|
||||||
--#! crate::api_tokens::ApiToken::insert(
|
|
||||||
--#! conn,
|
|
||||||
--#! crate::api_tokens::NewApiToken {
|
|
||||||
--#! app_id: app.id,
|
|
||||||
--#! user_id: user.id,
|
|
||||||
--#! value: random_hex(),
|
|
||||||
--#! scopes: "read+write".into(),
|
|
||||||
--#! },
|
|
||||||
--#! ).unwrap();
|
|
||||||
--#! }
|
|
||||||
--#! }
|
|
||||||
--#! }
|
|
||||||
--#!
|
|
||||||
--#! Ok(())
|
|
||||||
--#!}
|
|
||||||
@@ -28,5 +28,4 @@ pub struct PostData {
|
|||||||
pub license: String,
|
pub license: String,
|
||||||
pub tags: Vec<String>,
|
pub tags: Vec<String>,
|
||||||
pub cover_id: Option<i32>,
|
pub cover_id: Option<i32>,
|
||||||
pub url: String,
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,15 +109,7 @@ fn new<'a>(args: &ArgMatches<'a>, conn: &Connection) {
|
|||||||
rpassword::read_password().expect("Couldn't read your password.")
|
rpassword::read_password().expect("Couldn't read your password.")
|
||||||
});
|
});
|
||||||
|
|
||||||
NewUser::new_local(
|
NewUser::new_local(conn, username, display_name, admin, &bio, email, &password)
|
||||||
conn,
|
|
||||||
username,
|
|
||||||
display_name,
|
|
||||||
admin,
|
|
||||||
&bio,
|
|
||||||
email,
|
|
||||||
User::hash_pass(&password).expect("Couldn't hash password"),
|
|
||||||
)
|
|
||||||
.expect("Couldn't save new user");
|
.expect("Couldn't save new user");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,9 +10,3 @@ gettext = { git = "https://github.com/Plume-org/gettext/", rev = "294c54d74c699f
|
|||||||
gettext-macros = { git = "https://github.com/Plume-org/gettext-macros/", rev = "a7c605f7edd6bfbfbfe7778026bfefd88d82db10" }
|
gettext-macros = { git = "https://github.com/Plume-org/gettext-macros/", rev = "a7c605f7edd6bfbfbfe7778026bfefd88d82db10" }
|
||||||
gettext-utils = { git = "https://github.com/Plume-org/gettext-macros/", rev = "a7c605f7edd6bfbfbfe7778026bfefd88d82db10" }
|
gettext-utils = { git = "https://github.com/Plume-org/gettext-macros/", rev = "a7c605f7edd6bfbfbfe7778026bfefd88d82db10" }
|
||||||
lazy_static = "1.3"
|
lazy_static = "1.3"
|
||||||
plume-api = { path = "../plume-api" }
|
|
||||||
serde_json = "1.0"
|
|
||||||
|
|
||||||
[dependencies.pulldown-cmark]
|
|
||||||
default-features = false
|
|
||||||
version = "0.5"
|
|
||||||
|
|||||||
+284
-416
@@ -1,212 +1,32 @@
|
|||||||
use pulldown_cmark::{Event, Options, Parser, Tag};
|
|
||||||
use stdweb::{
|
use stdweb::{
|
||||||
unstable::{TryFrom, TryInto},
|
unstable::{TryFrom, TryInto},
|
||||||
web::{event::*, html_element::*, *},
|
web::{event::*, html_element::*, *},
|
||||||
};
|
};
|
||||||
use CATALOG;
|
use CATALOG;
|
||||||
|
|
||||||
fn from_md(md: &str) {
|
macro_rules! mv {
|
||||||
let md_parser = Parser::new_ext(md, Options::all());
|
( $( $var:ident ),* => $exp:expr ) => {
|
||||||
md_parser.fold(
|
|
||||||
document().get_element_by_id("editor-main").unwrap(),
|
|
||||||
|last_elt, event| {
|
|
||||||
match event {
|
|
||||||
Event::Start(tag) => {
|
|
||||||
let new = match tag {
|
|
||||||
Tag::Paragraph => document().create_element("p").unwrap(),
|
|
||||||
Tag::Rule => document().create_element("hr").unwrap(),
|
|
||||||
Tag::Header(level) => {
|
|
||||||
document().create_element(&format!("h{}", level)).unwrap()
|
|
||||||
}
|
|
||||||
Tag::BlockQuote => document().create_element("blockquote").unwrap(),
|
|
||||||
Tag::CodeBlock(code) => {
|
|
||||||
let pre = document().create_element("pre").unwrap();
|
|
||||||
let code_elt = document().create_element("code").unwrap();
|
|
||||||
code_elt.append_child(&document().create_text_node(&code));
|
|
||||||
pre.append_child(&code_elt);
|
|
||||||
pre
|
|
||||||
}
|
|
||||||
Tag::List(None) => document().create_element("ul").unwrap(),
|
|
||||||
Tag::List(Some(_start_index)) => document().create_element("ol").unwrap(), // TODO: handle start_index
|
|
||||||
Tag::Item => document().create_element("li").unwrap(),
|
|
||||||
Tag::FootnoteDefinition(def) => {
|
|
||||||
let note = document().create_element("div").unwrap();
|
|
||||||
note.class_list().add("footnote");
|
|
||||||
note.append_child(&document().create_text_node(&def));
|
|
||||||
note
|
|
||||||
}
|
|
||||||
Tag::HtmlBlock => document().create_element("div").unwrap(),
|
|
||||||
Tag::Table(_alignements) => document().create_element("table").unwrap(), // TODO: handle alignements
|
|
||||||
Tag::TableHead => document().create_element("th").unwrap(),
|
|
||||||
Tag::TableRow => document().create_element("tr").unwrap(),
|
|
||||||
Tag::TableCell => document().create_element("td").unwrap(),
|
|
||||||
Tag::Emphasis => document().create_element("em").unwrap(),
|
|
||||||
Tag::Strong => document().create_element("strong").unwrap(),
|
|
||||||
Tag::Strikethrough => document().create_element("s").unwrap(),
|
|
||||||
Tag::Link(_link_type, url, text) => {
|
|
||||||
let url: &str = &url;
|
|
||||||
let text: &str = &text;
|
|
||||||
let link = document().create_element("a").unwrap();
|
|
||||||
js! {
|
|
||||||
@{&link}.href = @{url};
|
|
||||||
@{&link}.title = @{text};
|
|
||||||
};
|
|
||||||
link
|
|
||||||
}
|
|
||||||
Tag::Image(_link_type, url, text) => {
|
|
||||||
let url: &str = &url;
|
|
||||||
let text: &str = &text;
|
|
||||||
let img = document().create_element("img").unwrap();
|
|
||||||
js! {
|
|
||||||
@{&img}.src = @{url};
|
|
||||||
@{&img}.title = @{text};
|
|
||||||
@{&img}.alt = @{text};
|
|
||||||
};
|
|
||||||
img
|
|
||||||
}
|
|
||||||
};
|
|
||||||
last_elt.append_child(&new);
|
|
||||||
new
|
|
||||||
}
|
|
||||||
Event::End(_) => last_elt.parent_element().unwrap(),
|
|
||||||
Event::Text(text) => {
|
|
||||||
let node = document().create_text_node(&text);
|
|
||||||
last_elt.append_child(&node);
|
|
||||||
last_elt
|
|
||||||
}
|
|
||||||
Event::Code(code) => {
|
|
||||||
let elt = document().create_element("code").unwrap();
|
|
||||||
let content = document().create_text_node(&code);
|
|
||||||
elt.append_child(&content);
|
|
||||||
last_elt.append_child(&elt);
|
|
||||||
last_elt
|
|
||||||
}
|
|
||||||
Event::Html(html) => {
|
|
||||||
// TODO: sanitize it?
|
|
||||||
last_elt.set_attribute("innerHtml", &html);
|
|
||||||
last_elt
|
|
||||||
}
|
|
||||||
Event::InlineHtml(html) => {
|
|
||||||
let elt = document().create_element("span").unwrap();
|
|
||||||
elt.set_attribute("innerHtml", &html);
|
|
||||||
last_elt.append_child(&elt);
|
|
||||||
last_elt
|
|
||||||
}
|
|
||||||
Event::FootnoteReference(reference) => {
|
|
||||||
last_elt // TODO
|
|
||||||
}
|
|
||||||
Event::SoftBreak => {
|
|
||||||
last_elt.append_child(&document().create_element("br").unwrap());
|
|
||||||
last_elt
|
|
||||||
}
|
|
||||||
Event::HardBreak => {
|
|
||||||
last_elt // TODO
|
|
||||||
}
|
|
||||||
Event::TaskListMarker(done) => {
|
|
||||||
last_elt // TODO
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
MutationObserver::new(|muts, _obs| {
|
|
||||||
for m in muts {
|
|
||||||
console!(log, "mut!!");
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.observe(
|
|
||||||
&document().get_element_by_id("editor-main").unwrap(),
|
|
||||||
MutationObserverInit {
|
|
||||||
child_list: true,
|
|
||||||
attributes: true,
|
|
||||||
character_data: false,
|
|
||||||
subtree: true,
|
|
||||||
attribute_old_value: true,
|
|
||||||
character_data_old_value: false,
|
|
||||||
attribute_filter: None,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_md() -> String {
|
|
||||||
let root = document().get_element_by_id("editor-main").unwrap();
|
|
||||||
fold_children(&root).join("")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fold_children(elt: &Element) -> Vec<String> {
|
|
||||||
elt.child_nodes().iter().fold(vec![], |mut blocks, node| {
|
|
||||||
blocks.push(html_to_md(&node));
|
|
||||||
blocks
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn html_to_md(node: &Node) -> String {
|
|
||||||
console!(log, node);
|
|
||||||
if let Ok(elt) = Element::try_from(node.clone()) {
|
|
||||||
console!(log, elt.node_name().to_lowercase());
|
|
||||||
match elt.node_name().to_lowercase().as_ref() {
|
|
||||||
"hr" => "---".into(),
|
|
||||||
"h1" => format!("# {}\n\n", fold_children(&elt).join("")),
|
|
||||||
"h2" => format!("## {}\n\n", fold_children(&elt).join("")),
|
|
||||||
"h3" => format!("### {}\n\n", fold_children(&elt).join("")),
|
|
||||||
"h4" => format!("#### {}\n\n", fold_children(&elt).join("")),
|
|
||||||
"h5" => format!("##### {}\n\n", fold_children(&elt).join("")),
|
|
||||||
"h6" => format!("###### {}\n\n", fold_children(&elt).join("")),
|
|
||||||
"blockquote" => format!("> {}\n\n", fold_children(&elt).join("> ")),
|
|
||||||
"pre" => format!("```\n{}\n```\n\n", node.text_content().unwrap_or_default()),
|
|
||||||
"li" => match elt
|
|
||||||
.parent_element()
|
|
||||||
.unwrap()
|
|
||||||
.node_name()
|
|
||||||
.to_lowercase()
|
|
||||||
.as_ref()
|
|
||||||
{
|
{
|
||||||
"ol" => format!(
|
$( let $var = $var.clone(); )*
|
||||||
"{}. {}\n",
|
$exp
|
||||||
elt.parent_element()
|
|
||||||
.unwrap()
|
|
||||||
.child_nodes()
|
|
||||||
.iter()
|
|
||||||
.position(|n| Element::try_from(n).unwrap() == elt)
|
|
||||||
.unwrap_or_default(),
|
|
||||||
fold_children(&elt).join(""),
|
|
||||||
),
|
|
||||||
_ => format!("- {}\n", fold_children(&elt).join("")),
|
|
||||||
},
|
|
||||||
"em" => format!("_{}_", fold_children(&elt).join("")),
|
|
||||||
"strong" => format!("**{}**", fold_children(&elt).join("")),
|
|
||||||
"s" => format!("~~{}~~", fold_children(&elt).join("")),
|
|
||||||
"a" => format!(
|
|
||||||
"[{}]({})",
|
|
||||||
fold_children(&elt).join(""),
|
|
||||||
String::try_from(js! { return @{&elt}.href }).unwrap()
|
|
||||||
),
|
|
||||||
"img" => format!(
|
|
||||||
"",
|
|
||||||
String::try_from(js! { return @{&elt}.alt }).unwrap(),
|
|
||||||
String::try_from(js! { return @{&elt}.src }).unwrap()
|
|
||||||
),
|
|
||||||
other => {
|
|
||||||
console!(log, "Warning: unhandled element:", other);
|
|
||||||
String::new()
|
|
||||||
} // TODO: refs, tables, raw html
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
node.text_content().unwrap_or_default()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_elt_value(id: &'static str) -> String {
|
fn get_elt_value(id: &'static str) -> String {
|
||||||
let elt = document().get_element_by_id(id).unwrap();
|
let elt = document().get_element_by_id(id).unwrap();
|
||||||
let inp: Result<InputElement, _> = elt.clone().try_into();
|
let inp: Result<InputElement, _> = elt.clone().try_into();
|
||||||
let select: Result<SelectElement, _> = elt.clone().try_into();
|
|
||||||
let textarea: Result<TextAreaElement, _> = elt.try_into();
|
let textarea: Result<TextAreaElement, _> = elt.try_into();
|
||||||
let res = inp.map(|i| i.raw_value()).unwrap_or_else(|_| {
|
inp.map(|i| i.raw_value())
|
||||||
textarea
|
.unwrap_or_else(|_| textarea.unwrap().value())
|
||||||
.map(|t| t.value())
|
}
|
||||||
.unwrap_or_else(|_| select.unwrap().value().unwrap_or_default())
|
|
||||||
});
|
fn set_value<S: AsRef<str>>(id: &'static str, val: S) {
|
||||||
res
|
let elt = document().get_element_by_id(id).unwrap();
|
||||||
|
let inp: Result<InputElement, _> = elt.clone().try_into();
|
||||||
|
let textarea: Result<TextAreaElement, _> = elt.try_into();
|
||||||
|
inp.map(|i| i.set_raw_value(val.as_ref()))
|
||||||
|
.unwrap_or_else(|_| textarea.unwrap().set_value(val.as_ref()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn no_return(evt: KeyDownEvent) {
|
fn no_return(evt: KeyDownEvent) {
|
||||||
@@ -243,7 +63,33 @@ impl From<stdweb::private::ConversionError> for EditorError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn filter_paste(elt: &Element) {
|
fn init_widget(
|
||||||
|
parent: &Element,
|
||||||
|
tag: &'static str,
|
||||||
|
placeholder_text: String,
|
||||||
|
content: String,
|
||||||
|
disable_return: bool,
|
||||||
|
) -> Result<HtmlElement, EditorError> {
|
||||||
|
let widget = placeholder(make_editable(tag).try_into()?, &placeholder_text);
|
||||||
|
if !content.is_empty() {
|
||||||
|
widget.dataset().insert("edited", "true")?;
|
||||||
|
}
|
||||||
|
widget.append_child(&document().create_text_node(&content));
|
||||||
|
if disable_return {
|
||||||
|
widget.add_event_listener(no_return);
|
||||||
|
}
|
||||||
|
|
||||||
|
parent.append_child(&widget);
|
||||||
|
// We need to do that to make sure the placeholder is correctly rendered
|
||||||
|
widget.focus();
|
||||||
|
widget.blur();
|
||||||
|
|
||||||
|
filter_paste(&widget);
|
||||||
|
|
||||||
|
Ok(widget)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn filter_paste(elt: &HtmlElement) {
|
||||||
// Only insert text when pasting something
|
// Only insert text when pasting something
|
||||||
js! {
|
js! {
|
||||||
@{&elt}.addEventListener("paste", function (evt) {
|
@{&elt}.addEventListener("paste", function (evt) {
|
||||||
@@ -281,69 +127,64 @@ pub fn init() -> Result<(), EditorError> {
|
|||||||
|
|
||||||
fn init_editor() -> Result<(), EditorError> {
|
fn init_editor() -> Result<(), EditorError> {
|
||||||
if let Some(ed) = document().get_element_by_id("plume-editor") {
|
if let Some(ed) = document().get_element_by_id("plume-editor") {
|
||||||
document().body()?.set_attribute("id", "editor")?;
|
|
||||||
|
|
||||||
let aside = document().get_element_by_id("plume-editor-aside")?;
|
|
||||||
|
|
||||||
// Show the editor
|
// Show the editor
|
||||||
js! {
|
js! { @{&ed}.style.display = "block"; };
|
||||||
@{&ed}.style.display = "grid";
|
|
||||||
@{&aside}.style.display = "block";
|
|
||||||
};
|
|
||||||
// And hide the HTML-only fallback
|
// And hide the HTML-only fallback
|
||||||
let old_ed = document().get_element_by_id("plume-fallback-editor")?;
|
let old_ed = document().get_element_by_id("plume-fallback-editor")?;
|
||||||
|
let old_title = document().get_element_by_id("plume-editor-title")?;
|
||||||
js! {
|
js! {
|
||||||
@{&old_ed}.style.display = "none";
|
@{&old_ed}.style.display = "none";
|
||||||
|
@{&old_title}.style.display = "none";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Get content from the old editor (when editing an article for instance)
|
||||||
|
let title_val = get_elt_value("title");
|
||||||
|
let subtitle_val = get_elt_value("subtitle");
|
||||||
|
let content_val = get_elt_value("editor-content");
|
||||||
// And pre-fill the new editor with this values
|
// And pre-fill the new editor with this values
|
||||||
let title = document().get_element_by_id("editor-title")?;
|
let title = init_widget(&ed, "h1", i18n!(CATALOG, "Title"), title_val, true)?;
|
||||||
let subtitle = document().get_element_by_id("editor-subtitle")?;
|
let subtitle = init_widget(
|
||||||
let source = get_elt_value("editor-content");
|
&ed,
|
||||||
|
"h2",
|
||||||
|
i18n!(CATALOG, "Subtitle, or summary"),
|
||||||
|
subtitle_val,
|
||||||
|
true,
|
||||||
|
)?;
|
||||||
|
let content = init_widget(
|
||||||
|
&ed,
|
||||||
|
"article",
|
||||||
|
i18n!(CATALOG, "Write your article here. Markdown is supported."),
|
||||||
|
content_val.clone(),
|
||||||
|
false,
|
||||||
|
)?;
|
||||||
|
js! { @{&content}.innerHTML = @{content_val}; };
|
||||||
|
|
||||||
setup_toolbar();
|
// character counter
|
||||||
from_md(&source);
|
content.add_event_listener(mv!(content => move |_: KeyDownEvent| {
|
||||||
|
window().set_timeout(mv!(content => move || {
|
||||||
title.add_event_listener(no_return);
|
if let Some(e) = document().get_element_by_id("char-count") {
|
||||||
subtitle.add_event_listener(no_return);
|
let count = chars_left("#plume-fallback-editor", &content).unwrap_or_default();
|
||||||
|
let text = i18n!(CATALOG, "Around {} characters left"; count);
|
||||||
filter_paste(&title);
|
HtmlElement::try_from(e).map(|e| {
|
||||||
filter_paste(&subtitle);
|
js!{@{e}.innerText = @{text}};
|
||||||
// TODO: filter_paste(&content);
|
}).ok();
|
||||||
|
|
||||||
document()
|
|
||||||
.get_element_by_id("publish")?
|
|
||||||
.add_event_listener(|_: ClickEvent| {
|
|
||||||
let publish_page = document().get_element_by_id("publish-page").unwrap();
|
|
||||||
let options_page = document().get_element_by_id("options-page").unwrap();
|
|
||||||
js! {
|
|
||||||
@{&options_page}.style.display = "none";
|
|
||||||
@{&publish_page}.style.display = "flex";
|
|
||||||
};
|
};
|
||||||
});
|
}), 0);
|
||||||
|
}));
|
||||||
|
|
||||||
document()
|
document().get_element_by_id("publish")?.add_event_listener(
|
||||||
.get_element_by_id("cancel-publish")?
|
mv!(title, subtitle, content, old_ed => move |_: ClickEvent| {
|
||||||
.add_event_listener(|_: ClickEvent| {
|
let popup = document().get_element_by_id("publish-popup").or_else(||
|
||||||
let publish_page = document().get_element_by_id("publish-page").unwrap();
|
init_popup(&title, &subtitle, &content, &old_ed).ok()
|
||||||
let options_page = document().get_element_by_id("options-page").unwrap();
|
).unwrap();
|
||||||
js! {
|
let bg = document().get_element_by_id("popup-bg").or_else(||
|
||||||
@{&publish_page}.style.display = "none";
|
init_popup_bg().ok()
|
||||||
@{&options_page}.style.display = "flex";
|
).unwrap();
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
document()
|
popup.class_list().add("show").unwrap();
|
||||||
.get_element_by_id("confirm-publish")?
|
bg.class_list().add("show").unwrap();
|
||||||
.add_event_listener(|_: ClickEvent| {
|
}),
|
||||||
save(false);
|
);
|
||||||
});
|
|
||||||
|
|
||||||
document()
|
|
||||||
.get_element_by_id("save-draft")?
|
|
||||||
.add_event_listener(|_: ClickEvent| {
|
|
||||||
save(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
show_errors();
|
show_errors();
|
||||||
setup_close_button();
|
setup_close_button();
|
||||||
@@ -351,176 +192,6 @@ fn init_editor() -> Result<(), EditorError> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn select_style(style: &str) {
|
|
||||||
if let Some(select) = document()
|
|
||||||
.get_element_by_id("toolbar-style")
|
|
||||||
.and_then(|e| SelectElement::try_from(e).ok())
|
|
||||||
{
|
|
||||||
select.set_value(Some(style));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup_toolbar() {
|
|
||||||
let toolbar = document().get_element_by_id("editor-toolbar").unwrap();
|
|
||||||
|
|
||||||
// List of styles (headings, quote, code, etc)
|
|
||||||
let style_select =
|
|
||||||
SelectElement::try_from(document().create_element("select").unwrap()).unwrap();
|
|
||||||
let options = vec![
|
|
||||||
("p", i18n!(CATALOG, "Paragraph")),
|
|
||||||
("ul", i18n!(CATALOG, "List")),
|
|
||||||
("ol", i18n!(CATALOG, "Ordered list")),
|
|
||||||
("h1", i18n!(CATALOG, "Heading 1")),
|
|
||||||
("h2", i18n!(CATALOG, "Heading 2")),
|
|
||||||
("h3", i18n!(CATALOG, "Heading 3")),
|
|
||||||
("h4", i18n!(CATALOG, "Heading 4")),
|
|
||||||
("h5", i18n!(CATALOG, "Heading 5")),
|
|
||||||
("h6", i18n!(CATALOG, "Heading 6")),
|
|
||||||
("blockquote", i18n!(CATALOG, "Quote")),
|
|
||||||
("pre", i18n!(CATALOG, "Code")),
|
|
||||||
];
|
|
||||||
for (tag, name) in options.clone() {
|
|
||||||
let opt = document().create_element("option").unwrap();
|
|
||||||
opt.set_attribute("value", tag);
|
|
||||||
opt.append_child(&document().create_text_node(&name));
|
|
||||||
style_select.append_child(&opt)
|
|
||||||
}
|
|
||||||
style_select.set_attribute("id", "toolbar-style");
|
|
||||||
|
|
||||||
let options_clone = options.clone();
|
|
||||||
document().add_event_listener(move |_: SelectionChangeEvent| {
|
|
||||||
let block = std::iter::successors(
|
|
||||||
window().get_selection().and_then(|s| s.anchor_node()),
|
|
||||||
|node| {
|
|
||||||
let t = node.node_name().to_lowercase();
|
|
||||||
if options_clone.iter().any(|(tag, _)| *tag == &t) {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
node.parent_node()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.last();
|
|
||||||
|
|
||||||
if let Some(b) = block {
|
|
||||||
select_style(&b.node_name().to_lowercase());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
style_select.add_event_listener(move |_: ChangeEvent| {
|
|
||||||
let block = std::iter::successors(
|
|
||||||
window().get_selection().and_then(|s| s.anchor_node()),
|
|
||||||
|node| {
|
|
||||||
let t = node.node_name().to_lowercase();
|
|
||||||
if options.iter().any(|(tag, _)| *tag == &t) {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
node.parent_node()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.last();
|
|
||||||
|
|
||||||
if let Some(block) = block {
|
|
||||||
if let Some(select) = document()
|
|
||||||
.get_element_by_id("toolbar-style")
|
|
||||||
.and_then(|e| SelectElement::try_from(e).ok())
|
|
||||||
{
|
|
||||||
let tag = select.value();
|
|
||||||
|
|
||||||
let new = document().create_element(&tag.unwrap_or_default()).unwrap();
|
|
||||||
for ch in block.child_nodes() {
|
|
||||||
block.remove_child(&ch);
|
|
||||||
new.append_child(&ch);
|
|
||||||
}
|
|
||||||
|
|
||||||
block.parent_node().unwrap().replace_child(&new, &block);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Bold
|
|
||||||
|
|
||||||
// Italics
|
|
||||||
|
|
||||||
// Insert an image
|
|
||||||
|
|
||||||
toolbar.append_child(&style_select);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn save(is_draft: bool) {
|
|
||||||
let req = XmlHttpRequest::new();
|
|
||||||
if bool::try_from(js! { return window.editing }).unwrap_or(false) {
|
|
||||||
req.open(
|
|
||||||
"PUT",
|
|
||||||
&format!(
|
|
||||||
"/api/v1/posts/{}",
|
|
||||||
i32::try_from(js! { return window.post_id }).unwrap()
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
} else {
|
|
||||||
req.open("POST", "/api/v1/posts").unwrap();
|
|
||||||
}
|
|
||||||
req.set_request_header("Accept", "application/json")
|
|
||||||
.unwrap();
|
|
||||||
req.set_request_header("Content-Type", "application/json")
|
|
||||||
.unwrap();
|
|
||||||
req.set_request_header(
|
|
||||||
"Authorization",
|
|
||||||
&format!(
|
|
||||||
"Bearer {}",
|
|
||||||
String::try_from(js! { return window.api_token }).unwrap()
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let req_clone = req.clone();
|
|
||||||
req.add_event_listener(move |_: ProgressLoadEvent| {
|
|
||||||
if let Ok(Some(res)) = req_clone.response_text() {
|
|
||||||
serde_json::from_str(&res)
|
|
||||||
.map(|res: plume_api::posts::PostData| {
|
|
||||||
let url = res.url;
|
|
||||||
js! {
|
|
||||||
window.location.href = @{url};
|
|
||||||
};
|
|
||||||
})
|
|
||||||
.map_err(|_| {
|
|
||||||
let json: serde_json::Value = serde_json::from_str(&res).unwrap();
|
|
||||||
window().alert(&format!(
|
|
||||||
"Error: {}",
|
|
||||||
json["error"].as_str().unwrap_or_default()
|
|
||||||
));
|
|
||||||
})
|
|
||||||
.ok();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
console!(log, to_md());
|
|
||||||
let data = plume_api::posts::NewPostData {
|
|
||||||
title: HtmlElement::try_from(document().get_element_by_id("editor-title").unwrap())
|
|
||||||
.unwrap()
|
|
||||||
.inner_text(),
|
|
||||||
subtitle: document()
|
|
||||||
.get_element_by_id("editor-subtitle")
|
|
||||||
.map(|s| HtmlElement::try_from(s).unwrap().inner_text()),
|
|
||||||
source: to_md(),
|
|
||||||
author: String::new(), // it is ignored anyway (TODO: remove it ??)
|
|
||||||
blog_id: i32::try_from(js! { return window.blog_id }).ok(),
|
|
||||||
published: Some(!is_draft),
|
|
||||||
creation_date: None,
|
|
||||||
license: Some(get_elt_value("license")),
|
|
||||||
tags: Some(
|
|
||||||
get_elt_value("tags")
|
|
||||||
.split(',')
|
|
||||||
.map(|t| t.trim().to_string())
|
|
||||||
.filter(|t| !t.is_empty())
|
|
||||||
.collect(),
|
|
||||||
),
|
|
||||||
cover_id: get_elt_value("cover").parse().ok(),
|
|
||||||
};
|
|
||||||
let json = serde_json::to_string(&data).unwrap();
|
|
||||||
req.send_with_string(&json).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup_close_button() {
|
fn setup_close_button() {
|
||||||
if let Some(button) = document().get_element_by_id("close-editor") {
|
if let Some(button) = document().get_element_by_id("close-editor") {
|
||||||
button.add_event_listener(|_: ClickEvent| {
|
button.add_event_listener(|_: ClickEvent| {
|
||||||
@@ -552,3 +223,200 @@ fn show_errors() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn init_popup(
|
||||||
|
title: &HtmlElement,
|
||||||
|
subtitle: &HtmlElement,
|
||||||
|
content: &HtmlElement,
|
||||||
|
old_ed: &Element,
|
||||||
|
) -> Result<Element, EditorError> {
|
||||||
|
let popup = document().create_element("div")?;
|
||||||
|
popup.class_list().add("popup")?;
|
||||||
|
popup.set_attribute("id", "publish-popup")?;
|
||||||
|
|
||||||
|
let tags = get_elt_value("tags")
|
||||||
|
.split(',')
|
||||||
|
.map(str::trim)
|
||||||
|
.map(str::to_string)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let license = get_elt_value("license");
|
||||||
|
make_input(&i18n!(CATALOG, "Tags"), "popup-tags", &popup).set_raw_value(&tags.join(", "));
|
||||||
|
make_input(&i18n!(CATALOG, "License"), "popup-license", &popup).set_raw_value(&license);
|
||||||
|
|
||||||
|
let cover_label = document().create_element("label")?;
|
||||||
|
cover_label.append_child(&document().create_text_node(&i18n!(CATALOG, "Cover")));
|
||||||
|
cover_label.set_attribute("for", "cover")?;
|
||||||
|
let cover = document().get_element_by_id("cover")?;
|
||||||
|
cover.parent_element()?.remove_child(&cover).ok();
|
||||||
|
popup.append_child(&cover_label);
|
||||||
|
popup.append_child(&cover);
|
||||||
|
|
||||||
|
if let Some(draft_checkbox) = document().get_element_by_id("draft") {
|
||||||
|
let draft_label = document().create_element("label")?;
|
||||||
|
draft_label.set_attribute("for", "popup-draft")?;
|
||||||
|
|
||||||
|
let draft = document().create_element("input").unwrap();
|
||||||
|
js! {
|
||||||
|
@{&draft}.id = "popup-draft";
|
||||||
|
@{&draft}.name = "popup-draft";
|
||||||
|
@{&draft}.type = "checkbox";
|
||||||
|
@{&draft}.checked = @{&draft_checkbox}.checked;
|
||||||
|
};
|
||||||
|
|
||||||
|
draft_label.append_child(&draft);
|
||||||
|
draft_label.append_child(&document().create_text_node(&i18n!(CATALOG, "This is a draft")));
|
||||||
|
popup.append_child(&draft_label);
|
||||||
|
}
|
||||||
|
|
||||||
|
let button = document().create_element("input")?;
|
||||||
|
js! {
|
||||||
|
@{&button}.type = "submit";
|
||||||
|
@{&button}.value = @{i18n!(CATALOG, "Publish")};
|
||||||
|
};
|
||||||
|
button.append_child(&document().create_text_node(&i18n!(CATALOG, "Publish")));
|
||||||
|
button.add_event_listener(
|
||||||
|
mv!(title, subtitle, content, old_ed => move |_: ClickEvent| {
|
||||||
|
title.focus(); // Remove the placeholder before publishing
|
||||||
|
set_value("title", title.inner_text());
|
||||||
|
subtitle.focus();
|
||||||
|
set_value("subtitle", subtitle.inner_text());
|
||||||
|
content.focus();
|
||||||
|
set_value("editor-content", content.child_nodes().iter().fold(String::new(), |md, ch| {
|
||||||
|
let to_append = match ch.node_type() {
|
||||||
|
NodeType::Element => {
|
||||||
|
if js!{ return @{&ch}.tagName; } == "DIV" {
|
||||||
|
(js!{ return @{&ch}.innerHTML; }).try_into().unwrap_or_default()
|
||||||
|
} else {
|
||||||
|
(js!{ return @{&ch}.outerHTML; }).try_into().unwrap_or_default()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
NodeType::Text => ch.node_value().unwrap_or_default(),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
format!("{}\n\n{}", md, to_append)
|
||||||
|
}));
|
||||||
|
set_value("tags", get_elt_value("popup-tags"));
|
||||||
|
if let Some(draft) = document().get_element_by_id("popup-draft") {
|
||||||
|
js!{
|
||||||
|
document.getElementById("draft").checked = @{draft}.checked;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
let cover = document().get_element_by_id("cover").unwrap();
|
||||||
|
cover.parent_element().unwrap().remove_child(&cover).ok();
|
||||||
|
old_ed.append_child(&cover);
|
||||||
|
set_value("license", get_elt_value("popup-license"));
|
||||||
|
js! {
|
||||||
|
@{&old_ed}.submit();
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
popup.append_child(&button);
|
||||||
|
|
||||||
|
document().body()?.append_child(&popup);
|
||||||
|
Ok(popup)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_popup_bg() -> Result<Element, EditorError> {
|
||||||
|
let bg = document().create_element("div")?;
|
||||||
|
bg.class_list().add("popup-bg")?;
|
||||||
|
bg.set_attribute("id", "popup-bg")?;
|
||||||
|
|
||||||
|
document().body()?.append_child(&bg);
|
||||||
|
bg.add_event_listener(|_: ClickEvent| close_popup());
|
||||||
|
Ok(bg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn chars_left(selector: &str, content: &HtmlElement) -> Option<i32> {
|
||||||
|
match document().query_selector(selector) {
|
||||||
|
Ok(Some(form)) => HtmlElement::try_from(form).ok().and_then(|form| {
|
||||||
|
if let Some(len) = form
|
||||||
|
.get_attribute("content-size")
|
||||||
|
.and_then(|s| s.parse::<i32>().ok())
|
||||||
|
{
|
||||||
|
(js! {
|
||||||
|
let x = encodeURIComponent(@{content}.innerHTML)
|
||||||
|
.replace(/%20/g, "+")
|
||||||
|
.replace(/%0A/g, "%0D%0A")
|
||||||
|
.replace(new RegExp("[!'*()]", "g"), "XXX") // replace exceptions of encodeURIComponent with placeholder
|
||||||
|
.length + 2;
|
||||||
|
console.log(x);
|
||||||
|
return x;
|
||||||
|
})
|
||||||
|
.try_into()
|
||||||
|
.map(|c: i32| len - c)
|
||||||
|
.ok()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn close_popup() {
|
||||||
|
let hide = |x: Element| x.class_list().remove("show");
|
||||||
|
document().get_element_by_id("publish-popup").map(hide);
|
||||||
|
document().get_element_by_id("popup-bg").map(hide);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_input(label_text: &str, name: &'static str, form: &Element) -> InputElement {
|
||||||
|
let label = document().create_element("label").unwrap();
|
||||||
|
label.append_child(&document().create_text_node(label_text));
|
||||||
|
label.set_attribute("for", name).unwrap();
|
||||||
|
|
||||||
|
let inp: InputElement = document()
|
||||||
|
.create_element("input")
|
||||||
|
.unwrap()
|
||||||
|
.try_into()
|
||||||
|
.unwrap();
|
||||||
|
inp.set_attribute("name", name).unwrap();
|
||||||
|
inp.set_attribute("id", name).unwrap();
|
||||||
|
|
||||||
|
form.append_child(&label);
|
||||||
|
form.append_child(&inp);
|
||||||
|
inp
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_editable(tag: &'static str) -> Element {
|
||||||
|
let elt = document()
|
||||||
|
.create_element(tag)
|
||||||
|
.expect("Couldn't create editable element");
|
||||||
|
elt.set_attribute("contenteditable", "true")
|
||||||
|
.expect("Couldn't make the element editable");
|
||||||
|
elt
|
||||||
|
}
|
||||||
|
|
||||||
|
fn placeholder(elt: HtmlElement, text: &str) -> HtmlElement {
|
||||||
|
elt.dataset().insert("placeholder", text).unwrap();
|
||||||
|
elt.dataset().insert("edited", "false").unwrap();
|
||||||
|
|
||||||
|
elt.add_event_listener(mv!(elt => move |_: FocusEvent| {
|
||||||
|
if elt.dataset().get("edited").unwrap().as_str() != "true" {
|
||||||
|
clear_children(&elt);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
elt.add_event_listener(mv!(elt => move |_: BlurEvent| {
|
||||||
|
if elt.dataset().get("edited").unwrap().as_str() != "true" {
|
||||||
|
clear_children(&elt);
|
||||||
|
|
||||||
|
let ph = document().create_element("span").expect("Couldn't create placeholder");
|
||||||
|
ph.class_list().add("placeholder").expect("Couldn't add class");
|
||||||
|
ph.append_child(&document().create_text_node(&elt.dataset().get("placeholder").unwrap_or_default()));
|
||||||
|
elt.append_child(&ph);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
elt.add_event_listener(mv!(elt => move |_: KeyUpEvent| {
|
||||||
|
elt.dataset().insert("edited", if elt.inner_text().trim_matches('\n').is_empty() {
|
||||||
|
"false"
|
||||||
|
} else {
|
||||||
|
"true"
|
||||||
|
}).expect("Couldn't update edition state");
|
||||||
|
}));
|
||||||
|
elt
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_children(elt: &HtmlElement) {
|
||||||
|
for child in elt.child_nodes() {
|
||||||
|
elt.remove_child(&child).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,10 +6,8 @@ extern crate gettext;
|
|||||||
extern crate gettext_macros;
|
extern crate gettext_macros;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
extern crate pulldown_cmark;
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate stdweb;
|
extern crate stdweb;
|
||||||
extern crate serde_json;
|
|
||||||
|
|
||||||
use stdweb::web::{event::*, *};
|
use stdweb::web::{event::*, *};
|
||||||
|
|
||||||
@@ -58,18 +56,6 @@ lazy_static! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
std::panic::set_hook(Box::new(|info: &std::panic::PanicInfo| {
|
|
||||||
let mut msg = info.to_string();
|
|
||||||
msg.push_str("\n\nStack:\n\n");
|
|
||||||
let e = error::Error::new("Panicked");
|
|
||||||
let stack = js! { return @{&e}.stack; }
|
|
||||||
.into_string()
|
|
||||||
.unwrap_or_default();
|
|
||||||
msg.push_str(&stack);
|
|
||||||
msg.push_str("\n\n");
|
|
||||||
console!(error, msg);
|
|
||||||
}));
|
|
||||||
|
|
||||||
menu();
|
menu();
|
||||||
search();
|
search();
|
||||||
editor::init()
|
editor::init()
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ guid-create = "0.1"
|
|||||||
heck = "0.3.0"
|
heck = "0.3.0"
|
||||||
itertools = "0.8.0"
|
itertools = "0.8.0"
|
||||||
lazy_static = "*"
|
lazy_static = "*"
|
||||||
|
ldap3 = "0.6.1"
|
||||||
migrations_internals= "1.4.0"
|
migrations_internals= "1.4.0"
|
||||||
openssl = "0.10.22"
|
openssl = "0.10.22"
|
||||||
rocket = "0.4.0"
|
rocket = "0.4.0"
|
||||||
@@ -23,7 +24,7 @@ serde_derive = "1.0"
|
|||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
tantivy = "0.9.1"
|
tantivy = "0.9.1"
|
||||||
url = "1.7"
|
url = "1.7"
|
||||||
webfinger = "0.4.1"
|
webfinger = "0.3.1"
|
||||||
whatlang = "0.7.1"
|
whatlang = "0.7.1"
|
||||||
shrinkwraprs = "0.2.1"
|
shrinkwraprs = "0.2.1"
|
||||||
diesel-derive-newtype = "0.1.2"
|
diesel-derive-newtype = "0.1.2"
|
||||||
|
|||||||
@@ -44,18 +44,6 @@ impl ApiToken {
|
|||||||
get!(api_tokens);
|
get!(api_tokens);
|
||||||
insert!(api_tokens, NewApiToken);
|
insert!(api_tokens, NewApiToken);
|
||||||
find_by!(api_tokens, find_by_value, value as &str);
|
find_by!(api_tokens, find_by_value, value as &str);
|
||||||
find_by!(
|
|
||||||
api_tokens,
|
|
||||||
find_by_app_and_user,
|
|
||||||
app_id as i32,
|
|
||||||
user_id as i32
|
|
||||||
);
|
|
||||||
|
|
||||||
/// The token for Plume's front-end
|
|
||||||
pub fn web_token(conn: &crate::Connection, user_id: i32) -> Result<ApiToken> {
|
|
||||||
let app = crate::apps::App::find_by_name(conn, "Plume web interface")?;
|
|
||||||
Self::find_by_app_and_user(conn, app.id, user_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn can(&self, what: &'static str, scope: &'static str) -> bool {
|
pub fn can(&self, what: &'static str, scope: &'static str) -> bool {
|
||||||
let full_scope = what.to_owned() + ":" + scope;
|
let full_scope = what.to_owned() + ":" + scope;
|
||||||
|
|||||||
@@ -29,5 +29,4 @@ impl App {
|
|||||||
get!(apps);
|
get!(apps);
|
||||||
insert!(apps, NewApp);
|
insert!(apps, NewApp);
|
||||||
find_by!(apps, find_by_client_id, client_id as &str);
|
find_by!(apps, find_by_client_id, client_id as &str);
|
||||||
find_by!(apps, find_by_name, name as &str);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ impl Blog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_from_webfinger(c: &PlumeRocket, acct: &str) -> Result<Blog> {
|
fn fetch_from_webfinger(c: &PlumeRocket, acct: &str) -> Result<Blog> {
|
||||||
resolve_with_prefix(Prefix::Group, acct.to_owned(), true)?
|
resolve(acct.to_owned(), true)?
|
||||||
.links
|
.links
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.find(|l| l.mime_type == Some(String::from("application/activity+json")))
|
.find(|l| l.mime_type == Some(String::from("application/activity+json")))
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ pub struct Config {
|
|||||||
pub search_index: String,
|
pub search_index: String,
|
||||||
pub rocket: Result<RocketConfig, RocketError>,
|
pub rocket: Result<RocketConfig, RocketError>,
|
||||||
pub logo: LogoConfig,
|
pub logo: LogoConfig,
|
||||||
|
pub ldap: LdapConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[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! {
|
lazy_static! {
|
||||||
pub static ref CONFIG: Config = Config {
|
pub static ref CONFIG: Config = Config {
|
||||||
base_url: var("BASE_URL").unwrap_or_else(|_| format!(
|
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()),
|
search_index: var("SEARCH_INDEX").unwrap_or_else(|_| "search_index".to_owned()),
|
||||||
rocket: get_rocket_config(),
|
rocket: get_rocket_config(),
|
||||||
logo: LogoConfig::default(),
|
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;
|
extern crate itertools;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
extern crate ldap3;
|
||||||
extern crate migrations_internals;
|
extern crate migrations_internals;
|
||||||
extern crate openssl;
|
extern crate openssl;
|
||||||
extern crate plume_api;
|
extern crate plume_api;
|
||||||
@@ -64,7 +65,6 @@ pub enum Error {
|
|||||||
Signature,
|
Signature,
|
||||||
Unauthorized,
|
Unauthorized,
|
||||||
Url,
|
Url,
|
||||||
Validation(String),
|
|
||||||
Webfinger,
|
Webfinger,
|
||||||
Expired,
|
Expired,
|
||||||
}
|
}
|
||||||
@@ -364,6 +364,7 @@ pub mod follows;
|
|||||||
pub mod headers;
|
pub mod headers;
|
||||||
pub mod inbox;
|
pub mod inbox;
|
||||||
pub mod instance;
|
pub mod instance;
|
||||||
|
pub mod ldap;
|
||||||
pub mod likes;
|
pub mod likes;
|
||||||
pub mod medias;
|
pub mod medias;
|
||||||
pub mod mentions;
|
pub mod mentions;
|
||||||
|
|||||||
+42
-10
@@ -41,6 +41,7 @@ use blogs::Blog;
|
|||||||
use db_conn::DbConn;
|
use db_conn::DbConn;
|
||||||
use follows::Follow;
|
use follows::Follow;
|
||||||
use instance::*;
|
use instance::*;
|
||||||
|
use ldap::Ldap;
|
||||||
use medias::Media;
|
use medias::Media;
|
||||||
use post_authors::PostAuthor;
|
use post_authors::PostAuthor;
|
||||||
use posts::Post;
|
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)
|
bcrypt::hash(pass, 10).map_err(Error::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn auth(&self, pass: &str) -> bool {
|
fn auth(&self, pass: &str) -> bool {
|
||||||
self.hashed_password
|
self.hashed_password
|
||||||
.clone()
|
.clone()
|
||||||
.map(|hashed| bcrypt::verify(pass, hashed.as_ref()).unwrap_or(false))
|
.map(|hashed| bcrypt::verify(pass, hashed.as_ref()).unwrap_or(false))
|
||||||
.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<()> {
|
pub fn reset_password(&self, conn: &Connection, pass: &str) -> Result<()> {
|
||||||
diesel::update(self)
|
diesel::update(self)
|
||||||
.set(users::hashed_password.eq(User::hash_pass(pass)?))
|
.set(users::hashed_password.eq(User::hash_pass(pass)?))
|
||||||
@@ -351,6 +376,13 @@ impl User {
|
|||||||
Ok(())
|
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>> {
|
pub fn get_local_page(conn: &Connection, (min, max): (i32, i32)) -> Result<Vec<User>> {
|
||||||
users::table
|
users::table
|
||||||
.filter(users::instance_id.eq(Instance::get_local()?.id))
|
.filter(users::instance_id.eq(Instance::get_local()?.id))
|
||||||
@@ -707,7 +739,7 @@ impl User {
|
|||||||
mime_type: None,
|
mime_type: None,
|
||||||
href: None,
|
href: None,
|
||||||
template: Some(format!(
|
template: Some(format!(
|
||||||
"https://{}/remote_interact?{{uri}}",
|
"{}/remote_interact?{{uri}}",
|
||||||
self.get_instance(conn)?.public_domain
|
self.get_instance(conn)?.public_domain
|
||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
@@ -923,7 +955,7 @@ impl NewUser {
|
|||||||
is_admin: bool,
|
is_admin: bool,
|
||||||
summary: &str,
|
summary: &str,
|
||||||
email: String,
|
email: String,
|
||||||
password: String,
|
password: &str,
|
||||||
) -> Result<User> {
|
) -> Result<User> {
|
||||||
let (pub_key, priv_key) = gen_keypair();
|
let (pub_key, priv_key) = gen_keypair();
|
||||||
User::insert(
|
User::insert(
|
||||||
@@ -935,7 +967,7 @@ impl NewUser {
|
|||||||
summary: summary.to_owned(),
|
summary: summary.to_owned(),
|
||||||
summary_html: SafeString::new(&utils::md_to_html(&summary, None, false, None).0),
|
summary_html: SafeString::new(&utils::md_to_html(&summary, None, false, None).0),
|
||||||
email: Some(email),
|
email: Some(email),
|
||||||
hashed_password: Some(password),
|
hashed_password: Some(User::hash_pass(password)?),
|
||||||
instance_id: Instance::get_local()?.id,
|
instance_id: Instance::get_local()?.id,
|
||||||
ap_url: String::new(),
|
ap_url: String::new(),
|
||||||
public_key: String::from_utf8(pub_key).or(Err(Error::Signature))?,
|
public_key: String::from_utf8(pub_key).or(Err(Error::Signature))?,
|
||||||
@@ -964,7 +996,7 @@ pub(crate) mod tests {
|
|||||||
true,
|
true,
|
||||||
"Hello there, I'm the admin",
|
"Hello there, I'm the admin",
|
||||||
"admin@example.com".to_owned(),
|
"admin@example.com".to_owned(),
|
||||||
"invalid_admin_password".to_owned(),
|
"invalid_admin_password",
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let user = NewUser::new_local(
|
let user = NewUser::new_local(
|
||||||
@@ -974,7 +1006,7 @@ pub(crate) mod tests {
|
|||||||
false,
|
false,
|
||||||
"Hello there, I'm no one",
|
"Hello there, I'm no one",
|
||||||
"user@example.com".to_owned(),
|
"user@example.com".to_owned(),
|
||||||
"invalid_user_password".to_owned(),
|
"invalid_user_password",
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let other = NewUser::new_local(
|
let other = NewUser::new_local(
|
||||||
@@ -984,7 +1016,7 @@ pub(crate) mod tests {
|
|||||||
false,
|
false,
|
||||||
"Hello there, I'm someone else",
|
"Hello there, I'm someone else",
|
||||||
"other@example.com".to_owned(),
|
"other@example.com".to_owned(),
|
||||||
"invalid_other_password".to_owned(),
|
"invalid_other_password",
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
vec![admin, user, other]
|
vec![admin, user, other]
|
||||||
@@ -1003,7 +1035,7 @@ pub(crate) mod tests {
|
|||||||
false,
|
false,
|
||||||
"Hello I'm a test",
|
"Hello I'm a test",
|
||||||
"test@example.com".to_owned(),
|
"test@example.com".to_owned(),
|
||||||
User::hash_pass("test_password").unwrap(),
|
"test_password",
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@@ -1109,7 +1141,7 @@ pub(crate) mod tests {
|
|||||||
false,
|
false,
|
||||||
"Hello I'm a test",
|
"Hello I'm a test",
|
||||||
"test@example.com".to_owned(),
|
"test@example.com".to_owned(),
|
||||||
User::hash_pass("test_password").unwrap(),
|
"test_password",
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|||||||
+1
-12
@@ -37,7 +37,6 @@ impl<'r> Responder<'r> for ApiError {
|
|||||||
"error": "You are not authorized to access this resource"
|
"error": "You are not authorized to access this resource"
|
||||||
}))
|
}))
|
||||||
.respond_to(req),
|
.respond_to(req),
|
||||||
Error::Validation(msg) => Json(json!({ "error": msg })).respond_to(req),
|
|
||||||
_ => Json(json!({
|
_ => Json(json!({
|
||||||
"error": "Server error"
|
"error": "Server error"
|
||||||
}))
|
}))
|
||||||
@@ -63,8 +62,7 @@ pub fn oauth(
|
|||||||
let conn = &*rockets.conn;
|
let conn = &*rockets.conn;
|
||||||
let app = App::find_by_client_id(conn, &query.client_id)?;
|
let app = App::find_by_client_id(conn, &query.client_id)?;
|
||||||
if app.client_secret == query.client_secret {
|
if app.client_secret == query.client_secret {
|
||||||
if let Ok(user) = User::find_by_fqn(&rockets, &query.username) {
|
if let Ok(user) = User::connect(&rockets, &query.username, &query.password) {
|
||||||
if user.auth(&query.password) {
|
|
||||||
let token = ApiToken::insert(
|
let token = ApiToken::insert(
|
||||||
conn,
|
conn,
|
||||||
NewApiToken {
|
NewApiToken {
|
||||||
@@ -82,15 +80,6 @@ pub fn oauth(
|
|||||||
"error": "Invalid credentials"
|
"error": "Invalid credentials"
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
} 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"
|
|
||||||
})))
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Ok(Json(json!({
|
Ok(Json(json!({
|
||||||
"error": "Invalid client_secret"
|
"error": "Invalid client_secret"
|
||||||
|
|||||||
+3
-154
@@ -1,7 +1,6 @@
|
|||||||
use chrono::{NaiveDateTime, Utc};
|
use chrono::NaiveDateTime;
|
||||||
use heck::{CamelCase, KebabCase};
|
use heck::{CamelCase, KebabCase};
|
||||||
use rocket_contrib::json::Json;
|
use rocket_contrib::json::Json;
|
||||||
use std::collections::HashSet;
|
|
||||||
|
|
||||||
use crate::api::{authorization::*, Api};
|
use crate::api::{authorization::*, Api};
|
||||||
use plume_api::posts::*;
|
use plume_api::posts::*;
|
||||||
@@ -45,7 +44,6 @@ pub fn get(id: i32, auth: Option<Authorization<Read, Post>>, conn: DbConn) -> Ap
|
|||||||
published: post.published,
|
published: post.published,
|
||||||
license: post.license,
|
license: post.license,
|
||||||
cover_id: post.cover_id,
|
cover_id: post.cover_id,
|
||||||
url: post.ap_url,
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +91,6 @@ pub fn list(
|
|||||||
published: p.published,
|
published: p.published,
|
||||||
license: p.license,
|
license: p.license,
|
||||||
cover_id: p.cover_id,
|
cover_id: p.cover_id,
|
||||||
url: p.ap_url,
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
@@ -117,20 +114,6 @@ pub fn create(
|
|||||||
NaiveDateTime::parse_from_str(format!("{} 00:00:00", d).as_ref(), "%Y-%m-%d %H:%M:%S").ok()
|
NaiveDateTime::parse_from_str(format!("{} 00:00:00", d).as_ref(), "%Y-%m-%d %H:%M:%S").ok()
|
||||||
});
|
});
|
||||||
|
|
||||||
if slug.as_str() == "new" {
|
|
||||||
return Err(
|
|
||||||
Error::Validation("Sorry, but your article can't have this title.".into()).into(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if payload.title.is_empty() {
|
|
||||||
return Err(Error::Validation("You have to give your article a title.".into()).into());
|
|
||||||
}
|
|
||||||
|
|
||||||
if payload.source.is_empty() {
|
|
||||||
return Err(Error::Validation("Your article can't be empty.".into()).into());
|
|
||||||
}
|
|
||||||
|
|
||||||
let domain = &Instance::get_local()?.public_domain;
|
let domain = &Instance::get_local()?.public_domain;
|
||||||
let (content, mentions, hashtags) = md_to_html(
|
let (content, mentions, hashtags) = md_to_html(
|
||||||
&payload.source,
|
&payload.source,
|
||||||
@@ -148,10 +131,6 @@ pub fn create(
|
|||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
if !author.is_author_in(conn, &Blog::get(conn, blog)?)? {
|
|
||||||
return Err(Error::Unauthorized.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
if Post::find_by_slug(conn, slug, blog).is_ok() {
|
if Post::find_by_slug(conn, slug, blog).is_ok() {
|
||||||
return Err(Error::InvalidValue.into());
|
return Err(Error::InvalidValue.into());
|
||||||
}
|
}
|
||||||
@@ -187,19 +166,11 @@ pub fn create(
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
if let Some(ref tags) = payload.tags {
|
if let Some(ref tags) = payload.tags {
|
||||||
let tags = tags
|
|
||||||
.iter()
|
|
||||||
.map(|t| t.to_camel_case())
|
|
||||||
.filter(|t| !t.is_empty())
|
|
||||||
.collect::<HashSet<_>>()
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|t| Tag::build_activity(t).ok());
|
|
||||||
|
|
||||||
for tag in tags {
|
for tag in tags {
|
||||||
Tag::insert(
|
Tag::insert(
|
||||||
conn,
|
conn,
|
||||||
NewTag {
|
NewTag {
|
||||||
tag: tag.name_string().unwrap(),
|
tag: tag.to_string(),
|
||||||
is_hashtag: false,
|
is_hashtag: false,
|
||||||
post_id: post.id,
|
post_id: post.id,
|
||||||
},
|
},
|
||||||
@@ -240,6 +211,7 @@ pub fn create(
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|t| t.tag)
|
.map(|t| t.tag)
|
||||||
.collect(),
|
.collect(),
|
||||||
|
|
||||||
id: post.id,
|
id: post.id,
|
||||||
title: post.title,
|
title: post.title,
|
||||||
subtitle: post.subtitle,
|
subtitle: post.subtitle,
|
||||||
@@ -249,132 +221,9 @@ pub fn create(
|
|||||||
published: post.published,
|
published: post.published,
|
||||||
license: post.license,
|
license: post.license,
|
||||||
cover_id: post.cover_id,
|
cover_id: post.cover_id,
|
||||||
url: post.ap_url,
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[put("/posts/<id>", data = "<payload>")]
|
|
||||||
pub fn update(
|
|
||||||
id: i32,
|
|
||||||
auth: Authorization<Write, Post>,
|
|
||||||
payload: Json<NewPostData>,
|
|
||||||
rockets: PlumeRocket,
|
|
||||||
) -> Api<PostData> {
|
|
||||||
let conn = &*rockets.conn;
|
|
||||||
let mut post = Post::get(&*conn, id)?;
|
|
||||||
let author = User::get(conn, auth.0.user_id)?;
|
|
||||||
let b = post.get_blog(&*conn)?;
|
|
||||||
|
|
||||||
let new_slug = if !post.published {
|
|
||||||
payload.title.to_string().to_kebab_case()
|
|
||||||
} else {
|
|
||||||
post.slug.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
if new_slug != post.slug && Post::find_by_slug(&*conn, &new_slug, b.id).is_ok() {
|
|
||||||
return Err(Error::Validation("A post with the same title already exists.".into()).into());
|
|
||||||
}
|
|
||||||
|
|
||||||
if !author.is_author_in(&*conn, &b)? {
|
|
||||||
Err(Error::Unauthorized.into())
|
|
||||||
} else {
|
|
||||||
let (content, mentions, hashtags) = md_to_html(
|
|
||||||
&payload.source,
|
|
||||||
Some(&Instance::get_local()?.public_domain),
|
|
||||||
false,
|
|
||||||
Some(Media::get_media_processor(
|
|
||||||
&conn,
|
|
||||||
b.list_authors(&conn)?.iter().collect(),
|
|
||||||
)),
|
|
||||||
);
|
|
||||||
|
|
||||||
// update publication date if when this article is no longer a draft
|
|
||||||
let newly_published = if !post.published && payload.published.unwrap_or(post.published) {
|
|
||||||
post.published = true;
|
|
||||||
post.creation_date = Utc::now().naive_utc();
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
};
|
|
||||||
|
|
||||||
post.slug = new_slug.clone();
|
|
||||||
post.title = payload.title.clone();
|
|
||||||
post.subtitle = payload.subtitle.clone().unwrap_or_default();
|
|
||||||
post.content = SafeString::new(&content);
|
|
||||||
post.source = payload.source.clone();
|
|
||||||
post.license = payload.license.clone().unwrap_or_default();
|
|
||||||
post.cover_id = payload.cover_id;
|
|
||||||
post.update(&*conn, &rockets.searcher)?;
|
|
||||||
|
|
||||||
if post.published {
|
|
||||||
post.update_mentions(
|
|
||||||
&conn,
|
|
||||||
mentions
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|m| Mention::build_activity(&rockets, &m).ok())
|
|
||||||
.collect(),
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let tags = payload
|
|
||||||
.tags
|
|
||||||
.clone()
|
|
||||||
.unwrap_or_default()
|
|
||||||
.iter()
|
|
||||||
.map(|t| t.trim().to_camel_case())
|
|
||||||
.filter(|t| !t.is_empty())
|
|
||||||
.collect::<HashSet<_>>()
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|t| Tag::build_activity(t).ok())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
post.update_tags(&conn, tags)?;
|
|
||||||
|
|
||||||
let hashtags = hashtags
|
|
||||||
.into_iter()
|
|
||||||
.map(|h| h.to_camel_case())
|
|
||||||
.collect::<HashSet<_>>()
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|t| Tag::build_activity(t).ok())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
post.update_hashtags(&conn, hashtags)?;
|
|
||||||
|
|
||||||
if post.published {
|
|
||||||
if newly_published {
|
|
||||||
let act = post.create_activity(&conn)?;
|
|
||||||
let dest = User::one_by_instance(&*conn)?;
|
|
||||||
rockets
|
|
||||||
.worker
|
|
||||||
.execute(move || broadcast(&author, act, dest));
|
|
||||||
} else {
|
|
||||||
let act = post.update_activity(&*conn)?;
|
|
||||||
let dest = User::one_by_instance(&*conn)?;
|
|
||||||
rockets
|
|
||||||
.worker
|
|
||||||
.execute(move || broadcast(&author, act, dest));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Json(PostData {
|
|
||||||
authors: post.get_authors(conn)?.into_iter().map(|a| a.fqn).collect(),
|
|
||||||
creation_date: post.creation_date.format("%Y-%m-%d").to_string(),
|
|
||||||
tags: Tag::for_post(conn, post.id)?
|
|
||||||
.into_iter()
|
|
||||||
.map(|t| t.tag)
|
|
||||||
.collect(),
|
|
||||||
id: post.id,
|
|
||||||
title: post.title,
|
|
||||||
subtitle: post.subtitle,
|
|
||||||
content: post.content.to_string(),
|
|
||||||
source: Some(post.source),
|
|
||||||
blog_id: post.blog_id,
|
|
||||||
published: post.published,
|
|
||||||
license: post.license,
|
|
||||||
cover_id: post.cover_id,
|
|
||||||
url: post.ap_url,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[delete("/posts/<id>")]
|
#[delete("/posts/<id>")]
|
||||||
pub fn delete(auth: Authorization<Write, Post>, rockets: PlumeRocket, id: i32) -> Api<()> {
|
pub fn delete(auth: Authorization<Write, Post>, rockets: PlumeRocket, id: i32) -> Api<()> {
|
||||||
let author = User::get(&*rockets.conn, auth.0.user_id)?;
|
let author = User::get(&*rockets.conn, auth.0.user_id)?;
|
||||||
|
|||||||
+9
-4
@@ -44,6 +44,7 @@ use diesel::r2d2::ConnectionManager;
|
|||||||
use plume_models::{
|
use plume_models::{
|
||||||
db_conn::{DbPool, PragmaForeignKey},
|
db_conn::{DbPool, PragmaForeignKey},
|
||||||
instance::Instance,
|
instance::Instance,
|
||||||
|
ldap::Ldap,
|
||||||
migrations::IMPORTED_MIGRATIONS,
|
migrations::IMPORTED_MIGRATIONS,
|
||||||
search::{Searcher as UnmanagedSearcher, SearcherError},
|
search::{Searcher as UnmanagedSearcher, SearcherError},
|
||||||
Connection, Error, CONFIG,
|
Connection, Error, CONFIG,
|
||||||
@@ -81,6 +82,7 @@ fn init_pool() -> Option<DbPool> {
|
|||||||
e => e.map(|_| ()).unwrap(),
|
e => e.map(|_| ()).unwrap(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let _ = Ldap::get_shared(); // force initialization of lazy static
|
||||||
let manager = ConnectionManager::<Connection>::new(CONFIG.database_url.as_str());
|
let manager = ConnectionManager::<Connection>::new(CONFIG.database_url.as_str());
|
||||||
let pool = DbPool::builder()
|
let pool = DbPool::builder()
|
||||||
.connection_customizer(Box::new(PragmaForeignKey))
|
.connection_customizer(Box::new(PragmaForeignKey))
|
||||||
@@ -275,7 +277,6 @@ Then try to restart Plume
|
|||||||
api::posts::get,
|
api::posts::get,
|
||||||
api::posts::list,
|
api::posts::list,
|
||||||
api::posts::create,
|
api::posts::create,
|
||||||
api::posts::update,
|
|
||||||
api::posts::delete,
|
api::posts::delete,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@@ -300,14 +301,18 @@ Then try to restart Plume
|
|||||||
(
|
(
|
||||||
"/inbox".to_owned(),
|
"/inbox".to_owned(),
|
||||||
"/inbox".to_owned(),
|
"/inbox".to_owned(),
|
||||||
Some(rocket::http::Method::Post),
|
rocket::http::Method::Post,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"/@/<name>/inbox".to_owned(),
|
"/@/<name>/inbox".to_owned(),
|
||||||
"/@/<name>/inbox".to_owned(),
|
"/@/<name>/inbox".to_owned(),
|
||||||
Some(rocket::http::Method::Post),
|
rocket::http::Method::Post,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"/api/<path..>".to_owned(),
|
||||||
|
"/api/<path..>".to_owned(),
|
||||||
|
rocket::http::Method::Post,
|
||||||
),
|
),
|
||||||
("/api/<path..>".to_owned(), "/api/<path..>".to_owned(), None),
|
|
||||||
])
|
])
|
||||||
.finalize()
|
.finalize()
|
||||||
.expect("main: csrf fairing creation error"),
|
.expect("main: csrf fairing creation error"),
|
||||||
|
|||||||
+4
-11
@@ -13,7 +13,6 @@ use validator::{Validate, ValidationError, ValidationErrors};
|
|||||||
use plume_common::activity_pub::{broadcast, ActivityStream, ApRequest};
|
use plume_common::activity_pub::{broadcast, ActivityStream, ApRequest};
|
||||||
use plume_common::utils;
|
use plume_common::utils;
|
||||||
use plume_models::{
|
use plume_models::{
|
||||||
api_tokens::ApiToken,
|
|
||||||
blogs::*,
|
blogs::*,
|
||||||
comments::{Comment, CommentTree},
|
comments::{Comment, CommentTree},
|
||||||
inbox::inbox,
|
inbox::inbox,
|
||||||
@@ -157,8 +156,7 @@ pub fn new(blog: String, cl: ContentLen, rockets: PlumeRocket) -> Result<Ructe,
|
|||||||
None,
|
None,
|
||||||
ValidationErrors::default(),
|
ValidationErrors::default(),
|
||||||
medias,
|
medias,
|
||||||
cl.0,
|
cl.0
|
||||||
ApiToken::web_token(&*conn, user.id)?.value
|
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,8 +210,7 @@ pub fn edit(
|
|||||||
Some(post),
|
Some(post),
|
||||||
ValidationErrors::default(),
|
ValidationErrors::default(),
|
||||||
medias,
|
medias,
|
||||||
cl.0,
|
cl.0
|
||||||
ApiToken::web_token(&*conn, user.id)?.value
|
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -369,10 +366,7 @@ pub fn update(
|
|||||||
Some(post),
|
Some(post),
|
||||||
errors.clone(),
|
errors.clone(),
|
||||||
medias.clone(),
|
medias.clone(),
|
||||||
cl.0,
|
cl.0
|
||||||
ApiToken::web_token(&*conn, user.id)
|
|
||||||
.expect("The default API token cannot be retrieved")
|
|
||||||
.value
|
|
||||||
))
|
))
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
@@ -556,8 +550,7 @@ pub fn create(
|
|||||||
None,
|
None,
|
||||||
errors.clone(),
|
errors.clone(),
|
||||||
medias,
|
medias,
|
||||||
cl.0,
|
cl.0
|
||||||
ApiToken::web_token(&*conn, user.id)?.value
|
|
||||||
))
|
))
|
||||||
.into())
|
.into())
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-30
@@ -33,53 +33,29 @@ pub fn new(m: Option<String>, rockets: PlumeRocket) -> Ructe {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, FromForm, Validate)]
|
#[derive(Default, FromForm)]
|
||||||
pub struct LoginForm {
|
pub struct LoginForm {
|
||||||
#[validate(length(min = "1", message = "We need an email, or a username to identify you"))]
|
|
||||||
pub email_or_name: String,
|
pub email_or_name: String,
|
||||||
#[validate(length(min = "1", message = "Your password can't be empty"))]
|
|
||||||
pub password: String,
|
pub password: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/login", data = "<form>")]
|
#[post("/login", data = "<form>")]
|
||||||
pub fn create(
|
pub fn create(
|
||||||
form: LenientForm<LoginForm>,
|
form: LenientForm<LoginForm>,
|
||||||
mut cookies: Cookies,
|
|
||||||
rockets: PlumeRocket,
|
rockets: PlumeRocket,
|
||||||
|
mut cookies: Cookies,
|
||||||
) -> RespondOrRedirect {
|
) -> RespondOrRedirect {
|
||||||
let conn = &*rockets.conn;
|
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 {
|
let user_id = if let Ok(user) = User::connect(&rockets, &form.email_or_name, &form.password) {
|
||||||
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()
|
user.id.to_string()
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Fake password verification, only to avoid different login times
|
let mut errors = ValidationErrors::new();
|
||||||
// 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 err = ValidationError::new("invalid_login");
|
let mut err = ValidationError::new("invalid_login");
|
||||||
err.message = Some(Cow::from("Invalid username, or password"));
|
err.message = Some(Cow::from("Invalid username, or password"));
|
||||||
errors.add("email_or_name", err);
|
errors.add("email_or_name", err);
|
||||||
String::new()
|
|
||||||
};
|
|
||||||
|
|
||||||
if !errors.is_empty() {
|
|
||||||
return render!(session::login(&rockets.to_context(), None, &*form, errors)).into();
|
return render!(session::login(&rockets.to_context(), None, &*form, errors)).into();
|
||||||
}
|
};
|
||||||
|
|
||||||
cookies.add_private(
|
cookies.add_private(
|
||||||
Cookie::build(AUTH_COOKIE, user_id)
|
Cookie::build(AUTH_COOKIE, user_id)
|
||||||
@@ -111,7 +87,7 @@ pub fn create(
|
|||||||
&(conn, &rockets.intl.catalog, None, None),
|
&(conn, &rockets.intl.catalog, None, None),
|
||||||
None,
|
None,
|
||||||
&*form,
|
&*form,
|
||||||
errors
|
ValidationErrors::new()
|
||||||
))
|
))
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -520,7 +520,7 @@ pub fn create(
|
|||||||
false,
|
false,
|
||||||
"",
|
"",
|
||||||
form.email.to_string(),
|
form.email.to_string(),
|
||||||
User::hash_pass(&form.password).map_err(to_validation)?,
|
&form.password,
|
||||||
)
|
)
|
||||||
.map_err(to_validation)?;
|
.map_err(to_validation)?;
|
||||||
Ok(Flash::success(
|
Ok(Flash::success(
|
||||||
|
|||||||
@@ -48,16 +48,14 @@ impl Resolver<PlumeRocket> for WebfingerResolver {
|
|||||||
CONFIG.base_url.as_str()
|
CONFIG.base_url.as_str()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find(prefix: Prefix, acct: String, ctx: PlumeRocket) -> Result<Webfinger, ResolverError> {
|
fn find(acct: String, ctx: PlumeRocket) -> Result<Webfinger, ResolverError> {
|
||||||
match prefix {
|
User::find_by_fqn(&ctx, &acct)
|
||||||
Prefix::Acct => User::find_by_fqn(&ctx, &acct)
|
|
||||||
.and_then(|usr| usr.webfinger(&*ctx.conn))
|
.and_then(|usr| usr.webfinger(&*ctx.conn))
|
||||||
.or(Err(ResolverError::NotFound)),
|
.or_else(|_| {
|
||||||
Prefix::Group => Blog::find_by_fqn(&ctx, &acct)
|
Blog::find_by_fqn(&ctx, &acct)
|
||||||
.and_then(|blog| blog.webfinger(&*ctx.conn))
|
.and_then(|blog| blog.webfinger(&*ctx.conn))
|
||||||
.or(Err(ResolverError::NotFound)),
|
.or(Err(ResolverError::NotFound))
|
||||||
Prefix::Custom(_) => Err(ResolverError::NotFound),
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +72,9 @@ pub fn webfinger(resource: String, rockets: PlumeRocket) -> Content<String> {
|
|||||||
"Invalid resource. Make sure to request an acct: URI"
|
"Invalid resource. Make sure to request an acct: URI"
|
||||||
}
|
}
|
||||||
ResolverError::NotFound => "Requested resource was not found",
|
ResolverError::NotFound => "Requested resource was not found",
|
||||||
ResolverError::WrongDomain => "This is not the instance of the requested resource",
|
ResolverError::WrongInstance => {
|
||||||
|
"This is not the instance of the requested resource"
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-72
@@ -364,89 +364,32 @@ main .article-meta {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#plume-editor {
|
#plume-editor {
|
||||||
margin: 0;
|
header {
|
||||||
grid: 50px 1fr / 1fr auto 20%;
|
|
||||||
min-height: 80vh;
|
|
||||||
|
|
||||||
& > header {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
background: transparent;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
padding: 0px 20px;
|
button {
|
||||||
border-bottom: 1px solid $purple;
|
flex: 0 0 10em;
|
||||||
max-height: 90px;
|
font-size: 1.25em;
|
||||||
background: $background;
|
margin: .5em 0em .5em 1em;
|
||||||
|
|
||||||
grid-column: 1 / 3;
|
|
||||||
grid-row: 1 / 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#edition-area {
|
|
||||||
margin: 0;
|
|
||||||
max-width: none;
|
|
||||||
max-height: 90vh;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
#edition-area > * {
|
|
||||||
min-height: 1em;
|
|
||||||
outline: none;
|
|
||||||
margin-left: 20%;
|
|
||||||
margin-bottom: 0.5em;
|
|
||||||
padding-right: 5%;
|
|
||||||
|
|
||||||
&:empty::before {
|
|
||||||
content: attr(data-placeholder);
|
|
||||||
display: none;
|
|
||||||
color: transparentize($black, 0.6);
|
|
||||||
cursor: text;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:empty:not(:focus)::before {
|
|
||||||
display: inline;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#edition-area > h1 {
|
|
||||||
margin-top: 110px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#editor-title, #editor-subtitle, #editor-main > * {
|
|
||||||
padding-left: 18px;
|
|
||||||
border-left: 2px solid transparent;
|
|
||||||
transition: border-left-color 0.1s ease-in;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
border-left-color: transparentize($black, 0.6);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
aside {
|
|
||||||
background: $gray;
|
|
||||||
margin: 0;
|
|
||||||
flex: 0 0 15%;
|
|
||||||
padding: 0 1em;
|
|
||||||
grid-row: 1 / 4;
|
|
||||||
|
|
||||||
& > * {
|
& > * {
|
||||||
display: flex;
|
min-height: 1em;
|
||||||
flex-direction: column;
|
outline: none;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
label {
|
.placeholder {
|
||||||
margin: 2em 0 .5em;
|
color: transparentize($black, 0.6);
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
article {
|
||||||
font-size: 1.25em;
|
max-width: none;
|
||||||
margin: 0;
|
min-height: 80vh;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
body#editor {
|
|
||||||
footer {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,52 +9,22 @@
|
|||||||
@use routes::posts::NewPostForm;
|
@use routes::posts::NewPostForm;
|
||||||
@use routes::*;
|
@use routes::*;
|
||||||
|
|
||||||
@(ctx: BaseContext, title: String, blog: Blog, editing: bool, form: &NewPostForm, is_draft: bool, article: Option<Post>, errors: ValidationErrors, medias: Vec<Media>, content_len: u64, api_token: String)
|
@(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(), {}, {}, {
|
@:base(ctx, title.clone(), {}, {}, {
|
||||||
<script>
|
<h1 id="plume-editor-title" dir="auto">@title</h1>
|
||||||
window.blog_id = @blog.id
|
|
||||||
window.api_token = '@api_token'
|
|
||||||
@if editing {
|
|
||||||
window.editing = true
|
|
||||||
window.post_id = @article.clone().unwrap().id
|
|
||||||
} else {
|
|
||||||
window.editing = false
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<div id="plume-editor" style="display: none;" dir="auto">
|
<div id="plume-editor" style="display: none;" dir="auto">
|
||||||
<header id="editor-toolbar">
|
<header>
|
||||||
|
<button id="publish" class="button">@i18n!(ctx.1, "Publish")</button>
|
||||||
|
<p id="char-count">@content_len</p>
|
||||||
<a href="#" id="close-editor">@i18n!(ctx.1, "Classic editor (any changes will be lost)")</a>
|
<a href="#" id="close-editor">@i18n!(ctx.1, "Classic editor (any changes will be lost)")</a>
|
||||||
</header>
|
</header>
|
||||||
<article id="edition-area">
|
|
||||||
<h1 contenteditable id="editor-title" data-placeholder="@i18n!(ctx.1, "Type your title")">@form.title</h1>
|
|
||||||
<h2 contenteditable id="editor-subtitle" data-placeholder="@i18n!(ctx.1, "Type a subtitle or a summary")">@form.subtitle</h2>
|
|
||||||
<article contenteditable id="editor-main" data-placeholder="@i18n!(ctx.1, "Write your article here. You can use markdown.")"></article>
|
|
||||||
</article>
|
|
||||||
<aside id="plume-editor-aside" style="display: none;">
|
|
||||||
<div id="options-page">
|
|
||||||
<button id="publish" class="button">@i18n!(ctx.1, "Publish")</button>
|
|
||||||
|
|
||||||
@input!(ctx.1, tags (optional text), "Tags, separated by commas", form, errors.clone(), "")
|
|
||||||
@input!(ctx.1, license (optional text), "License", "Leave it empty to reserve all rights", form, errors.clone(), "")
|
|
||||||
@:image_select(ctx, "cover", i18n!(ctx.1, "Illustration"), true, medias.clone(), form.cover)
|
|
||||||
</div>
|
</div>
|
||||||
<div id="publish-page" style="display: none">
|
|
||||||
<a href="#" id="cancel-publish">@i18n!(ctx.1, "Cancel")</a>
|
|
||||||
<p>@i18n!(ctx.1, "You are about to publish this article in {}"; &blog.title)</p>
|
|
||||||
<button id="confirm-publish" class="button">@i18n!(ctx.1, "Confirm publication")</button>
|
|
||||||
<button id="save-draft" class="button secondary">@i18n!(ctx.1, "Save as draft")</button>
|
|
||||||
</div>
|
|
||||||
</aside>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@if let Some(article) = article {
|
@if let Some(article) = article {
|
||||||
<form id="plume-fallback-editor" class="new-post" method="post" action="@uri!(posts::update: blog = blog.actor_id, slug = &article.slug)" content-size="@content_len">
|
<form id="plume-fallback-editor" class="new-post" method="post" action="@uri!(posts::update: blog = blog.actor_id, slug = &article.slug)" content-size="@content_len">
|
||||||
} else {
|
} else {
|
||||||
<form id="plume-fallback-editor" class="new-post" method="post" action="@uri!(posts::new: blog = blog.actor_id)" content-size="@content_len">
|
<form id="plume-fallback-editor" class="new-post" method="post" action="@uri!(posts::new: blog = blog.actor_id)" content-size="@content_len">
|
||||||
}
|
}
|
||||||
<h1 id="plume-editor-title" dir="auto">@title</h1>
|
|
||||||
|
|
||||||
@input!(ctx.1, title (text), "Title", form, errors.clone(), "required")
|
@input!(ctx.1, title (text), "Title", form, errors.clone(), "required")
|
||||||
@input!(ctx.1, subtitle (optional text), "Subtitle", form, errors.clone(), "")
|
@input!(ctx.1, subtitle (optional text), "Subtitle", form, errors.clone(), "")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user