Started on member migration
This commit is contained in:
parent
169e89cefb
commit
9cf9e5752f
@ -1,6 +1,10 @@
|
|||||||
{ ... }:
|
{ pkgs, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
|
packages = with pkgs; [
|
||||||
|
openssl
|
||||||
|
];
|
||||||
|
|
||||||
languages.rust.enable = true;
|
languages.rust.enable = true;
|
||||||
|
|
||||||
languages.javascript = {
|
languages.javascript = {
|
||||||
|
@ -1 +1,2 @@
|
|||||||
DATABASE_URL="postgres://wrbapp:password@localhost/wrbapp"
|
DATABASE_URL="postgres://wrbapp:password@localhost/wrbapp"
|
||||||
|
API_TOKEN="SuperSecretToken"
|
||||||
|
1
server/.gitignore
vendored
1
server/.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
target
|
target
|
||||||
|
.env
|
||||||
|
507
server/Cargo.lock
generated
507
server/Cargo.lock
generated
@ -17,12 +17,36 @@ version = "2.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "1.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "allocator-api2"
|
name = "allocator-api2"
|
||||||
version = "0.2.21"
|
version = "0.2.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||||
|
|
||||||
|
[[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 = "atoi"
|
name = "atoi"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
@ -93,6 +117,28 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "axum-extra"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "460fc6f625a1f7705c6cf62d0d070794e94668988b1c38111baeec177c715f7b"
|
||||||
|
dependencies = [
|
||||||
|
"axum",
|
||||||
|
"axum-core",
|
||||||
|
"bytes",
|
||||||
|
"futures-util",
|
||||||
|
"headers",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"http-body-util",
|
||||||
|
"mime",
|
||||||
|
"pin-project-lite",
|
||||||
|
"serde",
|
||||||
|
"tower",
|
||||||
|
"tower-layer",
|
||||||
|
"tower-service",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "axum-macros"
|
name = "axum-macros"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
@ -119,6 +165,12 @@ dependencies = [
|
|||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.21.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.22.1"
|
version = "0.22.1"
|
||||||
@ -149,6 +201,12 @@ dependencies = [
|
|||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bumpalo"
|
||||||
|
version = "3.16.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
@ -161,12 +219,35 @@ version = "1.9.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
|
checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.2.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229"
|
||||||
|
dependencies = [
|
||||||
|
"shlex",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.0"
|
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.39"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825"
|
||||||
|
dependencies = [
|
||||||
|
"android-tzdata",
|
||||||
|
"iana-time-zone",
|
||||||
|
"js-sys",
|
||||||
|
"num-traits",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"windows-targets 0.52.6",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "concurrent-queue"
|
name = "concurrent-queue"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
@ -182,6 +263,12 @@ version = "0.9.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
|
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-foundation-sys"
|
||||||
|
version = "0.8.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cpufeatures"
|
name = "cpufeatures"
|
||||||
version = "0.2.16"
|
version = "0.2.16"
|
||||||
@ -231,6 +318,62 @@ dependencies = [
|
|||||||
"typenum",
|
"typenum",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "csv"
|
||||||
|
version = "1.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf"
|
||||||
|
dependencies = [
|
||||||
|
"csv-core",
|
||||||
|
"itoa",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "csv-core"
|
||||||
|
version = "0.1.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling"
|
||||||
|
version = "0.20.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"darling_macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_core"
|
||||||
|
version = "0.20.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
|
||||||
|
dependencies = [
|
||||||
|
"fnv",
|
||||||
|
"ident_case",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"strsim",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_macro"
|
||||||
|
version = "0.20.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "der"
|
name = "der"
|
||||||
version = "0.7.9"
|
version = "0.7.9"
|
||||||
@ -446,7 +589,19 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"wasi 0.13.3+wasi-0.2.2",
|
||||||
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -475,6 +630,30 @@ dependencies = [
|
|||||||
"hashbrown",
|
"hashbrown",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "headers"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.21.7",
|
||||||
|
"bytes",
|
||||||
|
"headers-core",
|
||||||
|
"http",
|
||||||
|
"httpdate",
|
||||||
|
"mime",
|
||||||
|
"sha1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "headers-core"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4"
|
||||||
|
dependencies = [
|
||||||
|
"http",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
@ -595,6 +774,29 @@ dependencies = [
|
|||||||
"tower-service",
|
"tower-service",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iana-time-zone"
|
||||||
|
version = "0.1.61"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
|
||||||
|
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 = "icu_collections"
|
name = "icu_collections"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
@ -713,6 +915,12 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ident_case"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "1.0.3"
|
version = "1.0.3"
|
||||||
@ -744,12 +952,31 @@ dependencies = [
|
|||||||
"hashbrown",
|
"hashbrown",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.14.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.14"
|
version = "1.0.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
|
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "js-sys"
|
||||||
|
version = "0.3.77"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
"wasm-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
@ -853,7 +1080,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
|
checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -879,7 +1106,7 @@ dependencies = [
|
|||||||
"num-integer",
|
"num-integer",
|
||||||
"num-iter",
|
"num-iter",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"rand",
|
"rand 0.8.5",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
@ -1024,7 +1251,29 @@ version = "0.2.20"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
|
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zerocopy",
|
"zerocopy 0.7.35",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error-attr2"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error2"
|
||||||
|
version = "2.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-error-attr2",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1052,8 +1301,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"rand_chacha",
|
"rand_chacha 0.3.1",
|
||||||
"rand_core",
|
"rand_core 0.6.4",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
|
||||||
|
dependencies = [
|
||||||
|
"rand_chacha 0.9.0",
|
||||||
|
"rand_core 0.9.0",
|
||||||
|
"zerocopy 0.8.14",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1063,7 +1323,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ppv-lite86",
|
"ppv-lite86",
|
||||||
"rand_core",
|
"rand_core 0.6.4",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86",
|
||||||
|
"rand_core 0.9.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1072,7 +1342,17 @@ version = "0.6.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom 0.2.15",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.3.1",
|
||||||
|
"zerocopy 0.8.14",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1084,6 +1364,35 @@ dependencies = [
|
|||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-automata",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.4.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rsa"
|
name = "rsa"
|
||||||
version = "0.9.7"
|
version = "0.9.7"
|
||||||
@ -1097,7 +1406,7 @@ dependencies = [
|
|||||||
"num-traits",
|
"num-traits",
|
||||||
"pkcs1",
|
"pkcs1",
|
||||||
"pkcs8",
|
"pkcs8",
|
||||||
"rand_core",
|
"rand_core 0.6.4",
|
||||||
"signature",
|
"signature",
|
||||||
"spki",
|
"spki",
|
||||||
"subtle",
|
"subtle",
|
||||||
@ -1163,9 +1472,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.135"
|
version = "1.0.137"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9"
|
checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"memchr",
|
"memchr",
|
||||||
@ -1226,6 +1535,12 @@ dependencies = [
|
|||||||
"lazy_static",
|
"lazy_static",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shlex"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signature"
|
name = "signature"
|
||||||
version = "2.2.0"
|
version = "2.2.0"
|
||||||
@ -1233,7 +1548,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
|
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"digest",
|
"digest",
|
||||||
"rand_core",
|
"rand_core 0.6.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1375,7 +1690,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "4560278f0e00ce64938540546f59f590d60beee33fffbd3b9cd47851e5fff233"
|
checksum = "4560278f0e00ce64938540546f59f590d60beee33fffbd3b9cd47851e5fff233"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atoi",
|
"atoi",
|
||||||
"base64",
|
"base64 0.22.1",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"bytes",
|
"bytes",
|
||||||
@ -1397,7 +1712,7 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"rand",
|
"rand 0.8.5",
|
||||||
"rsa",
|
"rsa",
|
||||||
"serde",
|
"serde",
|
||||||
"sha1",
|
"sha1",
|
||||||
@ -1417,7 +1732,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "c5b98a57f363ed6764d5b3a12bfedf62f07aa16e1856a7ddc2a0bb190a959613"
|
checksum = "c5b98a57f363ed6764d5b3a12bfedf62f07aa16e1856a7ddc2a0bb190a959613"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atoi",
|
"atoi",
|
||||||
"base64",
|
"base64 0.22.1",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"crc",
|
"crc",
|
||||||
@ -1435,7 +1750,7 @@ dependencies = [
|
|||||||
"md-5",
|
"md-5",
|
||||||
"memchr",
|
"memchr",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rand",
|
"rand 0.8.5",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha2",
|
"sha2",
|
||||||
@ -1487,6 +1802,12 @@ dependencies = [
|
|||||||
"unicode-properties",
|
"unicode-properties",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "subtle"
|
name = "subtle"
|
||||||
version = "2.6.1"
|
version = "2.6.1"
|
||||||
@ -1529,7 +1850,7 @@ checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"fastrand",
|
"fastrand",
|
||||||
"getrandom",
|
"getrandom 0.2.15",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustix",
|
"rustix",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
@ -1770,6 +2091,42 @@ version = "1.0.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uuid"
|
||||||
|
version = "1.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "744018581f9a3454a9e15beb8a33b017183f1e7c0cd170232a2d1453b23a51c4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "validator"
|
||||||
|
version = "0.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d0b4a29d8709210980a09379f27ee31549b73292c87ab9899beee1c0d3be6303"
|
||||||
|
dependencies = [
|
||||||
|
"idna",
|
||||||
|
"once_cell",
|
||||||
|
"regex",
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
"serde_json",
|
||||||
|
"url",
|
||||||
|
"validator_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "validator_derive"
|
||||||
|
version = "0.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bac855a2ce6f843beb229757e6e570a42e837bcb15e5f449dd48d5747d41bf77"
|
||||||
|
dependencies = [
|
||||||
|
"darling",
|
||||||
|
"once_cell",
|
||||||
|
"proc-macro-error2",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "valuable"
|
name = "valuable"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -1794,12 +2151,79 @@ version = "0.11.0+wasi-snapshot-preview1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.13.3+wasi-0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
|
||||||
|
dependencies = [
|
||||||
|
"wit-bindgen-rt",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasite"
|
name = "wasite"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b"
|
checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen"
|
||||||
|
version = "0.2.100"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"once_cell",
|
||||||
|
"rustversion",
|
||||||
|
"wasm-bindgen-macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-backend"
|
||||||
|
version = "0.2.100"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
|
||||||
|
dependencies = [
|
||||||
|
"bumpalo",
|
||||||
|
"log",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"wasm-bindgen-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-macro"
|
||||||
|
version = "0.2.100"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"wasm-bindgen-macro-support",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-macro-support"
|
||||||
|
version = "0.2.100"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"wasm-bindgen-backend",
|
||||||
|
"wasm-bindgen-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-shared"
|
||||||
|
version = "0.2.100"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "whoami"
|
name = "whoami"
|
||||||
version = "1.5.2"
|
version = "1.5.2"
|
||||||
@ -1832,6 +2256,15 @@ 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.6",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.48.0"
|
version = "0.48.0"
|
||||||
@ -1980,17 +2413,35 @@ version = "0.52.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wit-bindgen-rt"
|
||||||
|
version = "0.33.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wrbapp_server"
|
name = "wrbapp_server"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum",
|
"axum",
|
||||||
|
"axum-extra",
|
||||||
|
"chrono",
|
||||||
|
"csv",
|
||||||
"dotenvy",
|
"dotenvy",
|
||||||
|
"itertools",
|
||||||
|
"rand 0.9.0",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_json",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
|
"uuid",
|
||||||
|
"validator",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2036,7 +2487,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"zerocopy-derive",
|
"zerocopy-derive 0.7.35",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy"
|
||||||
|
version = "0.8.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a367f292d93d4eab890745e75a778da40909cab4d6ff8173693812f79c4a2468"
|
||||||
|
dependencies = [
|
||||||
|
"zerocopy-derive 0.8.14",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2050,6 +2510,17 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy-derive"
|
||||||
|
version = "0.8.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d3931cb58c62c13adec22e38686b559c86a30565e16ad6e8510a337cedc611e1"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerofrom"
|
name = "zerofrom"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
|
@ -4,13 +4,26 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
axum = { version = "0.8", features = [ "macros" ] }
|
# Primary crates
|
||||||
|
axum = { version = "0.8", features = [ "macros", "json" ] }
|
||||||
|
axum-extra = { version = "0.10.0", features = [ "typed-header" ] }
|
||||||
tokio = { version = "1.43", features = [ "rt-multi-thread", "macros" ] }
|
tokio = { version = "1.43", features = [ "rt-multi-thread", "macros" ] }
|
||||||
sqlx = { version = "0.8", features = [ "runtime-tokio", "postgres" ] }
|
sqlx = { version = "0.8", features = [ "runtime-tokio", "postgres" ] }
|
||||||
|
|
||||||
|
# Secondary crates
|
||||||
|
csv = { version = "1.3" }
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
dotenvy = "0.15.7"
|
dotenvy = "0.15.7"
|
||||||
|
validator = { version = "0.19.0", features = [ "derive" ] }
|
||||||
|
|
||||||
# Tracing
|
|
||||||
|
# Tertiary crates
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-subscriber = "0.3"
|
tracing-subscriber = "0.3"
|
||||||
|
chrono = "0.4.39"
|
||||||
|
uuid = "1.12.0"
|
||||||
|
serde_json = "1.0.137"
|
||||||
|
rand = "0.9"
|
||||||
|
thiserror = { version = "2.0" }
|
||||||
|
itertools = "0.14"
|
||||||
|
|
||||||
|
5
server/build.rs
Normal file
5
server/build.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
// generated by `sqlx migrate build-script`
|
||||||
|
fn main() {
|
||||||
|
// trigger recompilation when a new migration is added
|
||||||
|
println!("cargo:rerun-if-changed=migrations");
|
||||||
|
}
|
@ -1,28 +0,0 @@
|
|||||||
CREATE TABLE user (
|
|
||||||
id bigint NOT NULL PRIMARY KEY,
|
|
||||||
email text NOT NULL UNIQUE,
|
|
||||||
password text NOT NULL,
|
|
||||||
admin boolean NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
CREATE TABLE member (
|
|
||||||
id varchar(7) NOT NULL PRIMARY KEY,
|
|
||||||
call_sign text NOT NULL,
|
|
||||||
name text NOT NULL,
|
|
||||||
registration_token text NOT NULL UNIQUE,
|
|
||||||
diploma text,
|
|
||||||
hours text[] NOT NULL,
|
|
||||||
groups text[] NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
CREATE TABLE session (
|
|
||||||
id bigint NOT NULL PRIMARY KEY,
|
|
||||||
user_id bigint NOT NULL,
|
|
||||||
token text NOT NULL UNIQUE,
|
|
||||||
expires timestamp NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
ALTER TABLE session ADD CONSTRAINT session_user_id_fk FOREIGN KEY (user_id) REFERENCES user (id);
|
|
10
server/migrations/001_create_members.sql
Normal file
10
server/migrations/001_create_members.sql
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
create table "members" (
|
||||||
|
id varchar(7) primary key,
|
||||||
|
first_name text not null,
|
||||||
|
full_name text not null,
|
||||||
|
registration_token text unique not null,
|
||||||
|
diploma text,
|
||||||
|
hours text[] not null,
|
||||||
|
groups text[] not null
|
||||||
|
);
|
||||||
|
|
48
server/src/auth.rs
Normal file
48
server/src/auth.rs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
use axum::{extract::FromRequestParts, http::request::Parts, RequestPartsExt};
|
||||||
|
use axum_extra::{
|
||||||
|
headers::{authorization::Bearer, Authorization},
|
||||||
|
typed_header::TypedHeaderRejectionReason,
|
||||||
|
TypedHeader,
|
||||||
|
};
|
||||||
|
use bearer::verify_bearer;
|
||||||
|
pub use error::AuthError;
|
||||||
|
|
||||||
|
mod bearer;
|
||||||
|
mod error;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Permissions<'a>(pub HashSet<&'a str>);
|
||||||
|
|
||||||
|
// Middleware for getting permissions
|
||||||
|
impl<S> FromRequestParts<S> for Permissions<'_>
|
||||||
|
where
|
||||||
|
S: Send + Sync,
|
||||||
|
{
|
||||||
|
type Rejection = crate::Error;
|
||||||
|
|
||||||
|
async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
|
||||||
|
// First check if the request has a beaerer token to authenticate
|
||||||
|
match parts.extract::<TypedHeader<Authorization<Bearer>>>().await {
|
||||||
|
Ok(bearer) => {
|
||||||
|
verify_bearer(bearer.token().to_string()).map_err(|_| AuthError::InvalidToken)?;
|
||||||
|
|
||||||
|
let permissions = Permissions {
|
||||||
|
0: HashSet::from(["root"]),
|
||||||
|
};
|
||||||
|
|
||||||
|
return Ok(permissions);
|
||||||
|
}
|
||||||
|
Err(err) => match err.reason() {
|
||||||
|
TypedHeaderRejectionReason::Missing => (),
|
||||||
|
TypedHeaderRejectionReason::Error(_err) => {
|
||||||
|
return Err(AuthError::InvalidToken.into())
|
||||||
|
}
|
||||||
|
_ => return Err(AuthError::Unexpected.into()),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Err(AuthError::Unexpected.into())
|
||||||
|
}
|
||||||
|
}
|
8
server/src/auth/bearer.rs
Normal file
8
server/src/auth/bearer.rs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
pub fn verify_bearer(token: String) -> Result<(), ()> {
|
||||||
|
let env_api_token = dotenvy::var("API_TOKEN").map_err(|_| ())?;
|
||||||
|
|
||||||
|
match env_api_token == token {
|
||||||
|
true => Ok(()),
|
||||||
|
false => Err(()),
|
||||||
|
}
|
||||||
|
}
|
20
server/src/auth/error.rs
Normal file
20
server/src/auth/error.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum AuthError {
|
||||||
|
NoPermssions,
|
||||||
|
InvalidToken,
|
||||||
|
Unexpected,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for AuthError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::NoPermssions => write!(f, "{}", "No permissions"),
|
||||||
|
Self::InvalidToken => write!(f, "{}", "Invalid token"),
|
||||||
|
Self::Unexpected => write!(f, "{}", "Unexpected error"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for AuthError {}
|
@ -1,3 +1,5 @@
|
|||||||
mod postgres;
|
mod postgres;
|
||||||
pub use postgres::apply_migrations;
|
pub use postgres::apply_migrations;
|
||||||
pub use postgres::connect;
|
pub use postgres::connect;
|
||||||
|
|
||||||
|
pub mod model;
|
||||||
|
5
server/src/database/model.rs
Normal file
5
server/src/database/model.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
pub mod member;
|
||||||
|
pub mod session;
|
||||||
|
pub mod user;
|
||||||
|
|
||||||
|
pub use member::Member;
|
54
server/src/database/model/member.rs
Normal file
54
server/src/database/model/member.rs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
use rand::distr::{Alphanumeric, SampleString};
|
||||||
|
use sqlx::{Postgres, QueryBuilder};
|
||||||
|
use validator::Validate;
|
||||||
|
|
||||||
|
#[derive(Debug, Validate)]
|
||||||
|
pub struct Member {
|
||||||
|
#[validate(length(equal = 7))]
|
||||||
|
pub id: String,
|
||||||
|
pub first_name: String,
|
||||||
|
pub full_name: String,
|
||||||
|
pub registration_token: Option<String>,
|
||||||
|
pub diploma: Option<String>,
|
||||||
|
pub hours: Vec<String>,
|
||||||
|
pub groups: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Member {
|
||||||
|
pub async fn insert_multiple(
|
||||||
|
transaction: &mut sqlx::Transaction<'_, Postgres>,
|
||||||
|
members: Vec<Self>,
|
||||||
|
) -> Result<(), sqlx::Error> {
|
||||||
|
let mut query_builder = QueryBuilder::new(
|
||||||
|
"INSERT INTO members(id, first_name, full_name, registration_token, diploma, hours, groups) "
|
||||||
|
);
|
||||||
|
|
||||||
|
query_builder.push_values(members.into_iter(), |mut b, member| {
|
||||||
|
let registration_token = Alphanumeric.sample_string(&mut rand::rng(), 16);
|
||||||
|
|
||||||
|
b.push_bind(member.id);
|
||||||
|
b.push_bind(member.first_name);
|
||||||
|
b.push_bind(member.full_name);
|
||||||
|
b.push_bind(registration_token);
|
||||||
|
b.push_bind(member.diploma);
|
||||||
|
b.push_bind(member.hours);
|
||||||
|
b.push_bind(member.groups);
|
||||||
|
});
|
||||||
|
|
||||||
|
let query = query_builder.build();
|
||||||
|
query.execute(&mut **transaction).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn update_multiple(
|
||||||
|
transaction: &mut sqlx::Transaction<'_, Postgres>,
|
||||||
|
members: Vec<Self>,
|
||||||
|
) -> Result<(), sqlx::Error> {
|
||||||
|
for member in members {
|
||||||
|
sqlx::query!("UPDATE ONLY members SET first_name = $1, full_name = $2, diploma = $3, hours = $4, groups = $5 WHERE id = $6", member.first_name, member.full_name, member.diploma, &member.hours, &member.groups, member.id).execute(&mut **transaction).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
6
server/src/database/model/session.rs
Normal file
6
server/src/database/model/session.rs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
struct Session {
|
||||||
|
id: u32,
|
||||||
|
user_id: u32,
|
||||||
|
token: String,
|
||||||
|
expires: chrono::NaiveDateTime,
|
||||||
|
}
|
8
server/src/database/model/user.rs
Normal file
8
server/src/database/model/user.rs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#[derive(validator::Validate)]
|
||||||
|
struct User {
|
||||||
|
pub id: uuid::Uuid,
|
||||||
|
#[validate(email)]
|
||||||
|
pub email: String,
|
||||||
|
pub password: String,
|
||||||
|
pub admin: bool,
|
||||||
|
}
|
@ -1 +1,18 @@
|
|||||||
|
use routes::member::migrate::MigrationStore;
|
||||||
|
use sqlx::{Pool, Postgres};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
pub mod auth;
|
||||||
pub mod database;
|
pub mod database;
|
||||||
|
pub mod model;
|
||||||
|
pub mod routes;
|
||||||
|
pub mod util;
|
||||||
|
|
||||||
|
pub use util::error::Error;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct AppState {
|
||||||
|
pub pool: Pool<Postgres>,
|
||||||
|
pub migration_store: Arc<Mutex<MigrationStore>>,
|
||||||
|
}
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
use axum::{http::StatusCode, routing::get, Router};
|
use std::sync::Arc;
|
||||||
use tokio::net::TcpListener;
|
|
||||||
|
use axum::Router;
|
||||||
|
use tokio::{net::TcpListener, sync::Mutex};
|
||||||
use tracing::Level;
|
use tracing::Level;
|
||||||
use tracing_subscriber::FmtSubscriber;
|
use tracing_subscriber::FmtSubscriber;
|
||||||
|
|
||||||
use wrbapp_server::database;
|
use wrbapp_server::routes::member::migrate::MigrationStore;
|
||||||
|
use wrbapp_server::routes::routes;
|
||||||
|
use wrbapp_server::{database, AppState};
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
@ -22,12 +26,19 @@ async fn main() {
|
|||||||
.await
|
.await
|
||||||
.expect("Database migrations failed");
|
.expect("Database migrations failed");
|
||||||
|
|
||||||
database::connect()
|
let pool = database::connect()
|
||||||
.await
|
.await
|
||||||
.expect("Database connection failed");
|
.expect("Database connection failed");
|
||||||
|
|
||||||
|
let migration_store = Arc::new(Mutex::new(MigrationStore::default()));
|
||||||
|
|
||||||
|
let app_state = AppState {
|
||||||
|
pool,
|
||||||
|
migration_store,
|
||||||
|
};
|
||||||
|
|
||||||
// Serve app
|
// Serve app
|
||||||
let app = Router::new().route("/", get(hello_world));
|
let app = Router::new().merge(routes()).with_state(app_state);
|
||||||
|
|
||||||
let listener = TcpListener::bind("127.0.0.1:3000")
|
let listener = TcpListener::bind("127.0.0.1:3000")
|
||||||
.await
|
.await
|
||||||
@ -39,7 +50,3 @@ async fn main() {
|
|||||||
.await
|
.await
|
||||||
.expect("Error while serving axum application");
|
.expect("Error while serving axum application");
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn hello_world() -> Result<String, (StatusCode, String)> {
|
|
||||||
Ok("Hello world".to_string())
|
|
||||||
}
|
|
||||||
|
6
server/src/model.rs
Normal file
6
server/src/model.rs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
pub mod member;
|
||||||
|
pub mod session;
|
||||||
|
pub mod user;
|
||||||
|
|
||||||
|
pub use member::Member;
|
||||||
|
pub use user::User;
|
46
server/src/model/member.rs
Normal file
46
server/src/model/member.rs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#[derive(Clone, serde::Serialize)]
|
||||||
|
pub struct Name {
|
||||||
|
pub first: String,
|
||||||
|
pub full: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, serde::Serialize)]
|
||||||
|
pub struct Member {
|
||||||
|
pub id: String,
|
||||||
|
pub name: Name,
|
||||||
|
pub registration_token: Option<String>,
|
||||||
|
pub diploma: Option<String>,
|
||||||
|
pub hours: Vec<String>,
|
||||||
|
pub groups: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
use crate::database::model::Member as DbMember;
|
||||||
|
impl From<DbMember> for Member {
|
||||||
|
fn from(value: DbMember) -> Self {
|
||||||
|
Member {
|
||||||
|
id: value.id,
|
||||||
|
name: Name {
|
||||||
|
first: value.first_name,
|
||||||
|
full: value.full_name,
|
||||||
|
},
|
||||||
|
registration_token: value.registration_token,
|
||||||
|
diploma: value.diploma,
|
||||||
|
hours: value.hours,
|
||||||
|
groups: value.groups,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Member> for DbMember {
|
||||||
|
fn from(value: Member) -> Self {
|
||||||
|
DbMember {
|
||||||
|
id: value.id,
|
||||||
|
first_name: value.name.first,
|
||||||
|
full_name: value.name.full,
|
||||||
|
registration_token: None,
|
||||||
|
diploma: value.diploma,
|
||||||
|
hours: value.hours,
|
||||||
|
groups: value.groups,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
0
server/src/model/session.rs
Normal file
0
server/src/model/session.rs
Normal file
5
server/src/model/user.rs
Normal file
5
server/src/model/user.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
pub struct User {
|
||||||
|
pub id: uuid::Uuid,
|
||||||
|
pub email: String,
|
||||||
|
pub admin: bool,
|
||||||
|
}
|
30
server/src/routes.rs
Normal file
30
server/src/routes.rs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
use axum::{
|
||||||
|
extract::State,
|
||||||
|
http::StatusCode,
|
||||||
|
routing::{get, post},
|
||||||
|
Router,
|
||||||
|
};
|
||||||
|
use member::migrate::{migrate_confirm, migrate_request};
|
||||||
|
|
||||||
|
use crate::{auth::Permissions, AppState};
|
||||||
|
|
||||||
|
pub mod auth;
|
||||||
|
pub mod member;
|
||||||
|
pub mod user;
|
||||||
|
|
||||||
|
pub fn routes() -> Router<AppState> {
|
||||||
|
Router::new()
|
||||||
|
.route("/", get(root))
|
||||||
|
// .route("/member/:id", get())
|
||||||
|
.route("/members/migrate_request", post(migrate_request))
|
||||||
|
.route("/members/migrate_confirm", post(migrate_confirm))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn root(
|
||||||
|
State(state): State<AppState>,
|
||||||
|
permissions: Permissions<'_>,
|
||||||
|
) -> Result<String, (StatusCode, String)> {
|
||||||
|
tracing::info!("{:?}", permissions);
|
||||||
|
|
||||||
|
Ok("Hello world".to_string())
|
||||||
|
}
|
1
server/src/routes/auth.rs
Normal file
1
server/src/routes/auth.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
1
server/src/routes/member.rs
Normal file
1
server/src/routes/member.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub mod migrate;
|
260
server/src/routes/member/migrate.rs
Normal file
260
server/src/routes/member/migrate.rs
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use axum::{extract::State, Json};
|
||||||
|
use itertools::Itertools;
|
||||||
|
use sqlx::PgPool;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
auth::{AuthError, Permissions},
|
||||||
|
database::model::Member as DbMember,
|
||||||
|
model::{member::Name, Member},
|
||||||
|
util::convert_vec,
|
||||||
|
AppState,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub async fn migrate_request<'a>(
|
||||||
|
State(state): State<AppState>,
|
||||||
|
permissions: Permissions<'a>,
|
||||||
|
body: String,
|
||||||
|
) -> Result<Json<MigrationResponse>, crate::Error> {
|
||||||
|
if !permissions.0.contains("root") {
|
||||||
|
return Err(AuthError::NoPermssions.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the input CSV to a vector of members
|
||||||
|
let members_new: Vec<Member> = Row::from_csv_multiple(&body)?
|
||||||
|
.into_iter()
|
||||||
|
.map(|m| m.into())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// TODO: Write function to get members from database
|
||||||
|
let members_old: Vec<Member> = Vec::new();
|
||||||
|
|
||||||
|
let members_diff = generate_diff(members_new, members_old);
|
||||||
|
|
||||||
|
let count = state
|
||||||
|
.migration_store
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.insert(members_diff.clone());
|
||||||
|
|
||||||
|
Ok(Json(MigrationResponse::from((count, members_diff))))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn migrate_confirm<'a>(
|
||||||
|
State(state): State<AppState>,
|
||||||
|
permissions: Permissions<'a>,
|
||||||
|
body: String,
|
||||||
|
) -> Result<(), crate::Error> {
|
||||||
|
if !permissions.0.contains("root") {
|
||||||
|
return Err(AuthError::NoPermssions.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Implement better error naming
|
||||||
|
let count = match body.trim().parse::<u32>() {
|
||||||
|
Ok(c) => c,
|
||||||
|
Err(_) => return Err(crate::Error::NotFound),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut store = state.migration_store.lock().await;
|
||||||
|
|
||||||
|
let members_diff = match store.remove(&count) {
|
||||||
|
Some(m) => m,
|
||||||
|
None => return Err(crate::Error::NotFound),
|
||||||
|
};
|
||||||
|
|
||||||
|
migrate_transaction(&state.pool, members_diff).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn migrate_transaction(pool: &PgPool, members_diff: MembersDiff) -> Result<(), sqlx::Error> {
|
||||||
|
let mut transaction = pool.begin().await?;
|
||||||
|
|
||||||
|
// DbMember::insert_multiple(&mut transaction, convert_vec(members_diff.insert)).await?;
|
||||||
|
DbMember::update_multiple(&mut transaction, convert_vec(members_diff.update)).await?;
|
||||||
|
|
||||||
|
transaction.commit().await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a row for the csv file
|
||||||
|
#[derive(Debug, serde::Deserialize, Clone)]
|
||||||
|
struct Row {
|
||||||
|
#[serde(rename = "Relatiecode")]
|
||||||
|
id: String,
|
||||||
|
#[serde(rename = "Roepnaam")]
|
||||||
|
first_name: String,
|
||||||
|
// #[serde(rename = "Tussenvoegsel(s)")]
|
||||||
|
// middle_name: String,
|
||||||
|
// #[serde(rename = "Achternaam")]
|
||||||
|
// last_name: String,
|
||||||
|
#[serde(rename = "E-mail")]
|
||||||
|
email: String,
|
||||||
|
#[serde(rename = "Verenigingssporten")]
|
||||||
|
hours: String,
|
||||||
|
#[serde(rename = "Diploma dropdown 1")]
|
||||||
|
diploma: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct MembersDiff {
|
||||||
|
insert: Vec<Member>,
|
||||||
|
update: Vec<Member>,
|
||||||
|
remove: Vec<Member>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Serialize)]
|
||||||
|
pub struct MigrationResponse {
|
||||||
|
count: u32,
|
||||||
|
insert: Vec<(String, Name)>,
|
||||||
|
update: Vec<(String, Name)>,
|
||||||
|
remove: Vec<(String, Name)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MigrationStore {
|
||||||
|
pub store: HashMap<u32, MembersDiff>,
|
||||||
|
pub count: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for MigrationStore {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
count: 0,
|
||||||
|
store: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Row {
|
||||||
|
fn from_csv_multiple(input: &str) -> Result<Vec<Self>, csv::Error> {
|
||||||
|
let mut rdr = csv::ReaderBuilder::new()
|
||||||
|
.delimiter(b';')
|
||||||
|
.from_reader(input.as_bytes());
|
||||||
|
|
||||||
|
let members: Result<Vec<Row>, csv::Error> = rdr.deserialize().collect();
|
||||||
|
|
||||||
|
members
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hours_parsed(&self) -> Vec<String> {
|
||||||
|
let mut hours: Vec<String> = Vec::new();
|
||||||
|
|
||||||
|
let group_parts: Vec<&str> = self.hours.split(", ").collect();
|
||||||
|
|
||||||
|
for group in group_parts {
|
||||||
|
let hour_parts: Vec<&str> = group.split(" - ").collect();
|
||||||
|
|
||||||
|
for part in hour_parts {
|
||||||
|
if &*part != "Groep" {
|
||||||
|
hours.push(part.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hours.into_iter().unique().collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<Name> for Row {
|
||||||
|
fn into(self) -> Name {
|
||||||
|
Name {
|
||||||
|
first: self.first_name,
|
||||||
|
full: "Temporarely full name".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<Member> for Row {
|
||||||
|
fn into(self) -> Member {
|
||||||
|
let name: Name = self.clone().into();
|
||||||
|
|
||||||
|
Member {
|
||||||
|
id: self.id.clone(),
|
||||||
|
name,
|
||||||
|
registration_token: None,
|
||||||
|
diploma: self.diploma.clone(),
|
||||||
|
hours: self.hours_parsed(),
|
||||||
|
groups: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(u32, MembersDiff)> for MigrationResponse {
|
||||||
|
fn from(value: (u32, MembersDiff)) -> Self {
|
||||||
|
let members_insert: Vec<(String, Name)> =
|
||||||
|
value.1.insert.into_iter().map(|m| (m.id, m.name)).collect();
|
||||||
|
let members_update: Vec<(String, Name)> =
|
||||||
|
value.1.update.into_iter().map(|m| (m.id, m.name)).collect();
|
||||||
|
let members_remove: Vec<(String, Name)> =
|
||||||
|
value.1.remove.into_iter().map(|m| (m.id, m.name)).collect();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
count: value.0,
|
||||||
|
insert: members_insert,
|
||||||
|
update: members_update,
|
||||||
|
remove: members_remove,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MigrationStore {
|
||||||
|
fn insert(&mut self, members_diff: MembersDiff) -> u32 {
|
||||||
|
let count = self.count + 1;
|
||||||
|
self.store.insert(count, members_diff);
|
||||||
|
self.count = count;
|
||||||
|
count
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get(&self, id: &u32) -> Option<&MembersDiff> {
|
||||||
|
self.store.get(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove(&mut self, id: &u32) -> Option<MembersDiff> {
|
||||||
|
self.store.remove(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_diff(members_new: Vec<Member>, members_old: Vec<Member>) -> MembersDiff {
|
||||||
|
let members_old_map: HashMap<String, Member> = members_old
|
||||||
|
.iter()
|
||||||
|
.map(|m| (m.id.clone(), m.clone()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let members_new_map: HashMap<String, Member> = members_new
|
||||||
|
.iter()
|
||||||
|
.map(|m| (m.id.clone(), m.clone()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut members_insert: Vec<Member> = Vec::new();
|
||||||
|
let mut members_update: Vec<Member> = Vec::new();
|
||||||
|
let mut members_remove: Vec<Member> = Vec::new();
|
||||||
|
|
||||||
|
for old_member in members_old {
|
||||||
|
if let Some(new_member) = members_new_map.get(&old_member.id) {
|
||||||
|
members_update.push(Member {
|
||||||
|
id: old_member.id,
|
||||||
|
name: new_member.name.clone(),
|
||||||
|
registration_token: old_member.registration_token,
|
||||||
|
diploma: new_member.diploma.clone(),
|
||||||
|
hours: new_member.hours.clone(),
|
||||||
|
groups: old_member.groups,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
members_remove.push(old_member);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for new_member in members_new {
|
||||||
|
if !members_old_map.contains_key(&new_member.id) {
|
||||||
|
members_insert.push(new_member);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MembersDiff {
|
||||||
|
insert: members_insert,
|
||||||
|
update: members_update,
|
||||||
|
remove: members_remove,
|
||||||
|
}
|
||||||
|
}
|
1
server/src/routes/user.rs
Normal file
1
server/src/routes/user.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
4
server/src/util.rs
Normal file
4
server/src/util.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
pub mod error;
|
||||||
|
mod helpers;
|
||||||
|
|
||||||
|
pub use helpers::convert_vec;
|
52
server/src/util/error.rs
Normal file
52
server/src/util/error.rs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
use crate::auth::AuthError;
|
||||||
|
use axum::{
|
||||||
|
http::StatusCode,
|
||||||
|
response::{IntoResponse, Response},
|
||||||
|
Json,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("CSV error: {0}")]
|
||||||
|
Csv(#[from] csv::Error),
|
||||||
|
|
||||||
|
#[error("Auth error: {0}")]
|
||||||
|
Auth(#[from] crate::auth::AuthError),
|
||||||
|
|
||||||
|
#[error("Database error: {0}")]
|
||||||
|
Database(#[from] sqlx::Error),
|
||||||
|
|
||||||
|
#[error("Resource not found")]
|
||||||
|
NotFound,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoResponse for Error {
|
||||||
|
fn into_response(self) -> Response {
|
||||||
|
tracing::error!("Error... {:?}", self);
|
||||||
|
|
||||||
|
let (status, error_message) = match self {
|
||||||
|
Error::Auth(AuthError::NoPermssions) => {
|
||||||
|
(StatusCode::UNAUTHORIZED, String::from("No permissions"))
|
||||||
|
}
|
||||||
|
Error::Auth(AuthError::InvalidToken) => {
|
||||||
|
(StatusCode::BAD_REQUEST, String::from("Invalid token"))
|
||||||
|
}
|
||||||
|
Error::Auth(AuthError::Unexpected) => (
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
String::from("Unexpected error occured"),
|
||||||
|
),
|
||||||
|
Error::Csv(err) => (StatusCode::BAD_REQUEST, err.to_string()),
|
||||||
|
Error::NotFound => (
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
String::from("Could not find resource"),
|
||||||
|
),
|
||||||
|
Error::Database(err) => (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let body = Json(serde_json::json!({
|
||||||
|
"error": error_message
|
||||||
|
}));
|
||||||
|
|
||||||
|
(status, body).into_response()
|
||||||
|
}
|
||||||
|
}
|
6
server/src/util/helpers.rs
Normal file
6
server/src/util/helpers.rs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
pub fn convert_vec<T, U>(vec: Vec<T>) -> Vec<U>
|
||||||
|
where
|
||||||
|
U: From<T>,
|
||||||
|
{
|
||||||
|
vec.into_iter().map(U::from).collect()
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user