Compare commits
6 Commits
release-20
...
release-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e9a042444 | ||
|
|
09a4c69282 | ||
|
|
a877e0c393 | ||
|
|
fd65df2962 | ||
|
|
9d160a7ef5 | ||
|
|
a24e4101e8 |
6
.gitignore
vendored
6
.gitignore
vendored
@@ -8,3 +8,9 @@ backend.log
|
|||||||
.runner
|
.runner
|
||||||
.env
|
.env
|
||||||
backend/.env
|
backend/.env
|
||||||
|
*.db
|
||||||
|
*.db-shm
|
||||||
|
*.db-wal
|
||||||
|
*.sqlite
|
||||||
|
*.sqlite-shm
|
||||||
|
*.sqlite-wal
|
||||||
|
|||||||
197
Cargo.lock
generated
197
Cargo.lock
generated
@@ -323,6 +323,7 @@ dependencies = [
|
|||||||
"jsonwebtoken",
|
"jsonwebtoken",
|
||||||
"leptos",
|
"leptos",
|
||||||
"leptos_axum",
|
"leptos_axum",
|
||||||
|
"leptos_router",
|
||||||
"mime_guess",
|
"mime_guess",
|
||||||
"openssl",
|
"openssl",
|
||||||
"quick-xml",
|
"quick-xml",
|
||||||
@@ -520,9 +521,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.57"
|
version = "4.5.58"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6899ea499e3fb9305a65d5ebf6e3d2248c5fab291f300ad0a704fbe142eae31a"
|
checksum = "63be97961acde393029492ce0be7a1af7e323e6bae9511ebfac33751be5e6806"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
@@ -530,9 +531,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.57"
|
version = "4.5.58"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7b12c8b680195a62a8364d16b8447b01b6c2c8f9aaf68bee653be34d4245e238"
|
checksum = "7f13174bda5dfd69d7e947827e5af4b0f2f94a4a3ee92912fba07a66150f21e2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
@@ -554,9 +555,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_lex"
|
name = "clap_lex"
|
||||||
version = "0.7.7"
|
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 = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32"
|
checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "coarsetime"
|
name = "coarsetime"
|
||||||
@@ -940,9 +941,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deranged"
|
name = "deranged"
|
||||||
version = "0.5.5"
|
version = "0.5.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587"
|
checksum = "cc3dc5ad92c2e2d1c193bbbbdf2ea477cb81331de4f3103f267ca18368b988c4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"powerfmt",
|
"powerfmt",
|
||||||
"serde_core",
|
"serde_core",
|
||||||
@@ -1426,6 +1427,19 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"r-efi",
|
||||||
|
"wasip2",
|
||||||
|
"wasip3",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gloo-console"
|
name = "gloo-console"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
@@ -1634,9 +1648,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hmac-sha512"
|
name = "hmac-sha512"
|
||||||
version = "1.1.10"
|
version = "1.1.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "425aae4cbcd7250fdcc9665de9cbec21348dd4b6c6a7321b2f5eaf41a3e97dcd"
|
checksum = "5075d41b75a022af043a5bbf49b89abf17665d5aebf6f6ec64ffff207d87654d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"digest",
|
"digest",
|
||||||
]
|
]
|
||||||
@@ -1945,6 +1959,12 @@ dependencies = [
|
|||||||
"zerovec",
|
"zerovec",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "id-arena"
|
||||||
|
version = "2.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ident_case"
|
name = "ident_case"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
@@ -2113,6 +2133,12 @@ dependencies = [
|
|||||||
"spin",
|
"spin",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "leb128fmt"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "leptos"
|
name = "leptos"
|
||||||
version = "0.8.15"
|
version = "0.8.15"
|
||||||
@@ -2373,9 +2399,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.180"
|
version = "0.2.181"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
|
checksum = "459427e2af2b9c839b132acb702a1c654d95e10f8c326bfc2ad11310e458b1c5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libm"
|
name = "libm"
|
||||||
@@ -2391,7 +2417,7 @@ checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"libc",
|
"libc",
|
||||||
"redox_syscall 0.7.0",
|
"redox_syscall 0.7.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3250,9 +3276,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.7.0"
|
version = "0.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27"
|
checksum = "35985aa610addc02e24fc232012c86fd11f14111180f902b67e2d5331f8ebf2b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
@@ -3757,10 +3783,12 @@ dependencies = [
|
|||||||
"quick-xml",
|
"quick-xml",
|
||||||
"rmp-serde",
|
"rmp-serde",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_json",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
"struct-patch",
|
"struct-patch",
|
||||||
"thiserror 2.0.18",
|
"thiserror 2.0.18",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tracing",
|
||||||
"utoipa",
|
"utoipa",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -4267,12 +4295,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.24.0"
|
version = "3.25.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c"
|
checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fastrand",
|
"fastrand",
|
||||||
"getrandom 0.3.4",
|
"getrandom 0.4.1",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustix",
|
"rustix",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
@@ -4469,9 +4497,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.9.11+spec-1.1.0"
|
version = "0.9.12+spec-1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f3afc9a848309fe1aaffaed6e1546a7a14de1f935dc9d89d32afd9a44bab7c46"
|
checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_core",
|
"serde_core",
|
||||||
"serde_spanned",
|
"serde_spanned",
|
||||||
@@ -4491,9 +4519,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_parser"
|
name = "toml_parser"
|
||||||
version = "1.0.6+spec-1.1.0"
|
version = "1.0.7+spec-1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44"
|
checksum = "247eaa3197818b831697600aadf81514e577e0cba5eab10f7e064e78ae154df1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winnow",
|
"winnow",
|
||||||
]
|
]
|
||||||
@@ -4965,6 +4993,15 @@ dependencies = [
|
|||||||
"wit-bindgen",
|
"wit-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasip3"
|
||||||
|
version = "0.4.0+wasi-0.3.0-rc-2026-01-06"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"
|
||||||
|
dependencies = [
|
||||||
|
"wit-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasite"
|
name = "wasite"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -5039,6 +5076,28 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-encoder"
|
||||||
|
version = "0.244.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319"
|
||||||
|
dependencies = [
|
||||||
|
"leb128fmt",
|
||||||
|
"wasmparser",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-metadata"
|
||||||
|
version = "0.244.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"indexmap",
|
||||||
|
"wasm-encoder",
|
||||||
|
"wasmparser",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-streams"
|
name = "wasm-streams"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
@@ -5074,6 +5133,18 @@ dependencies = [
|
|||||||
"syn 2.0.114",
|
"syn 2.0.114",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasmparser"
|
||||||
|
version = "0.244.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"hashbrown 0.15.5",
|
||||||
|
"indexmap",
|
||||||
|
"semver",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "web-push"
|
name = "web-push"
|
||||||
version = "0.10.4"
|
version = "0.10.4"
|
||||||
@@ -5452,6 +5523,88 @@ name = "wit-bindgen"
|
|||||||
version = "0.51.0"
|
version = "0.51.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
|
checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
|
||||||
|
dependencies = [
|
||||||
|
"wit-bindgen-rust-macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wit-bindgen-core"
|
||||||
|
version = "0.51.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"heck",
|
||||||
|
"wit-parser",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wit-bindgen-rust"
|
||||||
|
version = "0.51.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"heck",
|
||||||
|
"indexmap",
|
||||||
|
"prettyplease",
|
||||||
|
"syn 2.0.114",
|
||||||
|
"wasm-metadata",
|
||||||
|
"wit-bindgen-core",
|
||||||
|
"wit-component",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wit-bindgen-rust-macro"
|
||||||
|
version = "0.51.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"prettyplease",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.114",
|
||||||
|
"wit-bindgen-core",
|
||||||
|
"wit-bindgen-rust",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wit-component"
|
||||||
|
version = "0.244.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"bitflags",
|
||||||
|
"indexmap",
|
||||||
|
"log",
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
"serde_json",
|
||||||
|
"wasm-encoder",
|
||||||
|
"wasm-metadata",
|
||||||
|
"wasmparser",
|
||||||
|
"wit-parser",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wit-parser"
|
||||||
|
version = "0.244.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"id-arena",
|
||||||
|
"indexmap",
|
||||||
|
"log",
|
||||||
|
"semver",
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
"serde_json",
|
||||||
|
"unicode-xid",
|
||||||
|
"wasmparser",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "writeable"
|
name = "writeable"
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["swagger"] # push-notifications kaldırıldı
|
default = ["swagger"]
|
||||||
push-notifications = ["web-push", "openssl"]
|
push-notifications = ["web-push", "openssl"]
|
||||||
swagger = ["utoipa-swagger-ui"]
|
swagger = ["utoipa-swagger-ui"]
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ clap = { version = "4.4", features = ["derive", "env"] }
|
|||||||
rust-embed = "8.2"
|
rust-embed = "8.2"
|
||||||
mime_guess = "2.0"
|
mime_guess = "2.0"
|
||||||
shared = { path = "../shared", features = ["ssr"] }
|
shared = { path = "../shared", features = ["ssr"] }
|
||||||
thiserror = "2.0.18"
|
thiserror = "2.0"
|
||||||
dotenvy = "0.15.7"
|
dotenvy = "0.15.7"
|
||||||
utoipa = { version = "5.4.0", features = ["axum_extras"] }
|
utoipa = { version = "5.4.0", features = ["axum_extras"] }
|
||||||
utoipa-swagger-ui = { version = "9.0", features = ["axum"], optional = true }
|
utoipa-swagger-ui = { version = "9.0", features = ["axum"], optional = true }
|
||||||
@@ -38,12 +38,13 @@ openssl = { version = "0.10", features = ["vendored"], optional = true }
|
|||||||
bcrypt = "0.17.0"
|
bcrypt = "0.17.0"
|
||||||
axum-extra = { version = "0.10", features = ["cookie"] }
|
axum-extra = { version = "0.10", features = ["cookie"] }
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
anyhow = "1.0.101"
|
anyhow = "1.0"
|
||||||
time = { version = "0.3.47", features = ["serde", "formatting", "parsing"] }
|
time = { version = "0.3", features = ["serde", "formatting", "parsing"] }
|
||||||
tower_governor = "0.8.0"
|
tower_governor = "0.8.0"
|
||||||
governor = "0.10.4"
|
governor = "0.10.4"
|
||||||
|
|
||||||
# Leptos
|
# Leptos
|
||||||
leptos = { version = "0.8.15", features = ["nightly"] }
|
leptos = { version = "0.8.15", features = ["nightly", "msgpack"] }
|
||||||
leptos_axum = { version = "0.8.7" }
|
leptos_axum = { version = "0.8.7" }
|
||||||
|
leptos_router = { version = "0.8.11" }
|
||||||
jsonwebtoken = "9"
|
jsonwebtoken = "9"
|
||||||
@@ -26,7 +26,7 @@ use std::time::Duration;
|
|||||||
use tokio::sync::{broadcast, watch};
|
use tokio::sync::{broadcast, watch};
|
||||||
use tower::ServiceBuilder;
|
use tower::ServiceBuilder;
|
||||||
use tower_http::{
|
use tower_http::{
|
||||||
compression::{CompressionLayer, CompressionLevel},
|
compression::CompressionLayer,
|
||||||
cors::CorsLayer,
|
cors::CorsLayer,
|
||||||
trace::TraceLayer,
|
trace::TraceLayer,
|
||||||
};
|
};
|
||||||
@@ -407,37 +407,37 @@ async fn main() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
async fn server_fn_handler(
|
||||||
|
axum::extract::State(state): axum::extract::State<AppState>,
|
||||||
|
req: Request<Body>,
|
||||||
|
) -> impl axum::response::IntoResponse {
|
||||||
|
let scgi_path = state.scgi_socket_path.clone();
|
||||||
|
let db = state.db.clone();
|
||||||
|
|
||||||
|
leptos_axum::handle_server_fns_with_context(
|
||||||
|
move || {
|
||||||
|
leptos::context::provide_context(shared::ServerContext {
|
||||||
|
scgi_socket_path: scgi_path.clone(),
|
||||||
|
});
|
||||||
|
leptos::context::provide_context(shared::DbContext {
|
||||||
|
db: db.clone(),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
req,
|
||||||
|
).await
|
||||||
|
}
|
||||||
|
|
||||||
let app = Router::new();
|
let app = Router::new();
|
||||||
|
|
||||||
#[cfg(feature = "swagger")]
|
#[cfg(feature = "swagger")]
|
||||||
let app = app.merge(SwaggerUi::new("/swagger-ui").url("/api-docs/openapi.json", ApiDoc::openapi()));
|
let app = app.merge(SwaggerUi::new("/swagger-ui").url("/api-docs/openapi.json", ApiDoc::openapi()));
|
||||||
|
|
||||||
// Setup & Auth Routes (cookie-based, stay as REST)
|
// Setup & Auth Routes (cookie-based, stay as REST)
|
||||||
// Setup & Auth Routes (cookie-based, stay as REST)
|
|
||||||
let scgi_path_for_ctx = args.socket.clone();
|
|
||||||
let db_for_ctx = db.clone();
|
|
||||||
let app = app
|
let app = app
|
||||||
.route("/api/events", get(sse::sse_handler))
|
.route("/api/events", get(sse::sse_handler))
|
||||||
.route("/api/server_fns/{*fn_name}", post({
|
.route("/api/server_fns/{*fn_name}", post(server_fn_handler))
|
||||||
let scgi_path = scgi_path_for_ctx.clone();
|
.fallback(handlers::static_handler)
|
||||||
let db = db_for_ctx.clone();
|
.with_state(app_state.clone());
|
||||||
move |req: Request<Body>| {
|
|
||||||
let scgi_path = scgi_path.clone();
|
|
||||||
let db = db.clone();
|
|
||||||
leptos_axum::handle_server_fns_with_context(
|
|
||||||
move || {
|
|
||||||
leptos::context::provide_context(shared::ServerContext {
|
|
||||||
scgi_socket_path: scgi_path.clone(),
|
|
||||||
});
|
|
||||||
leptos::context::provide_context(shared::DbContext {
|
|
||||||
db: db.clone(),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
req,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
.fallback(handlers::static_handler);
|
|
||||||
|
|
||||||
let app = app
|
let app = app
|
||||||
.layer(middleware::from_fn_with_state(app_state.clone(), auth_middleware))
|
.layer(middleware::from_fn_with_state(app_state.clone(), auth_middleware))
|
||||||
@@ -445,8 +445,7 @@ async fn main() {
|
|||||||
.layer(
|
.layer(
|
||||||
CompressionLayer::new()
|
CompressionLayer::new()
|
||||||
.br(false)
|
.br(false)
|
||||||
.gzip(true)
|
.gzip(true),
|
||||||
.quality(CompressionLevel::Fastest),
|
|
||||||
)
|
)
|
||||||
.layer(
|
.layer(
|
||||||
ServiceBuilder::new()
|
ServiceBuilder::new()
|
||||||
|
|||||||
@@ -38,4 +38,7 @@ struct-patch = "0.5"
|
|||||||
# Rust/UI Components
|
# Rust/UI Components
|
||||||
leptos_ui = "0.3"
|
leptos_ui = "0.3"
|
||||||
tw_merge = "0.1"
|
tw_merge = "0.1"
|
||||||
strum = { version = "0.26", features = ["derive"] }
|
strum = { version = "0.26", features = ["derive"] }
|
||||||
|
|
||||||
|
[package.metadata.leptos]
|
||||||
|
tailwind-input-file = "input.css"
|
||||||
@@ -1,14 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "frontend",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "",
|
|
||||||
"main": "tailwind.config.js",
|
|
||||||
"scripts": {
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
|
||||||
},
|
|
||||||
"keywords": [],
|
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"dependencies": {
|
||||||
|
"@tailwindcss/cli": "^4.1.18",
|
||||||
|
"class-variance-authority": "^0.7.1",
|
||||||
|
"clsx": "^2.1.1",
|
||||||
|
"tailwind-merge": "^3.4.0",
|
||||||
|
"tailwindcss-animate": "^1.0.7"
|
||||||
|
},
|
||||||
|
"description": "",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/postcss": "^4.1.18",
|
"@tailwindcss/postcss": "^4.1.18",
|
||||||
"autoprefixer": "^10.4.23",
|
"autoprefixer": "^10.4.23",
|
||||||
@@ -17,11 +16,13 @@
|
|||||||
"postcss-preset-env": "^10.1.3",
|
"postcss-preset-env": "^10.1.3",
|
||||||
"tailwindcss": "^4.1.18"
|
"tailwindcss": "^4.1.18"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"keywords": [],
|
||||||
"@tailwindcss/cli": "^4.1.18",
|
"license": "ISC",
|
||||||
"class-variance-authority": "^0.7.1",
|
"main": "tailwind.config.js",
|
||||||
"clsx": "^2.1.1",
|
"name": "frontend",
|
||||||
"tailwind-merge": "^3.4.0",
|
"scripts": {
|
||||||
"tailwindcss-animate": "^1.0.7"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
}
|
},
|
||||||
}
|
"type": "module",
|
||||||
|
"version": "1.0.0"
|
||||||
|
}
|
||||||
@@ -6,20 +6,20 @@ use leptos::prelude::*;
|
|||||||
use leptos::task::spawn_local;
|
use leptos::task::spawn_local;
|
||||||
use leptos_router::components::{Router, Routes, Route};
|
use leptos_router::components::{Router, Routes, Route};
|
||||||
use leptos_router::hooks::use_navigate;
|
use leptos_router::hooks::use_navigate;
|
||||||
use crate::components::toast::Toaster;
|
use crate::components::ui::toast::Toaster;
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn App() -> impl IntoView {
|
pub fn App() -> impl IntoView {
|
||||||
|
crate::components::ui::toast::provide_toaster();
|
||||||
view! {
|
view! {
|
||||||
<InnerApp />
|
|
||||||
<Toaster />
|
<Toaster />
|
||||||
|
<InnerApp />
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
fn InnerApp() -> impl IntoView {
|
fn InnerApp() -> impl IntoView {
|
||||||
crate::store::provide_torrent_store();
|
crate::store::provide_torrent_store();
|
||||||
crate::components::toast::provide_toast_context();
|
|
||||||
let store = use_context::<crate::store::TorrentStore>();
|
let store = use_context::<crate::store::TorrentStore>();
|
||||||
|
|
||||||
let is_loading = signal(true);
|
let is_loading = signal(true);
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ pub fn Setup() -> impl IntoView {
|
|||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("Setup failed: {:?}", e);
|
log::error!("Setup failed: {:?}", e);
|
||||||
error.1.set(Some("Kurulum sırasında bir hata oluştu".to_string()));
|
// Hatanın sadece mesaj kısmını almaya çalışalım, yoksa full struct basılabilir
|
||||||
|
error.1.set(Some(format!("Hata: {}", e)));
|
||||||
loading.1.set(false);
|
loading.1.set(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,5 +2,5 @@ pub mod context_menu;
|
|||||||
pub mod layout;
|
pub mod layout;
|
||||||
pub mod torrent;
|
pub mod torrent;
|
||||||
pub mod auth;
|
pub mod auth;
|
||||||
pub mod toast;
|
// pub mod toast; (Removed)
|
||||||
pub mod ui;
|
pub mod ui;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
pub mod button;
|
pub mod button;
|
||||||
pub mod card;
|
pub mod card;
|
||||||
pub mod input;
|
pub mod input;
|
||||||
|
pub mod toast;
|
||||||
|
|||||||
232
frontend/src/components/ui/toast.rs
Normal file
232
frontend/src/components/ui/toast.rs
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
use leptos::prelude::*;
|
||||||
|
use tw_merge::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Default, strum::Display, Debug)]
|
||||||
|
pub enum ToastType {
|
||||||
|
#[default]
|
||||||
|
Default,
|
||||||
|
Success,
|
||||||
|
Error,
|
||||||
|
Warning,
|
||||||
|
Info,
|
||||||
|
Loading,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Default, strum::Display, Debug)]
|
||||||
|
pub enum SonnerPosition {
|
||||||
|
TopLeft,
|
||||||
|
TopCenter,
|
||||||
|
TopRight,
|
||||||
|
#[default]
|
||||||
|
BottomRight,
|
||||||
|
BottomCenter,
|
||||||
|
BottomLeft,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Default, strum::Display, Debug)]
|
||||||
|
pub enum SonnerDirection {
|
||||||
|
TopDown,
|
||||||
|
#[default]
|
||||||
|
BottomUp,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct ToastData {
|
||||||
|
pub id: u64,
|
||||||
|
pub title: String,
|
||||||
|
pub description: Option<String>,
|
||||||
|
pub variant: ToastType,
|
||||||
|
pub duration: u64, // ms
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct ToasterStore {
|
||||||
|
pub toasts: RwSignal<Vec<ToastData>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn SonnerTrigger(
|
||||||
|
#[prop(into, optional)] class: String,
|
||||||
|
#[prop(optional, default = ToastType::default())] variant: ToastType,
|
||||||
|
#[prop(into)] title: String,
|
||||||
|
description: Option<String>,
|
||||||
|
#[prop(into, optional)] position: String,
|
||||||
|
on_dismiss: Option<Callback<()>>,
|
||||||
|
) -> impl IntoView {
|
||||||
|
let variant_classes = match variant {
|
||||||
|
ToastType::Default => "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
|
||||||
|
ToastType::Success => "bg-green-500 text-white hover:bg-green-600",
|
||||||
|
ToastType::Error => "bg-red-500 text-white shadow-xs hover:bg-red-600",
|
||||||
|
ToastType::Warning => "bg-yellow-500 text-white hover:bg-yellow-600",
|
||||||
|
ToastType::Info => "bg-blue-500 text-white shadow-xs hover:bg-blue-600",
|
||||||
|
ToastType::Loading => "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
|
||||||
|
};
|
||||||
|
|
||||||
|
let merged_class = tw_merge!(
|
||||||
|
"inline-flex flex-col items-start justify-center gap-1 min-w-[300px] rounded-md text-sm font-medium transition-all shadow-lg p-4 cursor-pointer pointer-events-auto border border-border/50",
|
||||||
|
variant_classes,
|
||||||
|
class
|
||||||
|
);
|
||||||
|
|
||||||
|
// Only set position attribute if not empty
|
||||||
|
let position_attr = if position.is_empty() { None } else { Some(position) };
|
||||||
|
|
||||||
|
// Clone title for data attribute usage, original moved into view
|
||||||
|
let title_clone = title.clone();
|
||||||
|
|
||||||
|
view! {
|
||||||
|
<div
|
||||||
|
class=merged_class
|
||||||
|
data-name="SonnerTrigger"
|
||||||
|
data-variant=variant.to_string()
|
||||||
|
data-toast-title=title_clone
|
||||||
|
data-toast-position=position_attr
|
||||||
|
on:click=move |_| {
|
||||||
|
if let Some(cb) = on_dismiss {
|
||||||
|
cb.run(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div class="font-semibold">{title}</div>
|
||||||
|
{move || description.as_ref().map(|d| view! { <div class="text-xs opacity-90">{d.clone()}</div> })}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn SonnerContainer(
|
||||||
|
children: Children,
|
||||||
|
#[prop(into, optional)] class: String,
|
||||||
|
#[prop(optional, default = SonnerPosition::default())] position: SonnerPosition,
|
||||||
|
) -> impl IntoView {
|
||||||
|
let merged_class = tw_merge!("toast__container fixed z-[9999] flex flex-col gap-2 p-4 outline-none pointer-events-none", class);
|
||||||
|
|
||||||
|
view! {
|
||||||
|
<div class=merged_class data-position=position.to_string()>
|
||||||
|
{children()}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn SonnerList(
|
||||||
|
children: Children,
|
||||||
|
#[prop(into, optional)] class: String,
|
||||||
|
#[prop(optional, default = SonnerPosition::default())] position: SonnerPosition,
|
||||||
|
#[prop(optional, default = SonnerDirection::default())] direction: SonnerDirection,
|
||||||
|
#[prop(into, default = "false".to_string())] expanded: String,
|
||||||
|
#[prop(into, optional)] style: String,
|
||||||
|
) -> impl IntoView {
|
||||||
|
let merged_class = tw_merge!(
|
||||||
|
"contents",
|
||||||
|
class
|
||||||
|
);
|
||||||
|
|
||||||
|
view! {
|
||||||
|
<div
|
||||||
|
class=merged_class
|
||||||
|
data-name="SonnerList"
|
||||||
|
data-sonner-toaster="true"
|
||||||
|
data-sonner-theme="light"
|
||||||
|
data-position=position.to_string()
|
||||||
|
data-expanded=expanded
|
||||||
|
data-direction=direction.to_string()
|
||||||
|
style=style
|
||||||
|
>
|
||||||
|
{children()}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Thread local storage for global access without Context
|
||||||
|
thread_local! {
|
||||||
|
static TOASTS: std::cell::RefCell<Option<RwSignal<Vec<ToastData>>>> = std::cell::RefCell::new(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn provide_toaster() {
|
||||||
|
let toasts = RwSignal::new(Vec::<ToastData>::new());
|
||||||
|
|
||||||
|
// Set global thread_local
|
||||||
|
TOASTS.with(|t| *t.borrow_mut() = Some(toasts));
|
||||||
|
|
||||||
|
// Also provide context for components
|
||||||
|
provide_context(ToasterStore { toasts });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn Toaster(#[prop(default = SonnerPosition::default())] position: SonnerPosition) -> impl IntoView {
|
||||||
|
// Global store'u al
|
||||||
|
let store = use_context::<ToasterStore>().expect("Toaster context not found. Call provide_toaster() in App root.");
|
||||||
|
let toasts = store.toasts;
|
||||||
|
|
||||||
|
// Auto-derive direction from position
|
||||||
|
let direction = match position {
|
||||||
|
SonnerPosition::TopLeft | SonnerPosition::TopCenter | SonnerPosition::TopRight => SonnerDirection::TopDown,
|
||||||
|
_ => SonnerDirection::BottomUp,
|
||||||
|
};
|
||||||
|
|
||||||
|
let container_class = match position {
|
||||||
|
SonnerPosition::TopLeft => "left-0 top-0 items-start",
|
||||||
|
SonnerPosition::TopRight => "right-0 top-0 items-end",
|
||||||
|
SonnerPosition::TopCenter => "left-1/2 -translate-x-1/2 top-0 items-center",
|
||||||
|
SonnerPosition::BottomCenter => "left-1/2 -translate-x-1/2 bottom-0 items-center",
|
||||||
|
SonnerPosition::BottomLeft => "left-0 bottom-0 items-start",
|
||||||
|
SonnerPosition::BottomRight => "right-0 bottom-0 items-end",
|
||||||
|
};
|
||||||
|
|
||||||
|
view! {
|
||||||
|
<SonnerContainer class=container_class position=position>
|
||||||
|
<SonnerList position=position direction=direction>
|
||||||
|
<For
|
||||||
|
each=move || toasts.get()
|
||||||
|
key=|toast| toast.id
|
||||||
|
children=move |toast| {
|
||||||
|
let id = toast.id;
|
||||||
|
view! {
|
||||||
|
<SonnerTrigger
|
||||||
|
variant=toast.variant
|
||||||
|
title=toast.title
|
||||||
|
description=toast.description
|
||||||
|
on_dismiss=Some(Callback::new(move |_| {
|
||||||
|
toasts.update(|vec| vec.retain(|t| t.id != id));
|
||||||
|
}))
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</SonnerList>
|
||||||
|
</SonnerContainer>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Global Helper Functions
|
||||||
|
pub fn toast(title: impl Into<String>, variant: ToastType) {
|
||||||
|
let signal_opt = TOASTS.with(|t| *t.borrow());
|
||||||
|
|
||||||
|
if let Some(toasts) = signal_opt {
|
||||||
|
let id = js_sys::Math::random().to_bits();
|
||||||
|
let new_toast = ToastData {
|
||||||
|
id,
|
||||||
|
title: title.into(),
|
||||||
|
description: None,
|
||||||
|
variant,
|
||||||
|
duration: 4000,
|
||||||
|
};
|
||||||
|
|
||||||
|
toasts.update(|t| t.push(new_toast.clone()));
|
||||||
|
|
||||||
|
// Auto remove after duration
|
||||||
|
let duration = new_toast.duration;
|
||||||
|
leptos::task::spawn_local(async move {
|
||||||
|
gloo_timers::future::TimeoutFuture::new(duration as u32).await;
|
||||||
|
toasts.update(|vec| vec.retain(|t| t.id != id));
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
gloo_console::warn!("ToasterStore not found (global static). Make sure provide_toaster() is called.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toast_success(title: impl Into<String>) { toast(title, ToastType::Success); }
|
||||||
|
pub fn toast_error(title: impl Into<String>) { toast(title, ToastType::Error); }
|
||||||
|
pub fn toast_warning(title: impl Into<String>) { toast(title, ToastType::Warning); }
|
||||||
|
pub fn toast_info(title: impl Into<String>) { toast(title, ToastType::Info); }
|
||||||
@@ -7,19 +7,21 @@ use std::collections::HashMap;
|
|||||||
use struct_patch::traits::Patch;
|
use struct_patch::traits::Patch;
|
||||||
use base64::{Engine as _, engine::general_purpose::STANDARD as BASE64};
|
use base64::{Engine as _, engine::general_purpose::STANDARD as BASE64};
|
||||||
|
|
||||||
use crate::components::toast::ToastContext;
|
use crate::components::ui::toast::{ToastType, toast};
|
||||||
|
|
||||||
pub fn show_toast(level: NotificationLevel, message: impl Into<String>) {
|
pub fn show_toast(level: NotificationLevel, message: impl Into<String>) {
|
||||||
let msg = message.into();
|
let msg = message.into();
|
||||||
gloo_console::log!("TOAST CALL:", &msg, format!("{:?}", level));
|
gloo_console::log!("TOAST CALL:", &msg, format!("{:?}", level));
|
||||||
log::info!("Displaying toast: [{:?}] {}", level, msg);
|
log::info!("Displaying toast: [{:?}] {}", level, msg);
|
||||||
|
|
||||||
if let Some(context) = use_context::<ToastContext>() {
|
let variant = match level {
|
||||||
context.add(msg, level);
|
NotificationLevel::Success => ToastType::Success,
|
||||||
} else {
|
NotificationLevel::Error => ToastType::Error,
|
||||||
log::error!("ToastContext not found!");
|
NotificationLevel::Warning => ToastType::Warning,
|
||||||
gloo_console::error!("ToastContext not found!");
|
NotificationLevel::Info => ToastType::Info,
|
||||||
}
|
};
|
||||||
|
|
||||||
|
toast(msg, variant);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
2
frontend/ui_config.toml
Normal file
2
frontend/ui_config.toml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
base_color = "neutral"
|
||||||
|
base_path_components = "src/components"
|
||||||
@@ -6,14 +6,16 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
utoipa = { version = "5.4.0", features = ["axum_extras"] }
|
utoipa = { version = "5.4.0", features = ["axum_extras"] }
|
||||||
|
serde_json = "1"
|
||||||
struct-patch = "0.5"
|
struct-patch = "0.5"
|
||||||
rmp-serde = "1.3"
|
rmp-serde = "1.3"
|
||||||
bytes = "1"
|
bytes = "1"
|
||||||
http = "1"
|
http = "1"
|
||||||
|
tracing = "0.1"
|
||||||
|
|
||||||
# Leptos 0.8.7
|
# Leptos 0.8
|
||||||
leptos = { version = "0.8.15", features = ["nightly", "msgpack"] }
|
leptos = { version = "0.8.15", features = ["nightly", "msgpack"] }
|
||||||
leptos_router = { version = "0.8.7", features = ["nightly"] }
|
leptos_router = { version = "0.8.11", features = ["nightly"] }
|
||||||
leptos_axum = { version = "0.8.7", optional = true }
|
leptos_axum = { version = "0.8.7", optional = true }
|
||||||
axum = { version = "0.8", features = ["macros"], optional = true }
|
axum = { version = "0.8", features = ["macros"], optional = true }
|
||||||
|
|
||||||
|
|||||||
@@ -28,8 +28,17 @@ impl Db {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn run_migrations(&self) -> Result<()> {
|
async fn run_migrations(&self) -> Result<()> {
|
||||||
sqlx::migrate!("./migrations").run(&self.pool).await?;
|
tracing::info!("Starting database migrations...");
|
||||||
Ok(())
|
match sqlx::migrate!("./migrations").run(&self.pool).await {
|
||||||
|
Ok(_) => {
|
||||||
|
tracing::info!("Database migrations completed successfully.");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
tracing::error!("Database migration failed: {}", e);
|
||||||
|
Err(e.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- User Operations ---
|
// --- User Operations ---
|
||||||
|
|||||||
@@ -24,9 +24,19 @@ pub struct SetupStatus {
|
|||||||
pub async fn get_setup_status() -> Result<SetupStatus, ServerFnError> {
|
pub async fn get_setup_status() -> Result<SetupStatus, ServerFnError> {
|
||||||
use crate::DbContext;
|
use crate::DbContext;
|
||||||
|
|
||||||
let db_context = use_context::<DbContext>().ok_or_else(|| ServerFnError::new("DB Context missing"))?;
|
tracing::info!("Checking setup status...");
|
||||||
|
let db_context = use_context::<DbContext>().ok_or_else(|| {
|
||||||
|
tracing::error!("DB Context missing in GetSetupStatus");
|
||||||
|
ServerFnError::new("DB Context missing")
|
||||||
|
})?;
|
||||||
|
|
||||||
let has_users = db_context.db.has_users().await
|
let has_users = db_context.db.has_users().await
|
||||||
.map_err(|e| ServerFnError::new(format!("DB error: {}", e)))?;
|
.map_err(|e| {
|
||||||
|
tracing::error!("DB error in GetSetupStatus: {}", e);
|
||||||
|
ServerFnError::new(format!("DB error: {}", e))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
tracing::info!("Setup status: completed={}", has_users);
|
||||||
|
|
||||||
Ok(SetupStatus {
|
Ok(SetupStatus {
|
||||||
completed: has_users,
|
completed: has_users,
|
||||||
@@ -37,21 +47,33 @@ pub async fn get_setup_status() -> Result<SetupStatus, ServerFnError> {
|
|||||||
pub async fn setup(username: String, password: String) -> Result<(), ServerFnError> {
|
pub async fn setup(username: String, password: String) -> Result<(), ServerFnError> {
|
||||||
use crate::DbContext;
|
use crate::DbContext;
|
||||||
|
|
||||||
let db_context = use_context::<DbContext>().ok_or_else(|| ServerFnError::new("DB Context missing"))?;
|
tracing::info!("Attempting setup for user: {}", username);
|
||||||
|
let db_context = use_context::<DbContext>().ok_or_else(|| {
|
||||||
|
tracing::error!("DB Context missing in Setup");
|
||||||
|
ServerFnError::new("DB Context missing")
|
||||||
|
})?;
|
||||||
|
|
||||||
// Check if setup is already done
|
// Check if setup is already done
|
||||||
let has_users = db_context.db.has_users().await.unwrap_or(false);
|
let has_users = db_context.db.has_users().await.unwrap_or(false);
|
||||||
if has_users {
|
if has_users {
|
||||||
|
tracing::warn!("Setup attempt blocked: Setup already completed");
|
||||||
return Err(ServerFnError::new("Setup already completed"));
|
return Err(ServerFnError::new("Setup already completed"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash password (low cost for MIPS)
|
// Hash password (low cost for MIPS)
|
||||||
let password_hash = bcrypt::hash(&password, 6)
|
let password_hash = bcrypt::hash(&password, 6)
|
||||||
.map_err(|_| ServerFnError::new("Hashing error"))?;
|
.map_err(|e| {
|
||||||
|
tracing::error!("Hashing error: {}", e);
|
||||||
|
ServerFnError::new("Hashing error")
|
||||||
|
})?;
|
||||||
|
|
||||||
db_context.db.create_user(&username, &password_hash).await
|
db_context.db.create_user(&username, &password_hash).await
|
||||||
.map_err(|e| ServerFnError::new(format!("DB error: {}", e)))?;
|
.map_err(|e| {
|
||||||
|
tracing::error!("Failed to create user: {}", e);
|
||||||
|
ServerFnError::new(format!("DB error: {}", e))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
tracing::info!("Setup completed successfully for user: {}", username);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
BIN
vibetorrent.db
BIN
vibetorrent.db
Binary file not shown.
Reference in New Issue
Block a user