feat: progress on general portal
This commit is contained in:
parent
6b34a41b7d
commit
ba4e4af609
2
.env
2
.env
@ -1,5 +1,5 @@
|
||||
# Postgres
|
||||
# DATABASE_URL=postgres://postgres@localhost/my_database
|
||||
# SQLite
|
||||
DATABASE_URL=sqlite:brass.db
|
||||
DATABASE_URL=postgresql://max@localhost/brass
|
||||
|
||||
|
352
Cargo.lock
generated
352
Cargo.lock
generated
@ -8,7 +8,7 @@ version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "617a8268e3537fe1d8c9ead925fca49ef6400927ee7bc26750e90ecee14ce4b8"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
@ -19,6 +19,29 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "actix-files"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf0bdd6ff79de7c9a021f5d9ea79ce23e108d8bfc9b49b5b4a2cf6fad5a35212"
|
||||
dependencies = [
|
||||
"actix-http",
|
||||
"actix-service",
|
||||
"actix-utils",
|
||||
"actix-web",
|
||||
"bitflags 2.4.2",
|
||||
"bytes",
|
||||
"derive_more",
|
||||
"futures-core",
|
||||
"http-range",
|
||||
"log",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"v_htmlescape",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "actix-http"
|
||||
version = "3.3.1"
|
||||
@ -31,7 +54,7 @@ dependencies = [
|
||||
"actix-utils",
|
||||
"ahash 0.8.3",
|
||||
"base64 0.21.2",
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"brotli",
|
||||
"bytes",
|
||||
"bytestring",
|
||||
@ -304,6 +327,21 @@ dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.71"
|
||||
@ -508,6 +546,12 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.20.0"
|
||||
@ -541,6 +585,12 @@ version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
|
||||
|
||||
[[package]]
|
||||
name = "blake2"
|
||||
version = "0.10.6"
|
||||
@ -578,12 +628,14 @@ dependencies = [
|
||||
name = "brass"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"actix-files",
|
||||
"actix-identity",
|
||||
"actix-session",
|
||||
"actix-web",
|
||||
"anyhow",
|
||||
"argon2",
|
||||
"askama",
|
||||
"chrono",
|
||||
"dotenv",
|
||||
"serde",
|
||||
"sqlx",
|
||||
@ -652,6 +704,20 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f13690e35a5e4ace198e7beea2895d29f3a9cc55015fcebe6336bd2010af9eb"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"wasm-bindgen",
|
||||
"windows-targets 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cipher"
|
||||
version = "0.4.4"
|
||||
@ -695,6 +761,12 @@ dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.7"
|
||||
@ -791,6 +863,26 @@ dependencies = [
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "4.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
|
||||
dependencies = [
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_users",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dotenv"
|
||||
version = "0.15.0"
|
||||
@ -864,18 +956,6 @@ dependencies = [
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flume"
|
||||
version = "0.10.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"pin-project",
|
||||
"spin 0.9.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
@ -907,17 +987,6 @@ version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-intrusive"
|
||||
version = "0.4.2"
|
||||
@ -984,7 +1053,6 @@ dependencies = [
|
||||
"futures-task",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1132,6 +1200,12 @@ dependencies = [
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-range"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573"
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.8.0"
|
||||
@ -1153,6 +1227,29 @@ dependencies = [
|
||||
"libm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.59"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.4.0"
|
||||
@ -1263,14 +1360,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
|
||||
|
||||
[[package]]
|
||||
name = "libsqlite3-sys"
|
||||
version = "0.24.2"
|
||||
name = "libredox"
|
||||
version = "0.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "898745e570c7d0453cc1fbc4a701eb6c662ed54e8fec8b7d14be137ebeeb9d14"
|
||||
checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
"bitflags 2.4.2",
|
||||
"libc",
|
||||
"redox_syscall 0.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1316,6 +1413,16 @@ dependencies = [
|
||||
"value-bag",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "md-5"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
@ -1457,7 +1564,7 @@ dependencies = [
|
||||
"libc",
|
||||
"redox_syscall 0.3.5",
|
||||
"smallvec",
|
||||
"windows-targets",
|
||||
"windows-targets 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1483,26 +1590,6 @@ version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead"
|
||||
dependencies = [
|
||||
"pin-project-internal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-internal"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.9"
|
||||
@ -1528,7 +1615,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"cfg-if",
|
||||
"concurrent-queue",
|
||||
"libc",
|
||||
@ -1609,7 +1696,7 @@ version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1618,7 +1705,27 @@ version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"libredox",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1647,7 +1754,7 @@ dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"spin 0.5.2",
|
||||
"spin",
|
||||
"untrusted",
|
||||
"web-sys",
|
||||
"winapi",
|
||||
@ -1668,7 +1775,7 @@ version = "0.37.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"errno",
|
||||
"io-lifetimes",
|
||||
"libc",
|
||||
@ -1840,15 +1947,6 @@ version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.9.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sqlformat"
|
||||
version = "0.2.1"
|
||||
@ -1878,33 +1976,40 @@ checksum = "fa8241483a83a3f33aa5fff7e7d9def398ff9990b2752b6c6112b83c6d246029"
|
||||
dependencies = [
|
||||
"ahash 0.7.6",
|
||||
"atoi",
|
||||
"bitflags",
|
||||
"base64 0.13.1",
|
||||
"bitflags 1.3.2",
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"chrono",
|
||||
"crc",
|
||||
"crossbeam-queue",
|
||||
"dirs",
|
||||
"dotenvy",
|
||||
"either",
|
||||
"event-listener",
|
||||
"flume",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-intrusive",
|
||||
"futures-util",
|
||||
"hashlink",
|
||||
"hex",
|
||||
"hkdf",
|
||||
"hmac",
|
||||
"indexmap",
|
||||
"itoa",
|
||||
"libc",
|
||||
"libsqlite3-sys",
|
||||
"log",
|
||||
"md-5",
|
||||
"memchr",
|
||||
"once_cell",
|
||||
"paste",
|
||||
"percent-encoding",
|
||||
"rand",
|
||||
"rustls",
|
||||
"rustls-pemfile",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha1",
|
||||
"sha2",
|
||||
"smallvec",
|
||||
"sqlformat",
|
||||
@ -1913,6 +2018,7 @@ dependencies = [
|
||||
"thiserror",
|
||||
"url",
|
||||
"webpki-roots",
|
||||
"whoami",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2171,18 +2277,18 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "v_htmlescape"
|
||||
version = "0.15.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e8257fbc510f0a46eb602c10215901938b5c2a7d5e70fc11483b1d3c9b5b18c"
|
||||
|
||||
[[package]]
|
||||
name = "value-bag"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4d330786735ea358f3bc09eea4caa098569c1c93f342d9aca0514915022fe7e"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
@ -2296,6 +2402,16 @@ dependencies = [
|
||||
"webpki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "whoami"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
@ -2318,13 +2434,22 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
"windows-targets 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2333,13 +2458,28 @@ version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
|
||||
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.0",
|
||||
"windows_aarch64_msvc 0.48.0",
|
||||
"windows_i686_gnu 0.48.0",
|
||||
"windows_i686_msvc 0.48.0",
|
||||
"windows_x86_64_gnu 0.48.0",
|
||||
"windows_x86_64_gnullvm 0.48.0",
|
||||
"windows_x86_64_msvc 0.48.0",
|
||||
]
|
||||
|
||||
[[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]]
|
||||
@ -2348,42 +2488,84 @@ version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
|
||||
|
||||
[[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.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
|
||||
|
||||
[[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.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
|
||||
|
||||
[[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.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
|
||||
|
||||
[[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.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
|
||||
|
||||
[[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.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
|
||||
|
||||
[[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.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
||||
|
||||
[[package]]
|
||||
name = "zstd"
|
||||
version = "0.12.3+zstd.1.5.2"
|
||||
|
@ -6,7 +6,7 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
sqlx = { version = "0.6", features = [ "runtime-async-std-rustls", "sqlite" ] }
|
||||
sqlx = { version = "0.6", features = ["runtime-async-std-rustls", "postgres", "chrono"] }
|
||||
actix-web = { version = "4" }
|
||||
askama = "0.12.0"
|
||||
serde = { version = "1.0.164", features = [ "derive"]}
|
||||
@ -15,3 +15,5 @@ anyhow = "1.0.71"
|
||||
dotenv = "0.15.0"
|
||||
actix-session = { version = "0.7.2", features = ["cookie-session"] }
|
||||
actix-identity = "0.5.2"
|
||||
chrono = "0.4.33"
|
||||
actix-files = "0.6.5"
|
||||
|
@ -1,18 +1,79 @@
|
||||
CREATE TABLE IF NOT EXISTS roles
|
||||
CREATE TYPE role AS ENUM ('staff', 'area manager', 'admin');
|
||||
CREATE TYPE function AS ENUM ('posten', 'wachhabender');
|
||||
|
||||
CREATE TABLE area
|
||||
(
|
||||
id INTEGER PRIMARY KEY NOT NULL,
|
||||
definition TEXT NOT NULL
|
||||
id SERIAL PRIMARY KEY,
|
||||
name TEXT NOT NULL
|
||||
);
|
||||
|
||||
INSERT OR REPLACE INTO roles(id, definition) values(1, "Default");
|
||||
INSERT OR REPLACE INTO roles(id, definition) values(2, "Administrator");
|
||||
INSERT INTO area (name) VALUES ('Leipzig Ost');
|
||||
|
||||
CREATE TABLE IF NOT EXISTS users
|
||||
CREATE TABLE location
|
||||
(
|
||||
id INTEGER PRIMARY KEY NOT NULL,
|
||||
id SERIAL PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
password_hash TEXT NOT NULL,
|
||||
salt TEXT NOT NULL,
|
||||
role_id INTEGER NOT NULL,
|
||||
FOREIGN KEY(role_id) REFERENCES roles(id)
|
||||
areaId INTEGER NOT NULL REFERENCES area (id)
|
||||
);
|
||||
|
||||
CREATE TABLE user_
|
||||
(
|
||||
id SERIAL PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
email TEXT NOT NULL,
|
||||
password TEXT NOT NULL,
|
||||
salt TEXT NOT NULL,
|
||||
role role NOT NULL,
|
||||
function function NOT NULL,
|
||||
areaId INTEGER NOT NULL REFERENCES area (id),
|
||||
locked BOOLEAN NOT NULL DEFAULT false,
|
||||
lastLogin TIMESTAMP WITH TIME ZONE,
|
||||
receiveNotifications BOOLEAN NOT NULL DEFAULT true
|
||||
);
|
||||
|
||||
CREATE TABLE availabillity
|
||||
(
|
||||
id SERIAL PRIMARY KEY,
|
||||
userId INTEGER NOT NULL REFERENCES user_ (id),
|
||||
date DATE NOT NULL,
|
||||
startTime TIME,
|
||||
endTime TIME
|
||||
);
|
||||
|
||||
CREATE TABLE event
|
||||
(
|
||||
id SERIAL PRIMARY KEY,
|
||||
date DATE NOT NULL,
|
||||
startTime TIME NOT NULL,
|
||||
endTime TIME NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
locationId INTEGER NOT NULL REFERENCES location (id),
|
||||
voluntaryWachhabender BOOLEAN NOT NULL,
|
||||
amountOfPosten SMALLINT NOT NULL CHECK (amountOfPosten >= 0),
|
||||
clothing TEXT NOT NULL,
|
||||
canceled BOOLEAN NOT NULL DEFAULT false
|
||||
);
|
||||
|
||||
CREATE TABLE assignement
|
||||
(
|
||||
eventId INTEGER REFERENCES event (id),
|
||||
availabillityId INTEGER REFERENCES availabillity (id),
|
||||
function function NOT NULL,
|
||||
startTime TIME,
|
||||
endTime TIME,
|
||||
PRIMARY KEY (eventId, availabillityId)
|
||||
);
|
||||
|
||||
CREATE TABLE vehicle
|
||||
(
|
||||
id SERIAL PRIMARY KEY,
|
||||
radioCallName TEXT NOT NULL,
|
||||
station TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE vehicleassignement
|
||||
(
|
||||
eventId INTEGER REFERENCES event (id),
|
||||
vehicleId INTEGER REFERENCES vehicle (id),
|
||||
PRIMARY KEY (eventId, vehicleId)
|
||||
);
|
||||
|
@ -1,4 +1,4 @@
|
||||
pub mod routes;
|
||||
mod utils;
|
||||
pub mod utils;
|
||||
|
||||
pub use routes::init;
|
||||
|
@ -1,23 +1,18 @@
|
||||
use actix_web::{web, HttpResponse, Responder};
|
||||
use askama::Template;
|
||||
use sqlx::SqlitePool;
|
||||
|
||||
use crate::models::Role;
|
||||
use sqlx::PgPool;
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "register.html")]
|
||||
struct RegisterTemplate {
|
||||
roles: Vec<Role>,
|
||||
// roles: Vec<Role>,
|
||||
}
|
||||
|
||||
#[actix_web::get("/register")]
|
||||
async fn route(pool: web::Data<SqlitePool>) -> impl Responder {
|
||||
let roles = match Role::GetAll(pool.get_ref()).await {
|
||||
Ok(value) => value,
|
||||
Err(error) => return HttpResponse::InternalServerError().body(error.to_string()),
|
||||
};
|
||||
async fn route(pool: web::Data<PgPool>) -> impl Responder {
|
||||
|
||||
let bla = RegisterTemplate { roles };
|
||||
|
||||
let bla = RegisterTemplate { };
|
||||
|
||||
HttpResponse::Ok().body(bla.render().unwrap())
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
use actix_identity::Identity;
|
||||
use actix_web::{web, HttpMessage, HttpRequest, HttpResponse, Responder};
|
||||
use serde::Deserialize;
|
||||
use sqlx::SqlitePool;
|
||||
use sqlx::PgPool;
|
||||
|
||||
use crate::{auth::utils::hash_plain_password_with_salt, models::user::User};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct LoginForm {
|
||||
name: String,
|
||||
email: String,
|
||||
password: String,
|
||||
}
|
||||
|
||||
@ -15,20 +15,23 @@ struct LoginForm {
|
||||
async fn route(
|
||||
web::Form(form): web::Form<LoginForm>,
|
||||
request: HttpRequest,
|
||||
pool: web::Data<SqlitePool>,
|
||||
pool: web::Data<PgPool>,
|
||||
) -> impl Responder {
|
||||
match User::read_by_name(pool.get_ref(), &form.name).await {
|
||||
Some(potential_user) => {
|
||||
let hash = hash_plain_password_with_salt(&form.password, &potential_user.salt).unwrap();
|
||||
|
||||
if hash == potential_user.password_hash {
|
||||
Identity::login(&request.extensions(), potential_user.id.to_string());
|
||||
if let Ok(result) = User::read_for_login(pool.get_ref(), &form.email).await {
|
||||
if let Some(user) = result {
|
||||
let hash = hash_plain_password_with_salt(&form.password, &user.salt).unwrap();
|
||||
if hash == user.password {
|
||||
Identity::login(&request.extensions(), user.id.to_string());
|
||||
|
||||
return HttpResponse::Ok().body("Angemeldet!");
|
||||
} else {
|
||||
return HttpResponse::Unauthorized().body("Nutzername oder Passwort falsch.");
|
||||
}
|
||||
} else {
|
||||
return HttpResponse::Unauthorized().body("Nutzername oder Passwort falsch.");
|
||||
}
|
||||
None => return HttpResponse::Unauthorized().body("Nutzername oder Passwort falsch."),
|
||||
} else {
|
||||
return HttpResponse::Unauthorized().body("Nutzername oder Passwort falsch.");
|
||||
}
|
||||
}
|
||||
|
@ -1,24 +1,47 @@
|
||||
use actix_web::{http::header::LOCATION, web, HttpResponse, Responder};
|
||||
use serde::Deserialize;
|
||||
use sqlx::SqlitePool;
|
||||
use sqlx::PgPool;
|
||||
|
||||
use crate::{auth::utils::generate_salt_and_hash_plain_password, models::user::User};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct RegisterForm {
|
||||
name: String,
|
||||
password: String,
|
||||
role: i64,
|
||||
pub name: String,
|
||||
pub email: String,
|
||||
pub password: String,
|
||||
pub role_id: u8,
|
||||
pub function_id: u8,
|
||||
pub area_id: i32,
|
||||
}
|
||||
|
||||
#[actix_web::post("/register")]
|
||||
async fn route(
|
||||
web::Form(form): web::Form<RegisterForm>,
|
||||
pool: web::Data<SqlitePool>,
|
||||
pool: web::Data<PgPool>,
|
||||
) -> impl Responder {
|
||||
let (hash, salt) = generate_salt_and_hash_plain_password(&form.password).unwrap();
|
||||
|
||||
let result = User::create(pool.get_ref(), form.name, hash, salt, form.role).await;
|
||||
let role = match form.role_id.try_into() {
|
||||
Ok(role) => role,
|
||||
Err(_) => return HttpResponse::BadRequest().body("fsdf"),
|
||||
};
|
||||
|
||||
let function = match form.function_id.try_into() {
|
||||
Ok(function) => function,
|
||||
Err(_) => return HttpResponse::BadRequest().body("fsdf"),
|
||||
};
|
||||
|
||||
let result = User::create(
|
||||
pool.get_ref(),
|
||||
form.name,
|
||||
form.email,
|
||||
hash,
|
||||
salt,
|
||||
role,
|
||||
function,
|
||||
form.area_id,
|
||||
)
|
||||
.await;
|
||||
|
||||
match result {
|
||||
Ok(_) => {
|
||||
|
@ -1,12 +1,31 @@
|
||||
use actix_identity::Identity;
|
||||
use actix_web::{Responder, web, HttpResponse};
|
||||
use actix_web::{http::header::LOCATION, web, HttpResponse, Responder};
|
||||
use askama::Template;
|
||||
use sqlx::PgPool;
|
||||
|
||||
use crate::models::{role::Role, user::User};
|
||||
|
||||
pub fn init(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(get_login);
|
||||
cfg.service(get_index);
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "index.html")]
|
||||
struct CalendarTemplate {
|
||||
user_role: Role,
|
||||
}
|
||||
|
||||
#[actix_web::get("/")]
|
||||
async fn get_login(user: Identity) -> impl Responder {
|
||||
async fn get_index(user: Option<Identity>, pool: web::Data<PgPool>) -> impl Responder {
|
||||
if let Some(user) = user {
|
||||
let current_user = User::read_by_id(pool.get_ref(), user.id().unwrap().parse().unwrap()).await.unwrap();
|
||||
|
||||
HttpResponse::Ok().body("Hierfür muss man angemeldet sein!")
|
||||
let template = CalendarTemplate{ user_role: current_user.role };
|
||||
|
||||
HttpResponse::Ok().body(template.render().unwrap())
|
||||
} else {
|
||||
HttpResponse::PermanentRedirect()
|
||||
.insert_header((LOCATION, "/login"))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use actix_session::{storage::CookieSessionStore, SessionMiddleware};
|
||||
use actix_web::cookie::Key;
|
||||
use actix_web::{web, App, HttpServer};
|
||||
use dotenv::dotenv;
|
||||
use sqlx::sqlite::SqlitePool;
|
||||
use sqlx::postgres::PgPool;
|
||||
|
||||
mod auth;
|
||||
mod calendar;
|
||||
@ -14,7 +14,7 @@ mod models;
|
||||
#[actix_web::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
dotenv()?;
|
||||
let pool = SqlitePool::connect(&env::var("DATABASE_URL")?).await?;
|
||||
let pool = PgPool::connect(&env::var("DATABASE_URL")?).await?;
|
||||
let secret_key = Key::generate();
|
||||
|
||||
println!("Starting server on http://localhost:8080.");
|
||||
@ -29,6 +29,7 @@ async fn main() -> anyhow::Result<()> {
|
||||
CookieSessionStore::default(),
|
||||
secret_key.clone(),
|
||||
))
|
||||
.service(actix_files::Files::new("", "./static").show_files_listing())
|
||||
})
|
||||
.bind(("127.0.0.1", 8080))?
|
||||
.run()
|
||||
|
26
src/models/area.rs
Normal file
26
src/models/area.rs
Normal file
@ -0,0 +1,26 @@
|
||||
use sqlx::{query, query_as, PgPool};
|
||||
|
||||
pub struct Area {
|
||||
pub id: i32,
|
||||
pub name: String
|
||||
}
|
||||
|
||||
impl Area {
|
||||
pub async fn create(pool: &PgPool, name: &str) -> anyhow::Result<i32> {
|
||||
let result = query!("INSERT INTO area (name) VALUES ($1) RETURNING id;", name).fetch_one(pool).await?;
|
||||
|
||||
Ok(result.id)
|
||||
}
|
||||
|
||||
pub async fn read_by_id(pool: &PgPool, id: i32) -> anyhow::Result<Option<Area>> {
|
||||
let record = query_as!(Area, "SELECT * FROM area WHERE id = $1", id).fetch_optional(pool).await?;
|
||||
|
||||
Ok(record)
|
||||
}
|
||||
|
||||
pub async fn read_all(pool: &PgPool) -> anyhow::Result<Vec<Area>> {
|
||||
let records = query_as!(Area, "SELECT * FROM area").fetch_all(pool).await?;
|
||||
|
||||
Ok(records)
|
||||
}
|
||||
}
|
0
src/models/assignement.rs
Normal file
0
src/models/assignement.rs
Normal file
0
src/models/availabillity.rs
Normal file
0
src/models/availabillity.rs
Normal file
57
src/models/event.rs
Normal file
57
src/models/event.rs
Normal file
@ -0,0 +1,57 @@
|
||||
use chrono::{NaiveDate, NaiveTime};
|
||||
use sqlx::{query, query_as, PgPool};
|
||||
|
||||
pub struct Event {
|
||||
pub id: i32,
|
||||
pub date: NaiveDate,
|
||||
pub start_time: NaiveTime,
|
||||
pub end_time: NaiveTime,
|
||||
pub name: String,
|
||||
pub location_id: i32,
|
||||
pub voluntary_wachhabender: bool,
|
||||
pub amount_of_posten: i16,
|
||||
pub clothing: String,
|
||||
pub canceled: bool,
|
||||
}
|
||||
|
||||
impl Event {
|
||||
pub async fn create(
|
||||
pool: &PgPool,
|
||||
date: NaiveDate,
|
||||
start_time: NaiveTime,
|
||||
end_time: NaiveTime,
|
||||
name: String,
|
||||
location_id: i32,
|
||||
voluntary_wachhabender: bool,
|
||||
amount_of_posten: i16,
|
||||
clothing: String,
|
||||
) -> anyhow::Result<i32> {
|
||||
let result = query!("INSERT INTO event (date, startTime, endTime, name, locationId, voluntaryWachhabender, amountOfPosten, clothing) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING id;", date, start_time, end_time, name, location_id, voluntary_wachhabender, amount_of_posten, clothing).fetch_one(pool).await?;
|
||||
|
||||
Ok(result.id)
|
||||
}
|
||||
|
||||
pub async fn read_by_date(pool: &PgPool, date: NaiveDate) -> anyhow::Result<Vec<Event>> {
|
||||
let records = query!("SELECT * FROM event WHERE date = $1;", date)
|
||||
.fetch_all(pool)
|
||||
.await?;
|
||||
|
||||
let events = records
|
||||
.iter()
|
||||
.map(|record| Event {
|
||||
id: record.id,
|
||||
date: record.date,
|
||||
start_time: record.starttime,
|
||||
end_time: record.endtime,
|
||||
name: record.name.to_string(),
|
||||
location_id: record.locationid,
|
||||
voluntary_wachhabender: record.voluntarywachhabender,
|
||||
amount_of_posten: record.amountofposten,
|
||||
clothing: record.clothing.to_string(),
|
||||
canceled: record.canceled,
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(events)
|
||||
}
|
||||
}
|
18
src/models/function.rs
Normal file
18
src/models/function.rs
Normal file
@ -0,0 +1,18 @@
|
||||
#[derive(sqlx::Type, Debug)]
|
||||
#[sqlx(type_name = "function", rename_all = "lowercase")]
|
||||
pub enum Function {
|
||||
Posten = 1,
|
||||
Wachhabender = 10,
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for Function {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
1 => Ok(Function::Posten),
|
||||
10 => Ok(Function::Wachhabender),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
9
src/models/location.rs
Normal file
9
src/models/location.rs
Normal file
@ -0,0 +1,9 @@
|
||||
pub struct Location {
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
pub areaId: i32
|
||||
}
|
||||
|
||||
impl Location {
|
||||
|
||||
}
|
@ -1,34 +1,9 @@
|
||||
pub mod role;
|
||||
pub mod function;
|
||||
pub mod user;
|
||||
|
||||
use sqlx::sqlite::SqlitePool;
|
||||
|
||||
pub struct Role {
|
||||
pub id: u8,
|
||||
pub definition: String
|
||||
}
|
||||
|
||||
impl Role {
|
||||
pub async fn GetAll(pool: &SqlitePool) -> anyhow::Result<Vec<Role>> {
|
||||
let records = sqlx::query!(
|
||||
r#"
|
||||
SELECT id, definition
|
||||
FROM roles
|
||||
ORDER BY id
|
||||
"#
|
||||
)
|
||||
.fetch_all(pool)
|
||||
.await?;
|
||||
|
||||
let mut result = Vec::new();
|
||||
|
||||
for record in records {
|
||||
let role = Role {
|
||||
id: record.id as u8,
|
||||
definition: record.definition,
|
||||
};
|
||||
result.push(role);
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
pub mod event;
|
||||
pub mod area;
|
||||
pub mod vehicle;
|
||||
pub mod availabillity;
|
||||
pub mod assignement;
|
||||
pub mod location;
|
||||
|
20
src/models/role.rs
Normal file
20
src/models/role.rs
Normal file
@ -0,0 +1,20 @@
|
||||
#[derive(sqlx::Type, Debug)]
|
||||
#[sqlx(type_name = "role", rename_all = "lowercase")]
|
||||
pub enum Role {
|
||||
Staff = 1,
|
||||
AreaManager = 10,
|
||||
Admin = 100,
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for Role {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
1 => Ok(Role::Staff),
|
||||
10 => Ok(Role::AreaManager),
|
||||
100 => Ok(Role::Admin),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
@ -1,47 +1,72 @@
|
||||
use sqlx::sqlite::SqlitePool;
|
||||
use chrono::{DateTime, Utc};
|
||||
use sqlx::PgPool;
|
||||
|
||||
use super::{function::Function, role::Role};
|
||||
|
||||
pub struct User {
|
||||
pub id: i64,
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
pub password_hash: String,
|
||||
pub email: String,
|
||||
pub password: String,
|
||||
pub salt: String,
|
||||
pub role_id: i64,
|
||||
pub role: Role,
|
||||
pub function: Function,
|
||||
pub area_id: i32,
|
||||
pub locked: bool,
|
||||
pub last_login: Option<DateTime<Utc>>,
|
||||
pub receive_notifications: bool,
|
||||
}
|
||||
|
||||
impl User {
|
||||
pub async fn create(
|
||||
pool: &SqlitePool,
|
||||
pool: &PgPool,
|
||||
name: String,
|
||||
password_hash: String,
|
||||
email: String,
|
||||
password: String,
|
||||
salt: String,
|
||||
role_id: i64,
|
||||
) -> anyhow::Result<i64> {
|
||||
role: Role,
|
||||
function: Function,
|
||||
area_id: i32,
|
||||
) -> anyhow::Result<i32> {
|
||||
let created = sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO users (name, password_hash, salt, role_id)
|
||||
VALUES (?1, ?2, ?3, ?4);
|
||||
INSERT INTO user_ (name, email, password, salt, role, function, areaId)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
RETURNING id;
|
||||
"#,
|
||||
name,
|
||||
password_hash,
|
||||
email,
|
||||
password,
|
||||
salt,
|
||||
role_id
|
||||
role as Role,
|
||||
function as Function,
|
||||
area_id
|
||||
)
|
||||
.execute(pool)
|
||||
.fetch_one(pool)
|
||||
.await;
|
||||
|
||||
match created {
|
||||
Ok(result) => Ok(result.last_insert_rowid()),
|
||||
Ok(result) => Ok(result.id),
|
||||
Err(err) => Err(err.into()),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn read_by_id(pool: &SqlitePool, id: i64) -> Option<User> {
|
||||
let record = sqlx::query_as!(
|
||||
User,
|
||||
pub async fn read_by_id(pool: &PgPool, id: i32) -> Option<User> {
|
||||
let record = sqlx::query!(
|
||||
r#"
|
||||
SELECT *
|
||||
FROM users
|
||||
WHERE id = ?1;
|
||||
SELECT id,
|
||||
name,
|
||||
email,
|
||||
password,
|
||||
salt,
|
||||
role AS "role: Role",
|
||||
function AS "function: Function",
|
||||
areaId,
|
||||
locked,
|
||||
lastLogin,
|
||||
receiveNotifications
|
||||
FROM user_
|
||||
WHERE id = $1;
|
||||
"#,
|
||||
id,
|
||||
)
|
||||
@ -49,7 +74,19 @@ impl User {
|
||||
.await;
|
||||
|
||||
match record {
|
||||
Ok(record) => Some(record),
|
||||
Ok(record) => Some(User {
|
||||
id: record.id,
|
||||
name: record.name,
|
||||
email: record.email,
|
||||
password: record.password,
|
||||
salt: record.salt,
|
||||
role: record.role,
|
||||
function: record.function,
|
||||
area_id: record.areaid,
|
||||
locked: record.locked,
|
||||
last_login: record.lastlogin,
|
||||
receive_notifications: record.receivenotifications,
|
||||
}),
|
||||
Err(err) => {
|
||||
println!("User.read({id}): {err}");
|
||||
None
|
||||
@ -57,25 +94,57 @@ impl User {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn read_by_name(pool: &SqlitePool, name: &str) -> Option<User> {
|
||||
let record = sqlx::query_as!(
|
||||
User,
|
||||
pub async fn read_for_login(pool: &PgPool, email: &str) -> anyhow::Result<Option<User>> {
|
||||
let record = sqlx::query!(
|
||||
r#"
|
||||
SELECT *
|
||||
FROM users
|
||||
WHERE name = ?1;
|
||||
SELECT id,
|
||||
name,
|
||||
email,
|
||||
password,
|
||||
salt,
|
||||
role AS "role: Role",
|
||||
function AS "function: Function",
|
||||
areaId,
|
||||
locked,
|
||||
lastLogin,
|
||||
receiveNotifications
|
||||
FROM user_
|
||||
WHERE email = $1;
|
||||
"#,
|
||||
name
|
||||
email,
|
||||
)
|
||||
.fetch_one(pool)
|
||||
.await;
|
||||
.fetch_optional(pool)
|
||||
.await?;
|
||||
|
||||
match record {
|
||||
Ok(record) => Some(record),
|
||||
Err(err) => {
|
||||
println!("User.read({name}): {err}");
|
||||
None
|
||||
}
|
||||
}
|
||||
let result = match record {
|
||||
Some(record) => Some(User {
|
||||
id: record.id,
|
||||
name: record.name,
|
||||
email: record.email,
|
||||
password: record.password,
|
||||
salt: record.salt,
|
||||
role: record.role,
|
||||
function: record.function,
|
||||
area_id: record.areaid,
|
||||
locked: record.locked,
|
||||
last_login: record.lastlogin,
|
||||
receive_notifications: record.receivenotifications,
|
||||
}),
|
||||
None => None
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub async fn read_all(pool: &PgPool) -> Option<Vec<User>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub async fn update(pool: &PgPool, id: i32, updated_user: User) -> Option<User> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub async fn delete(pool: &PgPool, id: i32) -> anyhow::Result<bool> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
0
src/models/vehicle.rs
Normal file
0
src/models/vehicle.rs
Normal file
11851
static/bulma.css
vendored
Normal file
11851
static/bulma.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
static/bulma.css.map
Normal file
1
static/bulma.css.map
Normal file
File diff suppressed because one or more lines are too long
1
static/bulma.min.css
vendored
Normal file
1
static/bulma.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
16
templates/base.html
Normal file
16
templates/base.html
Normal file
@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Brass - Brasiwa Leipzig</title>
|
||||
<link rel="stylesheet" href="bulma.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{% block body %}
|
||||
{% endblock %}
|
||||
</body>
|
||||
|
||||
</html>
|
7
templates/index.html
Normal file
7
templates/index.html
Normal file
@ -0,0 +1,7 @@
|
||||
{% extends "nav.html" %}
|
||||
|
||||
{% block content %}
|
||||
<p>
|
||||
Content
|
||||
</p>
|
||||
{% endblock %}
|
@ -1,18 +1,15 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Brass - Login</title>
|
||||
</head>
|
||||
<body>
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block body %}
|
||||
<h1>Brass - Anmeldung</h1>
|
||||
<p>Gib dein Nutzernamen und das Passwort ein:</p>
|
||||
<form>
|
||||
<label for="name">Nutzername:</label>
|
||||
<input name="name" type="text">
|
||||
<label for="email">E-Mail:</label>
|
||||
<input name="email" type="text">
|
||||
|
||||
<label for="password">Passwort:</label>
|
||||
<input name="password" type="password">
|
||||
|
||||
<input type="submit" formmethod="post">
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
{% endblock %}
|
||||
|
47
templates/nav.html
Normal file
47
templates/nav.html
Normal file
@ -0,0 +1,47 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block body %}
|
||||
<nav class="navbar" role="navigation" aria-label="main navigation">
|
||||
<div class="navbar-brand">
|
||||
<a class="navbar-item" href="/">
|
||||
BRASS
|
||||
</a>
|
||||
|
||||
<a role="button" class="navbar-burger" aria-label="menu" aria-expanded="false" data-target="navbarBasicExample">
|
||||
<span aria-hidden="true"></span>
|
||||
<span aria-hidden="true"></span>
|
||||
<span aria-hidden="true"></span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="navbar-menu">
|
||||
<div class="navbar-start">
|
||||
<a class="navbar-item">
|
||||
Kalender
|
||||
</a>
|
||||
|
||||
{% match user_role %}
|
||||
{% when AreaManager %}
|
||||
<a class="navbar-item">
|
||||
Planung
|
||||
</a>
|
||||
{% endmatch %}
|
||||
</div>
|
||||
|
||||
<div class="navbar-end">
|
||||
<div class="navbar-item">
|
||||
<div class="buttons">
|
||||
<a class="button is-primary">
|
||||
Profil
|
||||
</a>
|
||||
<a class="button is-light">
|
||||
Abmelden
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
{% endblock %}
|
@ -14,9 +14,9 @@
|
||||
|
||||
<label for="role">Rolle:</label>
|
||||
<select name="role">
|
||||
{% for role in roles %}
|
||||
<option value="{{ role.id }}">{{ role.definition }}</option>
|
||||
{% endfor %}
|
||||
<option value="1">Staff</option>
|
||||
<option value="10">AreaManager</option>
|
||||
<option value="100">Admin</option>
|
||||
</select>
|
||||
|
||||
<input type="submit" formmethod="post">
|
||||
|
Loading…
x
Reference in New Issue
Block a user