diff --git a/Cargo.lock b/Cargo.lock index 46911fc..c089e69 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -126,18 +126,18 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.42", ] [[package]] name = "async-trait" -version = "0.1.74" +version = "0.1.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +checksum = "fdf6721fb0140e4f897002dd086c06f6c27775df19cfe1fccb21181a48fd2c98" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.42", ] [[package]] @@ -166,9 +166,9 @@ dependencies = [ [[package]] name = "atomic-write-file" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c232177ba50b16fe7a4588495bd474a62a9e45a8e4ca6fd7d0b7ac29d164631e" +checksum = "edcdbedc2236483ab103a53415653d6b4442ea6141baf1ffa85df29635e88436" dependencies = [ "nix", "rand", @@ -308,7 +308,7 @@ dependencies = [ "pure-rust-locales", "serde", "wasm-bindgen", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -345,9 +345,9 @@ dependencies = [ [[package]] name = "const-oid" -version = "0.9.5" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "cookie" @@ -368,9 +368,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "cpufeatures" @@ -398,9 +398,9 @@ checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crossbeam-channel" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +checksum = "14c3242926edf34aec4ac3a77108ad4854bffaa2e4ddc1824124ce59231302d5" dependencies = [ "cfg-if", "crossbeam-utils", @@ -408,9 +408,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751" dependencies = [ "cfg-if", "crossbeam-epoch", @@ -419,22 +419,21 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.15" +version = "0.9.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +checksum = "2d2fe95351b870527a5d09bf563ed3c97c0cffb87cf1c78a591bf48bb218d9aa" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "memoffset 0.9.0", - "scopeguard", + "memoffset", ] [[package]] name = "crossbeam-queue" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +checksum = "b9bcf5bdbfdd6030fb4a1c497b5d5fc5921aa2f60d359a17e249c0e6df3de153" dependencies = [ "cfg-if", "crossbeam-utils", @@ -442,9 +441,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +checksum = "c06d96137f14f244c37f989d9fff8f95e6c18b918e71f36638f8c49112e4c78f" dependencies = [ "cfg-if", ] @@ -482,18 +481,18 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" +checksum = "8eb30d70a07a3b04884d2677f06bec33509dc67ca60d92949e5535352d3191dc" dependencies = [ "powerfmt", ] [[package]] name = "deunicode" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a1abaf4d861455be59f64fd2b55606cb151fce304ede7165f410243ce96bde6" +checksum = "3ae2a35373c5c74340b79ae6780b498b2b183915ec5dacf263aac5a099bf485a" [[package]] name = "devise" @@ -525,7 +524,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.39", + "syn 2.0.42", ] [[package]] @@ -585,12 +584,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -601,7 +600,7 @@ checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" dependencies = [ "cfg-if", "home", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -632,14 +631,14 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.22" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.3.5", - "windows-sys", + "redox_syscall", + "windows-sys 0.52.0", ] [[package]] @@ -750,7 +749,7 @@ checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.42", ] [[package]] @@ -924,9 +923,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hkdf" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ "hmac", ] @@ -942,11 +941,11 @@ dependencies = [ [[package]] name = "home" -version = "0.5.5" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" dependencies = [ - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -962,9 +961,9 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", "http", @@ -1000,9 +999,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.27" +version = "0.14.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" dependencies = [ "bytes", "futures-channel", @@ -1015,7 +1014,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.10", + "socket2", "tokio", "tower-service", "tracing", @@ -1131,29 +1130,29 @@ checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", "rustix", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "itertools" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "js-sys" -version = "0.3.65" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" +checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" dependencies = [ "wasm-bindgen", ] @@ -1189,9 +1188,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.150" +version = "0.2.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" [[package]] name = "libm" @@ -1212,9 +1211,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" [[package]] name = "lock_api" @@ -1272,15 +1271,6 @@ version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" -[[package]] -name = "memoffset" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" -dependencies = [ - "autocfg", -] - [[package]] name = "memoffset" version = "0.9.0" @@ -1313,14 +1303,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ "libc", "log", "wasi", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1345,15 +1335,13 @@ dependencies = [ [[package]] name = "nix" -version = "0.26.4" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.1", "cfg-if", "libc", - "memoffset 0.7.1", - "pin-utils", ] [[package]] @@ -1372,7 +1360,7 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec60c60a693226186f5d6edf073232bfb6464ed97eb22cf3b01c1e8198fd97f5" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1391,7 +1379,7 @@ dependencies = [ "log", "mio", "walkdir", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1473,9 +1461,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "opaque-debug" @@ -1507,9 +1495,9 @@ checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.4.1", + "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -1540,9 +1528,9 @@ checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "pear" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a386cd715229d399604b50d1361683fe687066f42d56f54be995bc6868f71c" +checksum = "4ccca0f6c17acc81df8e242ed473ec144cbf5c98037e69aa6d144780aad103c8" dependencies = [ "inlinable_string", "pear_codegen", @@ -1551,14 +1539,14 @@ dependencies = [ [[package]] name = "pear_codegen" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f0f13dac8069c139e8300a6510e3f4143ecf5259c60b116a9b271b4ca0d54" +checksum = "2e22670e8eb757cff11d6c199ca7b987f352f0346e0be4dd23869ec72cb53c77" dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.39", + "syn 2.0.42", ] [[package]] @@ -1607,7 +1595,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.42", ] [[package]] @@ -1694,9 +1682,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" [[package]] name = "polyval" @@ -1724,9 +1712,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.70" +version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8" dependencies = [ "unicode-ident", ] @@ -1739,7 +1727,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.42", "version_check", "yansi", ] @@ -1789,15 +1777,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.4.1" @@ -1809,22 +1788,22 @@ dependencies = [ [[package]] name = "ref-cast" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acde58d073e9c79da00f2b5b84eed919c8326832648a5b109b3fce1bb1175280" +checksum = "53313ec9f12686aeeffb43462c3ac77aa25f590a5f630eb2cde0de59417b29c7" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7473c2cfcf90008193dd0e3e16599455cb601a9fce322b5bb55de799664925" +checksum = "2566c4bf6845f2c2e83b27043c3f5dfcd5ba8f2937d6c00dc009bfb51a079dc4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.42", ] [[package]] @@ -1873,16 +1852,16 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "ring" -version = "0.17.5" +version = "0.17.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" dependencies = [ "cc", "getrandom", "libc", "spin 0.9.8", "untrusted", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1934,7 +1913,7 @@ dependencies = [ "proc-macro2", "quote", "rocket_http", - "syn 2.0.39", + "syn 2.0.42", "unicode-xid", "version_check", ] @@ -2000,9 +1979,9 @@ dependencies = [ [[package]] name = "rsa" -version = "0.9.4" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a3211b01eea83d80687da9eef70e39d65144a3894866a5153a2723e425a157f" +checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" dependencies = [ "const-oid", "digest", @@ -2026,22 +2005,22 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.25" +version = "0.38.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e" +checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" dependencies = [ "bitflags 2.4.1", "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] name = "rustls" -version = "0.21.9" +version = "0.21.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "629648aced5775d558af50b2b4c7b02983a04b312126d45eeead26e7caa498b9" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" dependencies = [ "ring", "rustls-webpki", @@ -2075,9 +2054,9 @@ checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" [[package]] name = "same-file" @@ -2127,7 +2106,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.42", ] [[package]] @@ -2143,9 +2122,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" dependencies = [ "serde", ] @@ -2231,16 +2210,6 @@ version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" -[[package]] -name = "socket2" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "socket2" version = "0.5.5" @@ -2248,7 +2217,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2268,9 +2237,9 @@ dependencies = [ [[package]] name = "spki" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", "der", @@ -2278,9 +2247,9 @@ dependencies = [ [[package]] name = "sqlformat" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b7b278788e7be4d0d29c0f39497a0eef3fba6bbc8e70d8bf7fde46edeaa9e85" +checksum = "ce81b7bd7c4493975347ef60d8c7e8b742d4694f4c49f93e0a12ea263938176c" dependencies = [ "itertools", "nom", @@ -2543,9 +2512,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "5b7d0a2c048d661a1a59fcd7355baa232f7ed34e0ee4df2eef3c1c1c0d3852d8" dependencies = [ "proc-macro2", "quote", @@ -2560,9 +2529,9 @@ checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ "cfg-if", "fastrand", - "redox_syscall 0.4.1", + "redox_syscall", "rustix", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2598,22 +2567,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.42", ] [[package]] @@ -2628,9 +2597,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" +checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" dependencies = [ "deranged", "itoa", @@ -2648,9 +2617,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f" dependencies = [ "time-core", ] @@ -2672,9 +2641,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.34.0" +version = "1.35.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" +checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" dependencies = [ "backtrace", "bytes", @@ -2683,9 +2652,9 @@ dependencies = [ "num_cpus", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.5", + "socket2", "tokio-macros", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2696,7 +2665,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.42", ] [[package]] @@ -2784,7 +2753,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.42", ] [[package]] @@ -2828,9 +2797,9 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typenum" @@ -2915,9 +2884,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" [[package]] name = "unicode-ident" @@ -3030,9 +2999,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.88" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" +checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -3040,24 +3009,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.88" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" +checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.42", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.88" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" +checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3065,22 +3034,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.88" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" +checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.42", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.88" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" +checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" [[package]] name = "webpki-roots" @@ -3131,7 +3100,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -3140,7 +3109,7 @@ version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -3149,7 +3118,16 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", ] [[package]] @@ -3158,13 +3136,28 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] @@ -3173,36 +3166,72 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -3210,10 +3239,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] -name = "winnow" -version = "0.5.19" +name = "windows_x86_64_msvc" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "winnow" +version = "0.5.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b5c3db89721d50d0e2a673f5043fc4722f76dcc352d7b1ab8b8288bed4ed2c5" dependencies = [ "memchr", ] @@ -3229,22 +3264,22 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.26" +version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e97e415490559a91254a2979b4829267a57d2fcd741a98eee8b722fb57289aa0" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.26" +version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd7e48ccf166952882ca8bd778a43502c64f33bf94c12ebe2a7f08e5a0f6689f" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.42", ] [[package]] diff --git a/migration.sql b/migration.sql index f130e72..0a53d23 100644 --- a/migration.sql +++ b/migration.sql @@ -2,10 +2,6 @@ CREATE TABLE IF NOT EXISTS "user" ( "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" text NOT NULL UNIQUE, "pw" text, - "is_cox" boolean NOT NULL DEFAULT FALSE, - "is_admin" boolean NOT NULL DEFAULT FALSE, - "is_guest" boolean NOT NULL DEFAULT TRUE, - "is_tech" boolean NOT NULL DEFAULT FALSE, "deleted" boolean NOT NULL DEFAULT FALSE, "last_access" DATETIME, "dob" text, @@ -15,6 +11,17 @@ CREATE TABLE IF NOT EXISTS "user" ( "dirty_dozen" text ); +CREATE TABLE IF NOT EXISTS "role" ( + "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, + "name" text NOT NULL UNIQUE +); + +CREATE TABLE IF NOT EXISTS "user_role" ( + "user_id" INTEGER NOT NULL REFERENCES user(id), + "role_id" INTEGER NOT NULL REFERENCES role(id), + CONSTRAINT unq UNIQUE (user_id, role_id) +); + CREATE TABLE IF NOT EXISTS "trip_type" ( "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" text NOT NULL UNIQUE, diff --git a/seeds.sql b/seeds.sql index 1b2ca6a..9acfe7f 100644 --- a/seeds.sql +++ b/seeds.sql @@ -1,10 +1,19 @@ -INSERT INTO "user" (name, is_cox, is_admin, is_guest, pw) VALUES('admin', true, true, false, '$argon2id$v=19$m=19456,t=2,p=1$dS/X5/sPEKTj4Rzs/CuvzQ$4P4NCw4Ukhv80/eQYTsarHhnw61JuL1KMx/L9dm82YM'); -INSERT INTO "user" (name, is_cox, is_admin, is_guest, pw) VALUES('rower', false, false, false, '$argon2id$v=19$m=19456,t=2,p=1$dS/X5/sPEKTj4Rzs/CuvzQ$jWKzDmI0jqT2dqINFt6/1NjVF4Dx15n07PL1ZMBmFsY'); -INSERT INTO "user" (name, is_cox, is_admin, is_guest, pw) VALUES('guest', false, false, true, '$argon2id$v=19$m=19456,t=2,p=1$dS/X5/sPEKTj4Rzs/CuvzQ$GF6gizbI79Bh0zA9its8S0gram956v+YIV8w8VpwJnQ'); -INSERT INTO "user" (name, is_cox, is_admin, is_guest, pw) VALUES('cox', true, false, false, '$argon2id$v=19$m=19456,t=2,p=1$dS/X5/sPEKTj4Rzs/CuvzQ$lnWzHx3DdqS9GQyWYel82kIotZuK2wk9EyfhPFtjNzs'); +INSERT INTO "role" (name) VALUES ('admin'); +INSERT INTO "role" (name) VALUES ('cox'); +INSERT INTO "role" (name) VALUES ('scheckbuch'); +INSERT INTO "role" (name) VALUES ('tech'); +INSERT INTO "user" (name, pw) VALUES('admin', '$argon2id$v=19$m=19456,t=2,p=1$dS/X5/sPEKTj4Rzs/CuvzQ$4P4NCw4Ukhv80/eQYTsarHhnw61JuL1KMx/L9dm82YM'); +INSERT INTO "user_role" (user_id, role_id) VALUES(1,1); +INSERT INTO "user_role" (user_id, role_id) VALUES(1,2); +INSERT INTO "user" (name, pw) VALUES('rower', '$argon2id$v=19$m=19456,t=2,p=1$dS/X5/sPEKTj4Rzs/CuvzQ$jWKzDmI0jqT2dqINFt6/1NjVF4Dx15n07PL1ZMBmFsY'); +INSERT INTO "user" (name, pw) VALUES('guest', '$argon2id$v=19$m=19456,t=2,p=1$dS/X5/sPEKTj4Rzs/CuvzQ$GF6gizbI79Bh0zA9its8S0gram956v+YIV8w8VpwJnQ'); +INSERT INTO "user_role" (user_id, role_id) VALUES(3,3); +INSERT INTO "user" (name, pw) VALUES('cox', '$argon2id$v=19$m=19456,t=2,p=1$dS/X5/sPEKTj4Rzs/CuvzQ$lnWzHx3DdqS9GQyWYel82kIotZuK2wk9EyfhPFtjNzs'); +INSERT INTO "user_role" (user_id, role_id) VALUES(4,2); INSERT INTO "user" (name) VALUES('new'); -INSERT INTO "user" (name, is_cox, is_admin, is_guest, pw) VALUES('cox2', true, false, false, '$argon2id$v=19$m=19456,t=2,p=1$dS/X5/sPEKTj4Rzs/CuvzQ$lnWzHx3DdqS9GQyWYel82kIotZuK2wk9EyfhPFtjNzs'); -INSERT INTO "user" (name, is_cox, is_admin, is_guest, pw) VALUES('rower2', false, false, false, '$argon2id$v=19$m=19456,t=2,p=1$dS/X5/sPEKTj4Rzs/CuvzQ$jWKzDmI0jqT2dqINFt6/1NjVF4Dx15n07PL1ZMBmFsY'); +INSERT INTO "user" (name, pw) VALUES('cox2', '$argon2id$v=19$m=19456,t=2,p=1$dS/X5/sPEKTj4Rzs/CuvzQ$lnWzHx3DdqS9GQyWYel82kIotZuK2wk9EyfhPFtjNzs'); +INSERT INTO "user_role" (user_id, role_id) VALUES(6,2); +INSERT INTO "user" (name, pw) VALUES('rower2', '$argon2id$v=19$m=19456,t=2,p=1$dS/X5/sPEKTj4Rzs/CuvzQ$jWKzDmI0jqT2dqINFt6/1NjVF4Dx15n07PL1ZMBmFsY'); INSERT INTO "trip_details" (planned_starting_time, max_people, day, notes) VALUES('10:00', 2, '1970-01-01', 'trip_details for a planned event'); INSERT INTO "planned_event" (name, planned_amount_cox, trip_details_id) VALUES('test-planned-event', 2, 1); diff --git a/src/model/boat.rs b/src/model/boat.rs index 351404b..20077b1 100644 --- a/src/model/boat.rs +++ b/src/model/boat.rs @@ -89,7 +89,7 @@ impl Boat { .ok() } - pub async fn shipmaster_allowed(&self, user: &User) -> bool { + pub async fn shipmaster_allowed(&self, db: &SqlitePool, user: &User) -> bool { if let Some(owner_id) = self.owner { return owner_id == user.id; } @@ -98,7 +98,23 @@ impl Boat { return true; } - user.is_cox + user.has_role(db, "cox").await + } + + pub async fn shipmaster_allowed_tx( + &self, + db: &mut Transaction<'_, Sqlite>, + user: &User, + ) -> bool { + if let Some(owner_id) = self.owner { + return owner_id == user.id; + } + + if self.amount_seats == 1 { + return true; + } + + user.has_role_tx(db, "cox").await } pub async fn is_locked(&self, db: &SqlitePool) -> bool { @@ -156,10 +172,10 @@ ORDER BY amount_seats DESC } pub async fn for_user(db: &SqlitePool, user: &User) -> Vec { - if user.is_admin { + if user.has_role(db, "admin").await { return Self::all(db).await; } - let boats = if user.is_cox { + let boats = if user.has_role(db, "cox").await { sqlx::query_as!( Boat, " diff --git a/src/model/boatdamage.rs b/src/model/boatdamage.rs index ed0dbc0..37207f2 100644 --- a/src/model/boatdamage.rs +++ b/src/model/boatdamage.rs @@ -141,7 +141,7 @@ ORDER BY created_at DESC .map_err(|e| e.to_string())?; let user = User::find_by_id(db, boat.user_id_fixed).await.unwrap(); - if user.is_tech { + if user.has_role(db, "tech").await { return self .verified( db, @@ -162,7 +162,7 @@ ORDER BY created_at DESC boat: BoatDamageVerified<'_>, ) -> Result<(), String> { if let Some(verifier) = User::find_by_id(db, boat.user_id_verified).await { - if !verifier.is_tech { + if !verifier.has_role(db, "tech").await { Log::create(db, format!("User {verifier:?} tried to verify boat {boat:?}. The user is no tech. Manually craftted request?")).await; return Err("You are not allowed to verify the boat!".into()); } diff --git a/src/model/logbook.rs b/src/model/logbook.rs index 4ddd818..f0909fa 100644 --- a/src/model/logbook.rs +++ b/src/model/logbook.rs @@ -272,7 +272,7 @@ ORDER BY departure DESC if let Ok(log_to_finalize) = TryInto::::try_into(log.clone()) { //TODO: fix clone() above - if !boat.shipmaster_allowed(created_by_user).await { + if !boat.shipmaster_allowed(db, created_by_user).await { return Err(LogbookCreateError::UserNotAllowedToUseBoat); } @@ -343,7 +343,7 @@ ORDER BY departure DESC } } - if !boat.shipmaster_allowed(created_by_user).await { + if !boat.shipmaster_allowed(db, created_by_user).await { return Err(LogbookCreateError::UserNotAllowedToUseBoat); } @@ -452,7 +452,7 @@ ORDER BY departure DESC return Err(LogbookUpdateError::SteeringPersonNotInRowers); } - if !boat.shipmaster_allowed(user).await && self.shipmaster != user.id { + if !boat.shipmaster_allowed_tx(db, user).await && self.shipmaster != user.id { //second part: shipmaster has entered a different user, then the user should be able to //`home` it return Err(LogbookUpdateError::UserNotAllowedToUseBoat); @@ -471,7 +471,7 @@ ORDER BY departure DESC return Err(LogbookUpdateError::ArrivalNotAfterDeparture); } let today = Utc::now().date_naive(); - if arr.date() != today && !user.is_admin { + if arr.date() != today && !user.has_role_tx(db, "admin").await { return Err(LogbookUpdateError::OnlyAllowedToEndTripsEndingToday); } @@ -506,7 +506,7 @@ ORDER BY departure DESC pub async fn delete(&self, db: &SqlitePool, user: &User) -> Result<(), LogbookDeleteError> { Log::create(db, format!("{user:?} deleted trip: {self:?}")).await; - if user.is_admin || user.id == self.shipmaster { + if user.has_role(db, "admin").await || user.id == self.shipmaster { sqlx::query!("DELETE FROM logbook WHERE id=?", self.id) .execute(db) .await diff --git a/src/model/mod.rs b/src/model/mod.rs index b18a4cd..91d7df1 100644 --- a/src/model/mod.rs +++ b/src/model/mod.rs @@ -14,6 +14,7 @@ pub mod log; pub mod logbook; pub mod logtype; pub mod planned_event; +pub mod role; pub mod rower; pub mod stat; pub mod trip; @@ -22,7 +23,7 @@ pub mod triptype; pub mod user; pub mod usertrip; -#[derive(Serialize)] +#[derive(Serialize, Debug)] pub struct Day { day: NaiveDate, planned_events: Vec, diff --git a/src/model/planned_event.rs b/src/model/planned_event.rs index 8be4258..a4e61e8 100644 --- a/src/model/planned_event.rs +++ b/src/model/planned_event.rs @@ -6,7 +6,7 @@ use ics::{ Event, ICalendar, }; use serde::Serialize; -use sqlx::{FromRow, SqlitePool}; +use sqlx::{FromRow, SqlitePool, Row}; use super::{tripdetails::TripDetails, triptype::TripType, user::User}; @@ -47,27 +47,28 @@ pub struct Registration { impl Registration { pub async fn all_rower(db: &SqlitePool, trip_details_id: i64) -> Vec { - sqlx::query!( + sqlx::query( + &format!( r#" SELECT (SELECT name FROM user WHERE user_trip.user_id = user.id) as "name?", user_note, user_id, (SELECT created_at FROM user WHERE user_trip.user_id = user.id) as registered_at, - (SELECT is_guest FROM user WHERE user_trip.user_id = user.id) as is_guest -FROM user_trip WHERE trip_details_id = ? - "#, - trip_details_id, + (SELECT EXISTS (SELECT 1 FROM user_role WHERE user_role.user_id = user_trip.user_id AND user_role.role_id = (SELECT id FROM role WHERE name = 'scheckbuch'))) as is_guest +FROM user_trip WHERE trip_details_id = {} + "#,trip_details_id), ) .fetch_all(db) .await .unwrap() .into_iter() - .map(|r| Registration { - name: r.name.or(r.user_note).unwrap(), //Ok, either name or user_note needs to be set - registered_at: r.registered_at, - is_guest: r.is_guest, - is_real_guest: r.user_id.is_none(), + .map(|r| + Registration { + name: r.get::, usize>(0).or(r.get::, usize>(1)).unwrap(), //Ok, either name or user_note needs to be set + registered_at: r.get::(3), + is_guest: r.get::(4), + is_real_guest: r.get::, usize>(2).is_none(), }) .collect() } @@ -78,8 +79,7 @@ FROM user_trip WHERE trip_details_id = ? " SELECT (SELECT name FROM user WHERE cox_id = id) as name, - (SELECT created_at FROM user WHERE cox_id = id) as registered_at, - (SELECT is_guest FROM user WHERE cox_id = id) as is_guest + (SELECT created_at FROM user WHERE cox_id = id) as registered_at FROM trip WHERE planned_event_id = ? ", trip_details_id @@ -91,7 +91,7 @@ FROM trip WHERE planned_event_id = ? .map(|r| Registration { name: r.name, registered_at: r.registered_at, - is_guest: r.is_guest, + is_guest: false, is_real_guest: false, }) .collect() //Okay, as PlannedEvent can only be created with proper DB backing @@ -144,7 +144,7 @@ WHERE day=?", let mut ret = Vec::new(); for event in events { - let cox = Registration::all_cox(db, event.trip_details_id).await; + let cox = Registration::all_cox(db, event.id).await; let mut trip_type = None; if let Some(trip_type_id) = event.trip_type_id { trip_type = TripType::find_by_id(db, trip_type_id).await; diff --git a/src/model/role.rs b/src/model/role.rs new file mode 100644 index 0000000..8ad982f --- /dev/null +++ b/src/model/role.rs @@ -0,0 +1,17 @@ +use serde::Serialize; +use sqlx::{FromRow, SqlitePool}; + +#[derive(FromRow, Serialize, Clone)] +pub struct Role { + id: i64, + name: String, +} + +impl Role { + pub async fn all(db: &SqlitePool) -> Vec { + sqlx::query_as!(Role, "SELECT id, name FROM role") + .fetch_all(db) + .await + .unwrap() + } +} diff --git a/src/model/rower.rs b/src/model/rower.rs index 750c788..613b690 100644 --- a/src/model/rower.rs +++ b/src/model/rower.rs @@ -16,7 +16,7 @@ impl Rower { sqlx::query_as!( User, " -SELECT id, name, pw, is_cox, is_admin, is_guest, deleted, last_access, is_tech, dob, weight, sex +SELECT id, name, pw, deleted, last_access, dob, weight, sex FROM user WHERE id in (SELECT rower_id FROM rower WHERE logbook_id=?) ", diff --git a/src/model/trip.rs b/src/model/trip.rs index 2eba4ae..e6139ee 100644 --- a/src/model/trip.rs +++ b/src/model/trip.rs @@ -25,7 +25,7 @@ pub struct Trip { is_locked: bool, } -#[derive(Serialize)] +#[derive(Serialize, Debug)] pub struct TripWithUserAndType { #[serde(flatten)] pub trip: Trip, @@ -276,11 +276,12 @@ mod test { fn test_new_own() { let pool = testdb!(); - let cox: CoxUser = User::find_by_name(&pool, "cox".into()) - .await - .unwrap() - .try_into() - .unwrap(); + let cox = CoxUser::new( + &pool, + User::find_by_name(&pool, "cox".into()).await.unwrap(), + ) + .await + .unwrap(); let trip_details = TripDetails::find_by_id(&pool, 1).await.unwrap(); @@ -301,11 +302,12 @@ mod test { fn test_new_succ_join() { let pool = testdb!(); - let cox: CoxUser = User::find_by_name(&pool, "cox2".into()) - .await - .unwrap() - .try_into() - .unwrap(); + let cox = CoxUser::new( + &pool, + User::find_by_name(&pool, "cox2".into()).await.unwrap(), + ) + .await + .unwrap(); let planned_event = PlannedEvent::find_by_id(&pool, 1).await.unwrap(); @@ -316,11 +318,12 @@ mod test { fn test_new_failed_join_already_cox() { let pool = testdb!(); - let cox: CoxUser = User::find_by_name(&pool, "cox2".into()) - .await - .unwrap() - .try_into() - .unwrap(); + let cox = CoxUser::new( + &pool, + User::find_by_name(&pool, "cox2".into()).await.unwrap(), + ) + .await + .unwrap(); let planned_event = PlannedEvent::find_by_id(&pool, 1).await.unwrap(); @@ -332,11 +335,12 @@ mod test { fn test_succ_update_own() { let pool = testdb!(); - let cox: CoxUser = User::find_by_name(&pool, "cox".into()) - .await - .unwrap() - .try_into() - .unwrap(); + let cox = CoxUser::new( + &pool, + User::find_by_name(&pool, "cox".into()).await.unwrap(), + ) + .await + .unwrap(); let trip = Trip::find_by_id(&pool, 1).await.unwrap(); @@ -354,11 +358,12 @@ mod test { fn test_succ_update_own_with_triptype() { let pool = testdb!(); - let cox: CoxUser = User::find_by_name(&pool, "cox".into()) - .await - .unwrap() - .try_into() - .unwrap(); + let cox = CoxUser::new( + &pool, + User::find_by_name(&pool, "cox".into()).await.unwrap(), + ) + .await + .unwrap(); let trip = Trip::find_by_id(&pool, 1).await.unwrap(); @@ -377,11 +382,12 @@ mod test { fn test_fail_update_own_not_your_trip() { let pool = testdb!(); - let cox: CoxUser = User::find_by_name(&pool, "cox2".into()) - .await - .unwrap() - .try_into() - .unwrap(); + let cox = CoxUser::new( + &pool, + User::find_by_name(&pool, "cox2".into()).await.unwrap(), + ) + .await + .unwrap(); let trip = Trip::find_by_id(&pool, 1).await.unwrap(); @@ -397,11 +403,12 @@ mod test { fn test_succ_delete_by_planned_event() { let pool = testdb!(); - let cox: CoxUser = User::find_by_name(&pool, "cox".into()) - .await - .unwrap() - .try_into() - .unwrap(); + let cox = CoxUser::new( + &pool, + User::find_by_name(&pool, "cox".into()).await.unwrap(), + ) + .await + .unwrap(); let planned_event = PlannedEvent::find_by_id(&pool, 1).await.unwrap(); @@ -419,11 +426,12 @@ mod test { fn test_succ_delete() { let pool = testdb!(); - let cox: CoxUser = User::find_by_name(&pool, "cox".into()) - .await - .unwrap() - .try_into() - .unwrap(); + let cox = CoxUser::new( + &pool, + User::find_by_name(&pool, "cox".into()).await.unwrap(), + ) + .await + .unwrap(); let trip = Trip::find_by_id(&pool, 1).await.unwrap(); @@ -436,11 +444,12 @@ mod test { fn test_fail_delete_diff_cox() { let pool = testdb!(); - let cox: CoxUser = User::find_by_name(&pool, "cox2".into()) - .await - .unwrap() - .try_into() - .unwrap(); + let cox = CoxUser::new( + &pool, + User::find_by_name(&pool, "cox2".into()).await.unwrap(), + ) + .await + .unwrap(); let trip = Trip::find_by_id(&pool, 1).await.unwrap(); @@ -457,11 +466,12 @@ mod test { fn test_fail_delete_someone_registered() { let pool = testdb!(); - let cox: CoxUser = User::find_by_name(&pool, "cox".into()) - .await - .unwrap() - .try_into() - .unwrap(); + let cox = CoxUser::new( + &pool, + User::find_by_name(&pool, "cox".into()).await.unwrap(), + ) + .await + .unwrap(); let trip = Trip::find_by_id(&pool, 1).await.unwrap(); diff --git a/src/model/tripdetails.rs b/src/model/tripdetails.rs index 71a427c..aeec004 100644 --- a/src/model/tripdetails.rs +++ b/src/model/tripdetails.rs @@ -120,7 +120,7 @@ ORDER BY day;", pub(crate) async fn user_allowed_to_change(&self, db: &SqlitePool, user: &User) -> bool { if self.belongs_to_event(db).await { - user.is_admin + user.has_role(db, "admin").await } else { self.user_is_cox(db, user).await != CoxAtTrip::No } diff --git a/src/model/user.rs b/src/model/user.rs index 064d7da..c759b51 100644 --- a/src/model/user.rs +++ b/src/model/user.rs @@ -21,10 +21,6 @@ pub struct User { pub id: i64, pub name: String, pub pw: Option, - pub is_cox: bool, - pub is_admin: bool, - pub is_guest: bool, - pub is_tech: bool, pub dob: Option, pub weight: Option, pub sex: Option, @@ -32,17 +28,35 @@ pub struct User { pub last_access: Option, } +#[derive(Debug, Serialize, Deserialize)] +pub struct UserWithRoles { + #[serde(flatten)] + pub user: User, + pub roles: Vec, +} + +impl UserWithRoles { + pub async fn from_user(user: User, db: &SqlitePool) -> Self { + Self { + roles: user.roles(db).await, + user, + } + } +} + #[derive(Debug, Serialize, Deserialize)] pub struct UserWithWaterStatus { #[serde(flatten)] pub user: User, pub on_water: bool, + pub roles: Vec, } impl UserWithWaterStatus { pub async fn from_user(user: User, db: &SqlitePool) -> Self { Self { on_water: user.on_water(db).await, + roles: user.roles(db).await, user, } } @@ -91,11 +105,56 @@ impl User { .rowed_km } + pub async fn has_role(&self, db: &SqlitePool, role: &str) -> bool { + if sqlx::query!( + "SELECT * FROM user_role WHERE user_id=? AND role_id = (SELECT id FROM role WHERE name = ?)", + self.id, + role + ) + .fetch_optional(db) + .await + .unwrap() + .is_some() + { + return true; + } + + false + } + + pub async fn roles(&self, db: &SqlitePool) -> Vec { + sqlx::query!( + "SELECT r.name FROM role r JOIN user_role ur ON r.id = ur.role_id WHERE ur.user_id = ?;", + self.id + ) + .fetch_all(db) + .await + .unwrap() + .into_iter().map(|r| r.name).collect() + } + + pub async fn has_role_tx(&self, db: &mut Transaction<'_, Sqlite>, role: &str) -> bool { + if sqlx::query!( + "SELECT * FROM user_role WHERE user_id=? AND role_id = (SELECT id FROM role WHERE name = ?)", + self.id, + role + ) + .fetch_optional(db.deref_mut()) + .await + .unwrap() + .is_some() + { + return true; + } + + false + } + pub async fn find_by_id(db: &SqlitePool, id: i32) -> Option { sqlx::query_as!( Self, " -SELECT id, name, pw, is_cox, is_admin, is_guest, deleted, last_access, is_tech, dob, weight, sex +SELECT id, name, pw, deleted, last_access, dob, weight, sex FROM user WHERE id like ? ", @@ -110,7 +169,7 @@ WHERE id like ? sqlx::query_as!( Self, " -SELECT id, name, pw, is_cox, is_admin, is_guest, deleted, last_access, is_tech, dob, weight, sex +SELECT id, name, pw, deleted, last_access, dob, weight, sex FROM user WHERE id like ? ", @@ -125,7 +184,7 @@ WHERE id like ? sqlx::query_as!( Self, " -SELECT id, name, pw, is_cox, is_admin, is_guest, deleted, last_access, is_tech, dob, weight, sex +SELECT id, name, pw, deleted, last_access, dob, weight, sex FROM user WHERE name like ? ", @@ -167,7 +226,7 @@ WHERE name like ? sqlx::query_as!( Self, " -SELECT id, name, pw, is_cox, is_admin, is_guest, deleted, last_access, is_tech, dob, weight, sex +SELECT id, name, pw, deleted, last_access, dob, weight, sex FROM user WHERE deleted = 0 ORDER BY last_access DESC @@ -182,7 +241,7 @@ ORDER BY last_access DESC sqlx::query_as!( Self, " -SELECT id, name, pw, is_cox, is_admin, is_guest, deleted, last_access, is_tech, dob, weight, sex +SELECT id, name, pw, deleted, last_access, dob, weight, sex FROM user WHERE deleted = 0 AND dob != '' and weight != '' and sex != '' ORDER BY name @@ -197,9 +256,9 @@ ORDER BY name sqlx::query_as!( Self, " -SELECT id, name, pw, is_cox, is_admin, is_guest, deleted, last_access, is_tech, dob, weight, sex +SELECT id, name, pw, deleted, last_access, dob, weight, sex FROM user -WHERE deleted = 0 AND is_cox=true +WHERE deleted = 0 AND (SELECT COUNT(*) FROM user_role WHERE user_id=user.id AND role_id = (SELECT id FROM role WHERE name = 'cox')) > 0 ORDER BY last_access DESC " ) @@ -208,24 +267,16 @@ ORDER BY last_access DESC .unwrap() } - pub async fn create(db: &SqlitePool, name: &str, is_guest: bool) -> bool { - sqlx::query!( - "INSERT INTO USER(name, is_guest) VALUES (?,?)", - name, - is_guest, - ) - .execute(db) - .await - .is_ok() + pub async fn create(db: &SqlitePool, name: &str) -> bool { + sqlx::query!("INSERT INTO USER(name) VALUES (?)", name) + .execute(db) + .await + .is_ok() } pub async fn update(&self, db: &SqlitePool, data: UserEditForm) { sqlx::query!( - "UPDATE user SET is_cox = ?, is_admin = ?, is_guest = ?, is_tech = ?, dob = ?, weight = ?, sex = ? where id = ?", - data.is_cox, - data.is_admin, - data.is_guest, - data.is_tech, + "UPDATE user SET dob = ?, weight = ?, sex = ? where id = ?", data.dob, data.weight, data.sex, @@ -234,6 +285,23 @@ ORDER BY last_access DESC .execute(db) .await .unwrap(); //Okay, because we can only create a User of a valid id + + // handle roles + sqlx::query!("DELETE FROM user_role WHERE user_id = ?", self.id) + .execute(db) + .await + .unwrap(); + + for role_id in data.roles.into_keys() { + sqlx::query!( + "INSERT INTO user_role(user_id, role_id) VALUES (?, ?)", + self.id, + role_id + ) + .execute(db) + .await + .unwrap(); + } } pub async fn login(db: &SqlitePool, name: &str, pw: &str) -> Result { @@ -309,18 +377,18 @@ ORDER BY last_access DESC pub async fn get_days(&self, db: &SqlitePool) -> Vec { let mut days = Vec::new(); - for i in 0..self.amount_days_to_show() { + for i in 0..self.amount_days_to_show(db).await { let date = (Local::now() + chrono::Duration::days(i)).date_naive(); - if self.is_guest { + if self.has_role(db, "scheckbuch").await { days.push(Day::new_guest(db, date, false).await); } else { days.push(Day::new(db, date, false).await); } } - for date in TripDetails::pinned_days(db, self.amount_days_to_show() - 1).await { - if self.is_guest { + for date in TripDetails::pinned_days(db, self.amount_days_to_show(db).await - 1).await { + if self.has_role(db, "scheckbuch").await { let day = Day::new_guest(db, date, true).await; if !day.planned_events.is_empty() { days.push(day); @@ -332,8 +400,8 @@ ORDER BY last_access DESC days } - fn amount_days_to_show(&self) -> i64 { - if self.is_cox { + async fn amount_days_to_show(&self, db: &SqlitePool) -> i64 { + if self.has_role(db, "cox").await { let end_of_year = NaiveDate::from_ymd_opt(Local::now().year(), 12, 31).unwrap(); //Ok, //december //has 31 @@ -393,28 +461,21 @@ impl Deref for TechUser { } } -impl TryFrom for TechUser { - type Error = LoginError; - - fn try_from(user: User) -> Result { - if user.is_tech { - Ok(TechUser { user }) - } else { - Err(LoginError::NotATech) - } - } -} - #[async_trait] impl<'r> FromRequest<'r> for TechUser { type Error = LoginError; async fn from_request(req: &'r Request<'_>) -> request::Outcome { + let db = req.rocket().state::().unwrap(); + match User::from_request(req).await { - Outcome::Success(user) => match user.try_into() { - Ok(user) => Outcome::Success(user), - Err(_) => Outcome::Error((Status::Unauthorized, LoginError::NotACox)), - }, + Outcome::Success(user) => { + if user.has_role(db, "tech").await { + Outcome::Success(TechUser { user }) + } else { + Outcome::Error((Status::Unauthorized, LoginError::NotACox)) + } + } Outcome::Error(f) => Outcome::Error(f), Outcome::Forward(f) => Outcome::Forward(f), } @@ -433,14 +494,12 @@ impl Deref for CoxUser { } } -impl TryFrom for CoxUser { - type Error = LoginError; - - fn try_from(user: User) -> Result { - if user.is_cox { - Ok(CoxUser { user }) +impl CoxUser { + pub async fn new(db: &SqlitePool, user: User) -> Option { + if user.has_role(db, "cox").await { + Some(CoxUser { user }) } else { - Err(LoginError::NotACox) + None } } } @@ -450,11 +509,16 @@ impl<'r> FromRequest<'r> for CoxUser { type Error = LoginError; async fn from_request(req: &'r Request<'_>) -> request::Outcome { + let db = req.rocket().state::().unwrap(); + match User::from_request(req).await { - Outcome::Success(user) => match user.try_into() { - Ok(user) => Outcome::Success(user), - Err(_) => Outcome::Error((Status::Unauthorized, LoginError::NotACox)), - }, + Outcome::Success(user) => { + if user.has_role(db, "cox").await { + Outcome::Success(CoxUser { user }) + } else { + Outcome::Error((Status::Unauthorized, LoginError::NotACox)) + } + } Outcome::Error(f) => Outcome::Error(f), Outcome::Forward(f) => Outcome::Forward(f), } @@ -466,28 +530,20 @@ pub struct AdminUser { pub(crate) user: User, } -impl TryFrom for AdminUser { - type Error = LoginError; - - fn try_from(user: User) -> Result { - if user.is_admin { - Ok(AdminUser { user }) - } else { - Err(LoginError::NotAnAdmin) - } - } -} - #[async_trait] impl<'r> FromRequest<'r> for AdminUser { type Error = LoginError; async fn from_request(req: &'r Request<'_>) -> request::Outcome { + let db = req.rocket().state::().unwrap(); match User::from_request(req).await { - Outcome::Success(user) => match user.try_into() { - Ok(user) => Outcome::Success(user), - Err(_) => Outcome::Error((Status::Unauthorized, LoginError::NotAnAdmin)), - }, + Outcome::Success(user) => { + if user.has_role(db, "admin").await { + Outcome::Success(AdminUser { user }) + } else { + Outcome::Error((Status::Unauthorized, LoginError::NotACox)) + } + } Outcome::Error(f) => Outcome::Error(f), Outcome::Forward(f) => Outcome::Forward(f), } @@ -499,28 +555,20 @@ pub struct NonGuestUser { pub(crate) user: User, } -impl TryFrom for NonGuestUser { - type Error = LoginError; - - fn try_from(user: User) -> Result { - if user.is_guest { - Err(LoginError::GuestNotAllowed) - } else { - Ok(NonGuestUser { user }) - } - } -} - #[async_trait] impl<'r> FromRequest<'r> for NonGuestUser { type Error = LoginError; async fn from_request(req: &'r Request<'_>) -> request::Outcome { + let db = req.rocket().state::().unwrap(); match User::from_request(req).await { - Outcome::Success(user) => match user.try_into() { - Ok(user) => Outcome::Success(user), - Err(_) => Outcome::Error((Status::Unauthorized, LoginError::NotAnAdmin)), - }, + Outcome::Success(user) => { + if !user.has_role(db, "scheckbuch").await { + Outcome::Success(NonGuestUser { user }) + } else { + Outcome::Error((Status::Unauthorized, LoginError::NotACox)) + } + } Outcome::Error(f) => Outcome::Error(f), Outcome::Forward(f) => Outcome::Forward(f), } @@ -529,6 +577,8 @@ impl<'r> FromRequest<'r> for NonGuestUser { #[cfg(test)] mod test { + use std::collections::HashMap; + use crate::{tera::admin::user::UserEditForm, testdb}; use super::User; @@ -580,17 +630,14 @@ mod test { fn test_succ_create() { let pool = testdb!(); - assert_eq!( - User::create(&pool, "new-user-name".into(), false).await, - true - ); + assert_eq!(User::create(&pool, "new-user-name".into()).await, true); } #[sqlx::test] fn test_duplicate_name_create() { let pool = testdb!(); - assert_eq!(User::create(&pool, "admin".into(), false).await, false); + assert_eq!(User::create(&pool, "admin".into()).await, false); } #[sqlx::test] @@ -602,19 +649,17 @@ mod test { &pool, UserEditForm { id: 1, - is_guest: false, - is_cox: false, - is_admin: false, - is_tech: false, dob: None, weight: None, - sex: None, + sex: Some("m".into()), + roles: HashMap::new(), }, ) .await; let user = User::find_by_id(&pool, 1).await.unwrap(); - assert_eq!(user.is_admin, false); + + assert_eq!(user.sex, Some("m".into())); } #[sqlx::test] diff --git a/src/model/usertrip.rs b/src/model/usertrip.rs index de133ed..f727bf8 100644 --- a/src/model/usertrip.rs +++ b/src/model/usertrip.rs @@ -20,7 +20,7 @@ impl UserTrip { return Err(UserTripError::DetailsLocked); } - if user.is_guest && !trip_details.allow_guests { + if user.has_role(db, "scheckbuch").await && !trip_details.allow_guests { return Err(UserTripError::GuestNotAllowedForThisEvent); } @@ -211,11 +211,12 @@ mod test { fn test_fail_create_is_cox_planned_event() { let pool = testdb!(); - let cox: CoxUser = User::find_by_name(&pool, "cox".into()) - .await - .unwrap() - .try_into() - .unwrap(); + let cox = CoxUser::new( + &pool, + User::find_by_name(&pool, "cox".into()).await.unwrap(), + ) + .await + .unwrap(); let planned_event = PlannedEvent::find_by_id(&pool, 1).await.unwrap(); Trip::new_join(&pool, &cox, &planned_event).await.unwrap(); diff --git a/src/tera/admin/boat.rs b/src/tera/admin/boat.rs index 6ff6200..d8776f6 100644 --- a/src/tera/admin/boat.rs +++ b/src/tera/admin/boat.rs @@ -1,7 +1,7 @@ use crate::model::{ boat::{Boat, BoatToAdd, BoatToUpdate}, location::Location, - user::{AdminUser, User}, + user::{AdminUser, User, UserWithRoles}, }; use rocket::{ form::Form, @@ -30,7 +30,10 @@ async fn index( context.insert("boats", &boats); context.insert("locations", &locations); context.insert("users", &users); - context.insert("loggedin_user", &admin.user); + context.insert( + "loggedin_user", + &UserWithRoles::from_user(admin.user, db).await, + ); Template::render("admin/boat/index", context.into_json()) } diff --git a/src/tera/admin/user.rs b/src/tera/admin/user.rs index f0a719c..e688445 100644 --- a/src/tera/admin/user.rs +++ b/src/tera/admin/user.rs @@ -1,4 +1,10 @@ -use crate::model::user::{AdminUser, User}; +use std::collections::HashMap; + +use crate::model::{ + role::Role, + user::{AdminUser, User, UserWithRoles}, +}; +use futures::future::join_all; use rocket::{ form::Form, get, post, @@ -15,14 +21,26 @@ async fn index( admin: AdminUser, flash: Option>, ) -> Template { - let users = User::all(db).await; + let user_futures: Vec<_> = User::all(db) + .await + .into_iter() + .map(|u| async move { UserWithRoles::from_user(u, db).await }) + .collect(); + + let users: Vec = join_all(user_futures).await; + + let roles = Role::all(db).await; let mut context = Context::new(); if let Some(msg) = flash { context.insert("flash", &msg.into_inner()); } context.insert("users", &users); - context.insert("loggedin_user", &admin.user); + context.insert("roles", &roles); + context.insert( + "loggedin_user", + &UserWithRoles::from_user(admin.user, db).await, + ); Template::render("admin/user/index", context.into_json()) } @@ -57,16 +75,13 @@ async fn delete(db: &State, _admin: AdminUser, user: i32) -> Flash, pub(crate) weight: Option, pub(crate) sex: Option, + pub(crate) roles: HashMap, } #[post("/user", data = "")] @@ -91,7 +106,6 @@ async fn update( #[derive(FromForm)] struct UserAddForm<'r> { name: &'r str, - is_guest: bool, } #[post("/user/new", data = "")] @@ -100,7 +114,7 @@ async fn create( data: Form>, _admin: AdminUser, ) -> Flash { - if User::create(db, data.name, data.is_guest).await { + if User::create(db, data.name).await { Flash::success(Redirect::to("/admin/user"), "Successfully created user") } else { Flash::error( diff --git a/src/tera/boatdamage.rs b/src/tera/boatdamage.rs index 89260cd..c798791 100644 --- a/src/tera/boatdamage.rs +++ b/src/tera/boatdamage.rs @@ -13,7 +13,7 @@ use crate::{ model::{ boat::Boat, boatdamage::{BoatDamage, BoatDamageFixed, BoatDamageToAdd, BoatDamageVerified}, - user::{CoxUser, NonGuestUser, TechUser, User}, + user::{CoxUser, NonGuestUser, TechUser, User, UserWithRoles}, }, tera::log::KioskCookie, }; @@ -57,7 +57,10 @@ async fn index( context.insert("boatdamages", &boatdamages); context.insert("boats", &boats); - context.insert("loggedin_user", &user.user); + context.insert( + "loggedin_user", + &UserWithRoles::from_user(user.user, db).await, + ); Template::render("boatdamages", context.into_json()) } diff --git a/src/tera/ergo.rs b/src/tera/ergo.rs index 8b00446..8818d6b 100644 --- a/src/tera/ergo.rs +++ b/src/tera/ergo.rs @@ -18,7 +18,7 @@ use tera::Context; use crate::model::{ log::Log, - user::{AdminUser, User}, + user::{AdminUser, User, UserWithRoles}, }; #[derive(Serialize)] @@ -51,7 +51,7 @@ async fn send(db: &State, _user: AdminUser) -> Template { Template::render( "ergo.final", - context!(loggedin_user: &_user.user, thirty, dozen), + context!(loggedin_user: &UserWithRoles::from_user(_user.user, db).await, thirty, dozen), ) } @@ -120,7 +120,7 @@ async fn index(db: &State, user: User, flash: Option, user: NonGuestUser) -> Template { let logs = Logbook::completed(db).await; - Template::render("log.completed", context!(logs, loggedin_user: &user.user)) + Template::render( + "log.completed", + context!(logs, loggedin_user: &UserWithRoles::from_user(user.user, db).await), + ) } #[get("/show")] @@ -232,7 +238,7 @@ async fn create_kiosk( ) .await; - create_logbook(db, data, &NonGuestUser::try_from(creator).unwrap()).await //TODO: fixme + create_logbook(db, data, &NonGuestUser { user: creator }).await //TODO: fixme } async fn home_logbook( @@ -279,12 +285,11 @@ async fn home_kiosk( db, data, logbook_id, - &NonGuestUser::try_from( - User::find_by_id(db, logbook.shipmaster as i32) + &NonGuestUser { + user: User::find_by_id(db, logbook.shipmaster as i32) .await .unwrap(), //TODO: fixme - ) - .unwrap(), + }, ) .await } diff --git a/src/tera/mod.rs b/src/tera/mod.rs index 8cd4612..de9ff8b 100644 --- a/src/tera/mod.rs +++ b/src/tera/mod.rs @@ -16,7 +16,7 @@ use crate::model::{ log::Log, tripdetails::TripDetails, triptype::TripType, - user::User, + user::{User, UserWithRoles}, usertrip::{UserTrip, UserTripDeleteError, UserTripError}, }; @@ -47,7 +47,7 @@ async fn wikiauth(db: &State, login: Form>) -> String async fn index(db: &State, user: User, flash: Option>) -> Template { let mut context = Context::new(); - if user.is_cox || user.is_admin { + if user.has_role(db, "cox").await || user.has_role(db, "admin").await { let triptypes = TripType::all(db).await; context.insert("trip_types", &triptypes); } @@ -57,8 +57,8 @@ async fn index(db: &State, user: User, flash: Option, user: NonGuestUser, year: Option, user: NonGuestUser, year: Option) -> Template::render( "stat.people", - context!(loggedin_user: &user.user, stat, personal, kiosk, guest_km), + context!(loggedin_user: &UserWithRoles::from_user(user.user, db).await, stat, personal, kiosk, guest_km), ) } diff --git a/staging-diff.sql b/staging-diff.sql index e69de29..f52ac94 100644 --- a/staging-diff.sql +++ b/staging-diff.sql @@ -0,0 +1,95 @@ +CREATE TABLE IF NOT EXISTS "role" ( + "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, + "name" text NOT NULL UNIQUE +); +INSERT INTO "role" (name) VALUES ('admin'); +INSERT INTO "role" (name) VALUES ('cox'); +INSERT INTO "role" (name) VALUES ('scheckbuch'); +INSERT INTO "role" (name) VALUES ('tech'); + +CREATE TABLE IF NOT EXISTS "user_role" ( + "user_id" INTEGER NOT NULL REFERENCES user(id), + "role_id" INTEGER NOT NULL REFERENCES role(id), + CONSTRAINT unq UNIQUE (user_id, role_id) +); + +INSERT INTO "user_role" (user_id, role_id) VALUES (11,1); -- Marie Admin +INSERT INTO "user_role" (user_id, role_id) VALUES (40,1); -- PH Admin + +-- cox +INSERT INTO "user_role" (user_id, role_id) VALUES (1,2); +INSERT INTO "user_role" (user_id, role_id) VALUES (3,2); +INSERT INTO "user_role" (user_id, role_id) VALUES (11,2); +INSERT INTO "user_role" (user_id, role_id) VALUES (14,2); +INSERT INTO "user_role" (user_id, role_id) VALUES (24,2); +INSERT INTO "user_role" (user_id, role_id) VALUES (33,2); +INSERT INTO "user_role" (user_id, role_id) VALUES (34,2); +INSERT INTO "user_role" (user_id, role_id) VALUES (38,2); +INSERT INTO "user_role" (user_id, role_id) VALUES (39,2); +INSERT INTO "user_role" (user_id, role_id) VALUES (40,2); +INSERT INTO "user_role" (user_id, role_id) VALUES (46,2); +INSERT INTO "user_role" (user_id, role_id) VALUES (48,2); +INSERT INTO "user_role" (user_id, role_id) VALUES (57,2); +INSERT INTO "user_role" (user_id, role_id) VALUES (69,2); +INSERT INTO "user_role" (user_id, role_id) VALUES (70,2); +INSERT INTO "user_role" (user_id, role_id) VALUES (75,2); +INSERT INTO "user_role" (user_id, role_id) VALUES (83,2); +INSERT INTO "user_role" (user_id, role_id) VALUES (86,2); +INSERT INTO "user_role" (user_id, role_id) VALUES (90,2); +INSERT INTO "user_role" (user_id, role_id) VALUES (96,2); +INSERT INTO "user_role" (user_id, role_id) VALUES (105,2); +INSERT INTO "user_role" (user_id, role_id) VALUES (106,2); + +-- scheckbuch +INSERT INTO "user_role" (user_id, role_id) VALUES (109,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (112,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (113,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (114,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (115,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (116,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (118,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (119,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (120,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (121,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (122,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (123,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (124,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (126,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (127,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (128,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (129,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (130,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (131,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (132,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (133,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (135,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (136,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (137,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (138,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (139,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (140,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (141,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (142,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (143,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (144,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (145,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (146,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (147,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (153,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (154,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (155,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (159,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (669,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (670,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (671,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (672,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (673,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (674,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (675,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (676,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (677,3); +INSERT INTO "user_role" (user_id, role_id) VALUES (678,3); + +-- tech +INSERT INTO "user_role" (user_id, role_id) VALUES (38,4); +INSERT INTO "user_role" (user_id, role_id) VALUES (69,4); diff --git a/templates/admin/user/index.html.tera b/templates/admin/user/index.html.tera index 5e748ac..a23ec65 100644 --- a/templates/admin/user/index.html.tera +++ b/templates/admin/user/index.html.tera @@ -18,10 +18,6 @@ -
- -
@@ -53,10 +49,9 @@ {% endif %}
- {{ macros::checkbox(label='Scheckbuch', name='is_guest', id=loop.index , checked=user.is_guest) }} - {{ macros::checkbox(label='Steuerberechtigter', name='is_cox', id=loop.index , checked=user.is_cox) }} - {{ macros::checkbox(label='Technical', name='is_tech', id=loop.index , checked=user.is_tech) }} - {{ macros::checkbox(label='Admin', name='is_admin', id=loop.index , checked=user.is_admin) }} + {% for role in roles %} + {{ macros::checkbox(label=role.name, name="roles[" ~ role.id ~ "]", id=loop.index , checked=role.name in user.roles) }} + {% endfor%} {{ macros::input(label='DOB', name='dob', id=loop.index, type="text", value=user.dob) }} {{ macros::input(label='Weight (kg)', name='weight', id=loop.index, type="text", value=user.weight) }} {{ macros::input(label='Sex', name='sex', id=loop.index, type="text", value=user.sex) }} diff --git a/templates/boatdamages.html.tera b/templates/boatdamages.html.tera index 49e2d2f..391f166 100644 --- a/templates/boatdamages.html.tera +++ b/templates/boatdamages.html.tera @@ -57,10 +57,10 @@ {% if boatdamage.fixed_at %} Repariert von {{ boatdamage.user_fixed.name }} am/um {{ boatdamage.fixed_at | date(format='%d.%m.%Y (%H:%M)') }} {% else %} - {% if loggedin_user.is_cox %} + {% if "cox" in loggedin_user.roles %}
- {% if loggedin_user.is_tech %} + {% if "tech" in loggedin_user.roles %} {% else %} @@ -72,7 +72,7 @@ {% if boatdamage.verified_at %} Verifziert von {{ boatdamage.user_verified.name }} am/um {{ boatdamage.verified_at | date(format='%d.%m.%Y (%H:%M)') }} {% else %} - {% if loggedin_user.is_tech and boatdamage.fixed_at %} + {% if "tech" in loggedin_user.roles and boatdamage.fixed_at %} diff --git a/templates/ergo.html.tera b/templates/ergo.html.tera index 71e20db..be69f49 100644 --- a/templates/ergo.html.tera +++ b/templates/ergo.html.tera @@ -132,7 +132,7 @@
- {% if loggedin_user.is_admin %} + {% if "admin" in loggedin_user.roles %}

Update

diff --git a/templates/includes/buttons.html.tera b/templates/includes/buttons.html.tera index eb91a1f..5af6043 100644 --- a/templates/includes/buttons.html.tera +++ b/templates/includes/buttons.html.tera @@ -1,4 +1,4 @@ -{% if loggedin_user.is_cox %} +{% if "cox" in loggedin_user.roles %}
{% endif %} - {% if not loggedin_user.is_guest %} + {% if "scheckbuch" not in loggedin_user.roles %} Bootsauswertung - {% if loggedin_user.is_admin %} + {% if "admin" in loggedin_user.roles %}
{% endif %} - {% if loggedin_user.is_admin %} + {% if "admin" in loggedin_user.roles %} 0 %} {% set amount_cur_rower = planned_event.rower | length %} - {{ macros::box(participants=planned_event.rower, empty_seats=planned_event.max_people - amount_cur_rower, bg='primary-100', color='black', trip_details_id=planned_event.trip_details_id, allow_removing=loggedin_user.is_admin) }} + {{ macros::box(participants=planned_event.rower, empty_seats=planned_event.max_people - amount_cur_rower, bg='primary-100', color='black', trip_details_id=planned_event.trip_details_id, allow_removing="admin" in loggedin_user.roles) }} {% endif %} {# --- END List Rowers --- #} - {% if loggedin_user.is_admin %} + {% if "admin" in loggedin_user.roles %} {{ macros::input(label='Gast', class="input rounded-t", name='user_note', type='text', required=true) }} @@ -127,7 +127,7 @@
Gäste willkommen!
{% endif %} - {% if loggedin_user.is_admin %} + {% if "admin" in loggedin_user.roles %} {# --- START Edit Form --- #}
@@ -258,9 +258,9 @@
{# --- START Add Buttons --- #} - {% if loggedin_user.is_admin or loggedin_user.is_cox %} -
-{% if loggedin_user.is_cox %} +{% if "cox" in loggedin_user.roles %} {% include "forms/trip" %} {% endif %} -{% if loggedin_user.is_admin %} +{% if "admin" in loggedin_user.roles %} {% include "forms/event" %} {% endif %}{% endblock content %} diff --git a/templates/log.html.tera b/templates/log.html.tera index 24d54ee..7ed60bd 100644 --- a/templates/log.html.tera +++ b/templates/log.html.tera @@ -24,7 +24,7 @@

Neue Ausfahrt

- {{ log::new(only_ones=loggedin_user.is_cox==false, shipmaster=loggedin_user.id) }} + {{ log::new(only_ones="cox" not in loggedin_user.roles, shipmaster=loggedin_user.id) }}
@@ -33,7 +33,7 @@ {% if on_water | length > 0 %} {% for log in on_water %} {% if log.shipmaster == loggedin_user.id %} - {{ log::show(log=log, state="on_water", allowed_to_close=true, only_ones=loggedin_user.is_cox==false) }} + {{ log::show(log=log, state="on_water", allowed_to_close=true, only_ones="cox" not in loggedin_user.roles) }} {% else %} {{ log::show(log=log, state="on_water", only_ones=true) }} {% endif %}