initial create user

This commit is contained in:
Dietrich 2021-05-14 18:28:33 +02:00 committed by Franz Dietrich
parent b9866a8c19
commit 6837495eba
16 changed files with 650 additions and 288 deletions

250
Cargo.lock generated
View File

@ -107,7 +107,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"serde_urlencoded", "serde_urlencoded",
"sha-1 0.9.4", "sha-1 0.9.6",
"slab", "slab",
"time 0.2.26", "time 0.2.26",
] ]
@ -202,7 +202,7 @@ checksum = "c697a62a2f51c5c26af6b1dded0622f15bec690da191615947e0c1b2b7b75198"
dependencies = [ dependencies = [
"actix-web", "actix-web",
"chrono", "chrono",
"futures 0.3.14", "futures 0.3.15",
"pin-project 0.4.28", "pin-project 0.4.28",
"slog", "slog",
] ]
@ -327,16 +327,16 @@ dependencies = [
"actix-service", "actix-service",
"actix-web", "actix-web",
"derive_more", "derive_more",
"futures 0.3.14", "futures 0.3.15",
"mime_guess", "mime_guess",
"path-slash", "path-slash",
] ]
[[package]] [[package]]
name = "addr2line" name = "addr2line"
version = "0.14.1" version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7" checksum = "03345e98af8f3d786b6d9f656ccfa6ac316d954e92bc4841f0bba20789d5fb5a"
dependencies = [ dependencies = [
"gimli", "gimli",
] ]
@ -426,9 +426,9 @@ dependencies = [
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
version = "0.7.15" version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
@ -575,11 +575,12 @@ dependencies = [
[[package]] [[package]]
name = "backtrace" name = "backtrace"
version = "0.3.57" version = "0.3.59"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ed203b9ba68b242c62b3fb7480f589dd49829be1edb3fe8fc8b4ffda2dcb8d" checksum = "4717cfcbfaa661a0fd48f8453951837ae7e8f81e481fbb136e3202d72805a744"
dependencies = [ dependencies = [
"addr2line", "addr2line",
"cc",
"cfg-if 1.0.0", "cfg-if 1.0.0",
"libc", "libc",
"miniz_oxide 0.4.4", "miniz_oxide 0.4.4",
@ -706,9 +707,9 @@ dependencies = [
[[package]] [[package]]
name = "bstr" name = "bstr"
version = "0.2.15" 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 = "a40b47ad93e1a5404e6c18dec46b628214fee441c70f4ab5d6942142cc268a3d" checksum = "90682c8d613ad3373e66de8c6411e0ae2ab2571e879d2efbf73558cc66f21279"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
@ -983,10 +984,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b"
[[package]] [[package]]
name = "cpuid-bool" name = "cpufeatures"
version = "0.1.2" 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 = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" checksum = "281f563b2c3a0e535ab12d81d3c5859045795256ad269afa7c19542585b68f93"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "cpuid-bool" name = "cpuid-bool"
@ -1035,9 +1039,9 @@ dependencies = [
[[package]] [[package]]
name = "crossbeam-epoch" name = "crossbeam-epoch"
version = "0.9.3" 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 = "2584f639eb95fea8c798496315b297cf81b9b58b6d30ab066a75455333cf4b12" checksum = "52fb27eab85b17fbb9f6fd667089e07d6a2eb8743d02639ee7f6a7a7729c9c94"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"crossbeam-utils", "crossbeam-utils",
@ -1058,9 +1062,9 @@ dependencies = [
[[package]] [[package]]
name = "crossbeam-utils" name = "crossbeam-utils"
version = "0.8.3" version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" checksum = "4feb231f0d4d6af81aed15928e58ecf5816aa62a2393e2c82f46973e92a9a278"
dependencies = [ dependencies = [
"autocfg 1.0.1", "autocfg 1.0.1",
"cfg-if 1.0.0", "cfg-if 1.0.0",
@ -1197,9 +1201,9 @@ dependencies = [
[[package]] [[package]]
name = "enum-map" name = "enum-map"
version = "1.0.0" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88acdb627a242ba1bf36653fa200f72c037ca3324e0710d1ac4fee809a1539cd" checksum = "34c3f3c98ee954dbafd343b3e0d827bb167cdda151b3c88ae04b0e5fa7db1028"
dependencies = [ dependencies = [
"enum-map-derive", "enum-map-derive",
"serde", "serde",
@ -1315,7 +1319,7 @@ dependencies = [
"fluent-syntax 0.11.0", "fluent-syntax 0.11.0",
"intl-memoizer", "intl-memoizer",
"intl_pluralrules", "intl_pluralrules",
"ouroboros 0.9.1", "ouroboros 0.9.2",
"rustc-hash", "rustc-hash",
"smallvec", "smallvec",
"unic-langid", "unic-langid",
@ -1464,9 +1468,9 @@ checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678"
[[package]] [[package]]
name = "futures" name = "futures"
version = "0.3.14" version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9d5813545e459ad3ca1bff9915e9ad7f1a47dc6a91b627ce321d5863b7dd253" checksum = "0e7e43a803dae2fa37c1f6a8fe121e1f7bf9548b4dfc0522a42f34145dadfc27"
dependencies = [ dependencies = [
"futures-channel", "futures-channel",
"futures-core", "futures-core",
@ -1479,9 +1483,9 @@ dependencies = [
[[package]] [[package]]
name = "futures-channel" name = "futures-channel"
version = "0.3.14" version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce79c6a52a299137a6013061e0cf0e688fce5d7f1bc60125f520912fdb29ec25" checksum = "e682a68b29a882df0545c143dc3646daefe80ba479bcdede94d5a703de2871e2"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-sink", "futures-sink",
@ -1489,9 +1493,9 @@ dependencies = [
[[package]] [[package]]
name = "futures-core" name = "futures-core"
version = "0.3.14" version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "098cd1c6dda6ca01650f1a37a794245eb73181d0d4d4e955e2f3c37db7af1815" checksum = "0402f765d8a89a26043b889b26ce3c4679d268fa6bb22cd7c6aad98340e179d1"
[[package]] [[package]]
name = "futures-cpupool" name = "futures-cpupool"
@ -1505,9 +1509,9 @@ dependencies = [
[[package]] [[package]]
name = "futures-executor" name = "futures-executor"
version = "0.3.14" version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10f6cb7042eda00f0049b1d2080aa4b93442997ee507eb3828e8bd7577f94c9d" checksum = "badaa6a909fac9e7236d0620a2f57f7664640c56575b71a7552fbd68deafab79"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-task", "futures-task",
@ -1516,16 +1520,17 @@ dependencies = [
[[package]] [[package]]
name = "futures-io" name = "futures-io"
version = "0.3.14" version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "365a1a1fb30ea1c03a830fdb2158f5236833ac81fa0ad12fe35b29cddc35cb04" checksum = "acc499defb3b348f8d8f3f66415835a9131856ff7714bf10dadfc4ec4bdb29a1"
[[package]] [[package]]
name = "futures-macro" name = "futures-macro"
version = "0.3.14" version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "668c6733a182cd7deb4f1de7ba3bf2120823835b3bcfbeacf7d2c4a773c1bb8b" checksum = "a4c40298486cdf52cc00cd6d6987892ba502c7656a16a4192a9992b1ccedd121"
dependencies = [ dependencies = [
"autocfg 1.0.1",
"proc-macro-hack", "proc-macro-hack",
"proc-macro2 1.0.26", "proc-macro2 1.0.26",
"quote 1.0.9", "quote 1.0.9",
@ -1534,22 +1539,23 @@ dependencies = [
[[package]] [[package]]
name = "futures-sink" name = "futures-sink"
version = "0.3.14" version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c5629433c555de3d82861a7a4e3794a4c40040390907cfbfd7143a92a426c23" checksum = "a57bead0ceff0d6dde8f465ecd96c9338121bb7717d3e7b108059531870c4282"
[[package]] [[package]]
name = "futures-task" name = "futures-task"
version = "0.3.14" version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba7aa51095076f3ba6d9a1f702f74bd05ec65f555d70d2033d55ba8d69f581bc" checksum = "8a16bef9fc1a4dddb5bee51c989e3fbba26569cbb0e31f5b303c184e3dd33dae"
[[package]] [[package]]
name = "futures-util" name = "futures-util"
version = "0.3.14" version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c144ad54d60f23927f0a6b6d816e4271278b64f005ad65e4e35291d2de9c025" checksum = "feb5c238d27e2bf94ffdfd27b2c29e3df4a68c4193bb6427384259e2bf191967"
dependencies = [ dependencies = [
"autocfg 1.0.1",
"futures-channel", "futures-channel",
"futures-core", "futures-core",
"futures-io", "futures-io",
@ -1659,9 +1665,9 @@ dependencies = [
[[package]] [[package]]
name = "gimli" name = "gimli"
version = "0.23.0" version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189"
[[package]] [[package]]
name = "glob" name = "glob"
@ -1855,9 +1861,9 @@ dependencies = [
[[package]] [[package]]
name = "httparse" name = "httparse"
version = "1.4.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 = "4a1ce40d6fc9764887c2fdc7305c3dcc429ba11ff981c1509416afd5697e4437" checksum = "f3a87b616e37e93c22fb19bcd386f02f3af5ea98a25670ad0fce773de23c5e68"
[[package]] [[package]]
name = "httpdate" name = "httpdate"
@ -2063,9 +2069,9 @@ dependencies = [
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.50" version = "0.3.51"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d99f9e3e84b8f67f846ef5b4cbbc3b1c29f6c759fcbce6f01aa0e73d932a24c" checksum = "83bdfbace3a0e81a4253f73b49e960b053e396a11012cbd49b9b74d6a2b67062"
dependencies = [ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
@ -2107,9 +2113,9 @@ dependencies = [
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.93" version = "0.2.94"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41" checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"
[[package]] [[package]]
name = "libloading" name = "libloading"
@ -2140,9 +2146,9 @@ checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
[[package]] [[package]]
name = "lock_api" name = "lock_api"
version = "0.4.3" version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a3c91c24eae6777794bb1997ad98bbb87daf92890acab859f7eaa4320333176" checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb"
dependencies = [ dependencies = [
"scopeguard 1.1.0", "scopeguard 1.1.0",
] ]
@ -2194,9 +2200,9 @@ checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.3.4" 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 = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
[[package]] [[package]]
name = "memoffset" name = "memoffset"
@ -2398,9 +2404,9 @@ dependencies = [
[[package]] [[package]]
name = "object" name = "object"
version = "0.23.0" version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4" checksum = "1a5b3dd1c072ee7963717671d1ca129f1048fda25edea6b752bfc71ac8854170"
[[package]] [[package]]
name = "once_cell" name = "once_cell"
@ -2422,9 +2428,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]] [[package]]
name = "openssl" name = "openssl"
version = "0.10.33" version = "0.10.34"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a61075b62a23fef5a29815de7536d940aa35ce96d18ce0cc5076272db678a577" checksum = "6d7830286ad6a3973c0f1d9b73738f69c76b739301d0229c4b96501695cbe4c8"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"cfg-if 1.0.0", "cfg-if 1.0.0",
@ -2436,15 +2442,15 @@ dependencies = [
[[package]] [[package]]
name = "openssl-probe" name = "openssl-probe"
version = "0.1.2" version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a"
[[package]] [[package]]
name = "openssl-sys" name = "openssl-sys"
version = "0.9.61" version = "0.9.63"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "313752393519e876837e09e1fa183ddef0be7735868dced3196f4472d536277f" checksum = "b6b0d6fb7d80f877617dfcb014e605e2b5ab2fb0afdf27935219bb6bd984cb98"
dependencies = [ dependencies = [
"autocfg 1.0.1", "autocfg 1.0.1",
"cc", "cc",
@ -2460,7 +2466,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b91cea1dfd50064e52db033179952d18c770cbc5dfefc8eba45d619357ba3914" checksum = "b91cea1dfd50064e52db033179952d18c770cbc5dfefc8eba45d619357ba3914"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"futures 0.3.14", "futures 0.3.15",
"js-sys", "js-sys",
"lazy_static", "lazy_static",
"percent-encoding", "percent-encoding",
@ -2503,11 +2509,11 @@ dependencies = [
[[package]] [[package]]
name = "ouroboros" name = "ouroboros"
version = "0.9.1" version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc53e78022445d2d37b673c5aaeed945a7aacaa4aa89c867c1f28b2e6778e67d" checksum = "c8234affc3c31a8b744cc236fd3dc7443f57c6370cbb7d61f41f9c7dcc6c2530"
dependencies = [ dependencies = [
"ouroboros_macro 0.9.1", "ouroboros_macro 0.9.2",
"stable_deref_trait", "stable_deref_trait",
] ]
@ -2526,9 +2532,9 @@ dependencies = [
[[package]] [[package]]
name = "ouroboros_macro" name = "ouroboros_macro"
version = "0.9.1" version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee93af29e97048340c10f5c1a1d88c754f48337a41fbd4fb8e1e20ce41c76936" checksum = "3633332cd8c0b6a865e2e0e705fad9cde25fe458cd0c693629b58a7b15e4d852"
dependencies = [ dependencies = [
"Inflector", "Inflector",
"proc-macro-error", "proc-macro-error",
@ -2714,7 +2720,7 @@ version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eebcc4aa140b9abd2bc40d9c3f7ccec842679cd79045ac3a7ac698c1a064b7cd" checksum = "eebcc4aa140b9abd2bc40d9c3f7ccec842679cd79045ac3a7ac698c1a064b7cd"
dependencies = [ dependencies = [
"cpuid-bool 0.2.0", "cpuid-bool",
"opaque-debug 0.3.0", "opaque-debug 0.3.0",
"universal-hash", "universal-hash",
] ]
@ -2776,7 +2782,7 @@ version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
dependencies = [ dependencies = [
"unicode-xid 0.2.1", "unicode-xid 0.2.2",
] ]
[[package]] [[package]]
@ -3129,18 +3135,18 @@ dependencies = [
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.2.6" version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8270314b5ccceb518e7e578952f0b72b88222d02e8f77f5ecf7abbb673539041" checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc"
dependencies = [ dependencies = [
"bitflags", "bitflags",
] ]
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.4.6" version = "1.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a26af418b574bd56588335b3a3659a65725d4e636eb1016c2f9e3b38c7cc759" checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@ -3159,9 +3165,9 @@ dependencies = [
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.6.23" version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]] [[package]]
name = "remove_dir_all" name = "remove_dir_all"
@ -3247,9 +3253,9 @@ dependencies = [
[[package]] [[package]]
name = "rustc-demangle" name = "rustc-demangle"
version = "0.1.18" version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232" checksum = "410f7acf3cb3a44527c5d9546bad4bf4e6c460915d5f9f2fc524498bfe8f70ce"
[[package]] [[package]]
name = "rustc-hash" name = "rustc-hash"
@ -3365,7 +3371,7 @@ dependencies = [
"cookie", "cookie",
"dbg", "dbg",
"enclose", "enclose",
"futures 0.3.14", "futures 0.3.15",
"gloo-file", "gloo-file",
"gloo-timers", "gloo-timers",
"indexmap", "indexmap",
@ -3417,18 +3423,18 @@ dependencies = [
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.125" version = "1.0.126"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.125" version = "1.0.126"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
dependencies = [ dependencies = [
"proc-macro2 1.0.26", "proc-macro2 1.0.26",
"quote 1.0.9", "quote 1.0.9",
@ -3473,13 +3479,13 @@ dependencies = [
[[package]] [[package]]
name = "sha-1" name = "sha-1"
version = "0.9.4" version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfebf75d25bd900fd1e7d11501efab59bc846dbc76196839663e6637bba9f25f" checksum = "8c4cfa741c5832d0ef7fab46cabed29c2aae926db0b11bb2069edd8db5e64e16"
dependencies = [ dependencies = [
"block-buffer 0.9.0", "block-buffer 0.9.0",
"cfg-if 1.0.0", "cfg-if 1.0.0",
"cpuid-bool 0.1.2", "cpufeatures",
"digest 0.9.0", "digest 0.9.0",
"opaque-debug 0.3.0", "opaque-debug 0.3.0",
] ]
@ -3492,13 +3498,13 @@ checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
[[package]] [[package]]
name = "sha2" name = "sha2"
version = "0.9.3" version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa827a14b29ab7f44778d14a88d3cb76e949c45083f7dbfa507d0cb699dc12de" checksum = "b362ae5752fd2137731f9fa25fd4d9058af34666ca1966fb969119cc35719f12"
dependencies = [ dependencies = [
"block-buffer 0.9.0", "block-buffer 0.9.0",
"cfg-if 1.0.0", "cfg-if 1.0.0",
"cpuid-bool 0.1.2", "cpufeatures",
"digest 0.9.0", "digest 0.9.0",
"opaque-debug 0.3.0", "opaque-debug 0.3.0",
] ]
@ -3597,9 +3603,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]] [[package]]
name = "spinning_top" name = "spinning_top"
version = "0.2.3" 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 = "8bd0ab6b8c375d2d963503b90d3770010d95bc3b5f98036f948dee24bf4e8879" checksum = "75adad84ee84b521fb2cca2d4fd0f1dab1d8d026bda3c5bea4ca63b5f9f9293c"
dependencies = [ dependencies = [
"lock_api", "lock_api",
] ]
@ -3680,7 +3686,7 @@ dependencies = [
"cargo_metadata", "cargo_metadata",
"dotenv", "dotenv",
"either", "either",
"futures 0.3.14", "futures 0.3.15",
"heck", "heck",
"hex", "hex",
"lazy_static", "lazy_static",
@ -3820,13 +3826,13 @@ checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.70" version = "1.0.72"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9505f307c872bab8eb46f77ae357c8eba1fdacead58ee5a850116b1d7f82883" checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
dependencies = [ dependencies = [
"proc-macro2 1.0.26", "proc-macro2 1.0.26",
"quote 1.0.9", "quote 1.0.9",
"unicode-xid 0.2.1", "unicode-xid 0.2.2",
] ]
[[package]] [[package]]
@ -3838,7 +3844,7 @@ dependencies = [
"proc-macro2 1.0.26", "proc-macro2 1.0.26",
"quote 1.0.9", "quote 1.0.9",
"syn", "syn",
"unicode-xid 0.2.1", "unicode-xid 0.2.2",
] ]
[[package]] [[package]]
@ -4126,9 +4132,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
[[package]] [[package]]
name = "tracing" name = "tracing"
version = "0.1.25" version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01ebdc2bb4498ab1ab5f5b73c5803825e60199229ccba0698170e3be0e7f959f" checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"log", "log",
@ -4144,7 +4150,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc36fc2f840643e49d220d07cd7ca81bc31c7f6df25f164d4257971533dab354" checksum = "cc36fc2f840643e49d220d07cd7ca81bc31c7f6df25f164d4257971533dab354"
dependencies = [ dependencies = [
"actix-web", "actix-web",
"futures 0.3.14", "futures 0.3.15",
"tracing", "tracing",
"tracing-futures", "tracing-futures",
"uuid", "uuid",
@ -4163,9 +4169,9 @@ dependencies = [
[[package]] [[package]]
name = "tracing-bunyan-formatter" name = "tracing-bunyan-formatter"
version = "0.2.0" 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 = "05e6b1b6c038da11d8d704f93b3974b0394824cdcc8c818c48255183cf315fd5" checksum = "dce1eae70720bd6bb3944f7cf501761aeae658bd1f9293aa373c71a195064910"
dependencies = [ dependencies = [
"chrono", "chrono",
"gethostname", "gethostname",
@ -4180,9 +4186,9 @@ dependencies = [
[[package]] [[package]]
name = "tracing-core" name = "tracing-core"
version = "0.1.17" version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f" checksum = "a9ff14f98b1a4b289c6248a023c1c2fa1491062964e9fed67ab29c4e4da4a052"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
] ]
@ -4233,9 +4239,9 @@ dependencies = [
[[package]] [[package]]
name = "tracing-subscriber" name = "tracing-subscriber"
version = "0.2.17" version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "705096c6f83bf68ea5d357a6aa01829ddbdac531b357b45abeca842938085baa" checksum = "aa5553bf0883ba7c9cbe493b085c29926bd41b66afc31ff72cf17ff4fb60dcd5"
dependencies = [ dependencies = [
"ansi_term 0.12.1", "ansi_term 0.12.1",
"chrono", "chrono",
@ -4262,7 +4268,7 @@ dependencies = [
"async-trait", "async-trait",
"cfg-if 1.0.0", "cfg-if 1.0.0",
"enum-as-inner", "enum-as-inner",
"futures 0.3.14", "futures 0.3.15",
"idna", "idna",
"lazy_static", "lazy_static",
"log", "log",
@ -4280,7 +4286,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "710f593b371175db53a26d0b38ed2978fafb9e9e8d3868b1acd753ea18df0ceb" checksum = "710f593b371175db53a26d0b38ed2978fafb9e9e8d3868b1acd753ea18df0ceb"
dependencies = [ dependencies = [
"cfg-if 0.1.10", "cfg-if 0.1.10",
"futures 0.3.14", "futures 0.3.15",
"ipconfig", "ipconfig",
"lazy_static", "lazy_static",
"log", "log",
@ -4459,9 +4465,9 @@ checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
[[package]] [[package]]
name = "unicode-xid" name = "unicode-xid"
version = "0.2.1" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]] [[package]]
name = "unicode_categories" name = "unicode_categories"
@ -4487,9 +4493,9 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]] [[package]]
name = "url" name = "url"
version = "2.2.1" version = "2.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ccd964113622c8e9322cfac19eb1004a07e636c545f325da085d5cdde6f1f8b" checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
dependencies = [ dependencies = [
"form_urlencoded", "form_urlencoded",
"idna", "idna",
@ -4597,9 +4603,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]] [[package]]
name = "wasm-bindgen" name = "wasm-bindgen"
version = "0.2.73" version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9" checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"serde", "serde",
@ -4609,9 +4615,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-backend" name = "wasm-bindgen-backend"
version = "0.2.73" version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae70622411ca953215ca6d06d3ebeb1e915f0f6613e3b495122878d7ebec7dae" checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"lazy_static", "lazy_static",
@ -4624,9 +4630,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-futures" name = "wasm-bindgen-futures"
version = "0.4.23" version = "0.4.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81b8b767af23de6ac18bf2168b690bed2902743ddf0fb39252e36f9e2bfc63ea" checksum = "5fba7978c679d53ce2d0ac80c8c175840feb849a161664365d1287b41f2e67f1"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"js-sys", "js-sys",
@ -4636,9 +4642,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro" name = "wasm-bindgen-macro"
version = "0.2.73" version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f" checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4"
dependencies = [ dependencies = [
"quote 1.0.9", "quote 1.0.9",
"wasm-bindgen-macro-support", "wasm-bindgen-macro-support",
@ -4646,9 +4652,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro-support" name = "wasm-bindgen-macro-support"
version = "0.2.73" version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c" checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97"
dependencies = [ dependencies = [
"proc-macro2 1.0.26", "proc-macro2 1.0.26",
"quote 1.0.9", "quote 1.0.9",
@ -4659,15 +4665,15 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-shared" name = "wasm-bindgen-shared"
version = "0.2.73" version = "0.2.74"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9a543ae66aa233d14bb765ed9af4a33e81b8b58d1584cf1b47ff8cd0b9e4489" checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f"
[[package]] [[package]]
name = "web-sys" name = "web-sys"
version = "0.3.50" version = "0.3.51"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a905d57e488fec8861446d3393670fb50d27a262344013181c2cdf9fff5481be" checksum = "e828417b379f3df7111d3a2a9e5753706cae29c41f7c4029ee9fd77f3e09e582"
dependencies = [ dependencies = [
"js-sys", "js-sys",
"wasm-bindgen", "wasm-bindgen",

View File

@ -3,3 +3,9 @@ members = [
"pslink", "pslink",
"app", "app",
] ]
[profile]
[profile.release]
lto = true
#codegen-units = 1
opt-level = 'z'

View File

@ -19,12 +19,9 @@ crate-type = ["cdylib", "rlib"]
fluent = "0.15" fluent = "0.15"
seed = "0.8" seed = "0.8"
serde = "1.0" serde = "1.0"
strum_macros = "0.20"
unic-langid = "0.9" unic-langid = "0.9"
strum_macros = "0.20"
strum = "0.20" strum = "0.20"
enum-map = "1" enum-map = "1"
shared = { path = "../shared" } shared = { path = "../shared" }
[profile.release]
opt-level = 'z'

View File

@ -28,9 +28,11 @@ edit-user-headline = Benutzereinstellungen von: {$username}
username = Benutzername username = Benutzername
email = Email email = Email
password = Passwort password = Passwort
password-placeholder = Leer lassen um das Passwort nicht zu ändern leave-password-empty-hint = Leer lassen um das Passwort nicht zu ändern
save-user = Benutzer speichern save-user = Benutzer speichern
edit-user = Benutzer editieren edit-user = Benutzer editieren
create-user = Benutzer Erstellen
new-user = Neuer Benutzer
make-user-admin = Zum Administrator befördern make-user-admin = Zum Administrator befördern
make-user-regular = Zurückstufen zum normalen Nutzer make-user-regular = Zurückstufen zum normalen Nutzer

View File

@ -28,9 +28,11 @@ edit-user-headline = Change Settings of: {$username}
username = Username username = Username
email = Email email = Email
password = Password password = Password
password-placeholder = Leave this empty to keep the current password leave-password-empty-hint = Leave this empty to keep the current password
save-user = Save this user save-user = Save this user
edit-user = Edit this user edit-user = Edit this user
new-user = Neuer Benutzer
create-user = Create user
make-user-admin = Promote to admin make-user-admin = Promote to admin
make-user-regular = Demote to regular make-user-regular = Demote to regular

View File

@ -49,13 +49,13 @@ enum Page {
impl Page { impl Page {
fn init(mut url: Url, orders: &mut impl Orders<Msg>, i18n: I18n) -> Self { fn init(mut url: Url, orders: &mut impl Orders<Msg>, i18n: I18n) -> Self {
url.next_path_part(); url.next_path_part();
let result = match url.remaining_path_parts().as_slice() { let result = match url.next_path_part() {
[] | ["list_links"] => Self::Home(pages::list_links::init( None | Some("list_links") => Self::Home(pages::list_links::init(
url, url,
&mut orders.proxy(Msg::ListLinksMsg), &mut orders.proxy(Msg::ListLinksMsg),
i18n, i18n,
)), )),
["list_users"] => Self::ListUsers(pages::list_users::init( Some("list_users") => Self::ListUsers(pages::list_users::init(
url, url,
&mut orders.proxy(Msg::ListUsersMsg), &mut orders.proxy(Msg::ListUsersMsg),
i18n, i18n,
@ -144,6 +144,10 @@ impl<'a> Urls<'a> {
pub fn list_users(self) -> Url { pub fn list_users(self) -> Url {
self.base_url().add_path_part("list_users") self.base_url().add_path_part("list_users")
} }
#[must_use]
pub fn create_user(self) -> Url {
self.list_users().add_path_part("create_user")
}
} }
// ------ ------ // ------ ------

View File

@ -25,8 +25,12 @@ pub fn navigation(i18n: &I18n, base_url: &Url) -> Node<Msg> {
],], ],],
li![a![ev(Ev::Click, |_| Msg::NoMessage), t!("add-link"),],], li![a![ev(Ev::Click, |_| Msg::NoMessage), t!("add-link"),],],
li![a![ li![a![
attrs! {At::Href => "#"}, attrs! {At::Href => crate::Urls::new(base_url).create_user()},
ev(Ev::Click, |_| Msg::NoMessage), ev(Ev::Click, |_| Msg::ListUsersMsg(
super::pages::list_users::Msg::Edit(
super::pages::list_users::UserEditMsg::CreateNewUser
)
)),
t!("invite-user"), t!("invite-user"),
],], ],],
li![a![ li![a![

View File

@ -1,21 +1,33 @@
use std::cell::RefCell;
use enum_map::EnumMap; use enum_map::EnumMap;
use seed::{attrs, button, h1, input, log, prelude::*, section, table, td, th, tr, Url, C}; use seed::{
a, attrs, button, div, h1, input, log, p, prelude::*, section, table, td, th, tr, Url, C, IF,
};
use shared::{ use shared::{
apirequests::general::{Operation, Ordering}, apirequests::general::{Operation, Ordering},
apirequests::users::{UserOverviewColumns, UserRequestForm}, apirequests::{
general::{EditMode, SuccessMessage},
users::{UserDelta, UserOverviewColumns, UserRequestForm},
},
datatypes::User, datatypes::User,
}; };
use crate::i18n::I18n; use crate::i18n::I18n;
#[must_use] #[must_use]
pub fn init(_: Url, orders: &mut impl Orders<Msg>, i18n: I18n) -> Model { pub fn init(mut url: Url, orders: &mut impl Orders<Msg>, i18n: I18n) -> Model {
orders.send_msg(Msg::Fetch); orders.send_msg(Msg::Query(UserQueryMsg::Fetch));
let user_edit = match url.next_path_part() {
Some("create_user") => Some(RefCell::new(UserDelta::default())),
None | Some(_) => None,
};
Model { Model {
users: Vec::new(), users: Vec::new(),
i18n, i18n,
formconfig: UserRequestForm::default(), formconfig: UserRequestForm::default(),
inputs: EnumMap::default(), inputs: EnumMap::default(),
user_edit: None, user_edit,
last_message: None,
} }
} }
#[derive(Debug)] #[derive(Debug)]
@ -24,13 +36,8 @@ pub struct Model {
i18n: I18n, i18n: I18n,
formconfig: UserRequestForm, formconfig: UserRequestForm,
inputs: EnumMap<UserOverviewColumns, FilterInput>, inputs: EnumMap<UserOverviewColumns, FilterInput>,
user_edit: Option<UserEditMode>, user_edit: Option<RefCell<UserDelta>>,
} last_message: Option<SuccessMessage>,
#[derive(Debug)]
enum UserEditMode {
Create { user: User },
Edit { user: User },
} }
#[derive(Default, Debug, Clone)] #[derive(Default, Debug, Clone)]
@ -40,32 +47,61 @@ struct FilterInput {
#[derive(Clone)] #[derive(Clone)]
pub enum Msg { pub enum Msg {
Query(UserQueryMsg),
Edit(UserEditMsg),
}
/// All the messages on user Querying
#[derive(Clone)]
pub enum UserQueryMsg {
Fetch, Fetch,
FailedToFetchUsers,
OrderBy(UserOverviewColumns), OrderBy(UserOverviewColumns),
Received(Vec<User>), Received(Vec<User>),
IdFilterChanged(String), IdFilterChanged(String),
EmailFilterChanged(String), EmailFilterChanged(String),
UsernameFilterChanged(String), UsernameFilterChanged(String),
EditUserSelected(User), }
/// All the messages on user editing
#[derive(Clone)]
pub enum UserEditMsg {
EditUserSelected(UserDelta),
CreateNewUser,
UserCreated(SuccessMessage),
EditUsernameChanged(String),
EditEmailChanged(String),
EditPasswordChanged(String),
SaveUser,
FailedToCreateUser,
} }
/// # Panics /// # Panics
/// Sould only panic on bugs. /// Sould only panic on bugs.
pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) { pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
match msg { match msg {
Msg::Fetch => { Msg::Query(msg) => process_query_messages(msg, model, orders),
Msg::Edit(msg) => process_user_edit_messages(msg, model, orders),
}
}
pub fn process_query_messages(msg: UserQueryMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
match msg {
UserQueryMsg::Fetch => {
orders.skip(); // No need to rerender orders.skip(); // No need to rerender
let data = model.formconfig.clone(); // complicated way to move into the closure let data = model.formconfig.clone(); // complicated way to move into the closure
orders.perform_cmd(async { orders.perform_cmd(async {
let data = data; let data = data;
let response = fetch( let response = match fetch(
Request::new("/admin/json/list_users/") Request::new("/admin/json/list_users/")
.method(Method::Post) .method(Method::Post)
.json(&data) .json(&data)
.expect("serialization failed"), .expect("serialization failed"),
) )
.await .await
.expect("HTTP request failed"); {
Ok(response) => response,
Err(_) => return Msg::Query(UserQueryMsg::FailedToFetchUsers),
};
let users: Vec<User> = response let users: Vec<User> = response
.check_status() // ensure we've got 2xx status .check_status() // ensure we've got 2xx status
@ -74,10 +110,10 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
.await .await
.expect("deserialization failed"); .expect("deserialization failed");
Msg::Received(users) Msg::Query(UserQueryMsg::Received(users))
}); });
} }
Msg::OrderBy(column) => { UserQueryMsg::OrderBy(column) => {
model.formconfig.order = model.formconfig.order.as_ref().map_or_else( model.formconfig.order = model.formconfig.order.as_ref().map_or_else(
|| { || {
Some(Operation { Some(Operation {
@ -96,7 +132,7 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
}) })
}, },
); );
orders.send_msg(Msg::Fetch); orders.send_msg(Msg::Query(UserQueryMsg::Fetch));
model.users.sort_by(match column { model.users.sort_by(match column {
UserOverviewColumns::Id => |o: &User, t: &User| o.id.cmp(&t.id), UserOverviewColumns::Id => |o: &User, t: &User| o.id.cmp(&t.id),
@ -104,34 +140,115 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
UserOverviewColumns::Email => |o: &User, t: &User| o.email.cmp(&t.email), UserOverviewColumns::Email => |o: &User, t: &User| o.email.cmp(&t.email),
}) })
} }
Msg::Received(response) => { UserQueryMsg::Received(response) => {
model.users = response; model.users = response;
} }
Msg::IdFilterChanged(s) => { UserQueryMsg::IdFilterChanged(s) => {
log!("Filter is: ", &s); log!("Filter is: ", &s);
let sanit = s.chars().filter(|x| x.is_numeric()).collect(); let sanit = s.chars().filter(|x| x.is_numeric()).collect();
model.formconfig.filter[UserOverviewColumns::Id].sieve = sanit; model.formconfig.filter[UserOverviewColumns::Id].sieve = sanit;
orders.send_msg(Msg::Fetch); orders.send_msg(Msg::Query(UserQueryMsg::Fetch));
} }
Msg::UsernameFilterChanged(s) => { UserQueryMsg::UsernameFilterChanged(s) => {
log!("Filter is: ", &s); log!("Filter is: ", &s);
let sanit = s.chars().filter(|x| x.is_alphanumeric()).collect(); let sanit = s.chars().filter(|x| x.is_alphanumeric()).collect();
model.formconfig.filter[UserOverviewColumns::Username].sieve = sanit; model.formconfig.filter[UserOverviewColumns::Username].sieve = sanit;
orders.send_msg(Msg::Fetch); orders.send_msg(Msg::Query(UserQueryMsg::Fetch));
} }
Msg::EmailFilterChanged(s) => { UserQueryMsg::EmailFilterChanged(s) => {
log!("Filter is: ", &s); log!("Filter is: ", &s);
// FIXME: Sanitazion does not work for @ // FIXME: Sanitazion does not work for @
let sanit = s.chars().filter(|x| x.is_alphanumeric()).collect(); let sanit = s.chars().filter(|x| x.is_alphanumeric()).collect();
model.formconfig.filter[UserOverviewColumns::Email].sieve = sanit; model.formconfig.filter[UserOverviewColumns::Email].sieve = sanit;
orders.send_msg(Msg::Fetch); orders.send_msg(Msg::Query(UserQueryMsg::Fetch));
} }
Msg::EditUserSelected(user) => {
UserQueryMsg::FailedToFetchUsers => {
log!("Failed to fetch users");
}
}
}
pub fn process_user_edit_messages(
msg: UserEditMsg,
model: &mut Model,
orders: &mut impl Orders<Msg>,
) {
match msg {
UserEditMsg::EditUserSelected(user) => {
log!("Editing user: ", user); log!("Editing user: ", user);
model.user_edit = Some(UserEditMode::Edit { user }) model.user_edit = Some(RefCell::new(user))
}
UserEditMsg::CreateNewUser => {
log!("Creating new user");
model.user_edit = Some(RefCell::new(UserDelta::default()))
}
UserEditMsg::EditUsernameChanged(s) => {
log!("New Username is: ", &s);
if let Some(ref ue) = model.user_edit {
ue.try_borrow_mut()
.expect("Failed to borrow mutably")
.username = s;
};
}
UserEditMsg::EditEmailChanged(s) => {
log!("New Email is: ", &s);
if let Some(ref ue) = model.user_edit {
ue.try_borrow_mut().expect("Failed to borrow mutably").email = s;
};
}
UserEditMsg::EditPasswordChanged(s) => {
log!("New Password is: ", &s);
if let Some(ref ue) = model.user_edit {
ue.try_borrow_mut()
.expect("Failed to borrow mutably")
.password = Some(s);
};
}
UserEditMsg::SaveUser => {
let data = model
.user_edit
.as_ref()
.expect("Somehow a user should exist!")
.borrow()
.clone(); // complicated way to move into the closure
log!("Saving User: ", &data.username);
orders.perform_cmd(async {
let data = data;
let response = match fetch(
Request::new("/admin/json/create_user/")
.method(Method::Post)
.json(&data)
.expect("serialization failed"),
)
.await
{
Ok(response) => response,
Err(_) => return Msg::Edit(UserEditMsg::FailedToCreateUser),
};
let message: SuccessMessage = response
.check_status() // ensure we've got 2xx status
.expect("status check failed")
.json()
.await
.expect("deserialization failed");
Msg::Edit(UserEditMsg::UserCreated(message))
});
}
UserEditMsg::FailedToCreateUser => {
log!("Failed to create user");
}
UserEditMsg::UserCreated(u) => {
log!(u, "created user");
model.last_message = Some(u);
model.user_edit = None;
orders.send_msg(Msg::Query(UserQueryMsg::Fetch));
} }
} }
} }
#[must_use] #[must_use]
/// # Panics /// # Panics
/// Sould only panic on bugs. /// Sould only panic on bugs.
@ -140,6 +257,11 @@ pub fn view(model: &Model) -> Node<Msg> {
let t = move |key: &str| lang.translate(key, None); let t = move |key: &str| lang.translate(key, None);
section![ section![
h1!("List Users Page from list_users"), h1!("List Users Page from list_users"),
if let Some(message) = &model.last_message {
div![C!("Message"), &message.message]
} else {
section!()
},
table![ table![
// Column Headlines // Column Headlines
view_user_table_head(&t), view_user_table_head(&t),
@ -148,22 +270,36 @@ pub fn view(model: &Model) -> Node<Msg> {
// Add all the users one line for each // Add all the users one line for each
model.users.iter().map(view_user) model.users.iter().map(view_user)
], ],
button![ev(Ev::Click, |_| Msg::Fetch), "Refresh"] button![
ev(Ev::Click, |_| Msg::Query(UserQueryMsg::Fetch)),
"Refresh"
],
if let Some(l) = &model.user_edit {
edit_or_create_user(l, t)
} else {
section!()
},
] ]
} }
fn view_user_table_head<F: Fn(&str) -> String>(t: F) -> Node<Msg> { fn view_user_table_head<F: Fn(&str) -> String>(t: F) -> Node<Msg> {
tr![ tr![
th![ th![
ev(Ev::Click, |_| Msg::OrderBy(UserOverviewColumns::Id)), ev(Ev::Click, |_| Msg::Query(UserQueryMsg::OrderBy(
UserOverviewColumns::Id
))),
t("userid") t("userid")
], ],
th![ th![
ev(Ev::Click, |_| Msg::OrderBy(UserOverviewColumns::Email)), ev(Ev::Click, |_| Msg::Query(UserQueryMsg::OrderBy(
UserOverviewColumns::Email
))),
t("email") t("email")
], ],
th![ th![
ev(Ev::Click, |_| Msg::OrderBy(UserOverviewColumns::Username)), ev(Ev::Click, |_| Msg::Query(UserQueryMsg::OrderBy(
UserOverviewColumns::Username
))),
t("username") t("username")
], ],
] ]
@ -178,7 +314,9 @@ fn view_user_table_filter_input<F: Fn(&str) -> String>(model: &Model, t: F) -> N
At::Type => "search", At::Type => "search",
At::Placeholder => t("search-placeholder") At::Placeholder => t("search-placeholder")
}, },
input_ev(Ev::Input, Msg::IdFilterChanged), input_ev(Ev::Input, |s| {
Msg::Query(UserQueryMsg::IdFilterChanged(s))
}),
el_ref(&model.inputs[UserOverviewColumns::Id].filter_input), el_ref(&model.inputs[UserOverviewColumns::Id].filter_input),
]], ]],
td![input![ td![input![
@ -188,7 +326,9 @@ fn view_user_table_filter_input<F: Fn(&str) -> String>(model: &Model, t: F) -> N
At::Type => "search", At::Type => "search",
At::Placeholder => t("search-placeholder") At::Placeholder => t("search-placeholder")
}, },
input_ev(Ev::Input, Msg::EmailFilterChanged), input_ev(Ev::Input, |s| {
Msg::Query(UserQueryMsg::EmailFilterChanged(s))
}),
el_ref(&model.inputs[UserOverviewColumns::Email].filter_input), el_ref(&model.inputs[UserOverviewColumns::Email].filter_input),
]], ]],
td![input![ td![input![
@ -198,19 +338,100 @@ fn view_user_table_filter_input<F: Fn(&str) -> String>(model: &Model, t: F) -> N
At::Type => "search", At::Type => "search",
At::Placeholder => t("search-placeholder") At::Placeholder => t("search-placeholder")
}, },
input_ev(Ev::Input, Msg::UsernameFilterChanged), input_ev(Ev::Input, |s| {
Msg::Query(UserQueryMsg::UsernameFilterChanged(s))
}),
el_ref(&model.inputs[UserOverviewColumns::Username].filter_input), el_ref(&model.inputs[UserOverviewColumns::Username].filter_input),
]], ]],
] ]
} }
fn view_user(l: &User) -> Node<Msg> { fn view_user(l: &User) -> Node<Msg> {
let user = l.clone(); let user = UserDelta::from(l.clone());
tr![ tr![
ev(Ev::Click, |_| Msg::EditUserSelected(user)), ev(Ev::Click, |_| Msg::Edit(UserEditMsg::EditUserSelected(
user
))),
td![&l.id], td![&l.id],
td![&l.email], td![&l.email],
//td![a![attrs![At::Href => &l.link.target], &l.link.target]], //td![a![attrs![At::Href => &l.link.target], &l.link.target]],
td![&l.username], td![&l.username],
] ]
} }
fn edit_or_create_user<F: Fn(&str) -> String>(l: &RefCell<UserDelta>, t: F) -> Node<Msg> {
let user = l.borrow();
div![
C!["editdialog", "center"],
h1![match &user.edit {
EditMode::Edit => t("edit-user"),
EditMode::Create => t("new-user"),
}],
table![
tr![
th![
ev(Ev::Click, |_| Msg::Query(UserQueryMsg::OrderBy(
UserOverviewColumns::Username
))),
t("username")
],
td![input![
attrs! {
At::Value => &user.username,
At::Type => "text",
At::Placeholder => t("username")
},
input_ev(Ev::Input, |s| {
Msg::Edit(UserEditMsg::EditUsernameChanged(s))
}),
]]
],
tr![
th![
ev(Ev::Click, |_| Msg::Query(UserQueryMsg::OrderBy(
UserOverviewColumns::Email
))),
t("email")
],
td![input![
attrs! {
At::Value => &user.email,
At::Type => "email",
At::Placeholder => t("email")
},
input_ev(Ev::Input, |s| {
Msg::Edit(UserEditMsg::EditEmailChanged(s))
}),
]]
],
tr![
th![
ev(Ev::Click, |_| Msg::Query(UserQueryMsg::OrderBy(
UserOverviewColumns::Email
))),
t("password")
],
td![
input![
attrs! {
At::Type => "password",
At::Placeholder => t("password")
},
input_ev(Ev::Input, |s| {
Msg::Edit(UserEditMsg::EditPasswordChanged(s))
}),
],
IF!(user.edit == EditMode::Edit => p![t("leave-password-empty-hint")])
]
]
],
a![
match &user.edit {
EditMode::Edit => t("edit-user"),
EditMode::Create => t("create-user"),
},
C!["button"],
ev(Ev::Click, |_| Msg::Edit(UserEditMsg::SaveUser))
]
]
}

View File

@ -71,8 +71,3 @@ tokio = "0.2.25"
[dev-dependencies.reqwest] [dev-dependencies.reqwest]
features = ["cookies"] features = ["cookies"]
version = "0.10.10" version = "0.10.10"
[profile]
[profile.release]
lto = true
#codegen-units = 1

View File

@ -370,7 +370,11 @@ pub async fn webservice(
.service( .service(
web::scope("/json") web::scope("/json")
.route("/list_links/", web::post().to(views::index_json)) .route("/list_links/", web::post().to(views::index_json))
.route("/list_users/", web::post().to(views::index_users_json)), .route("/list_users/", web::post().to(views::index_users_json))
.route(
"/create_user/",
web::post().to(views::process_create_user_json),
),
) )
// login to the admin area // login to the admin area
.route("/login/", web::get().to(views::login)) .route("/login/", web::get().to(views::login))

View File

@ -23,7 +23,7 @@ pub trait UserDbOperations<T> {
} }
#[async_trait] #[async_trait]
impl UserDbOperations<User> for User { impl UserDbOperations<Self> for User {
async fn get_user(id: i64, server_config: &ServerConfig) -> Result<Self, ServerError> { async fn get_user(id: i64, server_config: &ServerConfig) -> Result<Self, ServerError> {
let user = sqlx::query_as!(Self, "Select * from users where id = ? ", id) let user = sqlx::query_as!(Self, "Select * from users where id = ? ", id)
.fetch_one(&server_config.db_pool) .fetch_one(&server_config.db_pool)
@ -186,7 +186,7 @@ pub trait LinkDbOperations<T> {
} }
#[async_trait] #[async_trait]
impl LinkDbOperations<Link> for Link { impl LinkDbOperations<Self> for Link {
async fn get_link_by_code( async fn get_link_by_code(
code: &str, code: &str,
server_config: &ServerConfig, server_config: &ServerConfig,

View File

@ -6,7 +6,7 @@ use shared::{
apirequests::{ apirequests::{
general::{Filter, Operation, Ordering}, general::{Filter, Operation, Ordering},
links::{LinkOverviewColumns, LinkRequestForm}, links::{LinkOverviewColumns, LinkRequestForm},
users::{UserOverviewColumns, UserRequestForm}, users::{UserDelta, UserOverviewColumns, UserRequestForm},
}, },
datatypes::{Count, FullLink, Link, User}, datatypes::{Count, FullLink, Link, User},
}; };
@ -389,6 +389,51 @@ pub async fn create_user(
} }
} }
} }
/// Create a new user and save it to the database
///
/// # Errors
/// Fails with [`ServerError`] if access to the database fails, this user does not have permissions or the user already exists.
#[instrument(skip(id))]
pub async fn create_user_json(
id: &Identity,
data: &web::Json<UserDelta>,
server_config: &ServerConfig,
) -> Result<Item<User>, ServerError> {
info!("Creating a User: {:?}", &data);
let auth = authenticate(id, server_config).await?;
// Require a password on user creation!
let password = match &data.password {
Some(pass) => pass,
None => {
return Err(ServerError::User(
"A new users does require a password".to_string(),
))
}
};
match auth {
Role::Admin { user } => {
let new_user = NewUser::new(
data.username.clone(),
data.email.clone(),
password,
&server_config.secret,
)?;
new_user.insert_user(server_config).await?;
// querry the new user
let new_user = get_user_by_name(&data.username, server_config).await?;
Ok(Item {
user,
item: new_user,
})
}
Role::Regular { .. } | Role::Disabled | Role::NotAuthenticated => {
Err(ServerError::User("Permission denied!".to_owned()))
}
}
}
/// Take a [`actix_web::web::Form<NewUser>`] and update the corresponding entry in the database. /// Take a [`actix_web::web::Form<NewUser>`] and update the corresponding entry in the database.
/// The password is only updated if a new password of at least 4 characters is provided. /// The password is only updated if a new password of at least 4 characters is provided.
/// The `user_id` is never changed. /// The `user_id` is never changed.

View File

@ -14,7 +14,11 @@ use fluent_templates::LanguageIdentifier;
use image::{DynamicImage, ImageOutputFormat, Luma}; use image::{DynamicImage, ImageOutputFormat, Luma};
use qrcode::{render::svg, QrCode}; use qrcode::{render::svg, QrCode};
use queries::{authenticate, Role}; use queries::{authenticate, Role};
use shared::apirequests::{links::LinkRequestForm, users::UserRequestForm}; use shared::apirequests::{
general::SuccessMessage,
links::LinkRequestForm,
users::{UserDelta, UserRequestForm},
};
use tera::{Context, Tera}; use tera::{Context, Tera};
use tracing::{error, info, instrument, warn}; use tracing::{error, info, instrument, warn};
@ -346,6 +350,21 @@ pub async fn process_signup(
} }
} }
#[instrument(skip(id))]
pub async fn process_create_user_json(
config: web::Data<crate::ServerConfig>,
form: web::Json<UserDelta>,
id: Identity,
) -> Result<HttpResponse, ServerError> {
info!("Listing Users to Json api");
match queries::create_user_json(&id, &form, &config).await {
Ok(item) => Ok(HttpResponse::Ok().json2(&SuccessMessage {
message: format!("Successfully saved user: {}", item.item.username),
})),
Err(e) => Err(e),
}
}
#[instrument(skip(id))] #[instrument(skip(id))]
pub async fn toggle_admin( pub async fn toggle_admin(
data: web::Path<String>, data: web::Path<String>,

View File

@ -1,4 +1,3 @@
body { body {
margin: 0; margin: 0;
padding: 0; padding: 0;
@ -7,13 +6,16 @@ body {
form { form {
width: 100%; width: 100%;
} }
.center { .center {
position: absolute; position: absolute;
width: 400px; width: 600px;
max-width: 100%;
height: 400px; height: 400px;
max-height: 100%;
top: 50%; top: 50%;
left: 50%; left: 50%;
margin-left: -200px; margin-left: -300px;
margin-top: -200px; margin-top: -200px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -22,22 +24,20 @@ align-items: center;
padding: 30px; padding: 30px;
color: #333; color: #333;
} }
.center input { .center input {
width: 100%; width: 100%;
padding: 15px; padding: 0;
margin: 5px; margin: 0;
border-radius: 1px; border-radius: 1px;
border: 1px solid rgb(90, 90, 90); border: 1px solid rgb(90, 90, 90);
font-family: inherit; font-family: inherit;
background-color: #eae9ea; background-color: #eae9ea;
} }
.center { .center table p {
width: 800px; font-size: x-small;
height: 600px; margin: 0;
margin-left: -400px;
margin-top: -300px;
} }
table { table {
@ -45,7 +45,8 @@ border-collapse: collapse;
width: 100%; width: 100%;
} }
th, td { th,
td {
text-align: center; text-align: center;
border: 1px solid #ccc; border: 1px solid #ccc;
padding: 10px; padding: 10px;
@ -54,6 +55,7 @@ padding: 10px;
table tr:nth-child(even) { table tr:nth-child(even) {
background-color: #eee; background-color: #eee;
} }
table tr:nth-child(odd) { table tr:nth-child(odd) {
background-color: #fff; background-color: #fff;
} }
@ -82,6 +84,7 @@ align-items:stretch;
width: 100%; width: 100%;
height: 60px; height: 60px;
} }
nav ol { nav ol {
display: flex; display: flex;
align-items: center; align-items: center;
@ -91,7 +94,8 @@ nav ol {
height: 40px; height: 40px;
} }
nav li a, nav li div.willkommen { nav li a,
nav li div.willkommen {
color: white; color: white;
text-align: center; text-align: center;
padding: 14px 16px; padding: 14px 16px;
@ -107,6 +111,7 @@ background: linear-gradient(180deg, rgba(2,0,36,1) 0%, rgba(9,9,121,1) 35%, rgb(
nav li { nav li {
float: left; float: left;
} }
nav li a:hover { nav li a:hover {
background: rgb(2, 0, 36); background: rgb(2, 0, 36);
background: linear-gradient(180deg, rgba(2, 0, 36, 1) 0%, rgba(9, 9, 121, 1) 35%, rgb(60, 170, 255) 100%); background: linear-gradient(180deg, rgba(2, 0, 36, 1) 0%, rgba(9, 9, 121, 1) 35%, rgb(60, 170, 255) 100%);
@ -123,7 +128,6 @@ nav li div{
border-radius: 0 0 10px 10px; border-radius: 0 0 10px 10px;
} }
svg { svg {
width: 100px; width: 100px;
height: 100px; height: 100px;
@ -150,7 +154,8 @@ div.danger h3 {
width: 100%; width: 100%;
} }
a.button, div.actions input { a.button,
div.actions input {
width: 250px; width: 250px;
display: block; display: block;
padding: 15px; padding: 15px;
@ -161,3 +166,8 @@ border: 1px solid rgb(90, 90, 90);
font-family: inherit; font-family: inherit;
background-color: #eae9ea; background-color: #eae9ea;
} }
div.editdialog {
background-color: aliceblue;
border: 5px solid rgb(90, 90, 90);
}

View File

@ -25,3 +25,20 @@ pub struct Operation<T, V> {
pub column: T, pub column: T,
pub value: V, pub value: V,
} }
#[derive(Clone, Deserialize, Serialize, Debug, PartialEq, Eq)]
pub enum EditMode {
Create,
Edit,
}
impl Default for EditMode {
fn default() -> Self {
Self::Create
}
}
#[derive(Clone, Deserialize, Serialize, Debug)]
pub struct SuccessMessage {
pub message: String,
}

View File

@ -1,12 +1,17 @@
use enum_map::{Enum, EnumMap}; use enum_map::{Enum, EnumMap};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::general::{Filter, Operation, Ordering}; use crate::datatypes::User;
use super::general::{EditMode, Filter, Operation, Ordering};
#[derive(Clone, Deserialize, Serialize, Debug)] #[derive(Clone, Deserialize, Serialize, Debug)]
pub struct UserRequestForm { pub struct UserRequestForm {
// The filters up to one for each column
pub filter: EnumMap<UserOverviewColumns, Filter>, pub filter: EnumMap<UserOverviewColumns, Filter>,
// Order According to this column
pub order: Option<Operation<UserOverviewColumns, Ordering>>, pub order: Option<Operation<UserOverviewColumns, Ordering>>,
// Return a maximum of `amount` results
pub amount: usize, pub amount: usize,
} }
@ -20,6 +25,31 @@ impl Default for UserRequestForm {
} }
} }
/// The Struct that is responsible for creating and editing users.
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct UserDelta {
pub edit: EditMode,
pub id: Option<i64>,
pub username: String,
pub email: String,
pub password: Option<String>,
}
impl From<User> for UserDelta {
/// Automatically create a `UserDelta` from a User.
fn from(u: User) -> Self {
Self {
edit: EditMode::Edit,
id: Some(u.id),
username: u.username,
email: u.email,
password: None,
}
}
}
/// The columns in the user view table. The table can be ordered according to these.
#[allow(clippy::use_self)]
#[derive(Clone, Deserialize, Serialize, Debug, PartialEq, Eq, Hash, Enum)] #[derive(Clone, Deserialize, Serialize, Debug, PartialEq, Eq, Hash, Enum)]
pub enum UserOverviewColumns { pub enum UserOverviewColumns {
Id, Id,