diff --git a/Cargo.lock b/Cargo.lock index 9b25d2a..ea88f32 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -107,7 +107,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sha-1 0.9.4", + "sha-1 0.9.6", "slab", "time 0.2.26", ] @@ -202,7 +202,7 @@ checksum = "c697a62a2f51c5c26af6b1dded0622f15bec690da191615947e0c1b2b7b75198" dependencies = [ "actix-web", "chrono", - "futures 0.3.14", + "futures 0.3.15", "pin-project 0.4.28", "slog", ] @@ -327,16 +327,16 @@ dependencies = [ "actix-service", "actix-web", "derive_more", - "futures 0.3.14", + "futures 0.3.15", "mime_guess", "path-slash", ] [[package]] name = "addr2line" -version = "0.14.1" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7" +checksum = "03345e98af8f3d786b6d9f656ccfa6ac316d954e92bc4841f0bba20789d5fb5a" dependencies = [ "gimli", ] @@ -426,9 +426,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.15" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" dependencies = [ "memchr", ] @@ -575,11 +575,12 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.57" +version = "0.3.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ed203b9ba68b242c62b3fb7480f589dd49829be1edb3fe8fc8b4ffda2dcb8d" +checksum = "4717cfcbfaa661a0fd48f8453951837ae7e8f81e481fbb136e3202d72805a744" dependencies = [ "addr2line", + "cc", "cfg-if 1.0.0", "libc", "miniz_oxide 0.4.4", @@ -706,9 +707,9 @@ dependencies = [ [[package]] name = "bstr" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a40b47ad93e1a5404e6c18dec46b628214fee441c70f4ab5d6942142cc268a3d" +checksum = "90682c8d613ad3373e66de8c6411e0ae2ab2571e879d2efbf73558cc66f21279" dependencies = [ "memchr", ] @@ -983,10 +984,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" [[package]] -name = "cpuid-bool" -version = "0.1.2" +name = "cpufeatures" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" +checksum = "281f563b2c3a0e535ab12d81d3c5859045795256ad269afa7c19542585b68f93" +dependencies = [ + "libc", +] [[package]] name = "cpuid-bool" @@ -1035,9 +1039,9 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2584f639eb95fea8c798496315b297cf81b9b58b6d30ab066a75455333cf4b12" +checksum = "52fb27eab85b17fbb9f6fd667089e07d6a2eb8743d02639ee7f6a7a7729c9c94" dependencies = [ "cfg-if 1.0.0", "crossbeam-utils", @@ -1058,9 +1062,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" +checksum = "4feb231f0d4d6af81aed15928e58ecf5816aa62a2393e2c82f46973e92a9a278" dependencies = [ "autocfg 1.0.1", "cfg-if 1.0.0", @@ -1197,9 +1201,9 @@ dependencies = [ [[package]] name = "enum-map" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88acdb627a242ba1bf36653fa200f72c037ca3324e0710d1ac4fee809a1539cd" +checksum = "34c3f3c98ee954dbafd343b3e0d827bb167cdda151b3c88ae04b0e5fa7db1028" dependencies = [ "enum-map-derive", "serde", @@ -1315,7 +1319,7 @@ dependencies = [ "fluent-syntax 0.11.0", "intl-memoizer", "intl_pluralrules", - "ouroboros 0.9.1", + "ouroboros 0.9.2", "rustc-hash", "smallvec", "unic-langid", @@ -1464,9 +1468,9 @@ checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" [[package]] name = "futures" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d5813545e459ad3ca1bff9915e9ad7f1a47dc6a91b627ce321d5863b7dd253" +checksum = "0e7e43a803dae2fa37c1f6a8fe121e1f7bf9548b4dfc0522a42f34145dadfc27" dependencies = [ "futures-channel", "futures-core", @@ -1479,9 +1483,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce79c6a52a299137a6013061e0cf0e688fce5d7f1bc60125f520912fdb29ec25" +checksum = "e682a68b29a882df0545c143dc3646daefe80ba479bcdede94d5a703de2871e2" dependencies = [ "futures-core", "futures-sink", @@ -1489,9 +1493,9 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "098cd1c6dda6ca01650f1a37a794245eb73181d0d4d4e955e2f3c37db7af1815" +checksum = "0402f765d8a89a26043b889b26ce3c4679d268fa6bb22cd7c6aad98340e179d1" [[package]] name = "futures-cpupool" @@ -1505,9 +1509,9 @@ dependencies = [ [[package]] name = "futures-executor" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f6cb7042eda00f0049b1d2080aa4b93442997ee507eb3828e8bd7577f94c9d" +checksum = "badaa6a909fac9e7236d0620a2f57f7664640c56575b71a7552fbd68deafab79" dependencies = [ "futures-core", "futures-task", @@ -1516,16 +1520,17 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "365a1a1fb30ea1c03a830fdb2158f5236833ac81fa0ad12fe35b29cddc35cb04" +checksum = "acc499defb3b348f8d8f3f66415835a9131856ff7714bf10dadfc4ec4bdb29a1" [[package]] name = "futures-macro" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "668c6733a182cd7deb4f1de7ba3bf2120823835b3bcfbeacf7d2c4a773c1bb8b" +checksum = "a4c40298486cdf52cc00cd6d6987892ba502c7656a16a4192a9992b1ccedd121" dependencies = [ + "autocfg 1.0.1", "proc-macro-hack", "proc-macro2 1.0.26", "quote 1.0.9", @@ -1534,22 +1539,23 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5629433c555de3d82861a7a4e3794a4c40040390907cfbfd7143a92a426c23" +checksum = "a57bead0ceff0d6dde8f465ecd96c9338121bb7717d3e7b108059531870c4282" [[package]] name = "futures-task" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba7aa51095076f3ba6d9a1f702f74bd05ec65f555d70d2033d55ba8d69f581bc" +checksum = "8a16bef9fc1a4dddb5bee51c989e3fbba26569cbb0e31f5b303c184e3dd33dae" [[package]] name = "futures-util" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c144ad54d60f23927f0a6b6d816e4271278b64f005ad65e4e35291d2de9c025" +checksum = "feb5c238d27e2bf94ffdfd27b2c29e3df4a68c4193bb6427384259e2bf191967" dependencies = [ + "autocfg 1.0.1", "futures-channel", "futures-core", "futures-io", @@ -1659,9 +1665,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.23.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" +checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189" [[package]] name = "glob" @@ -1855,9 +1861,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1ce40d6fc9764887c2fdc7305c3dcc429ba11ff981c1509416afd5697e4437" +checksum = "f3a87b616e37e93c22fb19bcd386f02f3af5ea98a25670ad0fce773de23c5e68" [[package]] name = "httpdate" @@ -2063,9 +2069,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.50" +version = "0.3.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d99f9e3e84b8f67f846ef5b4cbbc3b1c29f6c759fcbce6f01aa0e73d932a24c" +checksum = "83bdfbace3a0e81a4253f73b49e960b053e396a11012cbd49b9b74d6a2b67062" dependencies = [ "wasm-bindgen", ] @@ -2107,9 +2113,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.93" +version = "0.2.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41" +checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e" [[package]] name = "libloading" @@ -2140,9 +2146,9 @@ checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" [[package]] name = "lock_api" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3c91c24eae6777794bb1997ad98bbb87daf92890acab859f7eaa4320333176" +checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb" dependencies = [ "scopeguard 1.1.0", ] @@ -2194,9 +2200,9 @@ checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" [[package]] name = "memchr" -version = "2.3.4" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" +checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" [[package]] name = "memoffset" @@ -2398,9 +2404,9 @@ dependencies = [ [[package]] name = "object" -version = "0.23.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4" +checksum = "1a5b3dd1c072ee7963717671d1ca129f1048fda25edea6b752bfc71ac8854170" [[package]] name = "once_cell" @@ -2422,9 +2428,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.33" +version = "0.10.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a61075b62a23fef5a29815de7536d940aa35ce96d18ce0cc5076272db678a577" +checksum = "6d7830286ad6a3973c0f1d9b73738f69c76b739301d0229c4b96501695cbe4c8" dependencies = [ "bitflags", "cfg-if 1.0.0", @@ -2436,15 +2442,15 @@ dependencies = [ [[package]] name = "openssl-probe" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" +checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" [[package]] name = "openssl-sys" -version = "0.9.61" +version = "0.9.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "313752393519e876837e09e1fa183ddef0be7735868dced3196f4472d536277f" +checksum = "b6b0d6fb7d80f877617dfcb014e605e2b5ab2fb0afdf27935219bb6bd984cb98" dependencies = [ "autocfg 1.0.1", "cc", @@ -2460,7 +2466,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b91cea1dfd50064e52db033179952d18c770cbc5dfefc8eba45d619357ba3914" dependencies = [ "async-trait", - "futures 0.3.14", + "futures 0.3.15", "js-sys", "lazy_static", "percent-encoding", @@ -2503,11 +2509,11 @@ dependencies = [ [[package]] name = "ouroboros" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc53e78022445d2d37b673c5aaeed945a7aacaa4aa89c867c1f28b2e6778e67d" +checksum = "c8234affc3c31a8b744cc236fd3dc7443f57c6370cbb7d61f41f9c7dcc6c2530" dependencies = [ - "ouroboros_macro 0.9.1", + "ouroboros_macro 0.9.2", "stable_deref_trait", ] @@ -2526,9 +2532,9 @@ dependencies = [ [[package]] name = "ouroboros_macro" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee93af29e97048340c10f5c1a1d88c754f48337a41fbd4fb8e1e20ce41c76936" +checksum = "3633332cd8c0b6a865e2e0e705fad9cde25fe458cd0c693629b58a7b15e4d852" dependencies = [ "Inflector", "proc-macro-error", @@ -2714,7 +2720,7 @@ version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eebcc4aa140b9abd2bc40d9c3f7ccec842679cd79045ac3a7ac698c1a064b7cd" dependencies = [ - "cpuid-bool 0.2.0", + "cpuid-bool", "opaque-debug 0.3.0", "universal-hash", ] @@ -2776,7 +2782,7 @@ version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" dependencies = [ - "unicode-xid 0.2.1", + "unicode-xid 0.2.2", ] [[package]] @@ -3129,18 +3135,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8270314b5ccceb518e7e578952f0b72b88222d02e8f77f5ecf7abbb673539041" +checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.4.6" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a26af418b574bd56588335b3a3659a65725d4e636eb1016c2f9e3b38c7cc759" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" dependencies = [ "aho-corasick", "memchr", @@ -3159,9 +3165,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.23" +version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "remove_dir_all" @@ -3247,9 +3253,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232" +checksum = "410f7acf3cb3a44527c5d9546bad4bf4e6c460915d5f9f2fc524498bfe8f70ce" [[package]] name = "rustc-hash" @@ -3365,7 +3371,7 @@ dependencies = [ "cookie", "dbg", "enclose", - "futures 0.3.14", + "futures 0.3.15", "gloo-file", "gloo-timers", "indexmap", @@ -3417,18 +3423,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.125" +version = "1.0.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" +checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.125" +version = "1.0.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" +checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43" dependencies = [ "proc-macro2 1.0.26", "quote 1.0.9", @@ -3473,13 +3479,13 @@ dependencies = [ [[package]] name = "sha-1" -version = "0.9.4" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfebf75d25bd900fd1e7d11501efab59bc846dbc76196839663e6637bba9f25f" +checksum = "8c4cfa741c5832d0ef7fab46cabed29c2aae926db0b11bb2069edd8db5e64e16" dependencies = [ "block-buffer 0.9.0", "cfg-if 1.0.0", - "cpuid-bool 0.1.2", + "cpufeatures", "digest 0.9.0", "opaque-debug 0.3.0", ] @@ -3492,13 +3498,13 @@ checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" [[package]] name = "sha2" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa827a14b29ab7f44778d14a88d3cb76e949c45083f7dbfa507d0cb699dc12de" +checksum = "b362ae5752fd2137731f9fa25fd4d9058af34666ca1966fb969119cc35719f12" dependencies = [ "block-buffer 0.9.0", "cfg-if 1.0.0", - "cpuid-bool 0.1.2", + "cpufeatures", "digest 0.9.0", "opaque-debug 0.3.0", ] @@ -3597,9 +3603,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "spinning_top" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bd0ab6b8c375d2d963503b90d3770010d95bc3b5f98036f948dee24bf4e8879" +checksum = "75adad84ee84b521fb2cca2d4fd0f1dab1d8d026bda3c5bea4ca63b5f9f9293c" dependencies = [ "lock_api", ] @@ -3680,7 +3686,7 @@ dependencies = [ "cargo_metadata", "dotenv", "either", - "futures 0.3.14", + "futures 0.3.15", "heck", "hex", "lazy_static", @@ -3820,13 +3826,13 @@ checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" [[package]] name = "syn" -version = "1.0.70" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9505f307c872bab8eb46f77ae357c8eba1fdacead58ee5a850116b1d7f82883" +checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82" dependencies = [ "proc-macro2 1.0.26", "quote 1.0.9", - "unicode-xid 0.2.1", + "unicode-xid 0.2.2", ] [[package]] @@ -3838,7 +3844,7 @@ dependencies = [ "proc-macro2 1.0.26", "quote 1.0.9", "syn", - "unicode-xid 0.2.1", + "unicode-xid 0.2.2", ] [[package]] @@ -4126,9 +4132,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" -version = "0.1.25" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01ebdc2bb4498ab1ab5f5b73c5803825e60199229ccba0698170e3be0e7f959f" +checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d" dependencies = [ "cfg-if 1.0.0", "log", @@ -4144,7 +4150,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc36fc2f840643e49d220d07cd7ca81bc31c7f6df25f164d4257971533dab354" dependencies = [ "actix-web", - "futures 0.3.14", + "futures 0.3.15", "tracing", "tracing-futures", "uuid", @@ -4163,9 +4169,9 @@ dependencies = [ [[package]] name = "tracing-bunyan-formatter" -version = "0.2.0" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05e6b1b6c038da11d8d704f93b3974b0394824cdcc8c818c48255183cf315fd5" +checksum = "dce1eae70720bd6bb3944f7cf501761aeae658bd1f9293aa373c71a195064910" dependencies = [ "chrono", "gethostname", @@ -4180,9 +4186,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f" +checksum = "a9ff14f98b1a4b289c6248a023c1c2fa1491062964e9fed67ab29c4e4da4a052" dependencies = [ "lazy_static", ] @@ -4233,9 +4239,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "705096c6f83bf68ea5d357a6aa01829ddbdac531b357b45abeca842938085baa" +checksum = "aa5553bf0883ba7c9cbe493b085c29926bd41b66afc31ff72cf17ff4fb60dcd5" dependencies = [ "ansi_term 0.12.1", "chrono", @@ -4262,7 +4268,7 @@ dependencies = [ "async-trait", "cfg-if 1.0.0", "enum-as-inner", - "futures 0.3.14", + "futures 0.3.15", "idna", "lazy_static", "log", @@ -4280,7 +4286,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "710f593b371175db53a26d0b38ed2978fafb9e9e8d3868b1acd753ea18df0ceb" dependencies = [ "cfg-if 0.1.10", - "futures 0.3.14", + "futures 0.3.15", "ipconfig", "lazy_static", "log", @@ -4459,9 +4465,9 @@ checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" [[package]] name = "unicode-xid" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "unicode_categories" @@ -4487,9 +4493,9 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.2.1" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ccd964113622c8e9322cfac19eb1004a07e636c545f325da085d5cdde6f1f8b" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" dependencies = [ "form_urlencoded", "idna", @@ -4597,9 +4603,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "wasm-bindgen" -version = "0.2.73" +version = "0.2.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9" +checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd" dependencies = [ "cfg-if 1.0.0", "serde", @@ -4609,9 +4615,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.73" +version = "0.2.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae70622411ca953215ca6d06d3ebeb1e915f0f6613e3b495122878d7ebec7dae" +checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900" dependencies = [ "bumpalo", "lazy_static", @@ -4624,9 +4630,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.23" +version = "0.4.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81b8b767af23de6ac18bf2168b690bed2902743ddf0fb39252e36f9e2bfc63ea" +checksum = "5fba7978c679d53ce2d0ac80c8c175840feb849a161664365d1287b41f2e67f1" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -4636,9 +4642,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.73" +version = "0.2.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f" +checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4" dependencies = [ "quote 1.0.9", "wasm-bindgen-macro-support", @@ -4646,9 +4652,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.73" +version = "0.2.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c" +checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97" dependencies = [ "proc-macro2 1.0.26", "quote 1.0.9", @@ -4659,15 +4665,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.73" +version = "0.2.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9a543ae66aa233d14bb765ed9af4a33e81b8b58d1584cf1b47ff8cd0b9e4489" +checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f" [[package]] name = "web-sys" -version = "0.3.50" +version = "0.3.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a905d57e488fec8861446d3393670fb50d27a262344013181c2cdf9fff5481be" +checksum = "e828417b379f3df7111d3a2a9e5753706cae29c41f7c4029ee9fd77f3e09e582" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index b692ff7..7f8e797 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,4 +2,10 @@ members = [ "pslink", "app", -] \ No newline at end of file +] + +[profile] +[profile.release] +lto = true +#codegen-units = 1 +opt-level = 'z' \ No newline at end of file diff --git a/app/Cargo.toml b/app/Cargo.toml index c44b41f..d39a60c 100644 --- a/app/Cargo.toml +++ b/app/Cargo.toml @@ -19,12 +19,9 @@ crate-type = ["cdylib", "rlib"] fluent = "0.15" seed = "0.8" serde = "1.0" -strum_macros = "0.20" unic-langid = "0.9" +strum_macros = "0.20" strum = "0.20" enum-map = "1" shared = { path = "../shared" } - -[profile.release] -opt-level = 'z' \ No newline at end of file diff --git a/app/locales/de/main.ftl b/app/locales/de/main.ftl index 7ec4cc2..b6617d1 100644 --- a/app/locales/de/main.ftl +++ b/app/locales/de/main.ftl @@ -28,9 +28,11 @@ edit-user-headline = Benutzereinstellungen von: {$username} username = Benutzername email = Email 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 edit-user = Benutzer editieren +create-user = Benutzer Erstellen +new-user = Neuer Benutzer make-user-admin = Zum Administrator befördern make-user-regular = Zurückstufen zum normalen Nutzer diff --git a/app/locales/en/main.ftl b/app/locales/en/main.ftl index 6e7a2ab..a3bbf75 100644 --- a/app/locales/en/main.ftl +++ b/app/locales/en/main.ftl @@ -28,9 +28,11 @@ edit-user-headline = Change Settings of: {$username} username = Username email = Email 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 edit-user = Edit this user +new-user = Neuer Benutzer +create-user = Create user make-user-admin = Promote to admin make-user-regular = Demote to regular diff --git a/app/src/lib.rs b/app/src/lib.rs index 702721e..60ce3b2 100644 --- a/app/src/lib.rs +++ b/app/src/lib.rs @@ -49,13 +49,13 @@ enum Page { impl Page { fn init(mut url: Url, orders: &mut impl Orders, i18n: I18n) -> Self { url.next_path_part(); - let result = match url.remaining_path_parts().as_slice() { - [] | ["list_links"] => Self::Home(pages::list_links::init( + let result = match url.next_path_part() { + None | Some("list_links") => Self::Home(pages::list_links::init( url, &mut orders.proxy(Msg::ListLinksMsg), i18n, )), - ["list_users"] => Self::ListUsers(pages::list_users::init( + Some("list_users") => Self::ListUsers(pages::list_users::init( url, &mut orders.proxy(Msg::ListUsersMsg), i18n, @@ -144,6 +144,10 @@ impl<'a> Urls<'a> { pub fn list_users(self) -> Url { self.base_url().add_path_part("list_users") } + #[must_use] + pub fn create_user(self) -> Url { + self.list_users().add_path_part("create_user") + } } // ------ ------ diff --git a/app/src/navigation.rs b/app/src/navigation.rs index cf619af..4c307cb 100644 --- a/app/src/navigation.rs +++ b/app/src/navigation.rs @@ -25,8 +25,12 @@ pub fn navigation(i18n: &I18n, base_url: &Url) -> Node { ],], li![a![ev(Ev::Click, |_| Msg::NoMessage), t!("add-link"),],], li![a![ - attrs! {At::Href => "#"}, - ev(Ev::Click, |_| Msg::NoMessage), + attrs! {At::Href => crate::Urls::new(base_url).create_user()}, + ev(Ev::Click, |_| Msg::ListUsersMsg( + super::pages::list_users::Msg::Edit( + super::pages::list_users::UserEditMsg::CreateNewUser + ) + )), t!("invite-user"), ],], li![a![ diff --git a/app/src/pages/list_users.rs b/app/src/pages/list_users.rs index 1900448..715ecc7 100644 --- a/app/src/pages/list_users.rs +++ b/app/src/pages/list_users.rs @@ -1,21 +1,33 @@ +use std::cell::RefCell; + 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::{ apirequests::general::{Operation, Ordering}, - apirequests::users::{UserOverviewColumns, UserRequestForm}, + apirequests::{ + general::{EditMode, SuccessMessage}, + users::{UserDelta, UserOverviewColumns, UserRequestForm}, + }, datatypes::User, }; use crate::i18n::I18n; #[must_use] -pub fn init(_: Url, orders: &mut impl Orders, i18n: I18n) -> Model { - orders.send_msg(Msg::Fetch); +pub fn init(mut url: Url, orders: &mut impl Orders, i18n: I18n) -> Model { + 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 { users: Vec::new(), i18n, formconfig: UserRequestForm::default(), inputs: EnumMap::default(), - user_edit: None, + user_edit, + last_message: None, } } #[derive(Debug)] @@ -24,13 +36,8 @@ pub struct Model { i18n: I18n, formconfig: UserRequestForm, inputs: EnumMap, - user_edit: Option, -} - -#[derive(Debug)] -enum UserEditMode { - Create { user: User }, - Edit { user: User }, + user_edit: Option>, + last_message: Option, } #[derive(Default, Debug, Clone)] @@ -40,32 +47,61 @@ struct FilterInput { #[derive(Clone)] pub enum Msg { + Query(UserQueryMsg), + Edit(UserEditMsg), +} + +/// All the messages on user Querying +#[derive(Clone)] +pub enum UserQueryMsg { Fetch, + FailedToFetchUsers, OrderBy(UserOverviewColumns), Received(Vec), IdFilterChanged(String), EmailFilterChanged(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 /// Sould only panic on bugs. pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders) { 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) { + match msg { + UserQueryMsg::Fetch => { orders.skip(); // No need to rerender let data = model.formconfig.clone(); // complicated way to move into the closure orders.perform_cmd(async { let data = data; - let response = fetch( + let response = match fetch( Request::new("/admin/json/list_users/") .method(Method::Post) .json(&data) .expect("serialization failed"), ) .await - .expect("HTTP request failed"); + { + Ok(response) => response, + Err(_) => return Msg::Query(UserQueryMsg::FailedToFetchUsers), + }; let users: Vec = response .check_status() // ensure we've got 2xx status @@ -74,10 +110,10 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders) { .await .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( || { Some(Operation { @@ -96,7 +132,7 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders) { }) }, ); - orders.send_msg(Msg::Fetch); + orders.send_msg(Msg::Query(UserQueryMsg::Fetch)); model.users.sort_by(match column { 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) { UserOverviewColumns::Email => |o: &User, t: &User| o.email.cmp(&t.email), }) } - Msg::Received(response) => { + UserQueryMsg::Received(response) => { model.users = response; } - Msg::IdFilterChanged(s) => { + UserQueryMsg::IdFilterChanged(s) => { log!("Filter is: ", &s); let sanit = s.chars().filter(|x| x.is_numeric()).collect(); 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); let sanit = s.chars().filter(|x| x.is_alphanumeric()).collect(); 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); // FIXME: Sanitazion does not work for @ let sanit = s.chars().filter(|x| x.is_alphanumeric()).collect(); model.formconfig.filter[UserOverviewColumns::Email].sieve = sanit; - orders.send_msg(Msg::Fetch); + orders.send_msg(Msg::Query(UserQueryMsg::Fetch)); } - Msg::EditUserSelected(user) => { - log!("Editing user: ", user); - model.user_edit = Some(UserEditMode::Edit { user }) + + UserQueryMsg::FailedToFetchUsers => { + log!("Failed to fetch users"); } } } +pub fn process_user_edit_messages( + msg: UserEditMsg, + model: &mut Model, + orders: &mut impl Orders, +) { + match msg { + UserEditMsg::EditUserSelected(user) => { + log!("Editing user: ", 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] /// # Panics /// Sould only panic on bugs. @@ -140,6 +257,11 @@ pub fn view(model: &Model) -> Node { let t = move |key: &str| lang.translate(key, None); section![ h1!("List Users Page from list_users"), + if let Some(message) = &model.last_message { + div![C!("Message"), &message.message] + } else { + section!() + }, table![ // Column Headlines view_user_table_head(&t), @@ -148,22 +270,36 @@ pub fn view(model: &Model) -> Node { // Add all the users one line for each 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 String>(t: F) -> Node { tr![ th![ - ev(Ev::Click, |_| Msg::OrderBy(UserOverviewColumns::Id)), + ev(Ev::Click, |_| Msg::Query(UserQueryMsg::OrderBy( + UserOverviewColumns::Id + ))), t("userid") ], th![ - ev(Ev::Click, |_| Msg::OrderBy(UserOverviewColumns::Email)), + ev(Ev::Click, |_| Msg::Query(UserQueryMsg::OrderBy( + UserOverviewColumns::Email + ))), t("email") ], th![ - ev(Ev::Click, |_| Msg::OrderBy(UserOverviewColumns::Username)), + ev(Ev::Click, |_| Msg::Query(UserQueryMsg::OrderBy( + UserOverviewColumns::Username + ))), t("username") ], ] @@ -178,7 +314,9 @@ fn view_user_table_filter_input String>(model: &Model, t: F) -> N At::Type => "search", 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), ]], td![input![ @@ -188,7 +326,9 @@ fn view_user_table_filter_input String>(model: &Model, t: F) -> N At::Type => "search", 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), ]], td![input![ @@ -198,19 +338,100 @@ fn view_user_table_filter_input String>(model: &Model, t: F) -> N At::Type => "search", 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), ]], ] } fn view_user(l: &User) -> Node { - let user = l.clone(); + let user = UserDelta::from(l.clone()); tr![ - ev(Ev::Click, |_| Msg::EditUserSelected(user)), + ev(Ev::Click, |_| Msg::Edit(UserEditMsg::EditUserSelected( + user + ))), td![&l.id], td![&l.email], //td![a![attrs![At::Href => &l.link.target], &l.link.target]], td![&l.username], ] } + +fn edit_or_create_user String>(l: &RefCell, t: F) -> Node { + 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)) + ] + ] +} diff --git a/pslink/Cargo.toml b/pslink/Cargo.toml index 06f8821..ac3f1de 100644 --- a/pslink/Cargo.toml +++ b/pslink/Cargo.toml @@ -71,8 +71,3 @@ tokio = "0.2.25" [dev-dependencies.reqwest] features = ["cookies"] version = "0.10.10" - -[profile] -[profile.release] -lto = true -#codegen-units = 1 \ No newline at end of file diff --git a/pslink/src/lib.rs b/pslink/src/lib.rs index 4536894..2264c2f 100644 --- a/pslink/src/lib.rs +++ b/pslink/src/lib.rs @@ -370,7 +370,11 @@ pub async fn webservice( .service( web::scope("/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 .route("/login/", web::get().to(views::login)) diff --git a/pslink/src/models.rs b/pslink/src/models.rs index 63769dd..4ad2061 100644 --- a/pslink/src/models.rs +++ b/pslink/src/models.rs @@ -23,7 +23,7 @@ pub trait UserDbOperations { } #[async_trait] -impl UserDbOperations for User { +impl UserDbOperations for User { async fn get_user(id: i64, server_config: &ServerConfig) -> Result { let user = sqlx::query_as!(Self, "Select * from users where id = ? ", id) .fetch_one(&server_config.db_pool) @@ -186,7 +186,7 @@ pub trait LinkDbOperations { } #[async_trait] -impl LinkDbOperations for Link { +impl LinkDbOperations for Link { async fn get_link_by_code( code: &str, server_config: &ServerConfig, diff --git a/pslink/src/queries.rs b/pslink/src/queries.rs index c1a2e1c..862e458 100644 --- a/pslink/src/queries.rs +++ b/pslink/src/queries.rs @@ -6,7 +6,7 @@ use shared::{ apirequests::{ general::{Filter, Operation, Ordering}, links::{LinkOverviewColumns, LinkRequestForm}, - users::{UserOverviewColumns, UserRequestForm}, + users::{UserDelta, UserOverviewColumns, UserRequestForm}, }, 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, + server_config: &ServerConfig, +) -> Result, 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`] 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 `user_id` is never changed. diff --git a/pslink/src/views.rs b/pslink/src/views.rs index 83ddda2..48a4873 100644 --- a/pslink/src/views.rs +++ b/pslink/src/views.rs @@ -14,7 +14,11 @@ use fluent_templates::LanguageIdentifier; use image::{DynamicImage, ImageOutputFormat, Luma}; use qrcode::{render::svg, QrCode}; 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 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, + form: web::Json, + id: Identity, +) -> Result { + 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))] pub async fn toggle_admin( data: web::Path, diff --git a/pslink/static/admin.css b/pslink/static/admin.css index 6b1d8d3..5566103 100644 --- a/pslink/static/admin.css +++ b/pslink/static/admin.css @@ -1,163 +1,173 @@ - body { - margin: 0; - padding: 0; + margin: 0; + padding: 0; } form { - width: 100%; + width: 100%; } + .center { -position: absolute; -width: 400px; -height: 400px; -top: 50%; -left: 50%; -margin-left: -200px; -margin-top: -200px; -display: flex; -flex-direction: column; -justify-content: center; -align-items: center; -padding: 30px; -color: #333; + position: absolute; + width: 600px; + max-width: 100%; + height: 400px; + max-height: 100%; + top: 50%; + left: 50%; + margin-left: -300px; + margin-top: -200px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding: 30px; + color: #333; } + .center input { -width: 100%; -padding: 15px; -margin: 5px; -border-radius: 1px; -border: 1px solid rgb(90, 90, 90); -font-family: inherit; -background-color: #eae9ea; + width: 100%; + padding: 0; + margin: 0; + border-radius: 1px; + border: 1px solid rgb(90, 90, 90); + font-family: inherit; + background-color: #eae9ea; } -.center { -width: 800px; -height: 600px; -margin-left: -400px; -margin-top: -300px; - +.center table p { + font-size: x-small; + margin: 0; } table { -border-collapse: collapse; -width: 100%; + border-collapse: collapse; + width: 100%; } -th, td { -text-align: center; -border: 1px solid #ccc; -padding: 10px; +th, +td { + text-align: center; + border: 1px solid #ccc; + padding: 10px; } table tr:nth-child(even) { -background-color: #eee; + background-color: #eee; } + table tr:nth-child(odd) { -background-color: #fff; -} + background-color: #fff; +} table tr.filters input { - background-image: url("/static/search.svg"); - background-repeat: no-repeat; - background-size: contain; - width: 100%; - padding: 5px; - height: 20px; - text-align: center; - border-radius: 0; - border: none; + background-image: url("/static/search.svg"); + background-repeat: no-repeat; + background-size: contain; + width: 100%; + padding: 5px; + height: 20px; + text-align: center; + border-radius: 0; + border: none; } table tr.filters td { - padding:5px; + padding: 5px; } nav { -display: flex; -flex-flow: row wrap; -justify-content: space-between; -align-items:stretch; -width:100%; -height: 60px; -} -nav ol { - display:flex; - align-items: center; - list-style-type: none; - margin: 0; - padding: 0; - height: 40px; + display: flex; + flex-flow: row wrap; + justify-content: space-between; + align-items: stretch; + width: 100%; + height: 60px; } -nav li a, nav li div.willkommen { - color: white; - text-align: center; - padding: 14px 16px; - text-decoration: none; - border-radius: 0 0 10px 10px; +nav ol { + display: flex; + align-items: center; + list-style-type: none; + margin: 0; + padding: 0; + height: 40px; +} + +nav li a, +nav li div.willkommen { + color: white; + text-align: center; + padding: 14px 16px; + text-decoration: none; + border-radius: 0 0 10px 10px; } nav li a { -background: rgb(2,0,36); -background: linear-gradient(180deg, rgba(2,0,36,1) 0%, rgba(9,9,121,1) 35%, rgb(0, 145, 174) 100%); + background: rgb(2, 0, 36); + background: linear-gradient(180deg, rgba(2, 0, 36, 1) 0%, rgba(9, 9, 121, 1) 35%, rgb(0, 145, 174) 100%); } nav li { - float: left; + float: left; } + nav li a:hover { -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: 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%); } nav li { - margin: 5px; + margin: 5px; } -nav li div{ - background-color: burlywood; - text-align: center; - padding: 14px 16px; - border-radius: 0 0 10px 10px; +nav li div { + background-color: burlywood; + text-align: center; + padding: 14px 16px; + border-radius: 0 0 10px 10px; } - svg { -width: 100px; -height: 100px; + width: 100px; + height: 100px; } div.actions { -margin-left:5px; -display: flex; -width:100%; -align-items: center; -padding: 10px; -color: #333; -flex-flow: row wrap; -justify-content: center; + margin-left: 5px; + display: flex; + width: 100%; + align-items: center; + padding: 10px; + color: #333; + flex-flow: row wrap; + justify-content: center; } div.danger { -background-color: rgb(235, 127, 77); -font-size: smaller; -border: 2px solid crimson; + background-color: rgb(235, 127, 77); + font-size: smaller; + border: 2px solid crimson; } div.danger h3 { -width:100%; + width: 100%; } -a.button, div.actions input { -width: 250px; -display:block; -padding: 15px; -margin-left: 15px; -text-align: center; -border-radius: 1px; -border: 1px solid rgb(90, 90, 90); -font-family: inherit; -background-color: #eae9ea; +a.button, +div.actions input { + width: 250px; + display: block; + padding: 15px; + margin-left: 15px; + text-align: center; + border-radius: 1px; + border: 1px solid rgb(90, 90, 90); + font-family: inherit; + background-color: #eae9ea; +} + +div.editdialog { + background-color: aliceblue; + border: 5px solid rgb(90, 90, 90); } \ No newline at end of file diff --git a/shared/src/apirequests/general.rs b/shared/src/apirequests/general.rs index 38eda01..1bf183c 100644 --- a/shared/src/apirequests/general.rs +++ b/shared/src/apirequests/general.rs @@ -25,3 +25,20 @@ pub struct Operation { pub column: T, 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, +} diff --git a/shared/src/apirequests/users.rs b/shared/src/apirequests/users.rs index e0a6514..9f579d0 100644 --- a/shared/src/apirequests/users.rs +++ b/shared/src/apirequests/users.rs @@ -1,12 +1,17 @@ use enum_map::{Enum, EnumMap}; 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)] pub struct UserRequestForm { + // The filters up to one for each column pub filter: EnumMap, + // Order According to this column pub order: Option>, + // Return a maximum of `amount` results 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, + pub username: String, + pub email: String, + pub password: Option, +} + +impl From 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)] pub enum UserOverviewColumns { Id,