diff --git a/.gitignore b/.gitignore index e0ba536..a4c7fe2 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ rls /target **/*.rs.bk rls +translations +po/*.po~ diff --git a/Cargo.lock b/Cargo.lock index cb86b4e..c687510 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -263,11 +263,11 @@ dependencies = [ [[package]] name = "cookie" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.11.0-dev" +source = "git+https://github.com/alexcrichton/cookie-rs?rev=0365a18#0365a18e4518e498ac6a508dab6b006add7f162e" dependencies = [ - "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.13.0-alpha5 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -297,15 +297,6 @@ dependencies = [ "build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "crossbeam-deque" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "crossbeam-deque" version = "0.3.0" @@ -315,20 +306,6 @@ dependencies = [ "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "crossbeam-epoch" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "crossbeam-epoch" version = "0.4.1" @@ -420,14 +397,6 @@ name = "entities" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "error-chain" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "backtrace 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "error-chain" version = "0.11.0" @@ -505,11 +474,6 @@ dependencies = [ "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "gcc" -version = "0.3.54" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "generic-array" version = "0.9.0" @@ -518,6 +482,23 @@ dependencies = [ "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "gettext-rs" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gettext-sys 0.19.8 (registry+https://github.com/rust-lang/crates.io-index)", + "locale_config 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "gettext-sys" +version = "0.19.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "glob" version = "0.2.11" @@ -625,6 +606,11 @@ dependencies = [ "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "indexmap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "iovec" version = "0.1.2" @@ -699,6 +685,17 @@ dependencies = [ "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "locale_config" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "log" version = "0.3.9" @@ -745,14 +742,6 @@ name = "matches" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "memchr" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "memchr" version = "2.0.1" @@ -920,21 +909,22 @@ dependencies = [ "vcpkg 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "ordermap" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "pear" -version = "0.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.1.0" +source = "git+http://github.com/SergioBenitez/Pear?rev=54667ae#54667aefef084f2411e86392402a955770f1e7aa" +dependencies = [ + "pear_codegen 0.1.0 (git+http://github.com/SergioBenitez/Pear?rev=54667ae)", +] [[package]] name = "pear_codegen" -version = "0.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.1.0" +source = "git+http://github.com/SergioBenitez/Pear?rev=54667ae#54667aefef084f2411e86392402a955770f1e7aa" dependencies = [ + "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)", "version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "yansi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -944,11 +934,6 @@ name = "percent-encoding" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "pest" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "pest" version = "1.0.6" @@ -1019,18 +1004,21 @@ dependencies = [ "dotenv 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "gettext-rs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.11.25 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "openssl 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)", "reqwest 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rocket 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rocket_codegen 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rocket_contrib 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rocket 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)", + "rocket_codegen 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)", + "rocket_contrib 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)", + "rocket_i18n 0.1.1 (git+https://github.com/BaptisteGelez/rocket_i18n?rev=457b88c59ec31905a9193df43df58bee55b4b83d)", "serde 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tera 0.11.7 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1063,6 +1051,14 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "proc-macro2" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "quote" version = "0.3.15" @@ -1084,6 +1080,14 @@ dependencies = [ "proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "quote" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "r2d2" version = "0.8.2" @@ -1114,26 +1118,6 @@ dependencies = [ "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rayon" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rayon-core" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "redox_syscall" version = "0.1.37" @@ -1209,62 +1193,92 @@ dependencies = [ [[package]] name = "ring" -version = "0.11.0" +version = "0.13.0-alpha5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rocket" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.4.0-dev" +source = "git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba#df7111143e466c18d1f56377a8d9530a5a306aba" dependencies = [ - "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cookie 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "isatty 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ordermap 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "pear 0.0.16 (registry+https://github.com/rust-lang/crates.io-index)", - "pear_codegen 0.0.16 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "state 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pear 0.1.0 (git+http://github.com/SergioBenitez/Pear?rev=54667ae)", + "rocket_codegen_next 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)", + "rocket_http 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)", + "state 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "yansi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rocket_codegen" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.4.0-dev" +source = "git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba#df7111143e466c18d1f56377a8d9530a5a306aba" dependencies = [ - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "rocket 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rocket_http 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)", "version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "yansi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rocket_codegen_next" +version = "0.4.0-dev" +source = "git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba#df7111143e466c18d1f56377a8d9530a5a306aba" +dependencies = [ + "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rocket_contrib" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.4.0-dev" +source = "git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba#df7111143e466c18d1f56377a8d9530a5a306aba" dependencies = [ "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "rocket 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rocket 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)", "serde 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", - "tera 0.10.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tera 0.11.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rocket_http" +version = "0.4.0-dev" +source = "git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba#df7111143e466c18d1f56377a8d9530a5a306aba" +dependencies = [ + "cookie 0.11.0-dev (git+https://github.com/alexcrichton/cookie-rs?rev=0365a18)", + "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "pear 0.1.0 (git+http://github.com/SergioBenitez/Pear?rev=54667ae)", + "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rocket_i18n" +version = "0.1.1" +source = "git+https://github.com/BaptisteGelez/rocket_i18n?rev=457b88c59ec31905a9193df43df58bee55b4b83d#457b88c59ec31905a9193df43df58bee55b4b83d" +dependencies = [ + "gettext-rs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rocket 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)", + "serde_json 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tera 0.11.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1400,12 +1414,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "smallvec" -version = "0.4.4" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "state" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1474,6 +1488,16 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "syn" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.3 (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 = "synom" version = "0.11.3" @@ -1525,15 +1549,16 @@ dependencies = [ [[package]] name = "tera" -version = "0.10.10" +version = "0.11.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "humansize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "pest 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "pest_derive 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1837,7 +1862,7 @@ dependencies = [ [[package]] name = "untrusted" -version = "0.5.1" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1962,13 +1987,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1cce36c92cb605414e9b824f866f5babe0a0368e39ea07393b9b63cf3844c0e6" "checksum clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f16b89cbb9ee36d87483dc939fe9f1e13c05898d56d7b230a0d4dff033a536" "checksum comrak 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "053b26c8ce23b4c505a9479beace98f95899e0bf5c5255cf0219e9b0f48cf6ea" -"checksum cookie 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "477eb650753e319be2ae77ec368a58c638f9f0c4d941c39bad95e950fb1d1d0d" +"checksum cookie 0.11.0-dev (git+https://github.com/alexcrichton/cookie-rs?rev=0365a18)" = "" "checksum core-foundation 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25bfd746d203017f7d5cbd31ee5d8e17f94b6521c7af77ece6c9e4b2d4b16c67" "checksum core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "065a5d7ffdcbc8fa145d6f0746f3555025b9097a9e9cda59f7467abae670c78d" "checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" -"checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" "checksum crossbeam-deque 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c1bdc73742c36f7f35ebcda81dbb33a7e0d33757d03a06d9ddca762712ec5ea2" -"checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" "checksum crossbeam-epoch 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9b4e2817eb773f770dcb294127c011e22771899c21d18fce7dd739c0b9832e81" "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" "checksum crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d636a8b3bcc1b409d7ffd3facef8f21dcb4009626adbd0c5e6c4305c07253c7b" @@ -1979,7 +2002,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" "checksum encoding_rs 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "98fd0f24d1fb71a4a6b9330c8ca04cbd4e7cc5d846b54ca74ff376bc7c9f798d" "checksum entities 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca" -"checksum error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8" "checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" "checksum failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82" "checksum failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cdda555bb90c9bb67a3b670a0f42de8e73f5981524123ad8578aafec8ddb8b" @@ -1990,8 +2012,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum futf 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7c9c1ce3fa9336301af935ab852c437817d14cd33690446569392e65170aac3b" "checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c" "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" -"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" "checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" +"checksum gettext-rs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3b8c2412d5758f68a9eeba161f9ecb9a55f56bfdbf17857650b98f2b9b281a47" +"checksum gettext-sys 0.19.8 (registry+https://github.com/rust-lang/crates.io-index)" = "62c644c0b8b73706fb8c7420533fd30abf6f41c2703994bc6f0826fceb7fb3d6" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" "checksum heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea04fa3ead4e05e51a7c806fc07271fdbde4e246a6c6d1efd52e72230b771b82" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" @@ -2002,6 +2025,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum hyper 0.11.25 (registry+https://github.com/rust-lang/crates.io-index)" = "549dbb86397490ce69d908425b9beebc85bbaad25157d67479d4995bb56fdf9a" "checksum hyper-tls 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a5aa51f6ae9842239b0fac14af5f22123b8432b4cc774a44ff059fcba0f675ca" "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" +"checksum indexmap 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08173ba1e906efb6538785a8844dd496f5d34f0a2d88038e95195172fc667220" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum isatty 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a118a53ba42790ef25c82bb481ecf36e2da892646cccd361e69a6bb881e19398" "checksum itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c" @@ -2013,13 +2037,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" "checksum libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)" = "6fd41f331ac7c5b8ac259b8bf82c75c0fb2e469bbf37d2becbba9a6a2221965b" "checksum libflate 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "1a429b86418868c7ea91ee50e9170683f47fd9d94f5375438ec86ec3adb74e8e" +"checksum locale_config 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "14fbee0e39bc2dd6a2427c4fdea66e9826cc1fd09b0a0b7550359f5f6efe1dab" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" "checksum mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" "checksum maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08cbb6b4fef96b6d77bfc40ec491b1690c779e77b05cd9f07f787ed376fd4c43" "checksum markup5ever 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfedc97d5a503e96816d10fedcd5b42f760b2e525ce2f7ec71f6a41780548475" "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" -"checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" "checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" @@ -2038,11 +2062,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum openssl 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)" = "63246f69962e8d5ef865f82a65241d6483c8a2905a1801e2f7feb5d187d51320" "checksum openssl 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)" = "a3605c298474a3aa69de92d21139fb5e2a81688d308262359d85cdd0d12a7985" "checksum openssl-sys 0.9.28 (registry+https://github.com/rust-lang/crates.io-index)" = "0bbd90640b148b46305c1691eed6039b5c8509bed16991e3562a01eeb76902a3" -"checksum ordermap 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "b81cf3b8cb96aa0e73bbedfcdc9708d09fec2854ba8d474be4e6f666d7379e8b" -"checksum pear 0.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "b9b645aa07cf1010a67e9f67b4b9b96d6c5fb9315eee678a061d6ab58e9cb77f" -"checksum pear_codegen 0.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "ca34109829349aeefe22772916da5404b3f5cd0e63a72c5d91209fc809342265" +"checksum pear 0.1.0 (git+http://github.com/SergioBenitez/Pear?rev=54667ae)" = "" +"checksum pear_codegen 0.1.0 (git+http://github.com/SergioBenitez/Pear?rev=54667ae)" = "" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" -"checksum pest 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3e2e823a5967bb4cdc6d3e46f47baaf4ecfeae44413a642b74ad44e59e49c7f6" "checksum pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0fce5d8b5cc33983fc74f78ad552b5522ab41442c4ca91606e4236eb4b5ceefc" "checksum pest_derive 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ab94faafeb93f4c5e3ce81ca0e5a779529a602ad5d09ae6d21996bfb8b6a52bf" "checksum phf 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)" = "7d37a244c75a9748e049225155f56dbcb98fe71b192fd25fd23cb914b5ad62f2" @@ -2054,14 +2076,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" "checksum proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0" "checksum proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "49b6a521dc81b643e9a51e0d1cf05df46d5a2f3c0280ea72bcb68276ba64a118" +"checksum proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "effdb53b25cdad54f8f48843d67398f7ef2e14f12c1b4cb4effc549a6462a4d6" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eca14c727ad12702eb4b6bfb5a232287dcf8385cb8ca83a3eeaf6519c44c408" "checksum quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8" +"checksum quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e44651a0dc4cdd99f71c83b561e221f714912d11af1a4dff0631f923d53af035" "checksum r2d2 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f9078ca6a8a5568ed142083bb2f7dc9295b69d16f867ddcc9849e51b17d8db46" "checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" "checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" -"checksum rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a77c51c07654ddd93f6cb543c7a849863b03abc7e82591afda6dc8ad4ac3ac4a" -"checksum rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d24ad214285a7729b174ed6d3bcfcb80177807f959d95fafd5bfc5c4f201ac8" "checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "aec3f58d903a7d2a9dc2bf0e41a746f4530e0cab6b615494e058f67a3ef947fb" @@ -2069,10 +2091,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1576e382688d7e9deecea24417e350d3062d97e32e45d70b1cde65994ff1489a" "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" "checksum reqwest 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)" = "241faa9a8ca28a03cbbb9815a5d085f271d4c0168a19181f106aa93240c22ddb" -"checksum ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2a6dc7fc06a05e6de183c5b97058582e9da2de0c136eafe49609769c507724" -"checksum rocket 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c000cf7233aa997a19a43f77ddc80db11b58cdbbc12e2c1385bd62cbbace3964" -"checksum rocket_codegen 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "645dd494d1340a4c16ba8decc4bb94d3e687a7e6b57552e2341dbf436b75ffaa" -"checksum rocket_contrib 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "2b1f97dc98bf6fa9a861e3c0c71f150f1110350eaaebe56516377d7f4316a51a" +"checksum ring 0.13.0-alpha5 (registry+https://github.com/rust-lang/crates.io-index)" = "3845516753f91b4511f9b17c917ea6fa4bc5a7853a9947b0f66731aff51cdef5" +"checksum rocket 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)" = "" +"checksum rocket_codegen 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)" = "" +"checksum rocket_codegen_next 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)" = "" +"checksum rocket_contrib 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)" = "" +"checksum rocket_http 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)" = "" +"checksum rocket_i18n 0.1.1 (git+https://github.com/BaptisteGelez/rocket_i18n?rev=457b88c59ec31905a9193df43df58bee55b4b83d)" = "" "checksum rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11fb43a206a04116ffd7cfcf9bcb941f8eb6cc7ff667272246b0a1c74259a3cb" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" "checksum schannel 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "85fd9df495640643ad2d00443b3d78aae69802ad488debab4f1dd52fc1806ade" @@ -2091,8 +2116,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdeff4cd9ecff59ec7e3744cbca73dfe5ac35c2aedb2cfba8a1c715a18912e9d" "checksum slug 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "797bcb4d24e91239a8615415814f4afb2d8ca400c472de3c73f803a5a7689e11" "checksum smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c8cbcd6df1e117c2210e13ab5109635ad68a929fcbb8964dc965b76cb5ee013" -"checksum smallvec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ee4f357e8cd37bf8822e1b964e96fd39e2cb5a0424f8aaa284ccaccc2162411c" -"checksum state 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d5562ac59585fe3d9a1ccf6b4e298ce773f5063db80d59f783776b410c1714c2" +"checksum smallvec 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "312a7df010092e73d6bbaf141957e868d4f30efd2bfd9bb1028ad91abec58514" +"checksum state 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7345c971d1ef21ffdbd103a75990a15eb03604fc8b8852ca8cb418ee1a099028" "checksum string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25d70109977172b127fe834e5449e5ab1740b9ba49fa18a2020f509174f25423" "checksum string_cache_codegen 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "35293b05cf1494e8ddd042a7df6756bf18d07f42d234f32e71dce8a7aabb0191" "checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc" @@ -2100,13 +2125,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum syn 0.12.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c97c05b8ebc34ddd6b967994d5c6e9852fa92f8b82b3858c39451f97346dcce5" "checksum syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "91b52877572087400e83d24b9178488541e3d535259e04ff17a63df1e5ceff59" +"checksum syn 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c67da57e61ebc7b7b6fff56bb34440ca3a83db037320b0507af4c10368deda7d" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd" "checksum syntex_fmt_macros 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5386bdc48758d136af85b3880548e1f3a9fad8d7dc2b38bdb48c36a9cdefc0" "checksum take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b157868d8ac1f56b64604539990685fa7611d8fa9e5476cf0c02cf34d32917c5" "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" "checksum tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9de21546595a0873061940d994bbbc5c35f024ae4fd61ec5c5b159115684f508" -"checksum tera 0.10.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d706c3bec8103f346fc7b8a3887a2ff4195cf704bdbc6307069f32ea8a2b3af5" +"checksum tera 0.11.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e815b67d44c26feb06630011fb58b5b243f4e9585aac1ed0592c5795de64cd75" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693" "checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963" @@ -2141,7 +2167,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum unicode_categories 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" "checksum unidecode 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "402bb19d8e03f1d1a7450e2bd613980869438e0666331be3e073089124aa1adc" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -"checksum untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f392d7819dbe58833e26872f5f6f0d68b7bbbe90fc3667e98731c4a15ad9a7ae" +"checksum untrusted 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70afa43c8c5d23a53a3c39ec9b56232c5badc19f6bb5ad529c1d6448a7241365" "checksum url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f808aadd8cfec6ef90e4a14eb46f24511824d1ac596b9682703c87056c8678b7" "checksum utf-8 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1262dfab4c30d5cb7c07026be00ee343a6cf5027fdc0104a9160f354e5db75c" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" diff --git a/Cargo.toml b/Cargo.toml index 819d8a4..b175393 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ name = "plume" version = "0.1.0" [dependencies] activitypub = "0.1.1" +ammonia = "1.1.0" array_tool = "1.0" base64 = "0.9" bcrypt = "0.2" @@ -11,19 +12,18 @@ comrak = "0.2" dotenv = "*" failure = "0.1" failure_derive = "0.1" +gettext-rs = "0.4" heck = "0.3.0" hex = "0.3" hyper = "*" lazy_static = "*" openssl = "0.10.6" reqwest = "0.8" -rocket = "*" -rocket_codegen = "*" serde = "*" serde_derive = "1.0" serde_json = "1.0" +tera = "0.11" url = "1.7" -ammonia = "1.1.0" [dependencies.chrono] features = ["serde"] @@ -33,6 +33,19 @@ version = "0.4" features = ["postgres", "r2d2", "chrono"] version = "*" +[dependencies.rocket] +git = "https://github.com/SergioBenitez/Rocket" +rev = "df7111143e466c18d1f56377a8d9530a5a306aba" + +[dependencies.rocket_codegen] +git = "https://github.com/SergioBenitez/Rocket" +rev = "df7111143e466c18d1f56377a8d9530a5a306aba" + [dependencies.rocket_contrib] features = ["tera_templates", "json"] -version = "*" +git = "https://github.com/SergioBenitez/Rocket" +rev = "df7111143e466c18d1f56377a8d9530a5a306aba" + +[dependencies.rocket_i18n] +git = "https://github.com/BaptisteGelez/rocket_i18n" +rev = "457b88c59ec31905a9193df43df58bee55b4b83d" diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md new file mode 100644 index 0000000..c82d7db --- /dev/null +++ b/DEVELOPMENT.md @@ -0,0 +1,161 @@ +# Development Guide + +## Running Plume locally + +### Mac OSX + +All commands are run in the Mac Terminal or terminal emulator of your choice, such as iTerm2. First, you will need [Git](https://git-scm.com/download/mac), [Homebrew](https://brew.sh/), [Rust](https://www.rust-lang.org/en-US/), and [Postgres](https://www.postgresql.org/). Follow the instructions to install Homebrew before continuing if you don't already have it. + +#### Download the Repository + +Navigate to the directory on your machine where you would like to install the repository, such as in `~/dev` by running `cd dev`. Now, clone the remote repository by running `git clone https://github.com/Plume-org/Plume.git`. This will install the codebase to the `Plume` subdirectory. Navigate into that directory by running `cd Plume`. + +#### Rust + +If you think you might already have rust on your machine, you can check by running + +``` +rustc --version +# Should output something like +# rustc 1.28.0-nightly (a805a2a5e 2018-06-10) +``` + +If you don't already have Rust, install it by running + +``` +curl https://sh.rustup.rs -sSf | sh +``` + +In the interactive installation, choose the option of the nightly toolchain. Restart your console so that the `rustc` CLI tool is available. + +#### Postgres + +Now we will use Homebrew to install Postgres. If you think you might already have it, try running `brew info postgres`. If it is not available, continue to install Postgres by running the following: + +``` +brew install postgres +``` + +Now, you can use the following command to start Postgres on a one-time basis. + +``` +pg_ctl -D /usr/local/var/postgres start +``` + +After starting Postgres, we need to enter [PSQL](http://postgresguide.com/utilities/psql.html), the interactive terminal for running postgres queries. We'll be running this as the user `postgres` which is an admin-type postgres user. + +``` +psql postgres +``` + +Now that you are in psql, enter the following queries to prepare the database for Plume. + +``` +CREATE DATABASE plume; +CREATE USER plume WITH PASSWORD 'plume'; +GRANT ALL PRIVILEGES ON DATABASE plume to plume; +\q +``` + +The final command `\q` lets us exit psql and returns us to the Terminal. Now, we will open psql again, this time as the `plume` user we just created. Then we'll give all privileges on all tables and sequences to our `plume` user. This is for local development use only and it's not recommend to give complete access to this user in a production environment. + +``` +psql plume +GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO plume; +GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO plume; +\q +``` + +#### Database Migration + +Now that the Postgres database is set up and the `plume` user has the privileges it needs, we can set up the database using the diesel CLI. If this was your time installing Rust, you +will probably need to run that using `cargo`. `cargo` is installed with `rustc` so if you followed the earlier instructions it will already be available. + +``` +cargo install diesel_cli +``` + +The first time you run this, you can run setup. After that, every time you pull the repository you will want to run the migration command in case there were any migrations. Those commands are + +``` +diesel setup --database-url='postgres://localhost/plume' +diesel migration run --database-url='postgres://localhost/plume' +``` + +#### Running Plume + +To run Plume locally, make sure you are once again in the Plume directory, such as `~/dev/Plume`. Now you will be able to run the application using the command + +``` +cargo run +``` + +#### Configuration + +Now Plume should be running on your machine at [http://localhost:8000](http://localhost:8000). The first time you run the application, you'll want to configure your blog name on the [http://localhost:8000/configure](http://localhost:8000/configure) page. You'll be able to change this name later. + +#### Testing the federation + +To test the federation, you'll need to setup another database (see "Setup the database"), +also owned by the "plume" user, but with a different name. Then, you'll need to run the +migrations for this database too. + +``` +diesel migration run --database-url postgres://plume:plume@localhost/my_other_plume_db +``` + +To run this other instance, you'll need to give two environment variables: + +- `ROCKET_PORT`, the port on which your app will run +- `DB_NAME`, the name of the database you just created + +``` +ROCKET_PORT=3033 DB_NAME=my_other_plume_db cargo run +``` + +#### Making a Pull Request +To create an upstream fork of the repository in GitHub, click "Fork" in the top right button on the main page of the [Plume repository](https://github.com/Plume-org/Plume). Now, in the command line, set another remote for the repository by running the following command, replacing `myname` with the name under which you forked the repo. You can use another name besides `upstream` if you prefer. Using [SSH](https://help.github.com/articles/connecting-to-github-with-ssh/) is recommended. + +``` +git remote add upstream git@github.com/myname/Plume.git +# Alt # git remote add upstream https://github.com/myname/Plume.git +``` + +Now, make any changes to the code you want. After committing your changes, push to the upstream fork. Once your changes are made, visit the GitHub page for your fork and select "New pull request". Add descriptive text, any issue numbers using hashtags to reference the issue number, screenshots of your changes if relevant, a description of how you tested your changes, and any other information that will help the project maintainers be able to quickly accept your pull requests. + +The project maintainers may suggest further changes to improve the pull request even more. After implementing this locally, you can push to your upstream fork again and the changes will immediately show up in the pull request after pushing. Once all the suggested changes are made, the pull request may be accepted. Thanks for contributing. + +#### When working with Tera templates + +When working with the interface, or any message that will be displayed to the final user, keep in mind that Plume is an internationalized software. To make sure that the parts of the interface you are changing are translatable, you should: + +- Use the `_` and `_n` filters instead of directly writing strings in your HTML markup +- Add the strings to translate to the `po/plume.pot` file + +Here is an example: let's say we want to add two strings, a simple one and one that may deal with plurals. The first step is to add them to whatever template we want to display them in: + +```jinja +

{{ "Hello, world!" | _ }}

+ +

{{ "You have {{ count }} new notifications" | _n(singular="You have one new notification", count=n_notifications) }}

+``` + +As you can see, the `_` doesn't need any special argument to work, but `_n` requires `singular` (the singular form, in English) and `count` (the number of items, to determine which form to use) to be present. Note that any parameters given to these filters can be used as regular Tera variables inside of the translated strings, like we are doing with the `count` variable in the second string above. + +The second step is to add them to POT file. To add a simple message, just do: + +```po +msgid "Hello, world" # The string you used with your filter +msgstr "" # Always empty +``` + +For plural forms, the syntax is a bit different: + +```po +msgid "You have one new notification" # The singular form +msgid_plural "You have {{ count }} new notifications" # The plural one +msgstr[0] "" +msgstr[1] "" +``` + +And that's it! Once these new messages will have been translated, they will correctly be displayed in the requested locale! diff --git a/INTERNATIONALIZATION.md b/INTERNATIONALIZATION.md new file mode 100644 index 0000000..cbb0497 --- /dev/null +++ b/INTERNATIONALIZATION.md @@ -0,0 +1,35 @@ +# Making Plume available in your language + +*You will need to have basic git and GitHub knownledge to follow this guide. But we plan to setup a more user-friendly translation tool in the future.* + +To translate Plume in your language, you'll first need to make sure it is listed in the `po/LINGUAS` file. If it is not, you can ask anybody with a development environment to add it (or do it yourself if you have a development environment). Once it will be here, Plume must be launched once to generate all the needed files. + +Then you can start translating. Find the file corresponding to your locale, which is `po/YOUR_LOCALE.po`, and open it. Inside, you have a list of strings to translate. There are two kind of translatable strings. + +## Simple strings + +They look like this: + +```po +msgid "Hello, world" +msgstr "" +``` + +What is next to `msgid` is the string in English. To translate it, just fill the `msgstr` field with the translation. + +## Strings with plural forms + +Sometimes, strings may change depending on a number (for instance, a post counter). In the `.po` files, these strings look like this: + +``` +msgid "One post" +msgid_plural "{{ count }} posts" +msgstr[0] "" +msgstr[1] "" +``` + +Then you should fill the two `msgstr` field, one with the singular form, the second with the plural one. If your language as more than two forms, you can add another one by following the same pattern (`msgstr[n] ""`). + +## Interpolation + +Strings you translate may contain data from Plume (a username for instance). To tell Plume where to put these data, surround their identifier by `{{` and `}}`. The identifier is also present in this form in the English string to translate (this what you can see above, with the `{{ count }} posts` message). diff --git a/README.md b/README.md index bec7304..70ac657 100644 --- a/README.md +++ b/README.md @@ -1,65 +1,13 @@ # Plume [![Build Status](https://travis-ci.org/Plume-org/Plume.svg?branch=master)](https://travis-ci.org/Plume-org/Plume) -Federated blogging engine, based on ActivityPub. +Federated blogging engine, based on ActivityPub. It uses the Rocket framework, and Diesel to interact with the database. [**Demo instance**](https://baptiste.gelez.xyz/) -## Setup the database +It is not yet ready for production use, but we have all the basic features (account management, blogs, articles, comments, etc) and a basic federation. -You'll need Postgres. +Feel free to join our Matrix room: `#plume:disroot.org` to discuss about the project! -``` -sudo su postgres +If you are interested in coding, check out the [development guide](https://github.com/Plume-org/Plume/blob/master/DEVELOPMENT.md). You can also help by reporting issues, suggesting features, or writing documentation for instance. -psql - -CREATE DATABASE plume; -CREATE USER plume WITH PASSWORD 'plume'; -GRANT ALL PRIVILEGES ON DATABASE plume to plume; -\q - -exit -``` - -Then run the migrations - -``` -diesel migrations run # Install diesel with `cargo install diesel_cli` if needed -``` - -You should repeat this operation every time the database schema has been modified. -A good practice is to run it after every `git pull`. - -## Starting the app - -Just use: - -``` -cargo run -``` - -You'll need Rust nightly. - -Once the app started, try to visit [localhost:8000](http://localhost:8000). - -To configure the instance (needed before you can do anything else), -go on [/configure](http://localhost:8000/configure). - -## Testing the federation - -To test the federation, you'll need to setup another database (see "Setup the database"), -also owned by the "plume" user, but with a different name. Then, you'll need to run the -migrations for this database too. - -``` -diesel migration run --database-url postgres://plume:plume@localhost/my_other_plume_db -``` - -To run this other instance, you'll need to give two environment variables: - -- `ROCKET_PORT`, the port on which your app will run -- `DB_NAME`, the name of the database you just created - -``` -ROCKET_PORT=3033 DB_NAME=my_other_plume_db cargo run -``` +If you would like to help by translating Plume, we also have [a guide for you](https://github.com/Plume-org/Plume/blob/master/INTERNATIONALIZATION.md)! diff --git a/po/LINGUAS b/po/LINGUAS new file mode 100644 index 0000000..7e6d9e4 --- /dev/null +++ b/po/LINGUAS @@ -0,0 +1,2 @@ +en +fr diff --git a/po/en.po b/po/en.po new file mode 100644 index 0000000..2634ce4 --- /dev/null +++ b/po/en.po @@ -0,0 +1,255 @@ +msgid "" +msgstr "" +"Project-Id-Version: plume\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-06-15 16:33-0700\n" +"PO-Revision-Date: 2018-06-15 16:33-0700\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: en\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +msgid "Latest articles" +msgstr "" + +msgid "No posts to see here yet." +msgstr "" + +msgid "New article" +msgstr "" + +msgid "New blog" +msgstr "" + +msgid "Create a blog" +msgstr "" + +msgid "Title" +msgstr "" + +msgid "Create blog" +msgstr "" + +msgid "Comment \"{{ post }}\"" +msgstr "" + +msgid "Content" +msgstr "" + +msgid "Submit comment" +msgstr "" + +msgid "Something broke on our side." +msgstr "" + +msgid "Sorry about that. If you think this is a bug, please report it." +msgstr "" + +msgid "Configuration" +msgstr "" + +msgid "Configure your instance" +msgstr "" + +msgid "Name" +msgstr "" + +msgid "Let's go!" +msgstr "" + +msgid "Welcome on {{ instance_name }}" +msgstr "Welcome on {{ instance_name }}" + +msgid "Notifications" +msgstr "" + +msgid "Written by {{ link_1 }}{{ url }}{{ link_2 }}{{ name }}{{ link_3 }}" +msgstr "" + +msgid "This article is under the {{ license }} license." +msgstr "" + +#, fuzzy +msgid "One like" +msgid_plural "{{ count }} likes" +msgstr[0] "One follower" +msgstr[1] "{{ count }} followers" + +msgid "I don't like this anymore" +msgstr "" + +msgid "Add yours" +msgstr "" + +msgid "One reshare" +msgid_plural "{{ count }} reshares" +msgstr[0] "" +msgstr[1] "" + +msgid "I don't want to reshare this anymore" +msgstr "" + +msgid "Reshare" +msgstr "" + +msgid "Comments" +msgstr "" + +msgid "Respond" +msgstr "" + +msgid "Comment" +msgstr "" + +msgid "New post" +msgstr "" + +msgid "Create a post" +msgstr "" + +msgid "Publish" +msgstr "" + +msgid "Login" +msgstr "" + +msgid "Username or email" +msgstr "" + +msgid "Password" +msgstr "" + +msgid "Dashboard" +msgstr "" + +msgid "Your Dashboard" +msgstr "" + +msgid "Your Blogs" +msgstr "" + +msgid "You don't have any blog yet. Create your own, or ask to join one." +msgstr "" + +msgid "Start a new blog" +msgstr "" + +msgid "Admin" +msgstr "" + +msgid "It is you" +msgstr "" + +msgid "Edit your profile" +msgstr "" + +#, fuzzy +msgid "Open on {{ instance_url }}" +msgstr "Welcome on {{ instance_name }}" + +msgid "Follow" +msgstr "" + +#, fuzzy +msgid "Unfollow" +msgstr "One follower" + +msgid "Recently reshared" +msgstr "" + +msgid "One follower" +msgid_plural "{{ count }} followers" +msgstr[0] "One follower" +msgstr[1] "{{ count }} followers" + +msgid "Edit your account" +msgstr "" + +msgid "Your Profile" +msgstr "" + +msgid "Display Name" +msgstr "" + +msgid "Email" +msgstr "" + +msgid "Summary" +msgstr "" + +msgid "Update account" +msgstr "" + +#, fuzzy +msgid "{{ name }}'s followers" +msgstr "One follower" + +#, fuzzy +msgid "Followers" +msgstr "One follower" + +msgid "New Account" +msgstr "" + +msgid "Create an account" +msgstr "" + +msgid "Username" +msgstr "" + +msgid "Password confirmation" +msgstr "" + +msgid "Create account" +msgstr "" + +msgid "Plume" +msgstr "" + +msgid "Menu" +msgstr "" + +msgid "My account" +msgstr "" + +msgid "Log Out" +msgstr "" + +msgid "Log In" +msgstr "" + +msgid "Register" +msgstr "" + +msgid "You need to be logged in order to create a new blog" +msgstr "" + +msgid "You need to be logged in order to post a comment" +msgstr "" + +msgid "You need to be logged in order to like a post" +msgstr "" + +msgid "You need to be logged in order to see your notifications" +msgstr "" + +msgid "You need to be logged in order to write a new post" +msgstr "" + +msgid "You need to be logged in order to reshare a post" +msgstr "" + +msgid "Invalid username or password" +msgstr "" + +msgid "You need to be logged in order to access your dashboard" +msgstr "" + +msgid "You need to be logged in order to follow someone" +msgstr "" + +msgid "You need to be logged in order to edit your profile" +msgstr "" diff --git a/po/fr.po b/po/fr.po new file mode 100644 index 0000000..55a2a72 --- /dev/null +++ b/po/fr.po @@ -0,0 +1,254 @@ +msgid "" +msgstr "" +"Project-Id-Version: plume\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-06-15 16:33-0700\n" +"PO-Revision-Date: 2018-06-15 16:33-0700\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +msgid "Latest articles" +msgstr "Derniers articles" + +msgid "No posts to see here yet." +msgstr "Aucun article pour le moment" + +msgid "New article" +msgstr "Derniers articles" + +msgid "New blog" +msgstr "Nouveau blog" + +msgid "Create a blog" +msgstr "Créer un blog" + +msgid "Title" +msgstr "Titre" + +msgid "Create blog" +msgstr "Créer le blog" + +msgid "Comment \"{{ post }}\"" +msgstr "Commenter « {{ post }} »" + +msgid "Content" +msgstr "Contenu" + +msgid "Submit comment" +msgstr "Envoyer le commentaire" + +msgid "Something broke on our side." +msgstr "Nous avons cassé quelque chose" + +msgid "Sorry about that. If you think this is a bug, please report it." +msgstr "" +"Nous sommes désolé⋅e⋅s. Si vous pensez que c'est un bogue, merci de le " +"rapporter." + +msgid "Configuration" +msgstr "Configuration" + +msgid "Configure your instance" +msgstr "Configurez votre instance" + +msgid "Name" +msgstr "Nom" + +msgid "Let's go!" +msgstr "C'est parti !" + +msgid "Welcome on {{ instance_name }}" +msgstr "Bienvenue sur {{ instance_name }}" + +msgid "Notifications" +msgstr "Notifications" + +msgid "Written by {{ link_1 }}{{ url }}{{ link_2 }}{{ name }}{{ link_3 }}" +msgstr "Écrit par {{ link_1 }}{{ url }}{{ link_2 }}{{ name }}{{ link_3 }}" + +msgid "This article is under the {{ license }} license." +msgstr "Cet article est placé sous la licence {{ license }}" + +msgid "One like" +msgid_plural "{{ count }} likes" +msgstr[0] "{{ count }} personne aime cet article" +msgstr[1] "{{ count }} personnes aiment cet article" + +msgid "I don't like this anymore" +msgstr "Je n'aime plus" + +msgid "Add yours" +msgstr "J'aime" + +msgid "One reshare" +msgid_plural "{{ count }} reshares" +msgstr[0] "{{ count }} repartage" +msgstr[1] "{{ count }} repartages" + +msgid "I don't want to reshare this anymore" +msgstr "Je ne veux plus repartager" + +msgid "Reshare" +msgstr "Repartagez" + +msgid "Comments" +msgstr "Commentaires" + +msgid "Respond" +msgstr "Répondre" + +msgid "Comment" +msgstr "Commentez" + +msgid "New post" +msgstr "Nouvel article" + +msgid "Create a post" +msgstr "Créer un article" + +msgid "Publish" +msgstr "Publier" + +msgid "Login" +msgstr "Se connecter" + +msgid "Username or email" +msgstr "Nom d'utilisateur ou email" + +msgid "Password" +msgstr "Mot de passe" + +msgid "Dashboard" +msgstr "Tableau de bord" + +msgid "Your Dashboard" +msgstr "Votre tableau de bord" + +msgid "Your Blogs" +msgstr "Vos blogs" + +msgid "You don't have any blog yet. Create your own, or ask to join one." +msgstr "" +"Vous n'avez pas encore de blog. Créez le votre, ou demandez à en rejoindre " +"un." + +msgid "Start a new blog" +msgstr "Commencez un nouveau blog" + +msgid "Admin" +msgstr "Administrateur" + +msgid "It is you" +msgstr "C'est vous" + +msgid "Edit your profile" +msgstr "Éditez votre profil" + +msgid "Open on {{ instance_url }}" +msgstr "Bienvenue sur {{ instance_name }}" + +msgid "Follow" +msgstr "S'abonner" + +msgid "Unfollow" +msgstr "Se désabonner" + +msgid "Recently reshared" +msgstr "Récemment repartagé" + +msgid "One follower" +msgid_plural "{{ count }} followers" +msgstr[0] "{{ count }} abonné⋅e" +msgstr[1] "{{ count }} abonné⋅e⋅s" + +msgid "Edit your account" +msgstr "Éditer votre compte" + +msgid "Your Profile" +msgstr "Votre profil" + +msgid "Display Name" +msgstr "Nom affiché" + +msgid "Email" +msgstr "Email" + +msgid "Summary" +msgstr "Description" + +msgid "Update account" +msgstr "Mettre à jour mes informations" + +msgid "{{ name }}'s followers" +msgstr "{{ count }} abonné⋅e" + +msgid "Followers" +msgstr "{{ count }} abonné⋅e" + +msgid "New Account" +msgstr "Nouveau compte" + +msgid "Create an account" +msgstr "Créer un compte" + +msgid "Username" +msgstr "Nom d'utilisateur" + +msgid "Password confirmation" +msgstr "Confirmation du mot de passe" + +msgid "Create account" +msgstr "Créer mon compte" + +msgid "Plume" +msgstr "Plume" + +msgid "Menu" +msgstr "Menu" + +msgid "My account" +msgstr "Mon compte" + +msgid "Log Out" +msgstr "Se déconnecter" + +msgid "Log In" +msgstr "Se connecter" + +msgid "Register" +msgstr "S'inscrire" + +msgid "You need to be logged in order to create a new blog" +msgstr "Vous devez vous connecter pour créer un nouveau blog" + +msgid "You need to be logged in order to post a comment" +msgstr "Vous devez vous connecter pour commenter" + +msgid "You need to be logged in order to like a post" +msgstr "Vous devez vous connecter pour aimer un article" + +msgid "You need to be logged in order to see your notifications" +msgstr "Vous devez vous connecter pour voir vos notifications" + +msgid "You need to be logged in order to write a new post" +msgstr "Vous devez vous connecter pour écrire un article" + +msgid "You need to be logged in order to reshare a post" +msgstr "Vous devez vous connecter pour repartager un article" + +msgid "Invalid username or password" +msgstr "Nom d'utilisateur ou mot de passe invalide" + +msgid "You need to be logged in order to access your dashboard" +msgstr "Vous devez vous connecter pour accéder à votre tableau de bord" + +msgid "You need to be logged in order to follow someone" +msgstr "Vous devez vous connecter pour suivre quelqu'un" + +msgid "You need to be logged in order to edit your profile" +msgstr "Vous devez vous connecter pour modifier votre profil" diff --git a/po/plume.pot b/po/plume.pot new file mode 100644 index 0000000..7d698ed --- /dev/null +++ b/po/plume.pot @@ -0,0 +1,251 @@ +msgid "" +msgstr "" +"Project-Id-Version: plume\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-06-15 16:33-0700\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" + +msgid "Latest articles" +msgstr "" + +msgid "No posts to see here yet." +msgstr "" + +msgid "New article" +msgstr "" + +msgid "New blog" +msgstr "" + +msgid "Create a blog" +msgstr "" + +msgid "Title" +msgstr "" + +msgid "Create blog" +msgstr "" + +msgid "Comment \"{{ post }}\"" +msgstr "" + +msgid "Content" +msgstr "" + +msgid "Submit comment" +msgstr "" + +msgid "Something broke on our side." +msgstr "" + +msgid "Sorry about that. If you think this is a bug, please report it." +msgstr "" + +msgid "Configuration" +msgstr "" + +msgid "Configure your instance" +msgstr "" + +msgid "Name" +msgstr "" + +msgid "Let's go!" +msgstr "" + +msgid "Welcome on {{ instance_name }}" +msgstr "" + +msgid "Notifications" +msgstr "" + +msgid "Written by {{ link_1 }}{{ url }}{{ link_2 }}{{ name }}{{ link_3 }}" +msgstr "" + +msgid "This article is under the {{ license }} license." +msgstr "" + +msgid "One like" +msgid_plural "{{ count }} likes" +msgstr[0] "" +msgstr[1] "" + +msgid "I don't like this anymore" +msgstr "" + +msgid "Add yours" +msgstr "" + +msgid "One reshare" +msgid_plural "{{ count }} reshares" +msgstr[0] "" +msgstr[1] "" + +msgid "I don't want to reshare this anymore" +msgstr "" + +msgid "Reshare" +msgstr "" + +msgid "Comments" +msgstr "" + +msgid "Respond" +msgstr "" + +msgid "Comment" +msgstr "" + +msgid "New post" +msgstr "" + +msgid "Create a post" +msgstr "" + +msgid "Publish" +msgstr "" + +msgid "Login" +msgstr "" + +msgid "Username or email" +msgstr "" + +msgid "Password" +msgstr "" + +msgid "Dashboard" +msgstr "" + +msgid "Your Dashboard" +msgstr "" + +msgid "Your Blogs" +msgstr "" + +msgid "You don't have any blog yet. Create your own, or ask to join one." +msgstr "" + +msgid "Start a new blog" +msgstr "" + +msgid "Admin" +msgstr "" + +msgid "It is you" +msgstr "" + +msgid "Edit your profile" +msgstr "" + +msgid "Open on {{ instance_url }}" +msgstr "" + +msgid "Follow" +msgstr "" + +msgid "Unfollow" +msgstr "" + +msgid "Recently reshared" +msgstr "" + +msgid "One follower" +msgid_plural "{{ count }} followers" +msgstr[0] "" +msgstr[1] "" + +msgid "Edit your account" +msgstr "" + +msgid "Your Profile" +msgstr "" + +msgid "Display Name" +msgstr "" + +msgid "Email" +msgstr "" + +msgid "Summary" +msgstr "" + +msgid "Update account" +msgstr "" + +msgid "{{ name }}'s followers" +msgstr "" + +msgid "Followers" +msgstr "" + +msgid "New Account" +msgstr "" + +msgid "Create an account" +msgstr "" + +msgid "Username" +msgstr "" + +msgid "Password confirmation" +msgstr "" + +msgid "Create account" +msgstr "" + +msgid "Plume" +msgstr "" + +msgid "Menu" +msgstr "" + +msgid "My account" +msgstr "" + +msgid "Log Out" +msgstr "" + +msgid "Log In" +msgstr "" + +msgid "Register" +msgstr "" + +msgid "You need to be logged in order to create a new blog" +msgstr "" + +msgid "You need to be logged in order to post a comment" +msgstr "" + +msgid "You need to be logged in order to like a post" +msgstr "" + +msgid "You need to be logged in order to see your notifications" +msgstr "" + +msgid "You need to be logged in order to write a new post" +msgstr "" + +msgid "You need to be logged in order to reshare a post" +msgstr "" + +msgid "Invalid username or password" +msgstr "" + +msgid "You need to be logged in order to access your dashboard" +msgstr "" + +msgid "You need to be logged in order to follow someone" +msgstr "" + +msgid "You need to be logged in order to edit your profile" +msgstr "" + diff --git a/rust-toolchain b/rust-toolchain index 7b08dcc..27aefed 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2018-04-18 +nightly-2018-05-31 diff --git a/src/activity_pub/inbox.rs b/src/activity_pub/inbox.rs index 789ab13..cbd67f3 100644 --- a/src/activity_pub/inbox.rs +++ b/src/activity_pub/inbox.rs @@ -1,27 +1,21 @@ use activitypub::{ - Actor, - activity::{Accept, Announce, Create, Follow, Like, Undo}, - object::{Article, Note} + Activity, Object, + activity::{Create, Like, Undo} }; use diesel::PgConnection; use failure::Error; use serde_json; use activity_pub::{ - broadcast, Id, IntoId, - actor::Actor as APActor, - sign::* + Id }; use models::{ - blogs::Blog, comments::*, - follows, + follows::Follow, likes, posts::*, - reshares::*, - users::User + reshares::* }; -use safe_string::SafeString; #[derive(Fail, Debug)] enum InboxError { @@ -33,98 +27,69 @@ enum InboxError { CantUndo } +pub trait FromActivity: Sized { + fn from_activity(conn: &PgConnection, obj: T, actor: Id) -> Self; + + fn try_from_activity(conn: &PgConnection, act: Create) -> bool { + if let Ok(obj) = act.create_props.object_object() { + Self::from_activity(conn, obj, act.create_props.actor_link::().unwrap()); + true + } else { + false + } + } +} + +pub trait Notify { + fn notify(conn: &PgConnection, act: T, actor: Id); +} + +pub trait Deletable { + /// true if success + fn delete_activity(conn: &PgConnection, id: Id) -> bool; +} + pub trait Inbox { fn received(&self, conn: &PgConnection, act: serde_json::Value); - fn new_article(&self, conn: &PgConnection, article: Article) -> Result<(), Error> { - Post::insert(conn, NewPost { - blog_id: 0, // TODO - slug: String::from(""), // TODO - title: article.object_props.name_string().unwrap(), - content: SafeString::new(&article.object_props.content_string().unwrap()), - published: true, - license: String::from("CC-0"), - ap_url: article.object_props.url_string()? - }); - Ok(()) - } - - fn new_comment(&self, conn: &PgConnection, note: Note, actor_id: String) -> Result<(), Error> { - let previous_url = note.object_props.in_reply_to.clone().unwrap().as_str().unwrap().to_string(); - let previous_comment = Comment::find_by_ap_url(conn, previous_url.clone()); - Comment::insert(conn, NewComment { - content: SafeString::new(¬e.object_props.content_string().unwrap()), - spoiler_text: note.object_props.summary_string().unwrap_or(String::from("")), - ap_url: note.object_props.id_string().ok(), - in_response_to_id: previous_comment.clone().map(|c| c.id), - post_id: previous_comment - .map(|c| c.post_id) - .unwrap_or_else(|| Post::find_by_ap_url(conn, previous_url).unwrap().id), - author_id: User::from_url(conn, actor_id).unwrap().id, - sensitive: false // "sensitive" is not a standard property, we need to think about how to support it with the activitystreams crate - }); - Ok(()) - } - - fn follow(&self, conn: &PgConnection, follow: Follow) -> Result<(), Error> { - let from = User::from_url(conn, follow.follow_props.actor.as_str().unwrap().to_string()).unwrap(); - match User::from_url(conn, follow.follow_props.object.as_str().unwrap().to_string()) { - Some(u) => self.accept_follow(conn, &from, &u, follow, from.id, u.id), - None => { - let blog = Blog::from_url(conn, follow.follow_props.object.as_str().unwrap().to_string()).unwrap(); - self.accept_follow(conn, &from, &blog, follow, from.id, blog.id) - } - }; - Ok(()) - } - - fn like(&self, conn: &PgConnection, like: Like) -> Result<(), Error> { - let liker = User::from_url(conn, like.like_props.actor.as_str().unwrap().to_string()); - let post = Post::find_by_ap_url(conn, like.like_props.object.as_str().unwrap().to_string()); - likes::Like::insert(conn, likes::NewLike { - post_id: post.unwrap().id, - user_id: liker.unwrap().id, - ap_url: like.object_props.id_string()? - }); - Ok(()) - } - fn unlike(&self, conn: &PgConnection, undo: Undo) -> Result<(), Error> { let like = likes::Like::find_by_ap_url(conn, undo.undo_props.object_object::()?.object_props.id_string()?).unwrap(); like.delete(conn); Ok(()) } - fn announce(&self, conn: &PgConnection, announce: Announce) -> Result<(), Error> { - let user = User::from_url(conn, announce.announce_props.actor.as_str().unwrap().to_string()); - let post = Post::find_by_ap_url(conn, announce.announce_props.object.as_str().unwrap().to_string()); - Reshare::insert(conn, NewReshare { - post_id: post.unwrap().id, - user_id: user.unwrap().id, - ap_url: announce.object_props.id_string()? - }); - Ok(()) - } - fn save(&self, conn: &PgConnection, act: serde_json::Value) -> Result<(), Error> { + let actor_id = Id::new(act["actor"].as_str().unwrap()); match act["type"].as_str() { Some(t) => { match t { - "Announce" => self.announce(conn, serde_json::from_value(act.clone())?), + "Announce" => { + Reshare::from_activity(conn, serde_json::from_value(act.clone())?, actor_id); + Ok(()) + }, "Create" => { let act: Create = serde_json::from_value(act.clone())?; - match act.create_props.object["type"].as_str().unwrap() { - "Article" => self.new_article(conn, act.create_props.object_object()?), - "Note" => self.new_comment(conn, act.create_props.object_object()?, act.create_props.actor_link::()?.0), - _ => Err(InboxError::InvalidType)? + if Post::try_from_activity(conn, act.clone()) || Comment::try_from_activity(conn, act) { + Ok(()) + } else { + Err(InboxError::InvalidType)? } }, - "Follow" => self.follow(conn, serde_json::from_value(act.clone())?), - "Like" => self.like(conn, serde_json::from_value(act.clone())?), + "Follow" => { + Follow::from_activity(conn, serde_json::from_value(act.clone())?, actor_id); + Ok(()) + }, + "Like" => { + likes::Like::from_activity(conn, serde_json::from_value(act.clone())?, actor_id); + Ok(()) + }, "Undo" => { let act: Undo = serde_json::from_value(act.clone())?; match act.undo_props.object["type"].as_str().unwrap() { - "Like" => self.unlike(conn, act), + "Like" => { + likes::Like::delete_activity(conn, Id::new(act.undo_props.object_object::()?.object_props.id_string()?)); + Ok(()) + }, _ => Err(InboxError::CantUndo)? } } @@ -134,26 +99,6 @@ pub trait Inbox { None => Err(InboxError::NoType)? } } - - fn accept_follow( - &self, - conn: &PgConnection, - from: &A, - target: &B, - follow: Follow, - from_id: i32, - target_id: i32 - ) { - follows::Follow::insert(conn, follows::NewFollow { - follower_id: from_id, - following_id: target_id - }); - - let mut accept = Accept::default(); - accept.accept_props.set_actor_link::(from.clone().into_id()).unwrap(); - accept.accept_props.set_object_object(follow).unwrap(); - broadcast(conn, &*from, accept, vec![target.clone()]); - } } pub trait WithInbox { diff --git a/src/activity_pub/mod.rs b/src/activity_pub/mod.rs index febd959..af544ac 100644 --- a/src/activity_pub/mod.rs +++ b/src/activity_pub/mod.rs @@ -19,7 +19,7 @@ pub mod request; pub mod sign; pub mod webfinger; -pub type ActivityPub = Content; +pub type ActivityPub = Content>; pub const CONTEXT_URL: &'static str = "https://www.w3.org/ns/activitystreams"; pub const PUBLIC_VISIBILTY: &'static str = "https://www.w3.org/ns/activitystreams#Public"; @@ -111,6 +111,12 @@ impl Id { } } +impl Into for Id { + fn into(self) -> String { + self.0.clone() + } +} + pub trait IntoId { fn into_id(self) -> Id; } diff --git a/src/main.rs b/src/main.rs index ce8f78d..69df18e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,8 @@ -#![feature(plugin, custom_derive, iterator_find_map)] +#![feature(plugin, custom_derive, decl_macro, iterator_find_map)] #![plugin(rocket_codegen)] extern crate activitypub; +extern crate ammonia; extern crate array_tool; extern crate base64; extern crate bcrypt; @@ -10,6 +11,7 @@ extern crate comrak; extern crate failure; #[macro_use] extern crate failure_derive; +extern crate gettextrs; extern crate heck; extern crate hex; #[macro_use] @@ -23,13 +25,14 @@ extern crate openssl; extern crate reqwest; extern crate rocket; extern crate rocket_contrib; +extern crate rocket_i18n; extern crate serde; #[macro_use] extern crate serde_derive; #[macro_use] extern crate serde_json; +extern crate tera; extern crate url; -extern crate ammonia; use diesel::{pg::PgConnection, r2d2::{ConnectionManager, Pool}}; use dotenv::dotenv; @@ -66,8 +69,8 @@ fn main() { rocket::ignite() .mount("/", routes![ routes::blogs::details, - routes::blogs::activity_details, - routes::blogs::outbox, + routes::blogs::activity_details, + routes::blogs::outbox, routes::blogs::new, routes::blogs::new_auth, routes::blogs::create, @@ -108,7 +111,7 @@ fn main() { routes::user::details, routes::user::dashboard, routes::user::dashboard_auth, - routes::user::followers, + routes::user::followers, routes::user::edit, routes::user::edit_auth, routes::user::update, @@ -126,6 +129,9 @@ fn main() { routes::well_known::webfinger ]) .manage(init_pool()) - .attach(Template::fairing()) + .attach(Template::custom(|engines| { + rocket_i18n::tera(&mut engines.tera); + })) + .attach(rocket_i18n::I18n::new("plume")) .launch(); } diff --git a/src/models/comments.rs b/src/models/comments.rs index e763e90..be66f87 100644 --- a/src/models/comments.rs +++ b/src/models/comments.rs @@ -7,8 +7,9 @@ use diesel::{self, PgConnection, RunQueryDsl, QueryDsl, ExpressionMethods, dsl:: use serde_json; use activity_pub::{ - ap_url, IntoId, PUBLIC_VISIBILTY, + ap_url, Id, IntoId, PUBLIC_VISIBILTY, actor::Actor, + inbox::FromActivity, object::Object }; use models::{ @@ -123,6 +124,24 @@ impl Comment { } } +impl FromActivity for Comment { + fn from_activity(conn: &PgConnection, note: Note, actor: Id) -> Comment { + let previous_url = note.object_props.in_reply_to.clone().unwrap().as_str().unwrap().to_string(); + let previous_comment = Comment::find_by_ap_url(conn, previous_url.clone()); + Comment::insert(conn, NewComment { + content: SafeString::new(¬e.object_props.content_string().unwrap()), + spoiler_text: note.object_props.summary_string().unwrap_or(String::from("")), + ap_url: note.object_props.id_string().ok(), + in_response_to_id: previous_comment.clone().map(|c| c.id), + post_id: previous_comment + .map(|c| c.post_id) + .unwrap_or_else(|| Post::find_by_ap_url(conn, previous_url).unwrap().id), + author_id: User::from_url(conn, actor.into()).unwrap().id, + sensitive: false // "sensitive" is not a standard property, we need to think about how to support it with the activitypub crate + }) + } +} + impl Object for Comment { fn serialize(&self, conn: &PgConnection) -> serde_json::Value { let mut to = self.get_author(conn).get_followers(conn).into_iter().map(|f| f.ap_url).collect::>(); diff --git a/src/models/follows.rs b/src/models/follows.rs index 6debe46..fa5f66f 100644 --- a/src/models/follows.rs +++ b/src/models/follows.rs @@ -1,5 +1,8 @@ +use activitypub::{Actor, activity::{Accept, Follow as FollowAct}}; use diesel::{self, PgConnection, ExpressionMethods, QueryDsl, RunQueryDsl}; +use activity_pub::{broadcast, Id, IntoId, actor::Actor as ApActor, inbox::{FromActivity, WithInbox}, sign::Signer}; +use models::blogs::Blog; use models::users::User; use schema::follows; @@ -33,4 +36,37 @@ impl Follow { .expect("Unable to load follow by id") .into_iter().nth(0) } + + pub fn accept_follow( + conn: &PgConnection, + from: &A, + target: &B, + follow: FollowAct, + from_id: i32, + target_id: i32 + ) -> Follow { + let res = Follow::insert(conn, NewFollow { + follower_id: from_id, + following_id: target_id + }); + + let mut accept = Accept::default(); + accept.accept_props.set_actor_link::(from.clone().into_id()).unwrap(); + accept.accept_props.set_object_object(follow).unwrap(); + broadcast(conn, &*from, accept, vec![target.clone()]); + res + } +} + +impl FromActivity for Follow { + fn from_activity(conn: &PgConnection, follow: FollowAct, _actor: Id) -> Follow { + let from = User::from_url(conn, follow.follow_props.actor.as_str().unwrap().to_string()).unwrap(); + match User::from_url(conn, follow.follow_props.object.as_str().unwrap().to_string()) { + Some(u) => Follow::accept_follow(conn, &from, &u, follow, from.id, u.id), + None => { + let blog = Blog::from_url(conn, follow.follow_props.object.as_str().unwrap().to_string()).unwrap(); + Follow::accept_follow(conn, &from, &blog, follow, from.id, blog.id) + } + } + } } diff --git a/src/models/likes.rs b/src/models/likes.rs index 65b24ff..59bd48b 100644 --- a/src/models/likes.rs +++ b/src/models/likes.rs @@ -4,8 +4,10 @@ use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods}; use serde_json; use activity_pub::{ + Id, IntoId, actor::Actor, + inbox::{FromActivity, Deletable}, object::Object }; use models::{ @@ -94,6 +96,29 @@ impl Like { } } +impl FromActivity for Like { + fn from_activity(conn: &PgConnection, like: activity::Like, _actor: Id) -> Like { + let liker = User::from_url(conn, like.like_props.actor.as_str().unwrap().to_string()); + let post = Post::find_by_ap_url(conn, like.like_props.object.as_str().unwrap().to_string()); + Like::insert(conn, NewLike { + post_id: post.unwrap().id, + user_id: liker.unwrap().id, + ap_url: like.object_props.id_string().unwrap_or(String::from("")) + }) + } +} + +impl Deletable for Like { + fn delete_activity(conn: &PgConnection, id: Id) -> bool { + if let Some(like) = Like::find_by_ap_url(conn, id.into()) { + like.delete(conn); + true + } else { + false + } + } +} + impl Object for Like { fn serialize(&self, conn: &PgConnection) -> serde_json::Value { json!({ diff --git a/src/models/posts.rs b/src/models/posts.rs index be2ce42..6e3f489 100644 --- a/src/models/posts.rs +++ b/src/models/posts.rs @@ -10,6 +10,7 @@ use BASE_URL; use activity_pub::{ PUBLIC_VISIBILTY, ap_url, Id, IntoId, actor::Actor, + inbox::FromActivity, object::Object }; use models::{ @@ -195,6 +196,20 @@ impl Post { } } +impl FromActivity
for Post { + fn from_activity(conn: &PgConnection, article: Article, _actor: Id) -> Post { + Post::insert(conn, NewPost { + blog_id: 0, // TODO + slug: String::from(""), // TODO + title: article.object_props.name_string().unwrap(), + content: SafeString::new(&article.object_props.content_string().unwrap()), + published: true, + license: String::from("CC-0"), + ap_url: article.object_props.url_string().unwrap_or(String::from("")) + }) + } +} + impl IntoId for Post { fn into_id(self) -> Id { Id::new(self.ap_url.clone()) diff --git a/src/models/reshares.rs b/src/models/reshares.rs index 65c4739..2e2896d 100644 --- a/src/models/reshares.rs +++ b/src/models/reshares.rs @@ -1,8 +1,8 @@ -use activitypub::activity; +use activitypub::activity::{Announce, Undo}; use chrono::NaiveDateTime; use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods}; -use activity_pub::{IntoId, actor::Actor, object::Object}; +use activity_pub::{Id, IntoId, actor::Actor, inbox::FromActivity, object::Object}; use models::{posts::Post, users::User}; use schema::reshares; @@ -80,17 +80,17 @@ impl Reshare { Post::get(conn, self.post_id) } - pub fn delete(&self, conn: &PgConnection) -> activity::Undo { + pub fn delete(&self, conn: &PgConnection) -> Undo { diesel::delete(self).execute(conn).unwrap(); - let mut act = activity::Undo::default(); + let mut act = Undo::default(); act.undo_props.set_actor_link(User::get(conn, self.user_id).unwrap().into_id()).unwrap(); act.undo_props.set_object_object(self.into_activity(conn)).unwrap(); act } - pub fn into_activity(&self, conn: &PgConnection) -> activity::Announce { - let mut act = activity::Announce::default(); + pub fn into_activity(&self, conn: &PgConnection) -> Announce { + let mut act = Announce::default(); act.announce_props.set_actor_link(User::get(conn, self.user_id).unwrap().into_id()).unwrap(); act.announce_props.set_object_link(Post::get(conn, self.post_id).unwrap().into_id()).unwrap(); act.object_props.set_id_string(self.ap_url.clone()).unwrap(); @@ -98,3 +98,15 @@ impl Reshare { act } } + +impl FromActivity for Reshare { + fn from_activity(conn: &PgConnection, announce: Announce, _actor: Id) -> Reshare { + let user = User::from_url(conn, announce.announce_props.actor.as_str().unwrap().to_string()); + let post = Post::find_by_ap_url(conn, announce.announce_props.object.as_str().unwrap().to_string()); + Reshare::insert(conn, NewReshare { + post_id: post.unwrap().id, + user_id: user.unwrap().id, + ap_url: announce.object_props.id_string().unwrap_or(String::from("")) + }) + } +} diff --git a/src/models/users.rs b/src/models/users.rs index 8677154..0b10dfc 100644 --- a/src/models/users.rs +++ b/src/models/users.rs @@ -285,6 +285,16 @@ impl User { users::table.filter(users::id.eq(any(follows))).load::(conn).unwrap() } + pub fn is_following(&self, conn: &PgConnection, other_id: i32) -> bool { + use schema::follows; + follows::table + .filter(follows::follower_id.eq(other_id)) + .filter(follows::following_id.eq(self.id)) + .load::(conn) + .expect("Couldn't load follow relationship") + .len() > 0 + } + pub fn has_liked(&self, conn: &PgConnection, post: &Post) -> bool { use schema::likes; use models::likes::Like; diff --git a/src/routes/blogs.rs b/src/routes/blogs.rs index 1131a06..0a64e9e 100644 --- a/src/routes/blogs.rs +++ b/src/routes/blogs.rs @@ -83,7 +83,7 @@ fn create(conn: DbConn, data: Form, user: User) -> Redirect { is_owner: true }); - Redirect::to(format!("/~/{}/", slug).as_str()) + Redirect::to(format!("/~/{}/", slug)) } #[get("/~//outbox")] diff --git a/src/routes/comments.rs b/src/routes/comments.rs index 86542a1..7c039ee 100644 --- a/src/routes/comments.rs +++ b/src/routes/comments.rs @@ -55,5 +55,5 @@ fn create(blog: String, slug: String, query: CommentQuery, data: Form) -> Template { } None => { Template::render("errors/500", json!({ - "error_message": "You need to configure your instance before using it." + "error_message": gettext("You need to configure your instance before using it.".to_string()) })) } } @@ -78,7 +79,7 @@ fn shared_inbox(conn: DbConn, data: String) -> String { } #[get("/nodeinfo")] -fn nodeinfo(conn: DbConn) -> Json { +fn nodeinfo(conn: DbConn) -> Json { Json(json!({ "version": "2.0", "software": { diff --git a/src/routes/likes.rs b/src/routes/likes.rs index 55dce94..f99782e 100644 --- a/src/routes/likes.rs +++ b/src/routes/likes.rs @@ -29,7 +29,7 @@ fn create(blog: String, slug: String, user: User, conn: DbConn) -> Redirect { broadcast(&*conn, &user, delete_act, user.get_followers(&*conn)); } - Redirect::to(format!("/~/{}/{}/", blog, slug).as_ref()) + Redirect::to(format!("/~/{}/{}/", blog, slug)) } #[get("/~///like", rank = 2)] diff --git a/src/routes/posts.rs b/src/routes/posts.rs index 893670e..fef302a 100644 --- a/src/routes/posts.rs +++ b/src/routes/posts.rs @@ -36,7 +36,12 @@ fn details(blog: String, slug: String, conn: DbConn, user: Option) -> Temp json!({ "id": c.id, "content": c.content, - "author": c.get_author(&*conn) + "author": ({ + let author = &c.get_author(&*conn); + let mut json = serde_json::to_value(author).unwrap(); + json["fqn"] = serde_json::Value::String(author.get_fqn(&*conn)); + json + }) }) }).collect::>(), "n_likes": post.get_likes(&*conn).len(), @@ -115,5 +120,5 @@ fn create(blog_name: String, data: Form, user: User, conn: DbConn) let act = post.create_activity(&*conn); broadcast(&*conn, &user, act, user.get_followers(&*conn)); - Redirect::to(format!("/~/{}/{}/", blog_name, slug).as_str()) + Redirect::to(format!("/~/{}/{}/", blog_name, slug)) } diff --git a/src/routes/reshares.rs b/src/routes/reshares.rs index 19f6933..5069864 100644 --- a/src/routes/reshares.rs +++ b/src/routes/reshares.rs @@ -29,7 +29,7 @@ fn create(blog: String, slug: String, user: User, conn: DbConn) -> Redirect { broadcast(&*conn, &user, delete_act, user.get_followers(&*conn)); } - Redirect::to(format!("/~/{}/{}/", blog, slug).as_ref()) + Redirect::to(format!("/~/{}/{}/", blog, slug)) } #[get("/~///reshare", rank=1)] diff --git a/src/routes/session.rs b/src/routes/session.rs index bf7d5e6..057e63b 100644 --- a/src/routes/session.rs +++ b/src/routes/session.rs @@ -1,5 +1,6 @@ +use gettextrs::gettext; use rocket::{ - http::{Cookie, Cookies}, + http::{Cookie, Cookies, uri::Uri}, response::{Redirect, status::NotFound}, request::{Form,FlashMessage} }; @@ -42,19 +43,19 @@ fn create(conn: DbConn, data: Form, flash: Option, mut Some(usr) => Ok(usr), None => match User::find_local(&*conn, form.email_or_name.to_string()) { Some(usr) => Ok(usr), - None => Err("Invalid username or password") + None => Err(gettext("Invalid username or password")) } }; match user { Ok(usr) => { if usr.auth(form.password.to_string()) { cookies.add_private(Cookie::new(AUTH_COOKIE, usr.id.to_string())); - Ok(Redirect::to(&flash - .and_then(|f| if f.name()=="callback" { Some(f.msg().to_owned()) } else { None }) + Ok(Redirect::to(Uri::new(flash + .and_then(|f| if f.name() == "callback" { Some(f.msg().to_owned()) } else { None }) .unwrap_or("/".to_owned())) - ) + )) } else { - Err(NotFound(String::from("Invalid username or password"))) + Err(NotFound(gettext("Invalid username or password"))) } }, Err(e) => Err(NotFound(String::from(e))) diff --git a/src/routes/user.rs b/src/routes/user.rs index 49023c6..2bc25ec 100644 --- a/src/routes/user.rs +++ b/src/routes/user.rs @@ -27,7 +27,7 @@ use utils; #[get("/me")] fn me(user: Option) -> Result> { match user { - Some(user) => Ok(Redirect::to(format!("/@/{}/", user.username).as_ref())), + Some(user) => Ok(Redirect::to(format!("/@/{}/", user.username))), None => Err(utils::requires_login("", "/me")) } } @@ -41,7 +41,10 @@ fn details(name: String, conn: DbConn, account: Option) -> Template { let n_followers = user.get_followers(&*conn).len(); Template::render("users/details", json!({ - "user": serde_json::to_value(user).unwrap(), + "user": serde_json::to_value(user.clone()).unwrap(), + "instance_url": user.get_instance(&*conn).public_domain, + "is_remote": user.instance_id != Instance::local_id(&*conn), + "follows": account.clone().map(|x| x.is_following(&*conn, user.id)).unwrap_or(false), "account": account, "recents": recents.into_iter().map(|p| { json!({ @@ -101,7 +104,7 @@ fn follow(name: String, conn: DbConn, user: User) -> Redirect { act.follow_props.set_object_object(user.into_activity(&*conn)).unwrap(); act.object_props.set_id_string(format!("{}/follow/{}", user.ap_url, target.ap_url)).unwrap(); broadcast(&*conn, &user, act, vec![target]); - Redirect::to(format!("/@/{}/", name).as_ref()) + Redirect::to(format!("/@/{}/", name)) } #[get("/@//follow", rank = 2)] @@ -113,9 +116,12 @@ fn follow_auth(name: String) -> Flash { fn followers(name: String, conn: DbConn, account: Option) -> Template { let user = User::find_by_fqn(&*conn, name.clone()).unwrap(); let user_id = user.id.clone(); - + Template::render("users/followers", json!({ "user": serde_json::to_value(user.clone()).unwrap(), + "instance_url": user.get_instance(&*conn).public_domain, + "is_remote": user.instance_id != Instance::local_id(&*conn), + "follows": account.clone().map(|x| x.is_following(&*conn, user.id)).unwrap_or(false), "followers": user.get_followers(&*conn).into_iter().map(|f| { let fqn = f.get_fqn(&*conn); let mut json = serde_json::to_value(f).unwrap(); @@ -123,7 +129,8 @@ fn followers(name: String, conn: DbConn, account: Option) -> Template { json }).collect::>(), "account": account, - "is_self": account.map(|a| a.id == user_id).unwrap_or(false) + "is_self": account.map(|a| a.id == user_id).unwrap_or(false), + "n_followers": user.get_followers(&*conn).len() })) } @@ -202,7 +209,7 @@ fn create(conn: DbConn, data: Form) -> Result { User::hash_pass(form.password.to_string()), inst.id )).update_boxes(&*conn); - Ok(Redirect::to(format!("/@/{}/", data.get().username).as_str())) + Ok(Redirect::to(format!("/@/{}/", data.get().username))) } else { Err(String::from("Passwords don't match")) } diff --git a/src/utils.rs b/src/utils.rs index eb6d110..e9463e1 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,5 +1,9 @@ +use gettextrs::gettext; use heck::CamelCase; -use rocket::response::{Redirect, Flash}; +use rocket::{ + http::uri::Uri, + response::{Redirect, Flash} +}; /// Remove non alphanumeric characters and CamelCase a string pub fn make_actor_id(name: String) -> String { @@ -12,5 +16,5 @@ pub fn make_actor_id(name: String) -> String { } pub fn requires_login(message: &str, url: &str) -> Flash { - Flash::new(Redirect::to(&format!("/login?m={}", message)), "callback", url) + Flash::new(Redirect::to(Uri::new(format!("/login?m={}", gettext(message.to_string())))), "callback", url) } diff --git a/templates/base.html.tera b/templates/base.html.tera index 26a42b9..419f45d 100644 --- a/templates/base.html.tera +++ b/templates/base.html.tera @@ -2,28 +2,28 @@ - {% block title %}{% endblock title %} ⋅ Plume + {% block title %}{% endblock title %} ⋅ {{ "Plume" | _ }}
- +
diff --git a/templates/blogs/details.html.tera b/templates/blogs/details.html.tera index f976a61..ed9994a 100644 --- a/templates/blogs/details.html.tera +++ b/templates/blogs/details.html.tera @@ -10,12 +10,12 @@

{{ blog.summary }}

-

Latest articles

+

{{ "Latest articles" | _ }}

{% if recents | length < 1 %} -

No posts to see here yet.

+

{{ "No posts to see here yet." | _ }}

{% endif %} {% if is_author %} - New article + {{ "New article" | _ }} {% endif %}
{% for article in recents %} diff --git a/templates/blogs/new.html.tera b/templates/blogs/new.html.tera index c1b0f88..b1feda6 100644 --- a/templates/blogs/new.html.tera +++ b/templates/blogs/new.html.tera @@ -1,15 +1,15 @@ {% extends "base" %} {% block title %} -New blog +{{ "New blog" | _ }} {% endblock title %} {% block content %} -

Create a blog

+

{{ "Create a blog" | _ }}

- + - +
-{% endblock content %} + | _ {% endblock content %} diff --git a/templates/comments/new.html.tera b/templates/comments/new.html.tera index 4b76184..a02de4a 100644 --- a/templates/comments/new.html.tera +++ b/templates/comments/new.html.tera @@ -1,15 +1,15 @@ {% extends "base" %} {% block title %} -Comment "{{ post.title }}" +{{ 'Comment "{{ post }}"' | _(post=post.title) }} {% endblock title %} {% block content %} -

Comment "{{ post.title }}"

+

{{ 'Comment "{{ post }}"' | _(post=post.title) }}

- + - +
{% endblock content %} diff --git a/templates/errors/500.html.tera b/templates/errors/500.html.tera index 0eb37da..8dd5955 100644 --- a/templates/errors/500.html.tera +++ b/templates/errors/500.html.tera @@ -1,6 +1,6 @@ {% extends "errors/base" %} {% block error %} -

Something broke on our side.

-

Sorry about that. If you think this is a bug, please report it.

+

{{ "Something broke on our side." | _ }}

+

{{ "Sorry about that. If you think this is a bug, please report it." | _ }}

{% endblock error %} diff --git a/templates/instance/configure.html.tera b/templates/instance/configure.html.tera index 7abf892..fbc1445 100644 --- a/templates/instance/configure.html.tera +++ b/templates/instance/configure.html.tera @@ -1,15 +1,15 @@ {% extends "base" %} {% block title %} -Configuration +{{ "Configuration" | _ }} {% endblock title %} {% block content %} -

Configure your instance

+

{{ "Configure your instance" | _ }}

- + - +
{% endblock content %} diff --git a/templates/instance/index.html.tera b/templates/instance/index.html.tera index 480c758..49b0958 100644 --- a/templates/instance/index.html.tera +++ b/templates/instance/index.html.tera @@ -6,9 +6,9 @@ {% endblock title %} {% block content %} -

Welcome on {{ instance.name }}

+

{{ "Welcome on {{ instance_name }}" | _(instance_name=instance.name) }}

-

Latest articles

+

{{ "Latest articles" | _ }}

{% for article in recents %} {{ macros::post_card(article=article) }} diff --git a/templates/macros.html.tera b/templates/macros.html.tera index 6385f3a..e2f0e8b 100644 --- a/templates/macros.html.tera +++ b/templates/macros.html.tera @@ -1,11 +1,16 @@ {% macro post_card(article) %} + {% if article.author.display_name %} + {% set name = article.author.display_name %} + {% else %} + {% set name = article.author.username %} + {% endif %}

{{ article.post.title }}

{{ article.post.content | striptags | truncate(length=200) }}

- By {{ article.author.display_name }} ⋅ {{ article.date | date(format="%B %e") }} + By {{ name }} ⋅ {{ article.date | date(format="%B %e") }}

{% endmacro post_card %} diff --git a/templates/notifications/index.html.tera b/templates/notifications/index.html.tera index d25dedb..bbe7961 100644 --- a/templates/notifications/index.html.tera +++ b/templates/notifications/index.html.tera @@ -1,11 +1,11 @@ {% extends "base" %} {% block title %} -Notifications +{{ "Notifications" | _ }} {% endblock title %} {% block content %} -

Notifications

+

{{ "Notifications" | _ }}

{% for notification in notifications %}
diff --git a/templates/posts/details.html.tera b/templates/posts/details.html.tera index bdbb646..b7fd87b 100644 --- a/templates/posts/details.html.tera +++ b/templates/posts/details.html.tera @@ -9,9 +9,24 @@ {% endblock header %} {% block content %} +<<<<<<< HEAD

{{ post.title }}

@@ -20,43 +35,49 @@