feat: WIP implement event planning

This commit is contained in:
Max Hohlfeld 2024-12-01 00:00:06 +01:00
parent 95ca418875
commit 073cc8275b
19 changed files with 661 additions and 333 deletions

311
Cargo.lock generated
View File

@ -104,7 +104,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb"
dependencies = [
"quote",
"syn 2.0.79",
"syn 2.0.90",
]
[[package]]
@ -238,7 +238,7 @@ dependencies = [
"actix-router",
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.90",
]
[[package]]
@ -353,9 +353,9 @@ dependencies = [
[[package]]
name = "allocator-api2"
version = "0.2.18"
version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9"
[[package]]
name = "android-tzdata"
@ -374,9 +374,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.89"
version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6"
checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775"
[[package]]
name = "argon2"
@ -426,7 +426,7 @@ dependencies = [
"proc-macro2",
"quote",
"serde",
"syn 2.0.79",
"syn 2.0.90",
]
[[package]]
@ -497,9 +497,9 @@ dependencies = [
[[package]]
name = "async-io"
version = "2.3.4"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8"
checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059"
dependencies = [
"async-lock",
"cfg-if",
@ -603,7 +603,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.90",
]
[[package]]
@ -792,9 +792,9 @@ dependencies = [
[[package]]
name = "built"
version = "0.7.4"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "236e6289eda5a812bc6b53c3b024039382a2895fbbeef2d748b2931546d392c4"
checksum = "c360505aed52b7ec96a3636c3f039d99103c37d1d9b4f7a8c743d3ea9ffcd03b"
[[package]]
name = "bumpalo"
@ -810,24 +810,24 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "bytes"
version = "1.7.2"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3"
checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
[[package]]
name = "bytestring"
version = "1.3.1"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74d80203ea6b29df88012294f62733de21cfeab47f17b41af3a38bc30a03ee72"
checksum = "e465647ae23b2823b0753f50decb2d5a86d2bb2cac04788fafd1f80e45378e5f"
dependencies = [
"bytes",
]
[[package]]
name = "cc"
version = "1.1.30"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945"
checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc"
dependencies = [
"jobserver",
"libc",
@ -936,9 +936,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "cpufeatures"
version = "0.2.14"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0"
checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3"
dependencies = [
"libc",
]
@ -1023,7 +1023,7 @@ dependencies = [
"proc-macro2",
"quote",
"strsim",
"syn 2.0.79",
"syn 2.0.90",
]
[[package]]
@ -1034,7 +1034,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
dependencies = [
"darling_core",
"quote",
"syn 2.0.79",
"syn 2.0.90",
]
[[package]]
@ -1064,7 +1064,7 @@ dependencies = [
"darling",
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.90",
]
[[package]]
@ -1074,7 +1074,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
dependencies = [
"derive_builder_core",
"syn 2.0.79",
"syn 2.0.90",
]
[[package]]
@ -1087,7 +1087,7 @@ dependencies = [
"proc-macro2",
"quote",
"rustc_version",
"syn 2.0.79",
"syn 2.0.90",
]
[[package]]
@ -1129,7 +1129,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.90",
]
[[package]]
@ -1152,9 +1152,9 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "email-encoding"
version = "0.3.0"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60d1d33cdaede7e24091f039632eb5d3c7469fe5b066a985281a34fc70fa317f"
checksum = "ea3d894bbbab314476b265f9b2d46bf24b123a36dd0e96b06a1b49545b9d9dcc"
dependencies = [
"base64 0.22.1",
"memchr",
@ -1168,9 +1168,9 @@ checksum = "e079f19b08ca6239f47f8ba8509c11cf3ea30095831f7fed61441475edd8c449"
[[package]]
name = "encoding_rs"
version = "0.8.34"
version = "0.8.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59"
checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
dependencies = [
"cfg-if",
]
@ -1183,12 +1183,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "errno"
version = "0.3.9"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
dependencies = [
"libc",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
@ -1231,15 +1231,15 @@ dependencies = [
[[package]]
name = "fastrand"
version = "2.1.1"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4"
[[package]]
name = "flate2"
version = "1.0.34"
version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0"
checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c"
dependencies = [
"crc32fast",
"miniz_oxide",
@ -1310,9 +1310,9 @@ checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
[[package]]
name = "futures-lite"
version = "2.3.0"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5"
checksum = "cef40d21ae2c515b51041df9ed313ed21e572df340ea58a922a0aefe7e8891a1"
dependencies = [
"fastrand",
"futures-core",
@ -1329,7 +1329,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.90",
]
[[package]]
@ -1464,9 +1464,9 @@ dependencies = [
[[package]]
name = "hashbrown"
version = "0.15.0"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
[[package]]
name = "hashlink"
@ -1486,12 +1486,6 @@ dependencies = [
"unicode-segmentation",
]
[[package]]
name = "hermit-abi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
[[package]]
name = "hermit-abi"
version = "0.4.0"
@ -1709,7 +1703,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.90",
]
[[package]]
@ -1720,24 +1714,23 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "idna"
version = "0.5.0"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
dependencies = [
"unicode-bidi",
"unicode-normalization",
"idna_adapter",
"smallvec",
"utf8_iter",
]
[[package]]
name = "idna"
version = "1.0.2"
name = "idna_adapter"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd69211b9b519e98303c015e21a007e293db403b6c85b9b124e133d25e242cdd"
checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
dependencies = [
"icu_normalizer",
"icu_properties",
"smallvec",
"utf8_iter",
]
[[package]]
@ -1763,7 +1756,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
dependencies = [
"equivalent",
"hashbrown 0.15.0",
"hashbrown 0.15.2",
]
[[package]]
@ -1795,9 +1788,9 @@ dependencies = [
[[package]]
name = "itoa"
version = "1.0.11"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
[[package]]
name = "jobserver"
@ -1810,10 +1803,11 @@ dependencies = [
[[package]]
name = "js-sys"
version = "0.3.72"
version = "0.3.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9"
checksum = "a865e038f7f6ed956f788f0d7d60c541fff74c7bd74272c5d4cf15c63743e705"
dependencies = [
"once_cell",
"wasm-bindgen",
]
@ -1840,9 +1834,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "lettre"
version = "0.11.9"
version = "0.11.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69f204773bab09b150320ea1c83db41dc6ee606a4bc36dc1f43005fe7b58ce06"
checksum = "0161e452348e399deb685ba05e55ee116cae9410f4f51fe42d597361444521d9"
dependencies = [
"base64 0.22.1",
"chumsky",
@ -1852,7 +1846,7 @@ dependencies = [
"futures-util",
"hostname",
"httpdate",
"idna 1.0.2",
"idna",
"mime",
"native-tls",
"nom",
@ -1865,15 +1859,15 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.160"
version = "0.2.167"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0b21006cd1874ae9e650973c565615676dc4a274c965bb0a73796dac838ce4f"
checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc"
[[package]]
name = "libm"
version = "0.2.8"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa"
[[package]]
name = "libredox"
@ -1893,9 +1887,9 @@ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
[[package]]
name = "litemap"
version = "0.7.3"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704"
checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104"
[[package]]
name = "local-channel"
@ -1982,11 +1976,10 @@ dependencies = [
[[package]]
name = "mio"
version = "1.0.2"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
dependencies = [
"hermit-abi 0.3.9",
"libc",
"log",
"wasi",
@ -2079,7 +2072,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.90",
]
[[package]]
@ -2200,9 +2193,9 @@ checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315"
[[package]]
name = "pin-project-lite"
version = "0.2.14"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff"
[[package]]
name = "pin-utils"
@ -2229,13 +2222,13 @@ checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
[[package]]
name = "polling"
version = "3.7.3"
version = "3.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511"
checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f"
dependencies = [
"cfg-if",
"concurrent-queue",
"hermit-abi 0.4.0",
"hermit-abi",
"pin-project-lite",
"rustix",
"tracing",
@ -2271,18 +2264,18 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.88"
version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9"
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
dependencies = [
"unicode-ident",
]
[[package]]
name = "psm"
version = "0.1.23"
version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa37f80ca58604976033fae9515a8a2989fc13797d953f7c04fb8fa36a11f205"
checksum = "200b9ff220857e53e184257720a14553b2f4aa02577d2ed9842d45d4b9654810"
dependencies = [
"cc",
]
@ -2373,9 +2366,9 @@ dependencies = [
[[package]]
name = "regex"
version = "1.11.0"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8"
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
@ -2385,9 +2378,9 @@ dependencies = [
[[package]]
name = "regex-automata"
version = "0.4.8"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
@ -2453,9 +2446,9 @@ dependencies = [
[[package]]
name = "rustix"
version = "0.38.37"
version = "0.38.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811"
checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6"
dependencies = [
"bitflags 2.6.0",
"errno",
@ -2493,9 +2486,9 @@ checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]]
name = "schannel"
version = "0.1.26"
version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1"
checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d"
dependencies = [
"windows-sys 0.59.0",
]
@ -2531,9 +2524,9 @@ dependencies = [
[[package]]
name = "security-framework-sys"
version = "2.12.0"
version = "2.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6"
checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2"
dependencies = [
"core-foundation-sys",
"libc",
@ -2547,29 +2540,29 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
[[package]]
name = "serde"
version = "1.0.210"
version = "1.0.215"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.210"
version = "1.0.215"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.90",
]
[[package]]
name = "serde_json"
version = "1.0.128"
version = "1.0.133"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377"
dependencies = [
"itoa",
"memchr",
@ -2643,9 +2636,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
[[package]]
name = "socket2"
version = "0.5.7"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8"
dependencies = [
"libc",
"windows-sys 0.52.0",
@ -2831,9 +2824,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.79"
version = "2.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
dependencies = [
"proc-macro2",
"quote",
@ -2848,14 +2841,14 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.90",
]
[[package]]
name = "tempfile"
version = "3.13.0"
version = "3.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b"
checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c"
dependencies = [
"cfg-if",
"fastrand",
@ -2866,22 +2859,22 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.64"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84"
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.64"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3"
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.90",
]
[[package]]
@ -2942,9 +2935,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
version = "1.40.0"
version = "1.41.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998"
checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33"
dependencies = [
"backtrace",
"bytes",
@ -2972,9 +2965,9 @@ dependencies = [
[[package]]
name = "tracing"
version = "0.1.40"
version = "0.1.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
dependencies = [
"log",
"pin-project-lite",
@ -2983,9 +2976,9 @@ dependencies = [
[[package]]
name = "tracing-core"
version = "0.1.32"
version = "0.1.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
dependencies = [
"once_cell",
]
@ -2998,12 +2991,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "unicase"
version = "2.7.0"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89"
dependencies = [
"version_check",
]
checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df"
[[package]]
name = "unicode-bidi"
@ -3013,9 +3003,9 @@ checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893"
[[package]]
name = "unicode-ident"
version = "1.0.13"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
[[package]]
name = "unicode-normalization"
@ -3068,12 +3058,12 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]]
name = "url"
version = "2.5.2"
version = "2.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c"
checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
dependencies = [
"form_urlencoded",
"idna 0.5.0",
"idna",
"percent-encoding",
]
@ -3097,9 +3087,9 @@ checksum = "4e8257fbc510f0a46eb602c10215901938b5c2a7d5e70fc11483b1d3c9b5b18c"
[[package]]
name = "value-bag"
version = "1.9.0"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101"
checksum = "3ef4c4aa54d5d05a279399bfa921ec387b7aba77caf7a682ae8d86785b8fdad2"
[[package]]
name = "vcpkg"
@ -3127,9 +3117,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b"
[[package]]
name = "wasm-bindgen"
version = "0.2.95"
version = "0.2.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e"
checksum = "d15e63b4482863c109d70a7b8706c1e364eb6ea449b201a76c5b89cedcec2d5c"
dependencies = [
"cfg-if",
"once_cell",
@ -3138,36 +3128,37 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.95"
version = "0.2.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358"
checksum = "8d36ef12e3aaca16ddd3f67922bc63e48e953f126de60bd33ccc0101ef9998cd"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.90",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.45"
version = "0.4.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b"
checksum = "9dfaf8f50e5f293737ee323940c7d8b08a66a95a419223d9f41610ca08b0833d"
dependencies = [
"cfg-if",
"js-sys",
"once_cell",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.95"
version = "0.2.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56"
checksum = "705440e08b42d3e4b36de7d66c944be628d579796b8090bfa3471478a2260051"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@ -3175,28 +3166,28 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.95"
version = "0.2.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68"
checksum = "98c9ae5a76e46f4deecd0f0255cc223cfa18dc9b261213b8aa0c7b36f61b3f1d"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.90",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.95"
version = "0.2.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
checksum = "6ee99da9c5ba11bd675621338ef6fa52296b76b83305e9b6e5c77d4c286d6d49"
[[package]]
name = "web-sys"
version = "0.3.72"
version = "0.3.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112"
checksum = "a98bc3c33f0fe7e59ad7cd041b89034fa82a7c2d4365ca538dda6cdaf513863c"
dependencies = [
"js-sys",
"wasm-bindgen",
@ -3369,9 +3360,9 @@ checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
[[package]]
name = "yoke"
version = "0.7.4"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5"
checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40"
dependencies = [
"serde",
"stable_deref_trait",
@ -3381,13 +3372,13 @@ dependencies = [
[[package]]
name = "yoke-derive"
version = "0.7.4"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95"
checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.90",
"synstructure",
]
@ -3409,27 +3400,27 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.90",
]
[[package]]
name = "zerofrom"
version = "0.1.4"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55"
checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e"
dependencies = [
"zerofrom-derive",
]
[[package]]
name = "zerofrom-derive"
version = "0.1.4"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5"
checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.90",
"synstructure",
]
@ -3452,7 +3443,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
"syn 2.0.90",
]
[[package]]

View File

@ -0,0 +1,65 @@
use actix_web::{web, HttpResponse, Responder};
use askama_actix::TemplateToResponse;
use serde::Deserialize;
use sqlx::PgPool;
use crate::{
endpoints::assignment::PlanEventPersonalTablePartialTemplate,
models::{Assignment, Event, Role, User},
utils::{
event_planning_template::{
generate_availabillity_assignment_list, generate_status_whether_staff_is_required,
},
ApplicationError,
},
};
#[derive(Deserialize)]
struct AssignmentDeleteQuery {
availabillity: i32,
event: i32,
}
#[actix_web::delete("/assignments/delete")]
pub async fn delete(
user: web::ReqData<User>,
pool: web::Data<PgPool>,
query: web::Query<AssignmentDeleteQuery>,
) -> Result<impl Responder, ApplicationError> {
let Some(event) = Event::read_by_id_including_location(pool.get_ref(), query.event).await?
else {
return Ok(HttpResponse::NotFound().finish());
};
let user_is_admin_or_area_manager_of_event_area = user.role == Role::Admin
|| (user.role == Role::AreaManager
&& user.area_id == event.location.as_ref().unwrap().area_id);
if !user_is_admin_or_area_manager_of_event_area {
return Err(ApplicationError::Unauthorized);
}
let Some(assignment) = Assignment::read(pool.get_ref(), event.id, query.availabillity).await?
else {
return Ok(HttpResponse::NotFound().finish());
};
Assignment::delete(pool.get_ref(), event.id, assignment.availabillity_id).await?;
let availabillities = generate_availabillity_assignment_list(pool.get_ref(), &event).await?;
let (
further_posten_required,
further_fuehrungsassistent_required,
further_wachhabender_required,
) = generate_status_whether_staff_is_required(pool.get_ref(), &event).await?;
let template = PlanEventPersonalTablePartialTemplate {
event,
availabillities,
further_posten_required,
further_fuehrungsassistent_required,
further_wachhabender_required,
};
Ok(template.to_response())
}

View File

@ -1,46 +0,0 @@
use actix_identity::Identity;
use actix_web::{web, HttpResponse, Responder};
use askama::Template;
use askama_actix::TemplateToResponse;
use serde::Deserialize;
use sqlx::PgPool;
use crate::models::{Availabillity, Event, Function, Role, User};
#[derive(Deserialize)]
pub struct EventQuery {
event: i32
}
#[derive(Template)]
#[template(path = "assignment/new.html")]
pub struct NewAssignmentTemplate {
user: User,
event: Event,
available_wachhabende: Vec<Availabillity>,
available_posten: Vec<Availabillity>,
all: Vec<Availabillity>
}
#[actix_web::get("/assignments/new")]
pub async fn get(user: Identity, pool: web::Data<PgPool>, query: web::Query<EventQuery>) -> impl Responder {
//let current_user = User::read_by_id(pool.get_ref(), user.id().unwrap().parse().unwrap())
// .await
// .unwrap();
//
//if let Ok(event) = Event::read_by_id_including_location(pool.get_ref(), query.event).await {
// if current_user.role == Role::Admin || current_user.role == Role::AreaManager && event.location.as_ref().unwrap().area_id == current_user.area_id {
// let all = Availabillity::read_not_assigned_by_date_including_user(pool.get_ref(), event.date).await.unwrap();
// let available_posten = Availabillity::read_not_assigned_by_date_including_user(pool.get_ref(), event.date).await.unwrap();
// let available_wachhabende = available_posten.iter().filter(|a| a.user.as_ref().unwrap().function == Function::Wachhabender).map(|avl| avl.clone()).collect();
//
// let template = NewAssignmentTemplate { user: current_user, event, available_wachhabende, available_posten, all };
//
// return template.to_response();
// }
//
// return HttpResponse::Unauthorized().finish();
//}
HttpResponse::BadRequest().body("Fehler beim Laden für Assignment")
}

View File

@ -1,2 +1,19 @@
pub mod get_new;
use askama::Template;
use crate::{
filters,
models::{Availabillity, AvailabillityAssignmentState, Event, Function},
};
pub mod delete;
pub mod post_new;
#[derive(Template)]
#[template(path = "events/plan_personal_table.html")]
pub struct PlanEventPersonalTablePartialTemplate {
event: Event,
availabillities: Vec<(Availabillity, AvailabillityAssignmentState)>,
further_posten_required: bool,
further_fuehrungsassistent_required: bool,
further_wachhabender_required: bool,
}

View File

@ -1,59 +1,112 @@
use std::ops::AddAssign;
use actix_web::{web, HttpResponse, Responder};
use askama_actix::TemplateToResponse;
use serde::Deserialize;
use sqlx::PgPool;
use crate::models::{Assignment, Event, Function};
use crate::{
endpoints::assignment::PlanEventPersonalTablePartialTemplate,
models::{Assignment, Availabillity, Event, Function, Role, User},
utils::{
event_planning_template::{
generate_availabillity_assignment_list, generate_status_whether_staff_is_required,
},
ApplicationError,
},
};
#[derive(Deserialize)]
pub struct NewAssignmentsForm {
pub struct AssignmentQuery {
availabillity: i32,
function: u8,
event: i32,
wachhabender: Option<i32>,
posten: Vec<i32>
}
#[actix_web::post("/assignments/new")]
pub async fn post(pool: web::Data<PgPool>, form: web::Form<Vec<(String, String)>>) -> impl Responder {
//let event_id = form.iter().find(|x| x.0 == "event").unwrap().1.parse().unwrap();
//let wachhabender = form.iter().find(|x| x.0 == "wachhabender");
//let posten: Vec<i32> = form.iter().filter(|x| x.0 == "posten").map(|x| x.1.parse().unwrap()).collect();
//
//let event = Event::read_by_id_including_location(&pool, event_id).await.unwrap(); // TODO: Check if location is needed
//
//if event.voluntary_wachhabender && wachhabender.is_some() && posten.contains(&wachhabender.unwrap().1.parse().unwrap()) {
// return HttpResponse::BadRequest().body("Wachhabender kann nicht zugleich Posten sein!");
//}
//
//let mut joined_ids = posten.clone();
//if let Some((_,id)) = wachhabender {
// joined_ids.push(id.parse().unwrap());
//}
//
//for availabillity_id in joined_ids {
// let assignments = Assignment::read_by_availabillity(pool.get_ref(), availabillity_id).await.unwrap();
//
// let mut can_be_used = true;
//
//
// for assignment in assignments {
// if event.start_time >= assignment.start_time && event.start_time <= assignment.end_time {
// } else {
// can_be_used = false;
// break;
// }
// }
//
// if !can_be_used {
// return HttpResponse::BadRequest().body("availabillity time slot bereits genutzt!");
// }
//}
//
//if let Some((_,id)) = wachhabender {
// Assignment::create(pool.get_ref(), event.id, id.parse().unwrap(), Function::Wachhabender, event.start_time, event.end_time).await.unwrap();
//}
//
//for id in posten {
// Assignment::create(pool.get_ref(), event.id, id, Function::Posten, event.start_time, event.end_time).await.unwrap();
//}
//
HttpResponse::Ok().finish()
pub async fn post(
user: web::ReqData<User>,
pool: web::Data<PgPool>,
query: web::Query<AssignmentQuery>,
) -> Result<impl Responder, ApplicationError> {
let Some(event) = Event::read_by_id_including_location(pool.get_ref(), query.event).await?
else {
return Ok(HttpResponse::NotFound().finish());
};
let user_is_admin_or_area_manager_of_event_area = user.role == Role::Admin
|| (user.role == Role::AreaManager
&& user.area_id == event.location.as_ref().unwrap().area_id);
if !user_is_admin_or_area_manager_of_event_area {
return Err(ApplicationError::Unauthorized);
}
let Some(availability) =
Availabillity::read_by_id_including_user(pool.get_ref(), query.availabillity).await?
else {
return Ok(HttpResponse::NotFound().finish());
};
let availability_user_not_in_event_location_area =
availability.user.as_ref().unwrap().area_id != event.location.as_ref().unwrap().area_id;
let existing_assignments_for_availabillity =
Assignment::read_all_by_availabillity(pool.get_ref(), availability.id).await?;
let has_start_time_during_event =
|a: &Assignment| a.start_time >= event.start_time && a.start_time <= event.end_time;
let has_end_time_during_event =
|a: &Assignment| a.end_time >= event.start_time && a.end_time <= event.end_time;
let availability_already_assigned = existing_assignments_for_availabillity
.iter()
.any(|a| has_start_time_during_event(a) || has_end_time_during_event(a));
let function = Function::try_from(query.function)?;
let user_not_qualified_for_assigned_function =
availability.user.as_ref().unwrap().function < function;
let a = Assignment::count_by_event_and_function(pool.get_ref(), event.id, function).await?;
let event_already_has_enough_assignments_for_function = match function {
Function::Posten => a >= event.amount_of_posten as i64,
Function::Fuehrungsassistent => event.voluntary_wachhabender && a >= 1,
Function::Wachhabender => event.voluntary_wachhabender && a >= 1,
};
if availability_user_not_in_event_location_area
|| availability_already_assigned
|| user_not_qualified_for_assigned_function
|| event_already_has_enough_assignments_for_function
{
// TODO: Fehlermeldung verbessern
return Ok(HttpResponse::BadRequest().body(format!("{availability_user_not_in_event_location_area} {availability_already_assigned} {user_not_qualified_for_assigned_function} {event_already_has_enough_assignments_for_function}")));
}
Assignment::create(
pool.get_ref(),
event.id,
availability.id,
function,
event.start_time,
event.end_time,
)
.await?;
let availabillities = generate_availabillity_assignment_list(pool.get_ref(), &event).await?;
let (
further_posten_required,
further_fuehrungsassistent_required,
further_wachhabender_required,
) = generate_status_whether_staff_is_required(pool.get_ref(), &event).await?;
let template = PlanEventPersonalTablePartialTemplate {
event,
availabillities,
further_posten_required,
further_fuehrungsassistent_required,
further_wachhabender_required,
};
Ok(template.to_response())
}

View File

@ -1,13 +1,18 @@
use actix_web::{web, HttpResponse, Responder};
use askama::Template;
use askama_actix::TemplateToResponse;
use chrono::NaiveDate;
use sqlx::PgPool;
use crate::{
endpoints::{IdPath, NaiveDateQuery},
models::{Assignment, Availabillity, Event, Function, Location, Role, User},
utils::ApplicationError,
endpoints::IdPath,
filters,
models::{Availabillity, AvailabillityAssignmentState, Event, Function, Role, User},
utils::{
event_planning_template::{
generate_availabillity_assignment_list, generate_status_whether_staff_is_required,
},
ApplicationError,
},
};
#[derive(Template)]
@ -15,20 +20,10 @@ use crate::{
pub struct PlanEventTemplate {
user: User,
event: Event,
availabillities: Vec<(Availabillity, AssignmentState)>,
}
enum AssignmentState {
// availabillity is not assigned at all or at least not timely conflicting
Unassigned,
// availabillity is assigned for another event that is timely conflicting
Conflicting,
// availabillity is assigned to this event as Posten
AssignedPosten,
// availabillity is assigned to this event as Führungsassistent
AssignedFührungsassistent,
// availabillity is assigned to this event as Wachhabender
AssignedWachahabender,
availabillities: Vec<(Availabillity, AvailabillityAssignmentState)>,
further_posten_required: bool,
further_fuehrungsassistent_required: bool,
further_wachhabender_required: bool,
}
#[actix_web::get("/events/{id}/plan")]
@ -49,52 +44,21 @@ pub async fn get(
return Err(ApplicationError::Unauthorized);
}
let availabillities_in_db = Availabillity::read_by_date_and_area_including_user(
pool.get_ref(),
event.date,
event.location.as_ref().unwrap().area_id,
)
.await?;
let availabillities = generate_availabillity_assignment_list(pool.get_ref(), &event).await?;
let mut availabillities = Vec::new();
for availabillity in availabillities_in_db {
let assignments =
Assignment::read_all_by_availabillity(pool.get_ref(), availabillity.id).await?;
if let Some(assignment) = assignments
.iter()
.find(|assignment| assignment.event_id == event.id)
{
let state = match assignment.function {
Function::Posten => AssignmentState::AssignedPosten,
Function::Fuehrungsassistent => AssignmentState::AssignedFührungsassistent,
Function::Wachhabender => AssignmentState::AssignedWachahabender,
};
availabillities.push((availabillity, state));
continue;
}
let has_start_time_during_event =
|a: &Assignment| a.start_time >= event.start_time && a.start_time <= event.end_time;
let has_end_time_during_event =
|a: &Assignment| a.end_time >= event.start_time && a.end_time <= event.end_time;
if assignments
.iter()
.any(|a| has_start_time_during_event(a) || has_end_time_during_event(a))
{
availabillities.push((availabillity, AssignmentState::Conflicting));
continue;
}
availabillities.push((availabillity, AssignmentState::Unassigned));
}
let (
further_posten_required,
further_fuehrungsassistent_required,
further_wachhabender_required,
) = generate_status_whether_staff_is_required(pool.get_ref(), &event).await?;
let template = PlanEventTemplate {
user: user.into_inner(),
event,
availabillities,
further_posten_required,
further_fuehrungsassistent_required,
further_wachhabender_required,
};
Ok(template.to_response())

View File

@ -59,8 +59,8 @@ pub fn init(cfg: &mut ServiceConfig) {
cfg.service(events::post_new::post);
cfg.service(events::get_plan::get);
cfg.service(assignment::get_new::get);
cfg.service(assignment::post_new::post);
cfg.service(assignment::delete::delete);
cfg.service(area::get_new::get);
cfg.service(area::post_new::post);

View File

@ -31,7 +31,7 @@ async fn post(
let response = handle_password_change_request(
pool.get_ref(),
Some(&token),
token.id,
token.userid,
&form.password,
&form.passwordretyped,
None,

View File

@ -57,7 +57,7 @@ async fn post(
let response = handle_password_change_request(
pool.get_ref(),
Some(&token),
token.id,
token.userid,
form.password.as_ref().unwrap(),
form.passwordretyped.as_ref().unwrap(),
None,

View File

@ -70,4 +70,97 @@ impl Assignment {
Ok(assignemnets)
}
pub async fn read_all_by_event(pool: &PgPool, event_id: i32) -> Result<Vec<Assignment>> {
let records = query!(
r##"
SELECT
assignment.eventId,
assignment.availabillityId,
assignment.function AS "function: Function",
assignment.startTime,
assignment.endTime
FROM assignment
WHERE assignment.eventId = $1;
"##,
event_id,
)
.fetch_all(pool)
.await?;
let assignemnets = records
.iter()
.map(|r| Assignment {
event_id: r.eventid,
availabillity_id: r.availabillityid,
function: r.function,
start_time: r.starttime,
end_time: r.endtime,
})
.collect();
Ok(assignemnets)
}
pub async fn count_by_event_and_function(
pool: &PgPool,
event_id: i32,
function: Function,
) -> Result<i64> {
let result = query!("SELECT count(*) FROM assignment WHERE assignment.eventId = $1 AND assignment.function = $2;",
event_id,
function as Function
)
.fetch_one(pool)
.await?;
Ok(result.count.unwrap_or(0))
}
pub async fn read(
pool: &PgPool,
event_id: i32,
availabillity_id: i32,
) -> Result<Option<Assignment>> {
let record = query!(
r##"
SELECT
assignment.eventId,
assignment.availabillityId,
assignment.function AS "function: Function",
assignment.startTime,
assignment.endTime
FROM assignment
WHERE
assignment.eventId = $1 AND
assignment.availabillityId = $2;
"##,
event_id,
availabillity_id
)
.fetch_optional(pool)
.await?;
let assignemnet = record.and_then(|r| {
Some(Assignment {
event_id: r.eventid,
availabillity_id: r.availabillityid,
function: r.function,
start_time: r.starttime,
end_time: r.endtime,
})
});
Ok(assignemnet)
}
pub async fn delete(pool: &PgPool, event_id: i32, availabillity_id: i32) -> Result<()> {
query!("DELETE FROM assignment WHERE assignment.eventId = $1 AND assignment.availabillityId = $2;",
event_id,
availabillity_id
)
.execute(pool)
.await?;
Ok(())
}
}

View File

@ -1,9 +1,11 @@
use std::fmt::Display;
use chrono::{NaiveDate, NaiveTime};
use sqlx::{query, PgPool};
use super::{Area, Function, Result, Role, User};
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct Availabillity {
pub id: i32,
pub user_id: i32,
@ -14,6 +16,32 @@ pub struct Availabillity {
pub comment: Option<String>,
}
#[derive(PartialEq, Eq, Debug)]
pub enum AvailabillityAssignmentState {
// availabillity is not assigned at all or at least not timely conflicting
Unassigned,
// availabillity is assigned for another event that is timely conflicting
Conflicting,
// availabillity is assigned to this event as Posten
AssignedPosten(i32),
// availabillity is assigned to this event as Führungsassistent
AssignedFührungsassistent(i32),
// availabillity is assigned to this event as Wachhabender
AssignedWachahabender(i32),
}
impl Display for AvailabillityAssignmentState {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
AvailabillityAssignmentState::Unassigned => write!(f, "nicht zugewiesen"),
AvailabillityAssignmentState::Conflicting => write!(f, "bereits anders zugewiesen"),
AvailabillityAssignmentState::AssignedPosten(_) => write!(f, "zugewiesen als Posten"),
AvailabillityAssignmentState::AssignedFührungsassistent(_) => write!(f, "zugewiesen als Führungsassistent"),
AvailabillityAssignmentState::AssignedWachahabender(_) => write!(f, "zugewiesen als Wachhabender"),
}
}
}
impl Availabillity {
pub async fn create(
pool: &PgPool,
@ -104,11 +132,11 @@ impl Availabillity {
Ok(availabillities)
}
pub async fn read_not_assigned_by_date_including_user(
pub async fn read_by_id_including_user(
pool: &PgPool,
date: NaiveDate,
) -> Result<Vec<Availabillity>> {
let records = query!(
id: i32,
) -> Result<Option<Availabillity>> {
let record = query!(
r##"
SELECT
availabillity.id,
@ -130,16 +158,15 @@ impl Availabillity {
FROM availabillity
LEFT JOIN assignment ON availabillity.Id = assignment.availabillityId
JOIN user_ ON availabillity.userId = user_.id
WHERE availabillity.date = $1;
WHERE availabillity.id = $1;
"##,
date
id
)
.fetch_all(pool)
.fetch_optional(pool)
.await?;
let availabillities = records
.iter()
.map(|r| Availabillity {
let availabillity = record.and_then(|r| {
Some(Availabillity {
id: r.id,
user_id: r.userid,
user: Some(User {
@ -161,9 +188,9 @@ impl Availabillity {
end_time: r.endtime,
comment: r.comment.clone(),
})
.collect();
});
Ok(availabillities)
Ok(availabillity)
}
pub async fn read_by_id(pool: &PgPool, id: i32) -> Result<Option<Availabillity>> {

View File

@ -4,7 +4,7 @@ use serde::Serialize;
use crate::utils::ApplicationError;
#[derive(sqlx::Type, Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[derive(sqlx::Type, Debug, Clone, Copy, PartialEq, Eq, Serialize, PartialOrd, Ord)]
#[sqlx(type_name = "function", rename_all = "lowercase")]
pub enum Function {
Posten = 1,

View File

@ -19,7 +19,7 @@ impl Location {
name,
area_id
)
.fetch_one(pool)
.execute(pool)
.await?;
Ok(())

View File

@ -12,7 +12,7 @@ mod registration;
mod vehicle_assignement;
pub use area::Area;
pub use availabillity::Availabillity;
pub use availabillity::{Availabillity, AvailabillityAssignmentState};
pub use event::Event;
pub use function::Function;
pub use location::Location;

View File

@ -0,0 +1,93 @@
use sqlx::PgPool;
use crate::models::{Assignment, Availabillity, AvailabillityAssignmentState, Event, Function};
use super::ApplicationError;
pub async fn generate_availabillity_assignment_list(
pool: &PgPool,
event: &Event,
) -> Result<Vec<(Availabillity, AvailabillityAssignmentState)>, ApplicationError> {
let availabillities_in_db = Availabillity::read_by_date_and_area_including_user(
pool,
event.date,
event.location.as_ref().unwrap().area_id,
)
.await?;
let mut availabillities = Vec::new();
for availabillity in availabillities_in_db {
let assignments = Assignment::read_all_by_availabillity(pool, availabillity.id).await?;
if let Some(assignment) = assignments
.iter()
.find(|assignment| assignment.event_id == event.id)
{
let state = match assignment.function {
Function::Posten => {
AvailabillityAssignmentState::AssignedPosten(assignment.availabillity_id)
}
Function::Fuehrungsassistent => {
AvailabillityAssignmentState::AssignedFührungsassistent(
assignment.availabillity_id,
)
}
Function::Wachhabender => {
AvailabillityAssignmentState::AssignedWachahabender(assignment.availabillity_id)
}
};
availabillities.push((availabillity, state));
continue;
}
let has_start_time_during_event =
|a: &Assignment| a.start_time >= event.start_time && a.start_time <= event.end_time;
let has_end_time_during_event =
|a: &Assignment| a.end_time >= event.start_time && a.end_time <= event.end_time;
if assignments
.iter()
.any(|a| has_start_time_during_event(a) || has_end_time_during_event(a))
{
availabillities.push((availabillity, AvailabillityAssignmentState::Conflicting));
continue;
}
availabillities.push((availabillity, AvailabillityAssignmentState::Unassigned));
}
//println!(" {availabillities:#?}");
Ok(availabillities)
}
pub async fn generate_status_whether_staff_is_required(
pool: &PgPool,
event: &Event,
) -> Result<(bool, bool, bool), ApplicationError> {
let existing_assignments_for_event = Assignment::read_all_by_event(pool, event.id).await?;
let further_posten_required = existing_assignments_for_event
.iter()
.filter(|a| a.function == Function::Posten)
.count()
< event.amount_of_posten as usize;
// TODO change to Fuehrungsassistent
let further_fuehrungsassistent_required = event.voluntary_wachhabender
&& existing_assignments_for_event
.iter()
.all(|a| a.function != Function::Fuehrungsassistent);
let further_wachhabender_required = event.voluntary_wachhabender
&& existing_assignments_for_event
.iter()
.all(|a| a.function != Function::Wachhabender);
//println!("further_posten {further_posten_required}");
Ok((
further_posten_required,
further_fuehrungsassistent_required,
further_wachhabender_required,
))
}

View File

@ -2,6 +2,7 @@ pub mod email;
pub mod manage_commands;
pub mod password_help;
pub mod token_generation;
pub mod event_planning_template;
mod application_error;
pub use application_error::ApplicationError;

View File

@ -38,6 +38,7 @@ $primary: $crimson,
@forward "bulma/sass/helpers/spacing";
@forward "bulma/sass/helpers/flexbox";
@forward "bulma/sass/helpers/color";
// Import the themes so that all CSS variables have a value
@forward "bulma/sass/themes";

View File

@ -51,8 +51,14 @@
<div class="box">
<h5 class="title is-5">Einteilung Personal</h5>
<!--TODO: next: Use availabillities-->
<div class="icon-text">
<svg class="icon has-text-success">
<use href="/static/feather-sprite.svg#check" />
</svg>
<span>Alle Plätze verplant!</span>
</div>
{% include "plan_personal_table.html" %}
</div>
<div class="box">

View File

@ -0,0 +1,63 @@
<table class="table is-fullwidth">
<thead>
<tr>
<th>Name</th>
<th>Funktion</th>
<th>Zeitraum</th>
<th>Kommentar</th>
<th>Status</th>
<th>Planen als</th>
<th></th>
</tr>
</thead>
<tbody>
{% for (availabillity, status) in availabillities %}
{% let u = availabillity.user.as_ref().unwrap() %}
<tr>
<td>{{ u.name }}</td>
<td>
{{ u.function|show_tree|safe }}
</td>
<td>
{% if availabillity.start_time.is_some() && availabillity.end_time.is_some() %}
{{ availabillity.start_time.as_ref().unwrap().format("%R") }} bis {{
availabillity.end_time.as_ref().unwrap().format("%R") }}
{% else %}
ganztägig
{% endif %}
</td>
<td>
{{ availabillity.comment.as_deref().unwrap_or("") }}
</td>
<td>
{{ status }}
</td>
<td>
<div class="buttons has-addons">
<button hx-post="/assignments/new?event={{ event.id }}&availabillity={{ availabillity.id }}&function=1"
hx-target="closest table" hx-swap="outerHTML" class="button is-small" {% if !further_posten_required ||
status !=AvailabillityAssignmentState::Unassigned|as_ref %}disabled{% endif %}>Posten</button>
{% if u.function == Function::Wachhabender || u.function == Function::Fuehrungsassistent %}
<button hx-post="/assignments/new?event={{ event.id }}&availabillity={{ availabillity.id }}&function=5"
hx-target="closest table" hx-swap="outerHTML" class="button is-small" {% if
!further_fuehrungsassistent_required || status !=AvailabillityAssignmentState::Unassigned|as_ref
%}disabled{% endif %}>Führungsassistent</button>
{% endif %}
{% if u.function == Function::Wachhabender %}
<button hx-post="/assignments/new?event={{ event.id }}&availabillity={{ availabillity.id }}&function=10"
hx-target="closest table" hx-swap="outerHTML" class="button is-small" {% if !further_wachhabender_required
|| status !=AvailabillityAssignmentState::Unassigned|as_ref %}disabled{% endif %}>Wachhabender</button>
{% endif %}
</div>
</td>
<td>
{% if status != AvailabillityAssignmentState::Unassigned|as_ref && status !=
AvailabillityAssignmentState::Conflicting|as_ref %}
<button hx-delete="/assignments/delete?event={{ event.id }}&availabillity={{ availabillity.id }}"
hx-target="closest table" hx-swap="outerHTML" class="button is-small">Entplanen</button>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>