feat: progress on general portal

This commit is contained in:
Max Hohlfeld 2024-01-31 22:07:10 +01:00
parent 6b34a41b7d
commit ba4e4af609
28 changed files with 12593 additions and 213 deletions

2
.env
View File

@ -1,5 +1,5 @@
# Postgres # Postgres
# DATABASE_URL=postgres://postgres@localhost/my_database # DATABASE_URL=postgres://postgres@localhost/my_database
# SQLite # SQLite
DATABASE_URL=sqlite:brass.db DATABASE_URL=postgresql://max@localhost/brass

352
Cargo.lock generated
View File

@ -8,7 +8,7 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "617a8268e3537fe1d8c9ead925fca49ef6400927ee7bc26750e90ecee14ce4b8" checksum = "617a8268e3537fe1d8c9ead925fca49ef6400927ee7bc26750e90ecee14ce4b8"
dependencies = [ dependencies = [
"bitflags", "bitflags 1.3.2",
"bytes", "bytes",
"futures-core", "futures-core",
"futures-sink", "futures-sink",
@ -19,6 +19,29 @@ dependencies = [
"tracing", "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]] [[package]]
name = "actix-http" name = "actix-http"
version = "3.3.1" version = "3.3.1"
@ -31,7 +54,7 @@ dependencies = [
"actix-utils", "actix-utils",
"ahash 0.8.3", "ahash 0.8.3",
"base64 0.21.2", "base64 0.21.2",
"bitflags", "bitflags 1.3.2",
"brotli", "brotli",
"bytes", "bytes",
"bytestring", "bytestring",
@ -304,6 +327,21 @@ dependencies = [
"alloc-no-stdlib", "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]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.71" version = "1.0.71"
@ -508,6 +546,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "base64"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]] [[package]]
name = "base64" name = "base64"
version = "0.20.0" version = "0.20.0"
@ -541,6 +585,12 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
[[package]] [[package]]
name = "blake2" name = "blake2"
version = "0.10.6" version = "0.10.6"
@ -578,12 +628,14 @@ dependencies = [
name = "brass" name = "brass"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"actix-files",
"actix-identity", "actix-identity",
"actix-session", "actix-session",
"actix-web", "actix-web",
"anyhow", "anyhow",
"argon2", "argon2",
"askama", "askama",
"chrono",
"dotenv", "dotenv",
"serde", "serde",
"sqlx", "sqlx",
@ -652,6 +704,20 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 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]] [[package]]
name = "cipher" name = "cipher"
version = "0.4.4" version = "0.4.4"
@ -695,6 +761,12 @@ dependencies = [
"version_check", "version_check",
] ]
[[package]]
name = "core-foundation-sys"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
[[package]] [[package]]
name = "cpufeatures" name = "cpufeatures"
version = "0.2.7" version = "0.2.7"
@ -791,6 +863,26 @@ dependencies = [
"subtle", "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]] [[package]]
name = "dotenv" name = "dotenv"
version = "0.15.0" version = "0.15.0"
@ -864,18 +956,6 @@ dependencies = [
"miniz_oxide", "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]] [[package]]
name = "fnv" name = "fnv"
version = "1.0.7" version = "1.0.7"
@ -907,17 +987,6 @@ version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" 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]] [[package]]
name = "futures-intrusive" name = "futures-intrusive"
version = "0.4.2" version = "0.4.2"
@ -984,7 +1053,6 @@ dependencies = [
"futures-task", "futures-task",
"pin-project-lite", "pin-project-lite",
"pin-utils", "pin-utils",
"slab",
] ]
[[package]] [[package]]
@ -1132,6 +1200,12 @@ dependencies = [
"itoa", "itoa",
] ]
[[package]]
name = "http-range"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573"
[[package]] [[package]]
name = "httparse" name = "httparse"
version = "1.8.0" version = "1.8.0"
@ -1153,6 +1227,29 @@ dependencies = [
"libm", "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]] [[package]]
name = "idna" name = "idna"
version = "0.4.0" version = "0.4.0"
@ -1263,14 +1360,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
[[package]] [[package]]
name = "libsqlite3-sys" name = "libredox"
version = "0.24.2" version = "0.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "898745e570c7d0453cc1fbc4a701eb6c662ed54e8fec8b7d14be137ebeeb9d14" checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8"
dependencies = [ dependencies = [
"cc", "bitflags 2.4.2",
"pkg-config", "libc",
"vcpkg", "redox_syscall 0.4.1",
] ]
[[package]] [[package]]
@ -1316,6 +1413,16 @@ dependencies = [
"value-bag", "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]] [[package]]
name = "memchr" name = "memchr"
version = "2.5.0" version = "2.5.0"
@ -1457,7 +1564,7 @@ dependencies = [
"libc", "libc",
"redox_syscall 0.3.5", "redox_syscall 0.3.5",
"smallvec", "smallvec",
"windows-targets", "windows-targets 0.48.0",
] ]
[[package]] [[package]]
@ -1483,26 +1590,6 @@ version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" 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]] [[package]]
name = "pin-project-lite" name = "pin-project-lite"
version = "0.2.9" version = "0.2.9"
@ -1528,7 +1615,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"bitflags", "bitflags 1.3.2",
"cfg-if", "cfg-if",
"concurrent-queue", "concurrent-queue",
"libc", "libc",
@ -1609,7 +1696,7 @@ version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
dependencies = [ dependencies = [
"bitflags", "bitflags 1.3.2",
] ]
[[package]] [[package]]
@ -1618,7 +1705,27 @@ version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
dependencies = [ 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]] [[package]]
@ -1647,7 +1754,7 @@ dependencies = [
"cc", "cc",
"libc", "libc",
"once_cell", "once_cell",
"spin 0.5.2", "spin",
"untrusted", "untrusted",
"web-sys", "web-sys",
"winapi", "winapi",
@ -1668,7 +1775,7 @@ version = "0.37.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d"
dependencies = [ dependencies = [
"bitflags", "bitflags 1.3.2",
"errno", "errno",
"io-lifetimes", "io-lifetimes",
"libc", "libc",
@ -1840,15 +1947,6 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" 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]] [[package]]
name = "sqlformat" name = "sqlformat"
version = "0.2.1" version = "0.2.1"
@ -1878,33 +1976,40 @@ checksum = "fa8241483a83a3f33aa5fff7e7d9def398ff9990b2752b6c6112b83c6d246029"
dependencies = [ dependencies = [
"ahash 0.7.6", "ahash 0.7.6",
"atoi", "atoi",
"bitflags", "base64 0.13.1",
"bitflags 1.3.2",
"byteorder", "byteorder",
"bytes", "bytes",
"chrono",
"crc", "crc",
"crossbeam-queue", "crossbeam-queue",
"dirs",
"dotenvy", "dotenvy",
"either", "either",
"event-listener", "event-listener",
"flume",
"futures-channel", "futures-channel",
"futures-core", "futures-core",
"futures-executor",
"futures-intrusive", "futures-intrusive",
"futures-util", "futures-util",
"hashlink", "hashlink",
"hex", "hex",
"hkdf",
"hmac",
"indexmap", "indexmap",
"itoa", "itoa",
"libc", "libc",
"libsqlite3-sys",
"log", "log",
"md-5",
"memchr", "memchr",
"once_cell", "once_cell",
"paste", "paste",
"percent-encoding", "percent-encoding",
"rand",
"rustls", "rustls",
"rustls-pemfile", "rustls-pemfile",
"serde",
"serde_json",
"sha1",
"sha2", "sha2",
"smallvec", "smallvec",
"sqlformat", "sqlformat",
@ -1913,6 +2018,7 @@ dependencies = [
"thiserror", "thiserror",
"url", "url",
"webpki-roots", "webpki-roots",
"whoami",
] ]
[[package]] [[package]]
@ -2171,18 +2277,18 @@ dependencies = [
"percent-encoding", "percent-encoding",
] ]
[[package]]
name = "v_htmlescape"
version = "0.15.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e8257fbc510f0a46eb602c10215901938b5c2a7d5e70fc11483b1d3c9b5b18c"
[[package]] [[package]]
name = "value-bag" name = "value-bag"
version = "1.4.0" version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4d330786735ea358f3bc09eea4caa098569c1c93f342d9aca0514915022fe7e" checksum = "a4d330786735ea358f3bc09eea4caa098569c1c93f342d9aca0514915022fe7e"
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.4" version = "0.9.4"
@ -2296,6 +2402,16 @@ dependencies = [
"webpki", "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]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.9" version = "0.3.9"
@ -2318,13 +2434,22 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 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]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.48.0" version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [ dependencies = [
"windows-targets", "windows-targets 0.48.0",
] ]
[[package]] [[package]]
@ -2333,13 +2458,28 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
dependencies = [ dependencies = [
"windows_aarch64_gnullvm", "windows_aarch64_gnullvm 0.48.0",
"windows_aarch64_msvc", "windows_aarch64_msvc 0.48.0",
"windows_i686_gnu", "windows_i686_gnu 0.48.0",
"windows_i686_msvc", "windows_i686_msvc 0.48.0",
"windows_x86_64_gnu", "windows_x86_64_gnu 0.48.0",
"windows_x86_64_gnullvm", "windows_x86_64_gnullvm 0.48.0",
"windows_x86_64_msvc", "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]] [[package]]
@ -2348,42 +2488,84 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.48.0" version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.48.0" version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
[[package]]
name = "windows_i686_gnu"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.48.0" version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
[[package]]
name = "windows_i686_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.48.0" version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" 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]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.48.0" version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" 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]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.48.0" version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" 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]] [[package]]
name = "zstd" name = "zstd"
version = "0.12.3+zstd.1.5.2" version = "0.12.3+zstd.1.5.2"

View File

@ -6,7 +6,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [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" } actix-web = { version = "4" }
askama = "0.12.0" askama = "0.12.0"
serde = { version = "1.0.164", features = [ "derive"]} serde = { version = "1.0.164", features = [ "derive"]}
@ -15,3 +15,5 @@ anyhow = "1.0.71"
dotenv = "0.15.0" dotenv = "0.15.0"
actix-session = { version = "0.7.2", features = ["cookie-session"] } actix-session = { version = "0.7.2", features = ["cookie-session"] }
actix-identity = "0.5.2" actix-identity = "0.5.2"
chrono = "0.4.33"
actix-files = "0.6.5"

View File

@ -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, id SERIAL PRIMARY KEY,
definition TEXT NOT NULL name TEXT NOT NULL
); );
INSERT OR REPLACE INTO roles(id, definition) values(1, "Default"); INSERT INTO area (name) VALUES ('Leipzig Ost');
INSERT OR REPLACE INTO roles(id, definition) values(2, "Administrator");
CREATE TABLE IF NOT EXISTS users CREATE TABLE location
( (
id INTEGER PRIMARY KEY NOT NULL, id SERIAL PRIMARY KEY,
name TEXT NOT NULL, name TEXT NOT NULL,
password_hash TEXT NOT NULL, areaId INTEGER NOT NULL REFERENCES area (id)
salt TEXT NOT NULL, );
role_id INTEGER NOT NULL,
FOREIGN KEY(role_id) REFERENCES roles(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)
); );

View File

@ -1,4 +1,4 @@
pub mod routes; pub mod routes;
mod utils; pub mod utils;
pub use routes::init; pub use routes::init;

View File

@ -1,23 +1,18 @@
use actix_web::{web, HttpResponse, Responder}; use actix_web::{web, HttpResponse, Responder};
use askama::Template; use askama::Template;
use sqlx::SqlitePool; use sqlx::PgPool;
use crate::models::Role;
#[derive(Template)] #[derive(Template)]
#[template(path = "register.html")] #[template(path = "register.html")]
struct RegisterTemplate { struct RegisterTemplate {
roles: Vec<Role>, // roles: Vec<Role>,
} }
#[actix_web::get("/register")] #[actix_web::get("/register")]
async fn route(pool: web::Data<SqlitePool>) -> impl Responder { async fn route(pool: web::Data<PgPool>) -> impl Responder {
let roles = match Role::GetAll(pool.get_ref()).await {
Ok(value) => value,
Err(error) => return HttpResponse::InternalServerError().body(error.to_string()),
};
let bla = RegisterTemplate { roles };
let bla = RegisterTemplate { };
HttpResponse::Ok().body(bla.render().unwrap()) HttpResponse::Ok().body(bla.render().unwrap())
} }

View File

@ -1,13 +1,13 @@
use actix_identity::Identity; use actix_identity::Identity;
use actix_web::{web, HttpMessage, HttpRequest, HttpResponse, Responder}; use actix_web::{web, HttpMessage, HttpRequest, HttpResponse, Responder};
use serde::Deserialize; use serde::Deserialize;
use sqlx::SqlitePool; use sqlx::PgPool;
use crate::{auth::utils::hash_plain_password_with_salt, models::user::User}; use crate::{auth::utils::hash_plain_password_with_salt, models::user::User};
#[derive(Deserialize)] #[derive(Deserialize)]
struct LoginForm { struct LoginForm {
name: String, email: String,
password: String, password: String,
} }
@ -15,20 +15,23 @@ struct LoginForm {
async fn route( async fn route(
web::Form(form): web::Form<LoginForm>, web::Form(form): web::Form<LoginForm>,
request: HttpRequest, request: HttpRequest,
pool: web::Data<SqlitePool>, pool: web::Data<PgPool>,
) -> impl Responder { ) -> 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 { if let Ok(result) = User::read_for_login(pool.get_ref(), &form.email).await {
Identity::login(&request.extensions(), potential_user.id.to_string()); 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!"); return HttpResponse::Ok().body("Angemeldet!");
} else { } else {
return HttpResponse::Unauthorized().body("Nutzername oder Passwort falsch."); 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.");
} }
} }

View File

@ -1,24 +1,47 @@
use actix_web::{http::header::LOCATION, web, HttpResponse, Responder}; use actix_web::{http::header::LOCATION, web, HttpResponse, Responder};
use serde::Deserialize; use serde::Deserialize;
use sqlx::SqlitePool; use sqlx::PgPool;
use crate::{auth::utils::generate_salt_and_hash_plain_password, models::user::User}; use crate::{auth::utils::generate_salt_and_hash_plain_password, models::user::User};
#[derive(Deserialize)] #[derive(Deserialize)]
struct RegisterForm { struct RegisterForm {
name: String, pub name: String,
password: String, pub email: String,
role: i64, pub password: String,
pub role_id: u8,
pub function_id: u8,
pub area_id: i32,
} }
#[actix_web::post("/register")] #[actix_web::post("/register")]
async fn route( async fn route(
web::Form(form): web::Form<RegisterForm>, web::Form(form): web::Form<RegisterForm>,
pool: web::Data<SqlitePool>, pool: web::Data<PgPool>,
) -> impl Responder { ) -> impl Responder {
let (hash, salt) = generate_salt_and_hash_plain_password(&form.password).unwrap(); 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 { match result {
Ok(_) => { Ok(_) => {

View File

@ -1,12 +1,31 @@
use actix_identity::Identity; 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) { 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("/")] #[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()
}
} }

View File

@ -5,7 +5,7 @@ use actix_session::{storage::CookieSessionStore, SessionMiddleware};
use actix_web::cookie::Key; use actix_web::cookie::Key;
use actix_web::{web, App, HttpServer}; use actix_web::{web, App, HttpServer};
use dotenv::dotenv; use dotenv::dotenv;
use sqlx::sqlite::SqlitePool; use sqlx::postgres::PgPool;
mod auth; mod auth;
mod calendar; mod calendar;
@ -14,7 +14,7 @@ mod models;
#[actix_web::main] #[actix_web::main]
async fn main() -> anyhow::Result<()> { async fn main() -> anyhow::Result<()> {
dotenv()?; dotenv()?;
let pool = SqlitePool::connect(&env::var("DATABASE_URL")?).await?; let pool = PgPool::connect(&env::var("DATABASE_URL")?).await?;
let secret_key = Key::generate(); let secret_key = Key::generate();
println!("Starting server on http://localhost:8080."); println!("Starting server on http://localhost:8080.");
@ -29,6 +29,7 @@ async fn main() -> anyhow::Result<()> {
CookieSessionStore::default(), CookieSessionStore::default(),
secret_key.clone(), secret_key.clone(),
)) ))
.service(actix_files::Files::new("", "./static").show_files_listing())
}) })
.bind(("127.0.0.1", 8080))? .bind(("127.0.0.1", 8080))?
.run() .run()

