Compare commits
11 Commits
67d861325a
...
6d021e8d6b
Author | SHA1 | Date | |
---|---|---|---|
6d021e8d6b | |||
4ea9068850 | |||
2e4f45054a | |||
fb1bb429c3 | |||
998248acb7 | |||
84ad3432c9 | |||
161f4f4073 | |||
e120d19dc8 | |||
5755109dc8 | |||
652ea26b32 | |||
e991818c7d |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,3 +2,4 @@
|
|||||||
.history
|
.history
|
||||||
/frontend/node_modules/*
|
/frontend/node_modules/*
|
||||||
db.sqlite
|
db.sqlite
|
||||||
|
config.toml
|
||||||
|
420
Cargo.lock
generated
420
Cargo.lock
generated
@@ -17,6 +17,41 @@ version = "2.0.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aead"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
|
||||||
|
dependencies = [
|
||||||
|
"crypto-common",
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aes"
|
||||||
|
version = "0.8.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cipher",
|
||||||
|
"cpufeatures",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aes-gcm"
|
||||||
|
version = "0.10.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1"
|
||||||
|
dependencies = [
|
||||||
|
"aead",
|
||||||
|
"aes",
|
||||||
|
"cipher",
|
||||||
|
"ctr",
|
||||||
|
"ghash",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "1.1.3"
|
version = "1.1.3"
|
||||||
@@ -53,17 +88,6 @@ 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 = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
|
checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-trait"
|
|
||||||
version = "0.1.88"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atoi"
|
name = "atoi"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
@@ -156,22 +180,6 @@ dependencies = [
|
|||||||
"tower-service",
|
"tower-service",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "axum-messages"
|
|
||||||
version = "0.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d67ce6e7bc1e1e71f2a4e86d418045a29c63c4ebb631f3d9bb2f81c4958ea391"
|
|
||||||
dependencies = [
|
|
||||||
"axum-core",
|
|
||||||
"http",
|
|
||||||
"parking_lot",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"tower",
|
|
||||||
"tower-sessions-core",
|
|
||||||
"tracing",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "backtrace"
|
name = "backtrace"
|
||||||
version = "0.3.75"
|
version = "0.3.75"
|
||||||
@@ -290,6 +298,16 @@ dependencies = [
|
|||||||
"windows-link",
|
"windows-link",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cipher"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
||||||
|
dependencies = [
|
||||||
|
"crypto-common",
|
||||||
|
"inout",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "concurrent-queue"
|
name = "concurrent-queue"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
@@ -311,7 +329,11 @@ version = "0.18.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747"
|
checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"aes-gcm",
|
||||||
|
"base64",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
|
"rand",
|
||||||
|
"subtle",
|
||||||
"time",
|
"time",
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
@@ -387,9 +409,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"generic-array",
|
"generic-array",
|
||||||
|
"rand_core",
|
||||||
"typenum",
|
"typenum",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ctr"
|
||||||
|
version = "0.9.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835"
|
||||||
|
dependencies = [
|
||||||
|
"cipher",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "der"
|
name = "der"
|
||||||
version = "0.7.10"
|
version = "0.7.10"
|
||||||
@@ -408,7 +440,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
|
checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"powerfmt",
|
"powerfmt",
|
||||||
"serde",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -509,20 +540,6 @@ dependencies = [
|
|||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures"
|
|
||||||
version = "0.3.31"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
|
|
||||||
dependencies = [
|
|
||||||
"futures-channel",
|
|
||||||
"futures-core",
|
|
||||||
"futures-io",
|
|
||||||
"futures-sink",
|
|
||||||
"futures-task",
|
|
||||||
"futures-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-channel"
|
name = "futures-channel"
|
||||||
version = "0.3.31"
|
version = "0.3.31"
|
||||||
@@ -567,17 +584,6 @@ version = "0.3.31"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
|
checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures-macro"
|
|
||||||
version = "0.3.31"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-sink"
|
name = "futures-sink"
|
||||||
version = "0.3.31"
|
version = "0.3.31"
|
||||||
@@ -598,7 +604,6 @@ checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"futures-macro",
|
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"futures-task",
|
"futures-task",
|
||||||
"memchr",
|
"memchr",
|
||||||
@@ -640,6 +645,16 @@ dependencies = [
|
|||||||
"wasi 0.14.2+wasi-0.2.4",
|
"wasi 0.14.2+wasi-0.2.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ghash"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1"
|
||||||
|
dependencies = [
|
||||||
|
"opaque-debug",
|
||||||
|
"polyval",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gimli"
|
name = "gimli"
|
||||||
version = "0.31.1"
|
version = "0.31.1"
|
||||||
@@ -661,8 +676,8 @@ dependencies = [
|
|||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"bstr",
|
"bstr",
|
||||||
"log",
|
"log",
|
||||||
"regex-automata",
|
"regex-automata 0.4.9",
|
||||||
"regex-syntax",
|
"regex-syntax 0.8.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -963,7 +978,7 @@ dependencies = [
|
|||||||
"globset",
|
"globset",
|
||||||
"log",
|
"log",
|
||||||
"memchr",
|
"memchr",
|
||||||
"regex-automata",
|
"regex-automata 0.4.9",
|
||||||
"same-file",
|
"same-file",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
"winapi-util",
|
"winapi-util",
|
||||||
@@ -979,6 +994,15 @@ dependencies = [
|
|||||||
"hashbrown",
|
"hashbrown",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "inout"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "io-uring"
|
name = "io-uring"
|
||||||
version = "0.7.9"
|
version = "0.7.9"
|
||||||
@@ -1061,7 +1085,6 @@ checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"scopeguard",
|
"scopeguard",
|
||||||
"serde",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1070,6 +1093,15 @@ version = "0.4.27"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matchers"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
|
||||||
|
dependencies = [
|
||||||
|
"regex-automata 0.1.10",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "matchit"
|
name = "matchit"
|
||||||
version = "0.8.4"
|
version = "0.8.4"
|
||||||
@@ -1161,6 +1193,16 @@ dependencies = [
|
|||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nu-ansi-term"
|
||||||
|
version = "0.46.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
|
||||||
|
dependencies = [
|
||||||
|
"overload",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-bigint-dig"
|
name = "num-bigint-dig"
|
||||||
version = "0.8.4"
|
version = "0.8.4"
|
||||||
@@ -1229,6 +1271,18 @@ version = "1.21.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "opaque-debug"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "overload"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking"
|
name = "parking"
|
||||||
version = "2.2.1"
|
version = "2.2.1"
|
||||||
@@ -1312,6 +1366,18 @@ version = "0.3.32"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "polyval"
|
||||||
|
version = "0.6.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"opaque-debug",
|
||||||
|
"universal-hash",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "potential_utf"
|
name = "potential_utf"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
@@ -1419,8 +1485,17 @@ checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
"regex-automata",
|
"regex-automata 0.4.9",
|
||||||
"regex-syntax",
|
"regex-syntax 0.8.5",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
||||||
|
dependencies = [
|
||||||
|
"regex-syntax 0.6.29",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1431,9 +1506,15 @@ checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
"regex-syntax",
|
"regex-syntax 0.8.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.6.29"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-syntax"
|
||||||
version = "0.8.5"
|
version = "0.8.5"
|
||||||
@@ -1524,7 +1605,7 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
"siphasher",
|
"siphasher",
|
||||||
"toml",
|
"toml 0.8.23",
|
||||||
"triomphe",
|
"triomphe",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1646,6 +1727,15 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_spanned"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_urlencoded"
|
name = "serde_urlencoded"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
@@ -1693,6 +1783,15 @@ dependencies = [
|
|||||||
"digest",
|
"digest",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sharded-slab"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shlex"
|
name = "shlex"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
@@ -2024,6 +2123,15 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thread_local"
|
||||||
|
version = "1.1.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.3.41"
|
version = "0.3.41"
|
||||||
@@ -2140,11 +2248,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
|
checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_spanned",
|
"serde_spanned 0.6.9",
|
||||||
"toml_datetime",
|
"toml_datetime 0.6.11",
|
||||||
"toml_edit",
|
"toml_edit",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml"
|
||||||
|
version = "0.9.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "75129e1dc5000bfbaa9fee9d1b21f974f9fbad9daec557a521ee6e080825f6e8"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap",
|
||||||
|
"serde",
|
||||||
|
"serde_spanned 1.0.0",
|
||||||
|
"toml_datetime 0.7.0",
|
||||||
|
"toml_parser",
|
||||||
|
"toml_writer",
|
||||||
|
"winnow",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_datetime"
|
name = "toml_datetime"
|
||||||
version = "0.6.11"
|
version = "0.6.11"
|
||||||
@@ -2154,6 +2277,15 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_datetime"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_edit"
|
name = "toml_edit"
|
||||||
version = "0.22.27"
|
version = "0.22.27"
|
||||||
@@ -2162,18 +2294,33 @@ checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_spanned",
|
"serde_spanned 0.6.9",
|
||||||
"toml_datetime",
|
"toml_datetime 0.6.11",
|
||||||
"toml_write",
|
"toml_write",
|
||||||
"winnow",
|
"winnow",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_parser"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b551886f449aa90d4fe2bdaa9f4a2577ad2dde302c61ecf262d80b116db95c10"
|
||||||
|
dependencies = [
|
||||||
|
"winnow",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_write"
|
name = "toml_write"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
|
checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_writer"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tower"
|
name = "tower"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
@@ -2190,22 +2337,6 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tower-cookies"
|
|
||||||
version = "0.11.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "151b5a3e3c45df17466454bb74e9ecedecc955269bdedbf4d150dfa393b55a36"
|
|
||||||
dependencies = [
|
|
||||||
"axum-core",
|
|
||||||
"cookie",
|
|
||||||
"futures-util",
|
|
||||||
"http",
|
|
||||||
"parking_lot",
|
|
||||||
"pin-project-lite",
|
|
||||||
"tower-layer",
|
|
||||||
"tower-service",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tower-http"
|
name = "tower-http"
|
||||||
version = "0.6.6"
|
version = "0.6.6"
|
||||||
@@ -2244,57 +2375,6 @@ version = "0.3.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
|
checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tower-sessions"
|
|
||||||
version = "0.14.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "43a05911f23e8fae446005fe9b7b97e66d95b6db589dc1c4d59f6a2d4d4927d3"
|
|
||||||
dependencies = [
|
|
||||||
"async-trait",
|
|
||||||
"http",
|
|
||||||
"time",
|
|
||||||
"tokio",
|
|
||||||
"tower-cookies",
|
|
||||||
"tower-layer",
|
|
||||||
"tower-service",
|
|
||||||
"tower-sessions-core",
|
|
||||||
"tower-sessions-memory-store",
|
|
||||||
"tracing",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tower-sessions-core"
|
|
||||||
version = "0.14.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ce8cce604865576b7751b7a6bc3058f754569a60d689328bb74c52b1d87e355b"
|
|
||||||
dependencies = [
|
|
||||||
"async-trait",
|
|
||||||
"axum-core",
|
|
||||||
"base64",
|
|
||||||
"futures",
|
|
||||||
"http",
|
|
||||||
"parking_lot",
|
|
||||||
"rand",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"thiserror",
|
|
||||||
"time",
|
|
||||||
"tokio",
|
|
||||||
"tracing",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tower-sessions-memory-store"
|
|
||||||
version = "0.14.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fb05909f2e1420135a831dd5df9f5596d69196d0a64c3499ca474c4bd3d33242"
|
|
||||||
dependencies = [
|
|
||||||
"async-trait",
|
|
||||||
"time",
|
|
||||||
"tokio",
|
|
||||||
"tower-sessions-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing"
|
name = "tracing"
|
||||||
version = "0.1.41"
|
version = "0.1.41"
|
||||||
@@ -2325,6 +2405,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
|
checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
"valuable",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-log"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"once_cell",
|
||||||
|
"tracing-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-subscriber"
|
||||||
|
version = "0.3.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
|
||||||
|
dependencies = [
|
||||||
|
"matchers",
|
||||||
|
"nu-ansi-term",
|
||||||
|
"once_cell",
|
||||||
|
"regex",
|
||||||
|
"sharded-slab",
|
||||||
|
"smallvec",
|
||||||
|
"thread_local",
|
||||||
|
"tracing",
|
||||||
|
"tracing-core",
|
||||||
|
"tracing-log",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2377,6 +2487,16 @@ version = "0.1.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0"
|
checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "universal-hash"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
|
||||||
|
dependencies = [
|
||||||
|
"crypto-common",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unsafe-libyaml"
|
name = "unsafe-libyaml"
|
||||||
version = "0.2.11"
|
version = "0.2.11"
|
||||||
@@ -2418,6 +2538,12 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "valuable"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vcpkg"
|
name = "vcpkg"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
@@ -2543,15 +2669,17 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"axum",
|
"axum",
|
||||||
"axum-extra",
|
"axum-extra",
|
||||||
"axum-messages",
|
|
||||||
"chrono",
|
"chrono",
|
||||||
"maud",
|
"maud",
|
||||||
"rust-i18n",
|
"rust-i18n",
|
||||||
"serde",
|
"serde",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
|
"time",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"toml 0.9.5",
|
||||||
"tower-http",
|
"tower-http",
|
||||||
"tower-sessions",
|
"tracing",
|
||||||
|
"tracing-subscriber",
|
||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2565,6 +2693,22 @@ dependencies = [
|
|||||||
"wasite",
|
"wasite",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-i686-pc-windows-gnu",
|
||||||
|
"winapi-x86_64-pc-windows-gnu",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi-util"
|
name = "winapi-util"
|
||||||
version = "0.1.9"
|
version = "0.1.9"
|
||||||
@@ -2574,6 +2718,12 @@ dependencies = [
|
|||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-core"
|
name = "windows-core"
|
||||||
version = "0.61.2"
|
version = "0.61.2"
|
||||||
|
@@ -5,14 +5,16 @@ edition = "2024"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
axum = "0.8"
|
axum = "0.8"
|
||||||
axum-extra = { version = "0.10", features = ["cookie"] }
|
axum-extra = { version = "0.10", features = ["cookie-private", "cookie"] }
|
||||||
axum-messages = "0.8"
|
|
||||||
chrono = { version = "0.4", features = ["serde"] }
|
chrono = { version = "0.4", features = ["serde"] }
|
||||||
maud = { version = "0.27", features = ["axum"] }
|
maud = { version = "0.27", features = ["axum"] }
|
||||||
rust-i18n = "3.1"
|
rust-i18n = "3.1"
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
sqlx = { version = "0.8", features = ["runtime-tokio-rustls", "sqlite", "macros", "chrono"] }
|
sqlx = { version = "0.8", features = ["runtime-tokio-rustls", "sqlite", "macros", "chrono"] }
|
||||||
|
time = "0.3"
|
||||||
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
|
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
|
||||||
|
toml = "0.9"
|
||||||
tower-http = { version = "0.6", features = ["fs"] }
|
tower-http = { version = "0.6", features = ["fs"] }
|
||||||
tower-sessions = "0.14"
|
tracing = "0.1"
|
||||||
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||||
uuid = { version = "1.17", features = ["v4", "serde"] }
|
uuid = { version = "1.17", features = ["v4", "serde"] }
|
||||||
|
@@ -29,6 +29,7 @@ location_linz: "Wo: überall in Linz"
|
|||||||
game_title: "Wer findet die meisten Kameras?"
|
game_title: "Wer findet die meisten Kameras?"
|
||||||
game_explanation_todo: "Willkommen zu unserem Überwachungsbewusstseinsspiel! Als Teil unserer Digital Shadows Ausstellung beim Ars Electronica Festival haben wir QR-Codes bei Überwachungskameras in ganz Linz platziert. Deine Mission: Entdecke die Kameras, scanne unsere Codes und finde heraus, wie allgegenwärtig öffentliche Überwachung wirklich ist. Wir sind aber nur Menschen – wir haben nur einen kleinen Teil aller Kameras erfasst, die unsere Stadt beobachten. Wer beobachtet wen in unseren öffentlichen Räumen? Die Jagd beginnt jetzt! 🕵️"
|
game_explanation_todo: "Willkommen zu unserem Überwachungsbewusstseinsspiel! Als Teil unserer Digital Shadows Ausstellung beim Ars Electronica Festival haben wir QR-Codes bei Überwachungskameras in ganz Linz platziert. Deine Mission: Entdecke die Kameras, scanne unsere Codes und finde heraus, wie allgegenwärtig öffentliche Überwachung wirklich ist. Wir sind aber nur Menschen – wir haben nur einen kleinen Teil aller Kameras erfasst, die unsere Stadt beobachten. Wer beobachtet wen in unseren öffentlichen Räumen? Die Jagd beginnt jetzt! 🕵️"
|
||||||
save_button: "Speichern"
|
save_button: "Speichern"
|
||||||
|
amount_participants: "In total there are %{amount} participants so far."
|
||||||
cameras_found: "Du hast %{found}/%{total} Kameras gefunden:"
|
cameras_found: "Du hast %{found}/%{total} Kameras gefunden:"
|
||||||
highscore_title: "Bestenliste"
|
highscore_title: "Bestenliste"
|
||||||
not_found_title: "ups"
|
not_found_title: "ups"
|
||||||
|
@@ -29,6 +29,7 @@ location_linz: "Where: all over Linz"
|
|||||||
game_title: "Who finds the most cameras?"
|
game_title: "Who finds the most cameras?"
|
||||||
game_explanation_todo: "Welcome to our public surveillance awareness game! As part of our Digital Shadows exhibition at Ars Electronica Festival, we've placed QR codes near surveillance cameras throughout Linz. Your mission: spot the cameras, scan our codes, and discover how pervasive public monitoring really is. We're only human though – we've mapped just a small subset of all the cameras watching our city. Who's watching whom in our public spaces? The hunt begins now! 🕵️"
|
game_explanation_todo: "Welcome to our public surveillance awareness game! As part of our Digital Shadows exhibition at Ars Electronica Festival, we've placed QR codes near surveillance cameras throughout Linz. Your mission: spot the cameras, scan our codes, and discover how pervasive public monitoring really is. We're only human though – we've mapped just a small subset of all the cameras watching our city. Who's watching whom in our public spaces? The hunt begins now! 🕵️"
|
||||||
save_button: "Save"
|
save_button: "Save"
|
||||||
|
amount_participants: "Aktuell gibt es insgesamt %{amount} Teilnehmer."
|
||||||
cameras_found: "You have found %{found}/%{total} cameras:"
|
cameras_found: "You have found %{found}/%{total} cameras:"
|
||||||
highscore_title: "Highscore"
|
highscore_title: "Highscore"
|
||||||
not_found_title: "uups"
|
not_found_title: "uups"
|
||||||
|
142
src/game.rs
142
src/game.rs
@@ -1,13 +1,16 @@
|
|||||||
use crate::{language::language, page::Page, Backend, NameUpdateError};
|
use crate::{
|
||||||
|
language::language,
|
||||||
|
page::{MyMessage, Page},
|
||||||
|
AppState, Backend, NameUpdateError,
|
||||||
|
};
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::{Path, State},
|
extract::{Path, State},
|
||||||
http::HeaderMap,
|
http::HeaderMap,
|
||||||
response::{IntoResponse, Redirect, Response},
|
response::{IntoResponse, Response},
|
||||||
routing::{get, post},
|
routing::{get, post},
|
||||||
Form, Router,
|
Form, Router,
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use axum_extra::extract::{CookieJar, PrivateCookieJar};
|
||||||
use axum_messages::Messages;
|
|
||||||
use maud::{html, Markup, PreEscaped};
|
use maud::{html, Markup, PreEscaped};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@@ -15,23 +18,33 @@ use uuid::Uuid;
|
|||||||
|
|
||||||
async fn index(
|
async fn index(
|
||||||
State(backend): State<Arc<Backend>>,
|
State(backend): State<Arc<Backend>>,
|
||||||
cookies: CookieJar,
|
cookies: PrivateCookieJar,
|
||||||
messages: Messages,
|
lang_cookies: CookieJar,
|
||||||
headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
) -> Response {
|
) -> Response {
|
||||||
let lang = language(&cookies, &headers);
|
retu(backend, cookies, lang_cookies, headers, None).await
|
||||||
rust_i18n::set_locale(lang.to_locale());
|
}
|
||||||
|
|
||||||
let (cookies, req) = backend.client_full(cookies, &headers).await;
|
async fn retu(
|
||||||
|
backend: Arc<Backend>,
|
||||||
|
cookies: PrivateCookieJar,
|
||||||
|
lang_cookies: CookieJar,
|
||||||
|
headers: HeaderMap,
|
||||||
|
message: Option<MyMessage>,
|
||||||
|
) -> Response {
|
||||||
|
let (cookies, req) = backend.client_full(cookies, &lang_cookies, &headers).await;
|
||||||
let client = req.client;
|
let client = req.client;
|
||||||
|
rust_i18n::set_locale(&req.lang.to_string());
|
||||||
|
|
||||||
let sightings = backend.sightings_for_client(&client).await;
|
let sightings = backend.sightings_for_client(&client).await;
|
||||||
let amount_total_cameras = backend.amount_total_cameras().await;
|
let amount_total_cameras = backend.amount_total_cameras().await;
|
||||||
let highscore = backend.highscore().await;
|
let highscore = backend.highscore(&client).await;
|
||||||
|
let amount_participants = backend.amount_participants().await;
|
||||||
|
|
||||||
let lang = language(&cookies, &headers);
|
let mut page = Page::new(req.lang);
|
||||||
let mut page = Page::new(lang);
|
if let Some(message) = message {
|
||||||
page.messages(messages);
|
page.set_message(message);
|
||||||
|
}
|
||||||
let markup = page.content(html! {
|
let markup = page.content(html! {
|
||||||
hgroup {
|
hgroup {
|
||||||
h1 { (t!("game_title")) }
|
h1 { (t!("game_title")) }
|
||||||
@@ -42,7 +55,7 @@ async fn index(
|
|||||||
|
|
||||||
div.mb-sm { (t!("ask_to_change_name", name = client.get_display_name())) }
|
div.mb-sm { (t!("ask_to_change_name", name = client.get_display_name())) }
|
||||||
|
|
||||||
form action="/name" method="post" {
|
form action="/game" method="post" {
|
||||||
fieldset role="group" {
|
fieldset role="group" {
|
||||||
input
|
input
|
||||||
name="name"
|
name="name"
|
||||||
@@ -73,6 +86,13 @@ async fn index(
|
|||||||
h2 { (t!("highscore_title")) }
|
h2 { (t!("highscore_title")) }
|
||||||
ul.iterated {
|
ul.iterated {
|
||||||
@for rank in highscore {
|
@for rank in highscore {
|
||||||
|
@if rank.show_dots_above {
|
||||||
|
li.card {
|
||||||
|
span {
|
||||||
|
"⋮"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
li.card {
|
li.card {
|
||||||
span {
|
span {
|
||||||
span.font-headline.rank.text-muted { (rank.rank) "." }
|
span.font-headline.rank.text-muted { (rank.rank) "." }
|
||||||
@@ -88,6 +108,7 @@ async fn index(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
(t!("amount_participants", amount = amount_participants))
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -96,36 +117,34 @@ async fn index(
|
|||||||
|
|
||||||
async fn game(
|
async fn game(
|
||||||
State(backend): State<Arc<Backend>>,
|
State(backend): State<Arc<Backend>>,
|
||||||
cookies: CookieJar,
|
cookies: PrivateCookieJar,
|
||||||
|
lang_cookies: CookieJar,
|
||||||
headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
messages: Messages,
|
|
||||||
Path(uuid): Path<String>,
|
Path(uuid): Path<String>,
|
||||||
) -> Result<Redirect, Response> {
|
) -> Response {
|
||||||
let lang = language(&cookies, &headers);
|
let (cookies, req) = backend.client_full(cookies, &lang_cookies, &headers).await;
|
||||||
rust_i18n::set_locale(lang.to_locale());
|
let client = req.client;
|
||||||
|
rust_i18n::set_locale(req.lang.to_locale());
|
||||||
let (cookies, client) = backend.client(cookies).await;
|
|
||||||
|
|
||||||
let Ok(uuid) = Uuid::parse_str(&uuid) else {
|
let Ok(uuid) = Uuid::parse_str(&uuid) else {
|
||||||
return Err(not_found(cookies, headers).await.into_response());
|
return not_found(lang_cookies, headers).await.into_response();
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(camera) = backend.get_camera(&uuid).await else {
|
let Some(camera) = backend.get_camera(&uuid).await else {
|
||||||
return Err(not_found(cookies, headers).await.into_response());
|
return not_found(lang_cookies, headers).await.into_response();
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Ok(number) = backend.client_found_camera(&client, &camera).await {
|
let message = if let Ok(number) = backend.client_found_camera(&client, &camera).await {
|
||||||
messages.info(format!("found-cam|{}|{number}", camera.name));
|
MyMessage::FoundCam(camera.name, number)
|
||||||
} else {
|
} else {
|
||||||
messages.info(format!(
|
MyMessage::Error(
|
||||||
"err|{}|{}|{}",
|
t!("error_already_found_title").into(),
|
||||||
t!("error_already_found_title"),
|
t!("error_already_found_body").into(),
|
||||||
t!("error_already_found_body"),
|
t!("error_already_found_footer").into(),
|
||||||
t!("error_already_found_footer")
|
)
|
||||||
));
|
};
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Redirect::to("/game"))
|
retu(backend, cookies, lang_cookies, headers, Some(message)).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn not_found(cookies: CookieJar, headers: HeaderMap) -> Markup {
|
async fn not_found(cookies: CookieJar, headers: HeaderMap) -> Markup {
|
||||||
@@ -142,47 +161,40 @@ struct NameForm {
|
|||||||
|
|
||||||
async fn set_name(
|
async fn set_name(
|
||||||
State(backend): State<Arc<Backend>>,
|
State(backend): State<Arc<Backend>>,
|
||||||
cookies: CookieJar,
|
cookies: PrivateCookieJar,
|
||||||
messages: Messages,
|
lang_cookies: CookieJar,
|
||||||
headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
Form(form): Form<NameForm>,
|
Form(form): Form<NameForm>,
|
||||||
) -> Response {
|
) -> Response {
|
||||||
let lang = language(&cookies, &headers);
|
let (cookies, req) = backend.client_full(cookies, &lang_cookies, &headers).await;
|
||||||
rust_i18n::set_locale(lang.to_locale());
|
let client = req.client;
|
||||||
|
rust_i18n::set_locale(req.lang.to_locale());
|
||||||
|
|
||||||
let (cookies, client) = backend.client(cookies).await;
|
let message = match backend.set_client_name(&client, &form.name).await {
|
||||||
|
Ok(()) => MyMessage::NameChanged,
|
||||||
match backend.set_client_name(&client, &form.name).await {
|
Err(NameUpdateError::TooShort(expected, actual)) => MyMessage::Error(
|
||||||
Ok(()) => messages.info("set-name-succ"),
|
t!("error_name_too_short_title").into(),
|
||||||
Err(NameUpdateError::TooShort(expected, actual)) => messages.info(format!(
|
t!("error_name_too_short_body", expected = expected).into(),
|
||||||
"err|{}|{}|{}: {}",
|
format!("{}: {actual}", t!("received_characters")),
|
||||||
t!("error_name_too_short_title"),
|
),
|
||||||
t!("error_name_too_short_body", expected = expected),
|
Err(NameUpdateError::TooLong(expected, actual)) => MyMessage::Error(
|
||||||
t!("received_characters"),
|
t!("error_name_too_long_title").into(),
|
||||||
actual
|
t!("error_name_too_long_body", expected = expected).into(),
|
||||||
)),
|
format!("{}: {actual}", t!("received_characters")),
|
||||||
Err(NameUpdateError::TooLong(expected, actual)) => messages.info(format!(
|
),
|
||||||
"err|{}|{}|{}: {}",
|
Err(NameUpdateError::ContainsBadWord) => MyMessage::Error(
|
||||||
t!("error_name_too_long_title"),
|
t!("error_bad_word_title").into(),
|
||||||
t!("error_name_too_long_body", expected = expected),
|
t!("error_bad_word_body").into(),
|
||||||
t!("received_characters"),
|
t!("error_bad_word_footer").into(),
|
||||||
actual
|
),
|
||||||
)),
|
|
||||||
Err(NameUpdateError::ContainsBadWord) => messages.info(format!(
|
|
||||||
"err|{}|{}|{}",
|
|
||||||
t!("error_bad_word_title"),
|
|
||||||
t!("error_bad_word_body"),
|
|
||||||
t!("error_bad_word_footer")
|
|
||||||
)),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Redirect back to the game page
|
retu(backend, cookies, lang_cookies, headers, Some(message)).await
|
||||||
(cookies, Redirect::to("/game")).into_response()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn routes() -> Router<Arc<Backend>> {
|
pub(super) fn routes() -> Router<AppState> {
|
||||||
Router::new()
|
Router::new()
|
||||||
.route("/game", get(index))
|
.route("/game", get(index))
|
||||||
.route("/name", post(set_name))
|
.route("/game", post(set_name))
|
||||||
.route("/{*uuid}", get(game))
|
.route("/{*uuid}", get(game))
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
use crate::{language::language, page::Page};
|
use crate::{language::language, page::Page};
|
||||||
use axum::http::HeaderMap;
|
use axum::http::HeaderMap;
|
||||||
use axum_extra::extract::CookieJar;
|
use axum_extra::extract::CookieJar;
|
||||||
use maud::{html, Markup, PreEscaped};
|
use maud::{Markup, PreEscaped, html};
|
||||||
|
|
||||||
pub(super) async fn index(cookies: CookieJar, headers: HeaderMap) -> Markup {
|
pub(super) async fn index(cookies: CookieJar, headers: HeaderMap) -> Markup {
|
||||||
let lang = language(&cookies, &headers);
|
let lang = language(&cookies, &headers);
|
||||||
|
101
src/main.rs
101
src/main.rs
@@ -1,16 +1,22 @@
|
|||||||
use crate::model::client::Client;
|
use crate::model::client::Client;
|
||||||
use axum::{http::HeaderMap, routing::get, Router};
|
use axum::{Router, http::HeaderMap, routing::get};
|
||||||
use axum_extra::extract::{cookie::Cookie, CookieJar};
|
use axum_extra::extract::{
|
||||||
use axum_messages::MessagesManagerLayer;
|
CookieJar, PrivateCookieJar,
|
||||||
use sqlx::{pool::PoolOptions, sqlite::SqliteConnectOptions, SqlitePool};
|
cookie::{Cookie, Expiration, Key},
|
||||||
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use sqlx::{SqlitePool, pool::PoolOptions, sqlite::SqliteConnectOptions};
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashSet,
|
collections::HashSet,
|
||||||
fmt::Display,
|
fmt::Display,
|
||||||
|
fs,
|
||||||
|
path::Path,
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
sync::{Arc, LazyLock},
|
sync::{Arc, LazyLock},
|
||||||
};
|
};
|
||||||
|
use time::{Duration, OffsetDateTime};
|
||||||
use tower_http::services::ServeDir;
|
use tower_http::services::ServeDir;
|
||||||
use tower_sessions::{MemoryStore, SessionManagerLayer};
|
use tracing_subscriber::{EnvFilter, layer::SubscriberExt, util::SubscriberInitExt};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
@@ -70,6 +76,7 @@ impl From<String> for Language {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
struct Req {
|
struct Req {
|
||||||
client: Client,
|
client: Client,
|
||||||
lang: Language,
|
lang: Language,
|
||||||
@@ -140,7 +147,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Backend {
|
impl Backend {
|
||||||
async fn client(&self, cookies: CookieJar) -> (CookieJar, Client) {
|
async fn client(&self, cookies: PrivateCookieJar) -> (PrivateCookieJar, Client) {
|
||||||
let existing_uuid = cookies
|
let existing_uuid = cookies
|
||||||
.get("client_id")
|
.get("client_id")
|
||||||
.and_then(|cookie| Uuid::parse_str(cookie.value()).ok());
|
.and_then(|cookie| Uuid::parse_str(cookie.value()).ok());
|
||||||
@@ -149,16 +156,27 @@ impl Backend {
|
|||||||
Some(uuid) => (cookies, self.get_client(&uuid).await),
|
Some(uuid) => (cookies, self.get_client(&uuid).await),
|
||||||
None => {
|
None => {
|
||||||
let new_id = Uuid::new_v4();
|
let new_id = Uuid::new_v4();
|
||||||
let updated_cookies = cookies.add(Cookie::new("client_id", new_id.to_string()));
|
let expiration_date = OffsetDateTime::now_utc() + Duration::days(30);
|
||||||
|
let mut cookie = Cookie::new("client_id", new_id.to_string());
|
||||||
|
cookie.set_expires(Expiration::DateTime(expiration_date));
|
||||||
|
cookie.set_http_only(true);
|
||||||
|
cookie.set_secure(true);
|
||||||
|
|
||||||
|
let updated_cookies = cookies.add(cookie);
|
||||||
(updated_cookies, self.get_client(&new_id).await)
|
(updated_cookies, self.get_client(&new_id).await)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Combined method for getting both client and language
|
// Combined method for getting both client and language
|
||||||
async fn client_full(&self, cookies: CookieJar, headers: &HeaderMap) -> (CookieJar, Req) {
|
async fn client_full(
|
||||||
|
&self,
|
||||||
|
cookies: PrivateCookieJar,
|
||||||
|
lang_cookies: &CookieJar,
|
||||||
|
headers: &HeaderMap,
|
||||||
|
) -> (PrivateCookieJar, Req) {
|
||||||
let (cookies, client) = self.client(cookies).await;
|
let (cookies, client) = self.client(cookies).await;
|
||||||
let lang = language::language(&cookies, headers);
|
let lang = language::language(&lang_cookies, headers);
|
||||||
(cookies, Req { client, lang })
|
(cookies, Req { client, lang })
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,10 +208,61 @@ impl Backend {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct AppState {
|
||||||
|
pub(crate) backend: Arc<Backend>,
|
||||||
|
pub key: Key,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl axum::extract::FromRef<AppState> for Key {
|
||||||
|
fn from_ref(state: &AppState) -> Self {
|
||||||
|
state.key.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl axum::extract::FromRef<AppState> for Arc<Backend> {
|
||||||
|
fn from_ref(state: &AppState) -> Self {
|
||||||
|
state.backend.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct Config {
|
||||||
|
key: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Config {
|
||||||
|
fn generate() -> Self {
|
||||||
|
Self {
|
||||||
|
key: Key::generate().master().to_vec(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_or_create_key() -> Result<Key, Box<dyn std::error::Error>> {
|
||||||
|
let config_path = "config.toml";
|
||||||
|
|
||||||
|
// Try to read existing config
|
||||||
|
if Path::new(config_path).exists() {
|
||||||
|
let content = fs::read_to_string(config_path)?;
|
||||||
|
let config: Config = toml::from_str(&content)?;
|
||||||
|
return Ok(Key::from(&config.key));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new config if file doesn't exist
|
||||||
|
let config = Config::generate();
|
||||||
|
let toml_string = toml::to_string(&config)?;
|
||||||
|
fs::write(config_path, toml_string)?;
|
||||||
|
|
||||||
|
Ok(Key::from(&config.key))
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
let session_store = MemoryStore::default();
|
tracing_subscriber::registry()
|
||||||
let session_layer = SessionManagerLayer::new(session_store).with_secure(false);
|
.with(tracing_subscriber::fmt::layer())
|
||||||
|
.with(EnvFilter::from_default_env())
|
||||||
|
.init();
|
||||||
|
|
||||||
let connection_options = SqliteConnectOptions::from_str("sqlite://db.sqlite").unwrap();
|
let connection_options = SqliteConnectOptions::from_str("sqlite://db.sqlite").unwrap();
|
||||||
let db: SqlitePool = PoolOptions::new()
|
let db: SqlitePool = PoolOptions::new()
|
||||||
@@ -201,13 +270,17 @@ async fn main() {
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let key = load_or_create_key().unwrap();
|
||||||
|
let state = AppState {
|
||||||
|
backend: Arc::new(Backend::Sqlite(db)),
|
||||||
|
key,
|
||||||
|
};
|
||||||
|
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.route("/", get(index::index))
|
.route("/", get(index::index))
|
||||||
.nest_service("/static", ServeDir::new("./static/serve"))
|
.nest_service("/static", ServeDir::new("./static/serve"))
|
||||||
.merge(game::routes())
|
.merge(game::routes())
|
||||||
.with_state(Arc::new(Backend::Sqlite(db)))
|
.with_state(state);
|
||||||
.layer(MessagesManagerLayer)
|
|
||||||
.layer(session_layer);
|
|
||||||
|
|
||||||
// run our app with hyper, listening globally on port 3000
|
// run our app with hyper, listening globally on port 3000
|
||||||
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
|
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
|
||||||
|
@@ -1,40 +1,102 @@
|
|||||||
use crate::{Backend, model::client::Client};
|
use crate::{model::client::Client, Backend};
|
||||||
|
|
||||||
pub(crate) struct Rank {
|
pub(crate) struct Rank {
|
||||||
pub(crate) rank: i64,
|
pub(crate) rank: i64,
|
||||||
pub(crate) client: Client,
|
pub(crate) client: Client,
|
||||||
pub(crate) amount: i64,
|
pub(crate) amount: i64,
|
||||||
|
pub(crate) show_dots_above: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Backend {
|
impl Backend {
|
||||||
pub(crate) async fn highscore(&self) -> Vec<Rank> {
|
pub(crate) async fn amount_participants(&self) -> i64 {
|
||||||
|
match self {
|
||||||
|
Backend::Sqlite(db) => {
|
||||||
|
let row = sqlx::query!("SELECT COUNT(*) as count FROM client")
|
||||||
|
.fetch_one(db)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
row.count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn highscore(&self, client: &Client) -> Vec<Rank> {
|
||||||
match self {
|
match self {
|
||||||
Backend::Sqlite(db) => {
|
Backend::Sqlite(db) => {
|
||||||
let rows = sqlx::query!(
|
let rows = sqlx::query!(
|
||||||
"SELECT
|
"WITH ranked_clients AS (
|
||||||
RANK() OVER (ORDER BY COUNT(s.client_uuid) DESC) as rank,
|
SELECT
|
||||||
|
DENSE_RANK() OVER (ORDER BY COUNT(s.client_uuid) DESC) as rank,
|
||||||
c.name,
|
c.name,
|
||||||
c.uuid,
|
c.uuid,
|
||||||
COUNT(s.client_uuid) as amount
|
COUNT(s.client_uuid) as amount
|
||||||
FROM client c
|
FROM client c
|
||||||
LEFT JOIN sightings s ON c.uuid = s.client_uuid
|
LEFT JOIN sightings s ON c.uuid = s.client_uuid
|
||||||
GROUP BY c.uuid, c.name
|
GROUP BY c.uuid, c.name
|
||||||
ORDER BY amount DESC"
|
)
|
||||||
|
SELECT rank, name, uuid, amount
|
||||||
|
FROM ranked_clients
|
||||||
|
WHERE rank <= (
|
||||||
|
SELECT rank
|
||||||
|
FROM ranked_clients
|
||||||
|
ORDER BY rank
|
||||||
|
LIMIT 1 OFFSET 9
|
||||||
|
)
|
||||||
|
ORDER BY rank, name"
|
||||||
)
|
)
|
||||||
.fetch_all(db)
|
.fetch_all(db)
|
||||||
.await
|
.await
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
rows.into_iter()
|
let mut ret: Vec<Rank> = rows
|
||||||
|
.into_iter()
|
||||||
.map(|row| Rank {
|
.map(|row| Rank {
|
||||||
|
rank: row.rank.unwrap(),
|
||||||
|
client: Client {
|
||||||
|
uuid: row.uuid.unwrap(),
|
||||||
|
name: row.name,
|
||||||
|
},
|
||||||
|
amount: row.amount.unwrap(),
|
||||||
|
show_dots_above: false,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let user_is_in_top = ret.iter().find(|x| &x.client == client).is_some();
|
||||||
|
if !user_is_in_top {
|
||||||
|
let row = sqlx::query!(
|
||||||
|
"WITH ranked_clients AS (
|
||||||
|
SELECT
|
||||||
|
DENSE_RANK() OVER (ORDER BY COUNT(s.client_uuid) DESC) as rank,
|
||||||
|
c.name,
|
||||||
|
c.uuid,
|
||||||
|
COUNT(s.client_uuid) as amount
|
||||||
|
FROM client c
|
||||||
|
LEFT JOIN sightings s ON c.uuid = s.client_uuid
|
||||||
|
GROUP BY c.uuid, c.name
|
||||||
|
)
|
||||||
|
SELECT rank, name, uuid, amount
|
||||||
|
FROM ranked_clients
|
||||||
|
WHERE uuid = ?
|
||||||
|
ORDER BY rank, name",
|
||||||
|
client.uuid
|
||||||
|
)
|
||||||
|
.fetch_one(db)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
ret.push(Rank {
|
||||||
rank: row.rank,
|
rank: row.rank,
|
||||||
client: Client {
|
client: Client {
|
||||||
uuid: row.uuid,
|
uuid: row.uuid,
|
||||||
name: row.name,
|
name: row.name,
|
||||||
},
|
},
|
||||||
amount: row.amount,
|
amount: row.amount,
|
||||||
|
show_dots_above: true,
|
||||||
})
|
})
|
||||||
.collect()
|
}
|
||||||
|
|
||||||
|
ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
69
src/page.rs
69
src/page.rs
@@ -1,52 +1,27 @@
|
|||||||
use crate::Language;
|
use crate::Language;
|
||||||
use axum_messages::Messages;
|
|
||||||
use maud::{DOCTYPE, Markup, html};
|
use maud::{DOCTYPE, Markup, html};
|
||||||
|
|
||||||
pub(crate) struct Page {
|
pub(crate) struct Page {
|
||||||
lang: Language,
|
lang: Language,
|
||||||
found_camera: Option<(String, i64)>,
|
message: Option<MyMessage>,
|
||||||
new_name: bool,
|
}
|
||||||
err: Option<(String, String, String)>,
|
|
||||||
|
pub(crate) enum MyMessage {
|
||||||
|
NameChanged,
|
||||||
|
FoundCam(String, i64),
|
||||||
|
Error(String, String, String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Page {
|
impl Page {
|
||||||
pub fn new(lang: Language) -> Self {
|
pub fn new(lang: Language) -> Self {
|
||||||
Self {
|
Self {
|
||||||
lang,
|
lang,
|
||||||
found_camera: None,
|
message: None,
|
||||||
new_name: false,
|
|
||||||
err: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn messages(&mut self, messages: Messages) {
|
pub(crate) fn set_message(&mut self, message: MyMessage) {
|
||||||
for message in messages {
|
self.message = Some(message);
|
||||||
let text = &message.to_string()[..];
|
|
||||||
match (message.level, text) {
|
|
||||||
(_, "set-name-succ") => {
|
|
||||||
self.new_name = true;
|
|
||||||
}
|
|
||||||
(_, msg) if msg.starts_with("found-cam|") => {
|
|
||||||
let mut parts = msg.splitn(3, '|');
|
|
||||||
let _ = parts.next().expect("just checked |");
|
|
||||||
if let (Some(name), Some(amount)) = (parts.next(), parts.next()) {
|
|
||||||
if let Ok(amount) = amount.parse::<i64>() {
|
|
||||||
self.found_camera = Some((name.into(), amount));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(_, msg) if msg.starts_with("err|") => {
|
|
||||||
let mut parts = msg.splitn(4, '|');
|
|
||||||
let _ = parts.next().expect("just checked |");
|
|
||||||
if let (Some(title), Some(body), Some(footer)) =
|
|
||||||
(parts.next(), parts.next(), parts.next())
|
|
||||||
{
|
|
||||||
self.err = Some((title.into(), body.into(), footer.into()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(_, _) => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn content(self, content: Markup) -> Markup {
|
pub fn content(self, content: Markup) -> Markup {
|
||||||
@@ -92,35 +67,39 @@ impl Page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
main.container {
|
main.container {
|
||||||
@if let Some(found_camera) = &self.found_camera {
|
@if let Some(message) = &self.message {
|
||||||
|
@match message {
|
||||||
|
MyMessage::FoundCam(name, amount) => {
|
||||||
div.flex {
|
div.flex {
|
||||||
article class="succ msg" {
|
article class="succ msg" {
|
||||||
header { (t!("found_camera_title", name = found_camera.0)) }
|
header { (t!("found_camera_title", name = name)) }
|
||||||
(t!("found_camera_body", amount = found_camera.1))
|
(t!("found_camera_body", amount = amount))
|
||||||
footer {
|
footer {
|
||||||
a href="#ranking" { (t!("see_ranking")) }
|
a href="#ranking" { (t!("see_ranking")) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
@if self.new_name {
|
MyMessage::NameChanged => {
|
||||||
div.flex {
|
div.flex {
|
||||||
article class="name msg" {
|
article class="name msg" {
|
||||||
header { (t!("new_name_title")) }
|
header { (t!("new_name_title")) }
|
||||||
(t!("new_name_message"))
|
(t!("new_name_message"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
@if let Some(err) = &self.err {
|
MyMessage::Error(header, body, footer) => {
|
||||||
div.flex {
|
div.flex {
|
||||||
article class="error msg" {
|
article class="error msg" {
|
||||||
header { (err.0) }
|
header { (header) }
|
||||||
(err.1)
|
(body)
|
||||||
footer { (err.2) }
|
footer { (footer) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
section { (content) }
|
section { (content) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -13,7 +13,7 @@ function setLanguageCookie() {
|
|||||||
// set lang, if lang attribute doesn't exit set default en
|
// set lang, if lang attribute doesn't exit set default en
|
||||||
let lang = langToggle.getAttribute('lang') ? langToggle.getAttribute('lang') : 'en';
|
let lang = langToggle.getAttribute('lang') ? langToggle.getAttribute('lang') : 'en';
|
||||||
document.cookie = "language=" + lang;
|
document.cookie = "language=" + lang;
|
||||||
window.location.reload();
|
window.location.assign(window.location.href);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user