Compare commits

..

No commits in common. "7ee817de463d0dfe66702c50a878f67de70ea159" and "81681303b2ca21c75aed030863399bf70f80e635" have entirely different histories.

13 changed files with 238 additions and 636 deletions

414
Cargo.lock generated
View file

@ -69,9 +69,9 @@ dependencies = [
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
version = "0.7.20" version = "0.7.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
@ -116,9 +116,9 @@ checksum = "5f093eed78becd229346bf859eec0aa4dd7ddde0757287b2b4107a1f09c80002"
[[package]] [[package]]
name = "async-channel" name = "async-channel"
version = "1.8.0" version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833" checksum = "e14485364214912d3b19cc3435dde4df66065127f05fa0d75c712f36f12c2f28"
dependencies = [ dependencies = [
"concurrent-queue", "concurrent-queue",
"event-listener", "event-listener",
@ -137,23 +137,23 @@ dependencies = [
[[package]] [[package]]
name = "async-executor" name = "async-executor"
version = "1.5.0" version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17adb73da160dfb475c183343c8cccd80721ea5a605d3eb57125f0a7b7a92d0b" checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965"
dependencies = [ dependencies = [
"async-lock",
"async-task", "async-task",
"concurrent-queue", "concurrent-queue",
"fastrand", "fastrand",
"futures-lite", "futures-lite",
"once_cell",
"slab", "slab",
] ]
[[package]] [[package]]
name = "async-global-executor" name = "async-global-executor"
version = "2.3.1" version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776" checksum = "0da5b41ee986eed3f524c380e6d64965aea573882a8907682ad100f7859305ca"
dependencies = [ dependencies = [
"async-channel", "async-channel",
"async-executor", "async-executor",
@ -182,32 +182,31 @@ dependencies = [
[[package]] [[package]]
name = "async-io" name = "async-io"
version = "1.12.0" version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c374dda1ed3e7d8f0d9ba58715f924862c63eae6849c92d3a18e7fbde9e2794" checksum = "83e21f3a490c72b3b0cf44962180e60045de2925d8dff97918f7ee43c8f637c7"
dependencies = [ dependencies = [
"async-lock",
"autocfg", "autocfg",
"concurrent-queue", "concurrent-queue",
"futures-lite", "futures-lite",
"libc", "libc",
"log", "log",
"once_cell",
"parking", "parking",
"polling", "polling",
"slab", "slab",
"socket2", "socket2",
"waker-fn", "waker-fn",
"windows-sys", "winapi",
] ]
[[package]] [[package]]
name = "async-lock" name = "async-lock"
version = "2.6.0" version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8101efe8695a6c17e02911402145357e718ac92d3ff88ae8419e84b1707b685" checksum = "e97a171d191782fba31bb902b14ad94e24a68145032b7eedf871ab0bc0d077b6"
dependencies = [ dependencies = [
"event-listener", "event-listener",
"futures-lite",
] ]
[[package]] [[package]]
@ -218,20 +217,20 @@ checksum = "72faff1fdc615a0199d7bf71e6f389af54d46a66e9beb5d76c39e48eda93ecce"
[[package]] [[package]]
name = "async-process" name = "async-process"
version = "1.6.0" version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6381ead98388605d0d9ff86371043b5aa922a3905824244de40dc263a14fcba4" checksum = "02111fd8655a613c25069ea89fc8d9bb89331fa77486eb3bc059ee757cfa481c"
dependencies = [ dependencies = [
"async-io", "async-io",
"async-lock",
"autocfg", "autocfg",
"blocking", "blocking",
"cfg-if", "cfg-if",
"event-listener", "event-listener",
"futures-lite", "futures-lite",
"libc", "libc",
"once_cell",
"signal-hook", "signal-hook",
"windows-sys", "winapi",
] ]
[[package]] [[package]]
@ -304,9 +303,9 @@ checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524"
[[package]] [[package]]
name = "async-trait" name = "async-trait"
version = "0.1.59" version = "0.1.58"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31e6e93155431f3931513b243d371981bb2770112b370c82745a1d19d2f99364" checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -374,11 +373,11 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]] [[package]]
name = "blake2" name = "blake2"
version = "0.10.5" version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b12e5fd123190ce1c2e559308a94c9bacad77907d4c6005d9e58fe1a0689e55e" checksum = "b9cf849ee05b2ee5fba5e36f97ff8ec2533916700fc0758d40d92136a42f3388"
dependencies = [ dependencies = [
"digest 0.10.6", "digest 0.10.5",
] ]
[[package]] [[package]]
@ -401,16 +400,16 @@ dependencies = [
[[package]] [[package]]
name = "blocking" name = "blocking"
version = "1.3.0" version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c67b173a56acffd6d2326fb7ab938ba0b00a71480e14902b2591c87bc5741e8" checksum = "c6ccb65d468978a086b69884437ded69a90faab3bbe6e67f242173ea728acccc"
dependencies = [ dependencies = [
"async-channel", "async-channel",
"async-lock",
"async-task", "async-task",
"atomic-waker", "atomic-waker",
"fastrand", "fastrand",
"futures-lite", "futures-lite",
"once_cell",
] ]
[[package]] [[package]]
@ -436,15 +435,21 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]] [[package]]
name = "bytes" name = "bytes"
version = "1.3.0" version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db"
[[package]]
name = "cache-padded"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.77" version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
@ -454,9 +459,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "chrono" name = "chrono"
version = "0.4.23" version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1"
dependencies = [ dependencies = [
"iana-time-zone", "iana-time-zone",
"num-integer", "num-integer",
@ -498,9 +503,9 @@ dependencies = [
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.0.29" version = "4.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d63b9e9c07271b9957ad22c173bae2a4d9a81127680962039296abcd2f8251d" checksum = "335867764ed2de42325fafe6d18b8af74ba97ee0c590fa016f157535b42ab04b"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"clap_derive", "clap_derive",
@ -510,9 +515,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_derive" name = "clap_derive"
version = "4.0.21" version = "4.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" checksum = "16a1b0f6422af32d5da0c58e2703320f379216ee70198241c84173a8c5ac28f3"
dependencies = [ dependencies = [
"heck", "heck",
"proc-macro-error", "proc-macro-error",
@ -552,11 +557,11 @@ dependencies = [
[[package]] [[package]]
name = "concurrent-queue" name = "concurrent-queue"
version = "2.0.0" version = "1.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd7bef69dc86e3c610e4e7aed41035e2a7ed12e72dd7530f61327a6579a4390b" checksum = "af4780a44ab5696ea9e28294517f1fffb421a83a25af521333c838635509db9c"
dependencies = [ dependencies = [
"crossbeam-utils", "cache-padded",
] ]
[[package]] [[package]]
@ -624,9 +629,9 @@ dependencies = [
[[package]] [[package]]
name = "crossbeam-epoch" name = "crossbeam-epoch"
version = "0.9.13" version = "0.9.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" checksum = "f916dfc5d356b0ed9dae65f1db9fc9770aa2851d2662b988ccf4fe3516e86348"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"cfg-if", "cfg-if",
@ -637,9 +642,9 @@ dependencies = [
[[package]] [[package]]
name = "crossbeam-utils" name = "crossbeam-utils"
version = "0.8.14" version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" checksum = "edbafec5fa1f196ca66527c1b12c2ec4745ca14b50f1ad8f9f6f720b55d11fac"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
] ]
@ -685,9 +690,9 @@ dependencies = [
[[package]] [[package]]
name = "cxx" name = "cxx"
version = "1.0.83" version = "1.0.80"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdf07d07d6531bfcdbe9b8b739b104610c6508dcc4d63b410585faf338241daf" checksum = "6b7d4e43b25d3c994662706a1d4fcfc32aaa6afd287502c111b237093bb23f3a"
dependencies = [ dependencies = [
"cc", "cc",
"cxxbridge-flags", "cxxbridge-flags",
@ -697,9 +702,9 @@ dependencies = [
[[package]] [[package]]
name = "cxx-build" name = "cxx-build"
version = "1.0.83" version = "1.0.80"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2eb5b96ecdc99f72657332953d4d9c50135af1bac34277801cc3937906ebd39" checksum = "84f8829ddc213e2c1368e51a2564c552b65a8cb6a28f31e576270ac81d5e5827"
dependencies = [ dependencies = [
"cc", "cc",
"codespan-reporting", "codespan-reporting",
@ -712,15 +717,15 @@ dependencies = [
[[package]] [[package]]
name = "cxxbridge-flags" name = "cxxbridge-flags"
version = "1.0.83" version = "1.0.80"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac040a39517fd1674e0f32177648334b0f4074625b5588a64519804ba0553b12" checksum = "e72537424b474af1460806647c41d4b6d35d09ef7fe031c5c2fa5766047cc56a"
[[package]] [[package]]
name = "cxxbridge-macro" name = "cxxbridge-macro"
version = "1.0.83" version = "1.0.80"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1362b0ddcfc4eb0a1f57b68bd77dd99f0e826958a96abd0ae9bd092e114ffed6" checksum = "309e4fb93eed90e1e14bea0da16b209f81813ba9fc7830c20ed151dd7bc0a4d7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -729,9 +734,9 @@ dependencies = [
[[package]] [[package]]
name = "darling" name = "darling"
version = "0.14.2" version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0dd3cd20dc6b5a876612a6e5accfe7f3dd883db6d07acfbf14c128f61550dfa" checksum = "4529658bdda7fd6769b8614be250cdcfc3aeb0ee72fe66f9e41e5e5eb73eac02"
dependencies = [ dependencies = [
"darling_core", "darling_core",
"darling_macro", "darling_macro",
@ -739,9 +744,9 @@ dependencies = [
[[package]] [[package]]
name = "darling_core" name = "darling_core"
version = "0.14.2" version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a784d2ccaf7c98501746bf0be29b2022ba41fd62a2e622af997a03e9f972859f" checksum = "649c91bc01e8b1eac09fb91e8dbc7d517684ca6be8ebc75bb9cafc894f9fdb6f"
dependencies = [ dependencies = [
"fnv", "fnv",
"ident_case", "ident_case",
@ -753,9 +758,9 @@ dependencies = [
[[package]] [[package]]
name = "darling_macro" name = "darling_macro"
version = "0.14.2" version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7618812407e9402654622dd402b0a89dff9ba93badd6540781526117b92aab7e" checksum = "ddfc69c5bfcbd2fc09a0f38451d2daf0e372e367986a83906d1b0dbc88134fb5"
dependencies = [ dependencies = [
"darling_core", "darling_core",
"quote", "quote",
@ -772,7 +777,7 @@ dependencies = [
"hashbrown", "hashbrown",
"lock_api", "lock_api",
"once_cell", "once_cell",
"parking_lot_core 0.9.5", "parking_lot_core 0.9.4",
] ]
[[package]] [[package]]
@ -823,9 +828,9 @@ dependencies = [
[[package]] [[package]]
name = "digest" name = "digest"
version = "0.10.6" version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c"
dependencies = [ dependencies = [
"block-buffer 0.10.3", "block-buffer 0.10.3",
"crypto-common", "crypto-common",
@ -858,17 +863,6 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
[[package]]
name = "displaydoc"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "either" name = "either"
version = "1.8.0" version = "1.8.0"
@ -924,40 +918,6 @@ dependencies = [
"web-sys", "web-sys",
] ]
[[package]]
name = "fluent-bundle"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e242c601dec9711505f6d5bbff5bedd4b61b2469f2e8bb8e57ee7c9747a87ffd"
dependencies = [
"fluent-langneg",
"fluent-syntax",
"intl-memoizer",
"intl_pluralrules",
"rustc-hash",
"self_cell",
"smallvec",
"unic-langid",
]
[[package]]
name = "fluent-langneg"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c4ad0989667548f06ccd0e306ed56b61bd4d35458d54df5ec7587c0e8ed5e94"
dependencies = [
"unic-langid",
]
[[package]]
name = "fluent-syntax"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0abed97648395c902868fee9026de96483933faa54ea3b40d652f7dfe61ca78"
dependencies = [
"thiserror",
]
[[package]] [[package]]
name = "fnv" name = "fnv"
version = "1.0.7" version = "1.0.7"
@ -1177,9 +1137,9 @@ dependencies = [
[[package]] [[package]]
name = "gloo-timers" name = "gloo-timers"
version = "0.2.5" version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98c4a8d6391675c6b2ee1a6c8d06e8e2d03605c44cec1270675985a4c2a5500b" checksum = "5fb7d06c1c8cc2a29bee7ec961009a0b2caa0793ee4900c2ffb348734ba1c8f9"
dependencies = [ dependencies = [
"futures-channel", "futures-channel",
"futures-core", "futures-core",
@ -1326,9 +1286,9 @@ checksum = "02296996cb8796d7c6e3bc2d9211b7802812d36999a51bb754123ead7d37d026"
[[package]] [[package]]
name = "hyper" name = "hyper"
version = "0.14.23" version = "0.14.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c" checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac"
dependencies = [ dependencies = [
"bytes", "bytes",
"futures-channel", "futures-channel",
@ -1350,9 +1310,9 @@ dependencies = [
[[package]] [[package]]
name = "hyper-rustls" name = "hyper-rustls"
version = "0.23.1" version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59df7c4e19c950e6e0e868dcc0a300b09a9b88e9ec55bd879ca819087a77355d" checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac"
dependencies = [ dependencies = [
"http", "http",
"hyper", "hyper",
@ -1363,9 +1323,9 @@ dependencies = [
[[package]] [[package]]
name = "iana-time-zone" name = "iana-time-zone"
version = "0.1.53" version = "0.1.51"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" checksum = "f5a6ef98976b22b3b7f2f3a806f858cb862044cfa66805aa3ad84cb3d3b785ed"
dependencies = [ dependencies = [
"android_system_properties", "android_system_properties",
"core-foundation-sys", "core-foundation-sys",
@ -1421,9 +1381,9 @@ dependencies = [
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "1.9.2" version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"hashbrown", "hashbrown",
@ -1445,30 +1405,11 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "intl-memoizer"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c310433e4a310918d6ed9243542a6b83ec1183df95dff8f23f87bb88a264a66f"
dependencies = [
"type-map",
"unic-langid",
]
[[package]]
name = "intl_pluralrules"
version = "7.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "078ea7b7c29a2b4df841a7f6ac8775ff6074020c6776d48491ce2268e068f972"
dependencies = [
"unic-langid",
]
[[package]] [[package]]
name = "ipnet" name = "ipnet"
version = "2.5.1" version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f88c5561171189e69df9d98bcf18fd5f9558300f7ea7b801eb8a0fd748bd8745" checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b"
[[package]] [[package]]
name = "itertools" name = "itertools"
@ -1529,9 +1470,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.138" version = "0.2.136"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" checksum = "55edcf6c0bb319052dea84732cf99db461780fd5e8d3eb46ab6ff312ab31f197"
[[package]] [[package]]
name = "link-cplusplus" name = "link-cplusplus"
@ -1660,9 +1601,9 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]] [[package]]
name = "memoffset" name = "memoffset"
version = "0.7.1" version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
dependencies = [ dependencies = [
"autocfg", "autocfg",
] ]
@ -1706,9 +1647,9 @@ dependencies = [
[[package]] [[package]]
name = "num_cpus" name = "num_cpus"
version = "1.14.0" version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
dependencies = [ dependencies = [
"hermit-abi", "hermit-abi",
"libc", "libc",
@ -1716,9 +1657,9 @@ dependencies = [
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.16.0" version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1"
[[package]] [[package]]
name = "opaque-debug" name = "opaque-debug"
@ -1728,9 +1669,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]] [[package]]
name = "os_str_bytes" name = "os_str_bytes"
version = "6.4.1" version = "6.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff"
[[package]] [[package]]
name = "parking" name = "parking"
@ -1765,9 +1706,9 @@ dependencies = [
[[package]] [[package]]
name = "parking_lot_core" name = "parking_lot_core"
version = "0.9.5" version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
@ -1804,9 +1745,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
[[package]] [[package]]
name = "pest" name = "pest"
version = "2.5.1" version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc8bed3549e0f9b0a2a78bf7c0018237a2cdf085eecbbc048e52612438e4e9d0" checksum = "dbc7bc69c062e492337d74d59b120c274fd3d261b6bf6d3207d499b4b379c41a"
dependencies = [ dependencies = [
"thiserror", "thiserror",
"ucd-trie", "ucd-trie",
@ -1814,9 +1755,9 @@ dependencies = [
[[package]] [[package]]
name = "pest_derive" name = "pest_derive"
version = "2.5.1" version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdc078600d06ff90d4ed238f0119d84ab5d43dbaad278b0e33a8820293b32344" checksum = "60b75706b9642ebcb34dab3bc7750f811609a0eb1dd8b88c2d15bf628c1c65b2"
dependencies = [ dependencies = [
"pest", "pest",
"pest_generator", "pest_generator",
@ -1824,9 +1765,9 @@ dependencies = [
[[package]] [[package]]
name = "pest_generator" name = "pest_generator"
version = "2.5.1" version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28a1af60b1c4148bb269006a750cff8e2ea36aff34d2d96cf7be0b14d1bed23c" checksum = "f4f9272122f5979a6511a749af9db9bfc810393f63119970d7085fed1c4ea0db"
dependencies = [ dependencies = [
"pest", "pest",
"pest_meta", "pest_meta",
@ -1837,9 +1778,9 @@ dependencies = [
[[package]] [[package]]
name = "pest_meta" name = "pest_meta"
version = "2.5.1" version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fec8605d59fc2ae0c6c1aefc0c7c7a9769732017c0ce07f7a9cfffa7b4404f20" checksum = "4c8717927f9b79515e565a64fe46c38b8cd0427e64c40680b14a7365ab09ac8d"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"pest", "pest",
@ -1925,16 +1866,16 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]] [[package]]
name = "polling" name = "polling"
version = "2.5.1" version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "166ca89eb77fd403230b9c156612965a81e094ec6ec3aa13663d4c8b113fa748" checksum = "ab4609a838d88b73d8238967b60dd115cc08d38e2bbaf51ee1e4b695f89122e2"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"cfg-if", "cfg-if",
"libc", "libc",
"log", "log",
"wepoll-ffi", "wepoll-ffi",
"windows-sys", "winapi",
] ]
[[package]] [[package]]
@ -1950,9 +1891,9 @@ dependencies = [
[[package]] [[package]]
name = "ppv-lite86" name = "ppv-lite86"
version = "0.2.17" version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
[[package]] [[package]]
name = "proc-macro-crate" name = "proc-macro-crate"
@ -2112,9 +2053,9 @@ dependencies = [
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.7.0" version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@ -2123,15 +2064,15 @@ dependencies = [
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.6.28" version = "0.6.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
[[package]] [[package]]
name = "reqwest" name = "reqwest"
version = "0.11.13" version = "0.11.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68cc60575865c7831548863cc02356512e3f1dc2f3f82cb837d7fc4cc8f3c97c" checksum = "431949c384f4e2ae07605ccaa56d1d9d2ecdb5cadd4f9577ccfab29f2e5149fc"
dependencies = [ dependencies = [
"base64", "base64",
"bytes", "bytes",
@ -2189,20 +2130,9 @@ checksum = "56770675ebc04927ded3e60633437841581c285dc6236109ea25fbf3beb7b59e"
[[package]] [[package]]
name = "rpassword" name = "rpassword"
version = "7.2.0" version = "7.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6678cf63ab3491898c0d021b493c94c9b221d91295294a2a5746eacbe5928322" checksum = "20c9f5d2a0c3e2ea729ab3706d22217177770654c3ef5056b68b69d07332d3f5"
dependencies = [
"libc",
"rtoolbox",
"winapi",
]
[[package]]
name = "rtoolbox"
version = "0.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "034e22c514f5c0cb8a10ff341b9b048b5ceb21591f31c8f44c43b960f9b3524a"
dependencies = [ dependencies = [
"libc", "libc",
"winapi", "winapi",
@ -2305,12 +2235,6 @@ dependencies = [
"toml", "toml",
] ]
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]] [[package]]
name = "rustc_version" name = "rustc_version"
version = "0.2.3" version = "0.2.3"
@ -2378,12 +2302,6 @@ dependencies = [
"untrusted", "untrusted",
] ]
[[package]]
name = "self_cell"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ef965a420fe14fdac7dd018862966a4c14094f900e1650bbc71ddd7d580c8af"
[[package]] [[package]]
name = "semver" name = "semver"
version = "0.9.0" version = "0.9.0"
@ -2401,18 +2319,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.148" version = "1.0.147"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e53f64bb4ba0191d6d0676e1b141ca55047d83b74f5607e6d8eb88126c52c2dc" checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.148" version = "1.0.147"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a55492425aa53521babf6137309e7d34c20bbfbbfcfe2c7f3a047fd1f6b92c0c" checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -2430,9 +2348,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.89" version = "1.0.87"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45"
dependencies = [ dependencies = [
"itoa", "itoa",
"ryu", "ryu",
@ -2479,7 +2397,7 @@ checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"cpufeatures", "cpufeatures",
"digest 0.10.6", "digest 0.10.5",
] ]
[[package]] [[package]]
@ -2509,7 +2427,7 @@ checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"cpufeatures", "cpufeatures",
"digest 0.10.6", "digest 0.10.5",
] ]
[[package]] [[package]]
@ -2611,12 +2529,6 @@ dependencies = [
"version_check", "version_check",
] ]
[[package]]
name = "static-rc"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b91d0104a7b28aeda24b30919f83222570111ac0bf1aab23aaffb8f59330e654"
[[package]] [[package]]
name = "stdweb" name = "stdweb"
version = "0.4.20" version = "0.4.20"
@ -2689,9 +2601,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.105" version = "1.0.103"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908" checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -2830,15 +2742,6 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "tinystr"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8aeafdfd935e4a7fe16a91ab711fa52d54df84f9c8f7ca5837a9d1d902ef4c2"
dependencies = [
"displaydoc",
]
[[package]] [[package]]
name = "tinyvec" name = "tinyvec"
version = "1.6.0" version = "1.6.0"
@ -2856,9 +2759,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.22.0" version = "1.21.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d76ce4a75fb488c605c54bf610f221cea8b0dafb53333c1a67e8ee199dcd2ae3" checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"bytes", "bytes",
@ -2874,9 +2777,9 @@ dependencies = [
[[package]] [[package]]
name = "tokio-macros" name = "tokio-macros"
version = "1.8.2" version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -2983,15 +2886,6 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
[[package]]
name = "type-map"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6d3364c5e96cb2ad1603037ab253ddd34d7fb72a58bdddf4b7350760fc69a46"
dependencies = [
"rustc-hash",
]
[[package]] [[package]]
name = "typed-sled" name = "typed-sled"
version = "0.2.0" version = "0.2.0"
@ -3047,49 +2941,6 @@ version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc"
[[package]]
name = "unic-langid"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "398f9ad7239db44fd0f80fe068d12ff22d78354080332a5077dc6f52f14dcf2f"
dependencies = [
"unic-langid-impl",
"unic-langid-macros",
]
[[package]]
name = "unic-langid-impl"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e35bfd2f2b8796545b55d7d3fd3e89a0613f68a0d1c8bc28cb7ff96b411a35ff"
dependencies = [
"tinystr",
]
[[package]]
name = "unic-langid-macros"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "055e618bf694161ffff0466d95cef3e1a5edc59f6ba1888e97801f2b4ebdc4fe"
dependencies = [
"proc-macro-hack",
"tinystr",
"unic-langid-impl",
"unic-langid-macros-impl",
]
[[package]]
name = "unic-langid-macros-impl"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f5cdec05b907f4e2f6843f4354f4ce6a5bebe1a56df320a49134944477ce4d8"
dependencies = [
"proc-macro-hack",
"quote",
"syn",
"unic-langid-impl",
]
[[package]] [[package]]
name = "unic-segment" name = "unic-segment"
version = "0.9.0" version = "0.9.0"
@ -3182,9 +3033,9 @@ dependencies = [
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.2.2" version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c" checksum = "feb41e78f93363bb2df8b0e86a2ca30eed7806ea16ea0c790d757cf93f79be83"
dependencies = [ dependencies = [
"getrandom 0.2.8", "getrandom 0.2.8",
] ]
@ -3350,9 +3201,6 @@ dependencies = [
"clap", "clap",
"crossbeam-channel", "crossbeam-channel",
"directories", "directories",
"fluent-bundle",
"fluent-langneg",
"intl-memoizer",
"log", "log",
"matrix-sdk", "matrix-sdk",
"rand 0.8.5", "rand 0.8.5",
@ -3361,13 +3209,11 @@ dependencies = [
"serde", "serde",
"sha2 0.10.6", "sha2 0.10.6",
"sled", "sled",
"static-rc",
"tera", "tera",
"tide", "tide",
"tokio", "tokio",
"toml_edit", "toml_edit",
"typed-sled", "typed-sled",
"unic-langid",
] ]
[[package]] [[package]]
@ -3512,9 +3358,9 @@ dependencies = [
[[package]] [[package]]
name = "zeroize_derive" name = "zeroize_derive"
version = "1.3.3" version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",

View file

@ -10,24 +10,19 @@ edition = "2021"
[dependencies] [dependencies]
argon2 = "0.4.1" argon2 = "0.4.1"
base64 = "0.13.1" base64 = "0.13.1"
clap = { version = "4.0.29", default-features = false, features = ["derive", "error-context", "help", "std", "usage"] } clap = { version = "4.0.18", default-features = false, features = ["derive", "std"] }
crossbeam-channel = "0.5.6" crossbeam-channel = "0.5.6"
directories = "4.0.1" directories = "4.0.1"
fluent-bundle = "0.15.2"
fluent-langneg = "0.13.0"
intl-memoizer = "0.5.1"
log = "0.4.17" log = "0.4.17"
matrix-sdk = { version = "0.6.2", default-features = false, features = ["rustls-tls"] } matrix-sdk = { version = "0.6.2", default-features = false, features = ["rustls-tls"] }
rand = "0.8.5" rand = "0.8.5"
rand_core = { version = "0.6.4", features = ["std"] } rand_core = { version = "0.6.4", features = ["std"] }
rpassword = "7.2.0" rpassword = "7.1.0"
serde = { version = "1.0.148", features = ["derive", "rc"] } serde = { version = "1.0.147", features = ["derive", "rc"] }
sha2 = "0.10.6" sha2 = "0.10.6"
sled = "0.34.7" sled = "0.34.7"
static-rc = "0.6.1"
tera = { version = "1.17.1", features = ["builtins", "date-locale"] } tera = { version = "1.17.1", features = ["builtins", "date-locale"] }
tide = { version = "0.16.0", default-features = false, features = ["h1-server", "cookies", "logger"] } tide = { version = "0.16.0", default-features = false, features = ["h1-server", "cookies", "logger"] }
tokio = { version = "1.22.0", features = ["macros", "rt-multi-thread"] } tokio = { version = "1.21.2", features = ["macros", "rt-multi-thread"] }
toml_edit = { version = "0.15.0", features = ["easy"] } toml_edit = { version = "0.15.0", features = ["easy"] }
typed-sled = "0.2.0" typed-sled = "0.2.0"
unic-langid = { version = "0.9.1", features = ["macros"] }

View file

@ -10,9 +10,8 @@ Rust webserver for comments, that you can easily embed in a website.
* Admin approval * Admin approval
* Admin notification on new comment via Matrix * Admin notification on new comment via Matrix
* Embedded one-file webserver * Embedded one-file webserver
* Customizable [Tera](https://github.com/Keats/tera) templates * [Tera](https://github.com/Keats/tera) templates
* Comment frequency limit per IP * Comment frequency limit per IP
* i18n
## Use ## Use

View file

@ -1,14 +0,0 @@
admin-comment-approve = Approve
admin-comment-edit = Edit
admin-comment-remove = Remove
admin_login-password_prompt = Password:
admin_login-submit_button = Login
admin_login-title = Admin login | Comments
error-antispam = The edition quota from your IP is reached. You will be unblocked in { $antispam_timeout }s.
error-list = Whoops, the following error occurred:
comment_form-author = Your name:
comment_form-email = Your email:
comment_form-edit_button = Edit comment
comment_form-new_button = Post comment
comment_form-text = Your comment:
title = Comments

View file

@ -1,14 +0,0 @@
admin-comment-approve = Approuver
admin-comment-edit = Modifier
admin-comment-remove = Supprimer
admin_login-password_prompt = Mot de passe :
admin_login-submit_button = S'authentifier
admin_login-title = Authentification admin | Commentaires
error-antispam = Le quota d'édition de votre adresse IP est atteint, elle sera débloquée dans { $antispam_timeout }s.
error-list = Oups, l'erreur suivante est survenue :
comment_form-author = Votre nom :
comment_form-email = Votre e-mail :
comment_form-edit_button = Modifier
comment_form-new_button = Envoyer
comment_form-text = Votre commentaire :
title = Commentaires

View file

@ -1,8 +1,8 @@
use crate::{config::Config, db::*}; use crate::{config::Config, db::*};
use std::time::Duration; use std::{sync::Arc, time::Duration};
pub async fn run_cleaner(config: &Config, dbs: Dbs) { pub async fn run_cleaner(config: Arc<Config>, dbs: Dbs) {
let mut last_db_clean = 0; let mut last_db_clean = 0;
loop { loop {
let time = std::time::SystemTime::now() let time = std::time::SystemTime::now()
@ -11,7 +11,7 @@ pub async fn run_cleaner(config: &Config, dbs: Dbs) {
.as_secs(); .as_secs();
if time > last_db_clean + 3600 { if time > last_db_clean + 3600 {
clean_antispam(config, dbs.clone(), time); clean_antispam(config.clone(), dbs.clone(), time);
last_db_clean = time; last_db_clean = time;
} }
@ -19,7 +19,7 @@ pub async fn run_cleaner(config: &Config, dbs: Dbs) {
} }
} }
fn clean_antispam(config: &Config, dbs: Dbs, time: u64) { fn clean_antispam(config: Arc<Config>, dbs: Dbs, time: u64) {
for (addr, (last_mutation, _mutation_count)) in for (addr, (last_mutation, _mutation_count)) in
dbs.client_mutation.iter().filter_map(|o| o.ok()) dbs.client_mutation.iter().filter_map(|o| o.ok())
{ {

View file

@ -36,9 +36,8 @@ pub struct Config {
pub cookies_https_only: bool, pub cookies_https_only: bool,
#[serde(default = "Config::default_cookies_domain")] #[serde(default = "Config::default_cookies_domain")]
pub cookies_domain: Option<String>, pub cookies_domain: Option<String>,
/// Format: "language_REGION" #[serde(default = "Config::default_lang")]
#[serde(default = "Config::default_default_lang")] pub lang: String,
pub default_lang: String,
#[serde(default = "Config::default_listen")] #[serde(default = "Config::default_listen")]
pub listen: SocketAddr, pub listen: SocketAddr,
/// Send a matrix message on new comment /// Send a matrix message on new comment
@ -103,8 +102,8 @@ impl Config {
fn default_cookies_domain() -> Option<String> { fn default_cookies_domain() -> Option<String> {
None None
} }
fn default_default_lang() -> String { fn default_lang() -> String {
"en_US".into() "en_GB".into()
} }
fn default_listen() -> SocketAddr { fn default_listen() -> SocketAddr {
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 31720) SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 31720)
@ -153,7 +152,7 @@ impl Default for Config {
comment_text_max_len: Self::default_comment_text_max_len(), comment_text_max_len: Self::default_comment_text_max_len(),
cookies_https_only: Self::default_cookies_https_only(), cookies_https_only: Self::default_cookies_https_only(),
cookies_domain: Self::default_cookies_domain(), cookies_domain: Self::default_cookies_domain(),
default_lang: Self::default_default_lang(), lang: Self::default_lang(),
listen: Self::default_listen(), listen: Self::default_listen(),
matrix_notify: Self::default_matrix_notify(), matrix_notify: Self::default_matrix_notify(),
matrix_password: Self::default_matrix_password(), matrix_password: Self::default_matrix_password(),

View file

@ -1,103 +0,0 @@
use crate::config::Config;
use fluent_bundle::{bundle::FluentBundle, FluentArgs, FluentResource};
use fluent_langneg::{
accepted_languages, negotiate::filter_matches, negotiate_languages, NegotiationStrategy,
};
use intl_memoizer::concurrent::IntlLangMemoizer;
use log::error;
use std::{borrow::Cow, collections::HashMap, ops::Deref, str::FromStr};
use unic_langid::{langid, LanguageIdentifier};
static LOCALE_FILES: &[(LanguageIdentifier, &str)] = &[
(langid!("en"), include_str!("../locales/en.ftl")),
(langid!("fr"), include_str!("../locales/fr.ftl")),
];
pub struct Locales {
bundles: HashMap<LanguageIdentifier, FluentBundle<FluentResource, IntlLangMemoizer>>,
pub default_lang: LanguageIdentifier,
langs: Vec<LanguageIdentifier>,
}
impl Locales {
pub fn new(config: &Config) -> Self {
let mut langs = Vec::new();
Self {
bundles: LOCALE_FILES
.iter()
.map(|(lang, raw)| {
let mut bundle = FluentBundle::new_concurrent(vec![lang.clone()]);
bundle
.add_resource(
FluentResource::try_new(raw.to_string()).unwrap_or_else(|e| {
panic!("Failed parsing `{lang}` locale: {e:?}")
}),
)
.unwrap();
langs.push(lang.clone());
(lang.clone(), bundle)
})
.collect::<HashMap<LanguageIdentifier, FluentBundle<FluentResource, IntlLangMemoizer>>>(
),
default_lang: filter_matches(
&[LanguageIdentifier::from_str(&config.default_lang)
.expect("Invalid default language")],
&langs,
NegotiationStrategy::Filtering,
)
.get(0)
.expect("Unavailable default language")
.deref()
.clone(),
langs,
}
}
// TODO fix fluent-langneg's weird API
pub fn tr<'a>(
&'a self,
langs: &[LanguageIdentifier],
key: &str,
args: Option<&'a FluentArgs>,
) -> Option<Cow<str>> {
for prefered_lang in negotiate_languages(
langs,
&self.langs,
Some(&self.default_lang),
NegotiationStrategy::Filtering,
) {
if let Some(bundle) = self.bundles.get(prefered_lang.as_ref()) {
println!("got bundle");
if let Some(message) = bundle.get_message(key) {
let mut errors = Vec::new();
let ret = bundle.format_pattern(message.value().unwrap(), args, &mut errors);
for error in errors {
error!("Formatting message `{key}` in lang `{prefered_lang}`: {error}");
}
return Some(ret);
}
}
}
None
}
}
pub fn get_client_langs<State>(req: &tide::Request<State>) -> Vec<LanguageIdentifier> {
if let Some(header) = req.header("Accept-Language") {
accepted_languages::parse(header.as_str())
} else {
println!("NO HEADER");
Vec::new()
}
}
/// Get the first language that is likely to be usable with chrono
pub fn get_time_lang(langs: &[LanguageIdentifier]) -> Option<String> {
for lang in langs {
if let Some(region) = &lang.region {
return Some(format!("{}_{}", lang.language.as_str(), region.as_str()));
}
}
None
}

View file

@ -3,7 +3,6 @@ mod cli;
mod config; mod config;
mod db; mod db;
mod helpers; mod helpers;
mod locales;
mod notify; mod notify;
mod queries; mod queries;
mod server; mod server;
@ -14,9 +13,7 @@ use argon2::{
Argon2, Argon2,
}; };
use clap::Parser; use clap::Parser;
use log::warn; use std::sync::Arc;
use std::{collections::HashMap, str::FromStr};
use unic_langid::LanguageIdentifier;
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
@ -28,42 +25,10 @@ async fn main() {
} }
cli::MainSubcommand::Start(subopt) => { cli::MainSubcommand::Start(subopt) => {
let (config, dbs, templates) = init_all(opt.opt, subopt); let (config, dbs, templates) = init_all(opt.opt, subopt);
let config = Arc::new(config);
// These will never be dropped nor mutated let templates = Arc::new(templates);
let templates = Box::leak(Box::new(templates)); tokio::spawn(cleaner::run_cleaner(config.clone(), dbs.clone()));
let config = Box::leak(Box::new(config)); server::run_server(config, dbs, templates).await;
let locales = Box::leak(Box::new(locales::Locales::new(config)));
// TODO args
templates.tera.register_function(
"tr",
Box::new(
|args: &HashMap<String, tera::Value>| -> tera::Result<tera::Value> {
let langs = if let Some(tera::Value::Array(langs)) = args.get("l") {
langs
.iter()
.filter_map(|lang| lang.as_str())
.filter_map(|lang| LanguageIdentifier::from_str(lang).ok())
.collect()
} else {
vec![locales.default_lang.clone()]
};
let key = args
.get("k")
.ok_or_else(|| tera::Error::from("Missing argument `k`"))?
.as_str()
.ok_or_else(|| tera::Error::from("Argument `k` must be string"))?;
let res = locales.tr(&langs, key, None);
if res.is_none() {
warn!("(calling `tr` in template) translation key `{key}` not found");
}
Ok(res.into())
},
),
);
tokio::spawn(cleaner::run_cleaner(config, dbs.clone()));
server::run_server(config, dbs, templates, locales).await;
} }
cli::MainSubcommand::Psw => { cli::MainSubcommand::Psw => {
let mut config = config::read_config(&opt.opt.dir.0); let mut config = config::read_config(&opt.opt.dir.0);

View file

@ -3,7 +3,10 @@ use crate::config::Config;
use crossbeam_channel::Receiver; use crossbeam_channel::Receiver;
use log::error; use log::error;
use matrix_sdk::ruma; use matrix_sdk::ruma;
use std::time::{Duration, SystemTime}; use std::{
sync::Arc,
time::{Duration, SystemTime},
};
enum OptionSince<T> { enum OptionSince<T> {
Some(T), Some(T),
@ -77,10 +80,10 @@ impl Notifier {
} }
} }
pub async fn run_notifier(config: &Config, recv: Receiver<()>) { pub async fn run_notifier(config: Arc<Config>, recv: Receiver<()>) {
let mut notifier = Notifier::new(config).await; let mut notifier = Notifier::new(&config).await;
for () in recv { for () in recv {
notifier.notify(config).await; notifier.notify(&config).await;
} }
} }

View file

@ -1,72 +1,68 @@
#![allow(clippy::too_many_arguments)] use crate::{config::*, db::*, helpers, queries::*, templates::*};
use crate::{config::*, db::*, helpers, locales::*, queries::*, templates::*};
use argon2::{Argon2, PasswordHash, PasswordVerifier}; use argon2::{Argon2, PasswordHash, PasswordVerifier};
use crossbeam_channel::Sender; use crossbeam_channel::Sender;
use fluent_bundle::FluentArgs;
use log::{error, warn}; use log::{error, warn};
use std::sync::Arc;
use tera::Context; use tera::Context;
use unic_langid::LanguageIdentifier;
pub async fn run_server( pub async fn run_server(config: Arc<Config>, dbs: Dbs, templates: Arc<Templates>) {
config: &'static Config,
dbs: Dbs,
templates: &'static Templates,
locales: &'static Locales,
) {
tide::log::start(); tide::log::start();
let (notify_send, notify_recv) = crossbeam_channel::bounded(10); let (notify_send, notify_recv) = crossbeam_channel::bounded(10);
tokio::spawn(crate::notify::run_notifier(config, notify_recv)); tokio::spawn(crate::notify::run_notifier(config.clone(), notify_recv));
let mut app = tide::new(); let mut app = tide::new();
app.at(&format!("{}t/:topic", config.root_url)).get({ app.at(&format!("{}t/:topic", config.root_url)).get({
let config = config.clone();
let templates = templates.clone();
let dbs = dbs.clone(); let dbs = dbs.clone();
move |req: tide::Request<()>| { move |req: tide::Request<()>| {
let client_langs = get_client_langs(&req);
serve_comments( serve_comments(
req, req,
config, config.clone(),
templates, templates.clone(),
dbs.clone(), dbs.clone(),
client_langs,
Context::new(), Context::new(),
200, 200,
) )
} }
}); });
app.at(&format!("{}t/:topic", config.root_url)).post({ app.at(&format!("{}t/:topic", config.root_url)).post({
let config = config.clone();
let templates = templates.clone();
let dbs = dbs.clone(); let dbs = dbs.clone();
move |req: tide::Request<()>| { move |req: tide::Request<()>| {
handle_post_comments( handle_post_comments(
req, req,
config, config.clone(),
templates, templates.clone(),
dbs.clone(), dbs.clone(),
locales,
notify_send.clone(), notify_send.clone(),
) )
} }
}); });
app.at(&format!("{}admin", config.root_url)) app.at(&format!("{}admin", config.root_url)).get({
.get(move |req: tide::Request<()>| { let config = config.clone();
let client_langs = get_client_langs(&req); let templates = templates.clone();
serve_admin_login(req, config, templates, client_langs) move |req: tide::Request<()>| serve_admin_login(req, config.clone(), templates.clone())
}); });
app.at(&format!("{}admin", config.root_url)).post({ app.at(&format!("{}admin", config.root_url)).post({
let config = config.clone();
let templates = templates.clone();
let dbs = dbs.clone(); let dbs = dbs.clone();
move |req: tide::Request<()>| handle_post_admin(req, config, templates, dbs.clone()) move |req: tide::Request<()>| {
handle_post_admin(req, config.clone(), templates.clone(), dbs.clone())
}
}); });
app.listen(config.listen).await.unwrap(); app.listen(config.listen).await.unwrap();
} }
async fn serve_comments<'a>( async fn serve_comments<'a>(
req: tide::Request<()>, req: tide::Request<()>,
config: &Config, config: Arc<Config>,
templates: &Templates, templates: Arc<Templates>,
dbs: Dbs, dbs: Dbs,
client_langs: Vec<LanguageIdentifier>,
mut context: Context, mut context: Context,
status_code: u16, status_code: u16,
) -> tide::Result<tide::Response> { ) -> tide::Result<tide::Response> {
@ -75,25 +71,13 @@ async fn serve_comments<'a>(
}; };
let admin = req.cookie("admin").map_or(false, |psw| { let admin = req.cookie("admin").map_or(false, |psw| {
check_admin_password_hash(config, &String::from(psw.value())) check_admin_password_hash(&config, &String::from(psw.value()))
}); });
let topic_hash = TopicHash::from_topic(topic); let topic_hash = TopicHash::from_topic(topic);
context.insert("config", &config); context.insert("config", &config);
context.insert("admin", &admin); context.insert("admin", &admin);
let time_lang = get_time_lang(&client_langs);
context.insert(
"time_lang",
time_lang.as_ref().unwrap_or(&config.default_lang),
);
context.insert(
"l",
&client_langs
.iter()
.map(|lang| lang.language.as_str())
.collect::<Vec<&str>>(),
);
if admin { if admin {
if let Ok(query) = req.query::<ApproveQuery>() { if let Ok(query) = req.query::<ApproveQuery>() {
@ -158,26 +142,13 @@ async fn serve_comments<'a>(
async fn serve_admin<'a>( async fn serve_admin<'a>(
_req: tide::Request<()>, _req: tide::Request<()>,
config: &Config, config: Arc<Config>,
templates: &Templates, templates: Arc<Templates>,
dbs: Dbs, dbs: Dbs,
client_langs: &[LanguageIdentifier],
) -> tide::Result<tide::Response> { ) -> tide::Result<tide::Response> {
let mut context = Context::new(); let mut context = Context::new();
context.insert("config", &config); context.insert("config", &config);
context.insert("admin", &true); context.insert("admin", &true);
let time_lang = get_time_lang(client_langs);
context.insert(
"time_lang",
time_lang.as_ref().unwrap_or(&config.default_lang),
);
context.insert(
"l",
&client_langs
.iter()
.map(|lang| lang.language.as_str())
.collect::<Vec<&str>>(),
);
context.insert( context.insert(
"comments", "comments",
@ -216,24 +187,11 @@ async fn serve_admin<'a>(
async fn serve_admin_login( async fn serve_admin_login(
_req: tide::Request<()>, _req: tide::Request<()>,
config: &Config, config: Arc<Config>,
templates: &Templates, templates: Arc<Templates>,
client_langs: Vec<LanguageIdentifier>,
) -> tide::Result<tide::Response> { ) -> tide::Result<tide::Response> {
let mut context = Context::new(); let mut context = Context::new();
context.insert("config", &config); context.insert("config", &config);
let time_lang = get_time_lang(&client_langs);
context.insert(
"time_lang",
time_lang.as_ref().unwrap_or(&config.default_lang),
);
context.insert(
"l",
&client_langs
.iter()
.map(|lang| lang.language.as_str())
.collect::<Vec<&str>>(),
);
Ok(tide::Response::builder(200) Ok(tide::Response::builder(200)
.content_type(tide::http::mime::HTML) .content_type(tide::http::mime::HTML)
@ -243,20 +201,17 @@ async fn serve_admin_login(
async fn handle_post_comments( async fn handle_post_comments(
mut req: tide::Request<()>, mut req: tide::Request<()>,
config: &Config, config: Arc<Config>,
templates: &Templates, templates: Arc<Templates>,
dbs: Dbs, dbs: Dbs,
locales: &Locales,
notify_send: Sender<()>, notify_send: Sender<()>,
) -> tide::Result<tide::Response> { ) -> tide::Result<tide::Response> {
let admin = req.cookie("admin").map_or(false, |psw| { let admin = req.cookie("admin").map_or(false, |psw| {
check_admin_password_hash(config, &String::from(psw.value())) check_admin_password_hash(&config, &String::from(psw.value()))
}); });
let client_langs = get_client_langs(&req);
let client_addr = if !admin && config.antispam_enable { let client_addr = if !admin && config.antispam_enable {
match helpers::get_client_addr(config, &req) { match helpers::get_client_addr(&config, &req) {
Some(Ok(addr)) => { Some(Ok(addr)) => {
if config.antispam_whitelist.contains(&addr) { if config.antispam_whitelist.contains(&addr) {
None None
@ -286,25 +241,16 @@ async fn handle_post_comments(
return Err(tide::Error::from_str(404, "No topic")) return Err(tide::Error::from_str(404, "No topic"))
}; };
helpers::check_comment(config, &query.comment, &mut errors); helpers::check_comment(&config, &query.comment, &mut errors);
if let Some(client_addr) = &client_addr { if let Some(client_addr) = &client_addr {
if let Some(antispam_timeout) = if let Some(antispam_timeout) =
helpers::antispam_check_client_mutation(client_addr, &dbs, config).unwrap() helpers::antispam_check_client_mutation(client_addr, &dbs, &config).unwrap()
{ {
errors.push( errors.push(format!(
locales "The edition quota from your IP is reached. You will be unblocked in {}s.",
.tr( antispam_timeout
&client_langs, ));
"error-antispam",
Some(&FluentArgs::from_iter([(
"antispam_timeout",
antispam_timeout,
)])),
)
.unwrap()
.into_owned(),
);
} }
} }
@ -348,7 +294,7 @@ async fn handle_post_comments(
return Err(tide::Error::from_str(403, "Forbidden")); return Err(tide::Error::from_str(403, "Forbidden"));
} }
helpers::check_comment(config, &query.comment, &mut errors); helpers::check_comment(&config, &query.comment, &mut errors);
let comment_id = if let Ok(comment_id) = CommentId::from_base64(&query.id) { let comment_id = if let Ok(comment_id) = CommentId::from_base64(&query.id) {
comment_id comment_id
@ -362,33 +308,21 @@ async fn handle_post_comments(
return Err(tide::Error::from_str(404, "Not found")); return Err(tide::Error::from_str(404, "Not found"));
}; };
// We're admin if let Some(client_addr) = &client_addr {
/*if let Some(client_addr) = &client_addr {
if let Some(antispam_timeout) = if let Some(antispam_timeout) =
helpers::antispam_check_client_mutation(client_addr, &dbs, config).unwrap() helpers::antispam_check_client_mutation(client_addr, &dbs, &config).unwrap()
{ {
let client_langs = get_client_langs(&req); errors.push(format!(
errors.push( "The edition quota from your IP is reached. You will be unblocked in {}s.",
locales antispam_timeout
.tr( ));
&client_langs, }
"error-antispam",
Some(&FluentArgs::from_iter([(
"antispam_timeout",
antispam_timeout,
)])),
)
.unwrap()
.into_owned(),
);
} }
}*/
if errors.is_empty() { if errors.is_empty() {
// We're admin if let Some(client_addr) = &client_addr {
/*if let Some(client_addr) = &client_addr {
helpers::antispam_update_client_mutation(client_addr, &dbs).unwrap(); helpers::antispam_update_client_mutation(client_addr, &dbs).unwrap();
}*/ }
let time = std::time::SystemTime::now() let time = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH) .duration_since(std::time::UNIX_EPOCH)
@ -419,7 +353,6 @@ async fn handle_post_comments(
config, config,
templates, templates,
dbs, dbs,
client_langs,
context, context,
if errors.is_empty() { 200 } else { 400 }, if errors.is_empty() { 200 } else { 400 },
) )
@ -428,27 +361,22 @@ async fn handle_post_comments(
async fn handle_post_admin( async fn handle_post_admin(
mut req: tide::Request<()>, mut req: tide::Request<()>,
config: &Config, config: Arc<Config>,
templates: &Templates, templates: Arc<Templates>,
dbs: Dbs, dbs: Dbs,
) -> tide::Result<tide::Response> { ) -> tide::Result<tide::Response> {
if let Some(psw) = req.cookie("admin") { if let Some(psw) = req.cookie("admin") {
if check_admin_password(config, &String::from(psw.value())).is_some() { if check_admin_password(&config, &String::from(psw.value())).is_some() {
#[allow(clippy::match_single_binding)] #[allow(clippy::match_single_binding)]
match req.body_form::<AdminQuery>().await? { match req.body_form::<AdminQuery>().await? {
_ => { _ => serve_admin(req, config, templates, dbs).await,
let client_langs = get_client_langs(&req);
serve_admin(req, config, templates, dbs, &client_langs).await
}
} }
} else { } else {
let client_langs = get_client_langs(&req); serve_admin_login(req, config, templates).await
serve_admin_login(req, config, templates, client_langs).await
} }
} else if let AdminQuery::Login(query) = req.body_form::<AdminQuery>().await? { } else if let AdminQuery::Login(query) = req.body_form::<AdminQuery>().await? {
if let Some(password_hash) = check_admin_password(config, &query.psw) { if let Some(password_hash) = check_admin_password(&config, &query.psw) {
let client_langs = get_client_langs(&req); serve_admin(req, config.clone(), templates, dbs)
serve_admin(req, config, templates, dbs, &client_langs)
.await .await
.map(|mut r| { .map(|mut r| {
let mut cookie = tide::http::Cookie::new("admin", password_hash); let mut cookie = tide::http::Cookie::new("admin", password_hash);
@ -464,12 +392,10 @@ async fn handle_post_admin(
r r
}) })
} else { } else {
let client_langs = get_client_langs(&req); serve_admin_login(req, config, templates).await
serve_admin_login(req, config, templates, client_langs).await
} }
} else { } else {
let client_langs = get_client_langs(&req); serve_admin_login(req, config, templates).await
serve_admin_login(req, config, templates, client_langs).await
} }
} }

View file

@ -1,14 +1,14 @@
<!doctype html> <!doctype html>
<html lang="{{ time_lang }}"> <html lang="en">
<head> <head>
<meta charset="utf-8"/> <meta charset="utf-8"/>
<title>{{ tr(l=l,k="admin_login-title")|safe }}</title> <title>Admin login | Comments</title>
</head> </head>
<body> <body>
<form action="#" method="post"> <form action="#" method="post">
<label for="login-psw">{{ tr(l=l,k="admin_login-password_prompt")|safe }}</label> <label for="login-psw">Password:</label>
<input type="password" id="login-psw" name="psw"/><br/> <input type="password" id="login-psw" name="psw"/><br/>
<button type="submit" name="a" value="login">{{ tr(l=l,k="admin_login-submit_button")|safe }}</button> <button type="submit" name="a" value="login">Login</button>
</form> </form>
</body> </body>
</html> </html>

View file

@ -1,8 +1,8 @@
<!doctype html> <!doctype html>
<html lang="{{ time_lang }}"> <html lang="en">
<head> <head>
<meta charset="utf-8"/> <meta charset="utf-8"/>
<title>{{ tr(l=l,k="title")|safe }}</title> <title>Comments</title>
</head> </head>
<body> <body>
{% if comments_pending %} {% if comments_pending %}
@ -10,15 +10,15 @@
{% for comment in comments_pending %} {% for comment in comments_pending %}
<div class="comment{% if comment.needs_approval %} comment_pending{% endif %}" id="comment-{{ comment.id | safe }}"> <div class="comment{% if comment.needs_approval %} comment_pending{% endif %}" id="comment-{{ comment.id | safe }}">
<span class="comment-author">{{ comment.author }}</span> <span class="comment-author">{{ comment.author }}</span>
<span class="comment-date">{{ comment.post_time | date(format="%F %R", locale=time_lang) }}</span> <span class="comment-date">{{ comment.post_time | date(format="%F %R", locale=config.lang) }}</span>
{% if comment.editable %} {% if comment.editable %}
<a href="?edit={{ comment.id | safe }}#edit_comment-form">{{ tr(l=l,k="admin-comment-edit")|safe }}</a> <a href="?edit={{ comment.id | safe }}#edit_comment-form">Edit</a>
{% endif %} {% endif %}
{% if admin and comment.needs_approval %} {% if admin and comment.needs_approval %}
<a href="?approve={{ comment.id | safe }}">{{ tr(l=l,k="admin-comment-approve")|safe }}</a> <a href="?approve={{ comment.id | safe }}">Approve</a>
{% endif %} {% endif %}
{% if admin %} {% if admin %}
<a href="?remove={{ comment.id | safe }}">{{ tr(l=l,k="admin-comment-remove")|safe }}</a> <a href="?remove={{ comment.id | safe }}">Remove</a>
{% endif %} {% endif %}
<p class="comment-text">{{ comment.text }}</p> <p class="comment-text">{{ comment.text }}</p>
</div> </div>
@ -29,15 +29,15 @@
{% for comment in comments %} {% for comment in comments %}
<div class="comment{% if comment.needs_approval %} comment_pending{% endif %}" id="comment-{{ comment.id | safe }}"> <div class="comment{% if comment.needs_approval %} comment_pending{% endif %}" id="comment-{{ comment.id | safe }}">
<span class="comment-author">{{ comment.author }}</span> <span class="comment-author">{{ comment.author }}</span>
<span class="comment-date">{{ comment.post_time | date(format="%F %R", locale=time_lang) }}</span> <span class="comment-date">{{ comment.post_time | date(format="%F %R", locale=config.lang) }}</span>
{% if comment.editable %} {% if comment.editable %}
<a href="?edit={{ comment.id | safe }}#edit_comment-form">{{ tr(l=l,k="admin-comment-edit")|safe }}</a> <a href="?edit={{ comment.id | safe }}#edit_comment-form">Edit</a>
{% endif %} {% endif %}
{% if admin and comment.needs_approval %} {% if admin and comment.needs_approval %}
<a href="?approve={{ comment.id | safe }}">{{ tr(l=l,k="admin-comment-approve")|safe }}</a> <a href="?approve={{ comment.id | safe }}">Approve</a>
{% endif %} {% endif %}
{% if admin %} {% if admin %}
<a href="?remove={{ comment.id | safe }}">{{ tr(l=l,k="admin-comment-remove")|safe }}</a> <a href="?remove={{ comment.id | safe }}">Remove</a>
{% endif %} {% endif %}
<p class="comment-text">{{ comment.text }}</p> <p class="comment-text">{{ comment.text }}</p>
</div> </div>
@ -45,25 +45,25 @@
</div> </div>
<form id="new_comment-form" action="#new_comment-form" method="post"> <form id="new_comment-form" action="#new_comment-form" method="post">
{% if new_comment_errors %} {% if new_comment_errors %}
<p>{{ tr(l=l,k="error-list")|safe }}</p> <p>Whoops, the following error occurred:</p>
<ul id="new_comment-errors" class="errors"> <ul id="new_comment-errors" class="errors">
{% for error in new_comment_errors %} {% for error in new_comment_errors %}
<li class="error">{{ error | safe }}</li> <li class="error">{{ error | safe }}</li>
{% endfor %} {% endfor %}
</ul> </ul>
{% endif %} {% endif %}
<label for="new_comment-author">{{ tr(l=l,k="comment_form-author")|safe }}</label> <label for="new_comment-author">Your name:</label>
<input type="text" id="new_comment-author" name="author" maxlength="{{ config.comment_author_max_len | safe }}"{% if new_comment_author %} value="{{ new_comment_author }}"{% endif %}/><br/> <input type="text" id="new_comment-author" name="author" maxlength="{{ config.comment_author_max_len | safe }}"{% if new_comment_author %} value="{{ new_comment_author }}"{% endif %}/><br/>
<label for="new_comment-email">{{ tr(l=l,k="comment_form-email")|safe }}</label> <label for="new_comment-email">Your e-mail:</label>
<input type="email" id="new_comment-email" name="email" maxlength="{{ config.comment_email_max_len | safe }}"{% if new_comment_email %} value="{{ new_comment_email }}"{% endif %}/><br/> <input type="email" id="new_comment-email" name="email" maxlength="{{ config.comment_email_max_len | safe }}"{% if new_comment_email %} value="{{ new_comment_email }}"{% endif %}/><br/>
<label for="new_comment-text">{{ tr(l=l,k="comment_form-text")|safe }}</label><br/> <label for="new_comment-text">Your comment:</label><br/>
<textarea id="new_comment-text" name="text" maxlength="{{ config.comment_text_max_len | safe }}">{% if new_comment_text %}{{ new_comment_text }}{% endif %}</textarea><br/> <textarea id="new_comment-text" name="text" maxlength="{{ config.comment_text_max_len | safe }}">{% if new_comment_text %}{{ new_comment_text }}{% endif %}</textarea><br/>
<button type="submit" name="a" value="new_comment">{{ tr(l=l,k="comment_form-new_button")|safe }}</button> <button type="submit" name="a" value="new_comment">Post comment</button>
</form> </form>
{% if edit_comment %} {% if edit_comment %}
<form id="edit_comment-form" action="#edit_comment-form" method="post"> <form id="edit_comment-form" action="#edit_comment-form" method="post">
{% if edit_comment_errors %} {% if edit_comment_errors %}
<p>{{ tr(l=l,k="error-list")|safe }}</p> <p>Whoops, the following error occurred:</p>
<ul id="edit_comment-errors" class="errors"> <ul id="edit_comment-errors" class="errors">
{% for error in edit_comment_errors %} {% for error in edit_comment_errors %}
<li class="error">{{ error | safe }}</li> <li class="error">{{ error | safe }}</li>
@ -71,13 +71,13 @@
</ul> </ul>
{% endif %} {% endif %}
<input type="hidden" name="id" value="{{ edit_comment | safe }}" autocomplete="off"/> <input type="hidden" name="id" value="{{ edit_comment | safe }}" autocomplete="off"/>
<label for="edit_comment-author">{{ tr(l=l,k="comment_form-author")|safe }}</label> <label for="edit_comment-author">Your name:</label>
<input type="text" id="edit_comment-author" name="author" maxlength="{{ config.comment_author_max_len | safe }}"{% if edit_comment_author %} value="{{ edit_comment_author }}"{% endif %}/><br/> <input type="text" id="edit_comment-author" name="author" maxlength="{{ config.comment_author_max_len | safe }}"{% if edit_comment_author %} value="{{ edit_comment_author }}"{% endif %}/><br/>
<label for="edit_comment-email">{{ tr(l=l,k="comment_form-email")|safe }}</label> <label for="edit_comment-email">Your e-mail:</label>
<input type="email" id="edit_comment-email" name="email" maxlength="{{ config.comment_email_max_len | safe }}"{% if edit_comment_email %} value="{{ edit_comment_email }}"{% endif %}/><br/> <input type="email" id="edit_comment-email" name="email" maxlength="{{ config.comment_email_max_len | safe }}"{% if edit_comment_email %} value="{{ edit_comment_email }}"{% endif %}/><br/>
<label for="edit_comment-text">{{ tr(l=l,k="comment_form-text")|safe }}</label><br/> <label for="edit_comment-text">Your comment:</label><br/>
<textarea id="edit_comment-text" name="text" maxlength="{{ config.comment_text_max_len | safe }}">{% if edit_comment_text %}{{ edit_comment_text }}{% endif %}</textarea><br/> <textarea id="edit_comment-text" name="text" maxlength="{{ config.comment_text_max_len | safe }}">{% if edit_comment_text %}{{ edit_comment_text }}{% endif %}</textarea><br/>
<button type="submit" name="a" value="edit_comment">{{ tr(l=l,k="comment_form-edit_button")|safe }}</button> <button type="submit" name="a" value="edit_comment">Edit comment</button>
</form> </form>
{% endif %} {% endif %}
</body> </body>