26
src/models/area.rs Normal file
View 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)
}
}

View File

View File

57
src/models/event.rs Normal file
View 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
View 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
View File

@ -0,0 +1,9 @@
pub struct Location {
pub id: i32,
pub name: String,
pub areaId: i32
}
impl Location {
}

View File

@ -1,34 +1,9 @@
pub mod role;
pub mod function;
pub mod user; pub mod user;
pub mod event;
use sqlx::sqlite::SqlitePool; pub mod area;
pub mod vehicle;
pub struct Role { pub mod availabillity;
pub id: u8, pub mod assignement;
pub definition: String pub mod location;
}
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)
}
}

20
src/models/role.rs Normal file
View 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(()),
}
}
}

View File

@ -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 struct User {
pub id: i64, pub id: i32,
pub name: String, pub name: String,
pub password_hash: String, pub email: String,
pub password: String,
pub salt: 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 { impl User {
pub async fn create( pub async fn create(
pool: &SqlitePool, pool: &PgPool,
name: String, name: String,
password_hash: String, email: String,
password: String,
salt: String, salt: String,
role_id: i64, role: Role,
) -> anyhow::Result<i64> { function: Function,
area_id: i32,
) -> anyhow::Result<i32> {
let created = sqlx::query!( let created = sqlx::query!(
r#" r#"
INSERT INTO users (name, password_hash, salt, role_id) INSERT INTO user_ (name, email, password, salt, role, function, areaId)
VALUES (?1, ?2, ?3, ?4); VALUES ($1, $2, $3, $4, $5, $6, $7)
RETURNING id;
"#, "#,
name, name,
password_hash, email,
password,
salt, salt,
role_id role as Role,
function as Function,
area_id
) )
.execute(pool) .fetch_one(pool)
.await; .await;
match created { match created {
Ok(result) => Ok(result.last_insert_rowid()), Ok(result) => Ok(result.id),
Err(err) => Err(err.into()), Err(err) => Err(err.into()),
} }
} }
pub async fn read_by_id(pool: &SqlitePool, id: i64) -> Option<User> { pub async fn read_by_id(pool: &PgPool, id: i32) -> Option<User> {
let record = sqlx::query_as!( let record = sqlx::query!(
User,
r#" r#"
SELECT * SELECT id,
FROM users name,
WHERE id = ?1; email,
password,
salt,
role AS "role: Role",
function AS "function: Function",
areaId,
locked,
lastLogin,
receiveNotifications
FROM user_
WHERE id = $1;
"#, "#,
id, id,
) )
@ -49,7 +74,19 @@ impl User {
.await; .await;
match record { 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) => { Err(err) => {
println!("User.read({id}): {err}"); println!("User.read({id}): {err}");
None None
@ -57,25 +94,57 @@ impl User {
} }
} }
pub async fn read_by_name(pool: &SqlitePool, name: &str) -> Option<User> { pub async fn read_for_login(pool: &PgPool, email: &str) -> anyhow::Result<Option<User>> {
let record = sqlx::query_as!( let record = sqlx::query!(
User,
r#" r#"
SELECT * SELECT id,
FROM users name,
WHERE name = ?1; 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) .fetch_optional(pool)
.await; .await?;
match record { let result = match record {
Ok(record) => Some(record), Some(record) => Some(User {
Err(err) => { id: record.id,
println!("User.read({name}): {err}"); name: record.name,
None 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
View 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

File diff suppressed because one or more lines are too long

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
View 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
View File

@ -0,0 +1,7 @@
{% extends "nav.html" %}
{% block content %}
<p>
Content
</p>
{% endblock %}

View File

@ -1,18 +1,15 @@
<html> {% extends "base.html" %}
<head>
<title>Brass - Login</title> {% block body %}
</head>
<body>
<h1>Brass - Anmeldung</h1> <h1>Brass - Anmeldung</h1>
<p>Gib dein Nutzernamen und das Passwort ein:</p> <p>Gib dein Nutzernamen und das Passwort ein:</p>
<form> <form>
<label for="name">Nutzername:</label> <label for="email">E-Mail:</label>
<input name="name" type="text"> <input name="email" type="text">
<label for="password">Passwort:</label> <label for="password">Passwort:</label>
<input name="password" type="password"> <input name="password" type="password">
<input type="submit" formmethod="post"> <input type="submit" formmethod="post">
</form> </form>
</body> {% endblock %}
</html>

47
templates/nav.html Normal file
View 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 %}

View File

@ -14,9 +14,9 @@
<label for="role">Rolle:</label> <label for="role">Rolle:</label>
<select name="role"> <select name="role">
{% for role in roles %} <option value="1">Staff</option>
<option value="{{ role.id }}">{{ role.definition }}</option> <option value="10">AreaManager</option>
{% endfor %} <option value="100">Admin</option>
</select> </select>
<input type="submit" formmethod="post"> <input type="submit" formmethod="post">