finish the migration to julids
This commit is contained in:
parent
7aefedf993
commit
b8481dc106
13 changed files with 236 additions and 414 deletions
289
Cargo.lock
generated
289
Cargo.lock
generated
|
@ -234,17 +234,6 @@ dependencies = [
|
||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "atty"
|
|
||||||
version = "0.2.14"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
|
||||||
dependencies = [
|
|
||||||
"hermit-abi 0.1.19",
|
|
||||||
"libc",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "auto-future"
|
name = "auto-future"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
@ -450,29 +439,6 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bindgen"
|
|
||||||
version = "0.60.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "062dddbc1ba4aca46de6338e2bf87771414c335f7b2f2036e8f3e9befebf88e6"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 1.3.2",
|
|
||||||
"cexpr",
|
|
||||||
"clang-sys",
|
|
||||||
"clap 3.2.25",
|
|
||||||
"env_logger",
|
|
||||||
"lazy_static",
|
|
||||||
"lazycell",
|
|
||||||
"log",
|
|
||||||
"peeking_take_while",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"regex",
|
|
||||||
"rustc-hash",
|
|
||||||
"shlex",
|
|
||||||
"which",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
|
@ -554,15 +520,6 @@ version = "1.0.79"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cexpr"
|
|
||||||
version = "0.6.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
|
|
||||||
dependencies = [
|
|
||||||
"nom",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "0.1.10"
|
version = "0.1.10"
|
||||||
|
@ -585,35 +542,10 @@ dependencies = [
|
||||||
"iana-time-zone",
|
"iana-time-zone",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"serde",
|
"serde",
|
||||||
|
"time 0.1.45",
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "clang-sys"
|
|
||||||
version = "1.6.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f"
|
|
||||||
dependencies = [
|
|
||||||
"glob",
|
|
||||||
"libc",
|
|
||||||
"libloading",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "clap"
|
|
||||||
version = "3.2.25"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123"
|
|
||||||
dependencies = [
|
|
||||||
"atty",
|
|
||||||
"bitflags 1.3.2",
|
|
||||||
"clap_lex 0.2.4",
|
|
||||||
"indexmap 1.9.3",
|
|
||||||
"strsim",
|
|
||||||
"termcolor",
|
|
||||||
"textwrap",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.3.19"
|
version = "4.3.19"
|
||||||
|
@ -633,7 +565,7 @@ checksum = "01c6a3f08f1fe5662a35cfe393aec09c4df95f60ee93b7556505260f75eee9e1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"clap_lex 0.5.0",
|
"clap_lex",
|
||||||
"strsim",
|
"strsim",
|
||||||
"unicase",
|
"unicase",
|
||||||
"unicode-width",
|
"unicode-width",
|
||||||
|
@ -651,15 +583,6 @@ dependencies = [
|
||||||
"syn 2.0.27",
|
"syn 2.0.27",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "clap_lex"
|
|
||||||
version = "0.2.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
|
|
||||||
dependencies = [
|
|
||||||
"os_str_bytes",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_lex"
|
name = "clap_lex"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
|
@ -696,7 +619,7 @@ dependencies = [
|
||||||
"rand",
|
"rand",
|
||||||
"sha2 0.10.7",
|
"sha2 0.10.7",
|
||||||
"subtle",
|
"subtle",
|
||||||
"time",
|
"time 0.3.23",
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -832,19 +755,6 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "env_logger"
|
|
||||||
version = "0.9.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7"
|
|
||||||
dependencies = [
|
|
||||||
"atty",
|
|
||||||
"humantime",
|
|
||||||
"log",
|
|
||||||
"regex",
|
|
||||||
"termcolor",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "equivalent"
|
name = "equivalent"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
|
@ -1040,7 +950,7 @@ checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1049,18 +959,6 @@ version = "0.27.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e"
|
checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "glob"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hashbrown"
|
|
||||||
version = "0.12.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.14.0"
|
version = "0.14.0"
|
||||||
|
@ -1077,7 +975,7 @@ version = "0.8.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "312f66718a2d7789ffef4f4b7b213138ed9f1eb3aa1d0d82fc99f88fb3ffd26f"
|
checksum = "312f66718a2d7789ffef4f4b7b213138ed9f1eb3aa1d0d82fc99f88fb3ffd26f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hashbrown 0.14.0",
|
"hashbrown",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1114,15 +1012,6 @@ dependencies = [
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hermit-abi"
|
|
||||||
version = "0.1.19"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
|
@ -1221,12 +1110,6 @@ dependencies = [
|
||||||
"libm",
|
"libm",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "humantime"
|
|
||||||
version = "2.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "0.14.27"
|
version = "0.14.27"
|
||||||
|
@ -1283,16 +1166,6 @@ dependencies = [
|
||||||
"unicode-normalization",
|
"unicode-normalization",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "indexmap"
|
|
||||||
version = "1.9.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
"hashbrown 0.12.3",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
|
@ -1300,7 +1173,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
|
checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown 0.14.0",
|
"hashbrown",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1309,7 +1182,7 @@ version = "0.4.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
|
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi 0.3.2",
|
"hermit-abi",
|
||||||
"rustix",
|
"rustix",
|
||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
@ -1340,11 +1213,13 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "julid-rs"
|
name = "julid-rs"
|
||||||
version = "0.1.6"
|
version = "1.6.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2081aa5e2e85795e4e2b36e95df914655cf281d0e3eafb7e538754d704ac18e3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
"rand",
|
"rand",
|
||||||
"serde",
|
"serde",
|
||||||
"sqlite-loadable",
|
|
||||||
"sqlx",
|
"sqlx",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1368,28 +1243,12 @@ dependencies = [
|
||||||
"spin 0.5.2",
|
"spin 0.5.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lazycell"
|
|
||||||
version = "1.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.147"
|
version = "0.2.147"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libloading"
|
|
||||||
version = "0.7.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if 1.0.0",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libm"
|
name = "libm"
|
||||||
version = "0.2.7"
|
version = "0.2.7"
|
||||||
|
@ -1497,7 +1356,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
|
checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1575,7 +1434,7 @@ version = "1.16.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi 0.3.2",
|
"hermit-abi",
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1608,12 +1467,6 @@ dependencies = [
|
||||||
"syn 2.0.27",
|
"syn 2.0.27",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "os_str_bytes"
|
|
||||||
version = "6.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "overload"
|
name = "overload"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
|
@ -1660,12 +1513,6 @@ 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 = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
|
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "peeking_take_while"
|
|
||||||
version = "0.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pem-rfc7468"
|
name = "pem-rfc7468"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
|
@ -1909,12 +1756,6 @@ version = "0.1.23"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustc-hash"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.4"
|
version = "0.38.4"
|
||||||
|
@ -1997,18 +1838,18 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.176"
|
version = "1.0.177"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "76dc28c9523c5d70816e393136b86d48909cfb27cecaa902d338c19ed47164dc"
|
checksum = "63ba2516aa6bf82e0b19ca8b50019d52df58455d3cf9bdaf6315225fdd0c560a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.176"
|
version = "1.0.177"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a4e7b8c5dc823e3b90651ff1d3808419cd14e5ad76de04feaf37da114e7a306f"
|
checksum = "401797fe7833d72109fedec6bfcbe67c0eed9b99772f26eb8afd261f0abc6fd3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -2101,12 +1942,6 @@ dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "shlex"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook-registry"
|
name = "signal-hook-registry"
|
||||||
version = "1.4.1"
|
version = "1.4.1"
|
||||||
|
@ -2187,40 +2022,6 @@ dependencies = [
|
||||||
"unicode_categories",
|
"unicode_categories",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sqlite-loadable"
|
|
||||||
version = "0.0.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a916b7bb8738eef189dea88731b619b80bf3f62b3acf05138fa43fbf8621cc94"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 1.3.2",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"sqlite-loadable-macros",
|
|
||||||
"sqlite3ext-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sqlite-loadable-macros"
|
|
||||||
version = "0.0.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f98bc75a8d6fd24f6a2cfea34f28758780fa17279d3051eec926efa381971e48"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 1.0.109",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sqlite3ext-sys"
|
|
||||||
version = "0.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3afdc2b3dc08f16d6eecf8aa07d19975a268603ab1cca67d3f9b4172c507cf16"
|
|
||||||
dependencies = [
|
|
||||||
"bindgen",
|
|
||||||
"cc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sqlx"
|
name = "sqlx"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
|
@ -2256,7 +2057,7 @@ dependencies = [
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"hashlink",
|
"hashlink",
|
||||||
"hex",
|
"hex",
|
||||||
"indexmap 2.0.0",
|
"indexmap",
|
||||||
"log",
|
"log",
|
||||||
"memchr",
|
"memchr",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
@ -2481,21 +2282,6 @@ dependencies = [
|
||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "termcolor"
|
|
||||||
version = "1.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
|
|
||||||
dependencies = [
|
|
||||||
"winapi-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "textwrap"
|
|
||||||
version = "0.16.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.44"
|
version = "1.0.44"
|
||||||
|
@ -2526,6 +2312,17 @@ dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time"
|
||||||
|
version = "0.1.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.3.23"
|
version = "0.3.23"
|
||||||
|
@ -2844,6 +2641,12 @@ dependencies = [
|
||||||
"try-lock",
|
"try-lock",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.10.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
@ -2936,7 +2739,7 @@ dependencies = [
|
||||||
"axum-macros",
|
"axum-macros",
|
||||||
"axum-test",
|
"axum-test",
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap 4.3.19",
|
"clap",
|
||||||
"julid-rs",
|
"julid-rs",
|
||||||
"justerror",
|
"justerror",
|
||||||
"optional_optional_user",
|
"optional_optional_user",
|
||||||
|
@ -2957,17 +2760,6 @@ dependencies = [
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "which"
|
|
||||||
version = "4.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269"
|
|
||||||
dependencies = [
|
|
||||||
"either",
|
|
||||||
"libc",
|
|
||||||
"once_cell",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "whoami"
|
name = "whoami"
|
||||||
version = "1.4.1"
|
version = "1.4.1"
|
||||||
|
@ -2990,15 +2782,6 @@ 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 = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-util"
|
|
||||||
version = "0.1.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
|
||||||
dependencies = [
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi-x86_64-pc-windows-gnu"
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
|
|
@ -18,7 +18,7 @@ axum-login = { git = "https://github.com/nebkor/axum-login", branch = "sqlx-0.7"
|
||||||
axum-macros = "0.3"
|
axum-macros = "0.3"
|
||||||
chrono = { version = "0.4", default-features = false, features = ["std", "clock"] }
|
chrono = { version = "0.4", default-features = false, features = ["std", "clock"] }
|
||||||
clap = { version = "4", features = ["derive", "env", "unicode", "suggestions", "usage"] }
|
clap = { version = "4", features = ["derive", "env", "unicode", "suggestions", "usage"] }
|
||||||
julid-rs = { path = "../julid" }
|
julid-rs = "1"
|
||||||
justerror = "1"
|
justerror = "1"
|
||||||
password-hash = { version = "0.5", features = ["std", "getrandom"] }
|
password-hash = { version = "0.5", features = ["std", "getrandom"] }
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
|
|
|
@ -1,18 +1,29 @@
|
||||||
use std::{ffi::OsString, time::Duration};
|
use std::{ffi::OsString, time::Duration};
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions};
|
use sqlx::{
|
||||||
|
query_as,
|
||||||
|
sqlite::{SqliteConnectOptions, SqlitePoolOptions},
|
||||||
|
};
|
||||||
use what2watch::{get_db_pool, import_utils::add_omega_watches};
|
use what2watch::{get_db_pool, import_utils::add_omega_watches};
|
||||||
|
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
#[clap(long, short)]
|
#[clap(long, short)]
|
||||||
pub db_path: OsString,
|
pub db_path: OsString,
|
||||||
|
#[clap(
|
||||||
|
long,
|
||||||
|
short,
|
||||||
|
help = "Number of movies to add in the benchmark.",
|
||||||
|
default_value_t = 10_000
|
||||||
|
)]
|
||||||
|
pub number: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
let path = cli.db_path;
|
let path = cli.db_path;
|
||||||
|
let num = cli.number;
|
||||||
|
|
||||||
let opts = SqliteConnectOptions::new().filename(path).read_only(true);
|
let opts = SqliteConnectOptions::new().filename(path).read_only(true);
|
||||||
let movie_db = {
|
let movie_db = {
|
||||||
|
@ -31,26 +42,45 @@ fn main() {
|
||||||
|
|
||||||
let w2w_db = get_db_pool();
|
let w2w_db = get_db_pool();
|
||||||
|
|
||||||
let start = std::time::Instant::now();
|
let dur = {
|
||||||
let rows = {
|
|
||||||
let rt = tokio::runtime::Builder::new_multi_thread()
|
let rt = tokio::runtime::Builder::new_multi_thread()
|
||||||
.enable_all()
|
.enable_all()
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
rt.block_on(async {
|
rt.block_on(async {
|
||||||
add_omega_watches(&w2w_db, &movie_db).await.unwrap();
|
let dur = add_omega_watches(&w2w_db, &movie_db, num).await.unwrap();
|
||||||
|
|
||||||
let rows: i32 = sqlx::query_scalar("select count(*) from watches")
|
|
||||||
.fetch_one(&w2w_db)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
w2w_db.close().await;
|
w2w_db.close().await;
|
||||||
rows
|
dur
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
let end = std::time::Instant::now();
|
let w2w_db = get_db_pool();
|
||||||
let dur = (end - start).as_secs_f32();
|
let movies: Vec<(String, f64, i64)> = {
|
||||||
println!("Added {rows} movies in {dur} seconds");
|
let rt = tokio::runtime::Builder::new_multi_thread()
|
||||||
|
.enable_all()
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
let movies = rt.block_on(
|
||||||
|
query_as(
|
||||||
|
"select julid_string(id), julid_seconds(id) * 1000, julid_counter(id) from watches",
|
||||||
|
)
|
||||||
|
.fetch_all(&w2w_db),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
rt.block_on(w2w_db.close());
|
||||||
|
movies
|
||||||
|
};
|
||||||
|
let rows = movies.len();
|
||||||
|
|
||||||
|
for m in movies.iter() {
|
||||||
|
println!("{}: {}ms, {} count", m.0, m.1, m.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"Added {rows} movies in {} seconds ({}ms, {}us)",
|
||||||
|
dur.as_secs_f64(),
|
||||||
|
dur.as_millis(),
|
||||||
|
dur.as_micros()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
use std::{ffi::OsString, time::Duration};
|
use std::{ffi::OsString, time::Duration};
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
use julid::Julid;
|
||||||
use rand::{seq::SliceRandom, thread_rng, Rng};
|
use rand::{seq::SliceRandom, thread_rng, Rng};
|
||||||
use rand_distr::Normal;
|
use rand_distr::Normal;
|
||||||
use sqlx::{
|
use sqlx::{
|
||||||
|
query_as,
|
||||||
sqlite::{SqliteConnectOptions, SqlitePoolOptions},
|
sqlite::{SqliteConnectOptions, SqlitePoolOptions},
|
||||||
SqlitePool,
|
SqlitePool,
|
||||||
};
|
};
|
||||||
|
@ -12,7 +14,7 @@ use tokio_retry::Retry;
|
||||||
use what2watch::{
|
use what2watch::{
|
||||||
get_db_pool,
|
get_db_pool,
|
||||||
import_utils::{add_omega_watches, add_users, add_watch_quests},
|
import_utils::{add_omega_watches, add_users, add_watch_quests},
|
||||||
DbId, User, WatchQuest,
|
User, Watch, WatchQuest,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -29,7 +31,7 @@ fn main() {
|
||||||
let words = std::fs::read_to_string(dict).expect("tried to open {dict:?}");
|
let words = std::fs::read_to_string(dict).expect("tried to open {dict:?}");
|
||||||
let words: Vec<&str> = words.split('\n').collect();
|
let words: Vec<&str> = words.split('\n').collect();
|
||||||
|
|
||||||
let opts = SqliteConnectOptions::new().filename(&path).read_only(true);
|
let opts = SqliteConnectOptions::new().filename(path).read_only(true);
|
||||||
|
|
||||||
let rt = runtime::Builder::new_multi_thread()
|
let rt = runtime::Builder::new_multi_thread()
|
||||||
.enable_all()
|
.enable_all()
|
||||||
|
@ -47,7 +49,14 @@ fn main() {
|
||||||
|
|
||||||
let users = &rt.block_on(gen_users(num_users, &words, &w2w_db));
|
let users = &rt.block_on(gen_users(num_users, &words, &w2w_db));
|
||||||
|
|
||||||
let movies = &rt.block_on(add_omega_watches(&w2w_db, &movie_db)).unwrap();
|
let _ = &rt
|
||||||
|
.block_on(add_omega_watches(&w2w_db, &movie_db, 10_000))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let movies: Vec<Watch> = rt
|
||||||
|
.block_on(query_as("select * from watches").fetch_all(&w2w_db))
|
||||||
|
.unwrap();
|
||||||
|
let movies: Vec<Julid> = movies.into_iter().map(|m| m.id).collect();
|
||||||
|
|
||||||
let rng = &mut thread_rng();
|
let rng = &mut thread_rng();
|
||||||
|
|
||||||
|
@ -55,7 +64,7 @@ fn main() {
|
||||||
let start = std::time::Instant::now();
|
let start = std::time::Instant::now();
|
||||||
rt.block_on(async {
|
rt.block_on(async {
|
||||||
for &user in users {
|
for &user in users {
|
||||||
add_quests(user, movies, &w2w_db, rng, normal).await;
|
add_quests(user, &movies, &w2w_db, rng, normal).await;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let rows: i32 = rt
|
let rows: i32 = rt
|
||||||
|
@ -70,7 +79,7 @@ fn main() {
|
||||||
//-************************************************************************
|
//-************************************************************************
|
||||||
// add the users
|
// add the users
|
||||||
//-************************************************************************
|
//-************************************************************************
|
||||||
async fn gen_users(num: usize, words: &[&str], pool: &SqlitePool) -> Vec<DbId> {
|
async fn gen_users(num: usize, words: &[&str], pool: &SqlitePool) -> Vec<Julid> {
|
||||||
let mut rng = thread_rng();
|
let mut rng = thread_rng();
|
||||||
let rng = &mut rng;
|
let rng = &mut rng;
|
||||||
let range = 0usize..(words.len());
|
let range = 0usize..(words.len());
|
||||||
|
@ -88,9 +97,9 @@ async fn gen_users(num: usize, words: &[&str], pool: &SqlitePool) -> Vec<DbId> {
|
||||||
let username = format!("{n1}_{n2}{nn}");
|
let username = format!("{n1}_{n2}{nn}");
|
||||||
let displayname = Some(format!("{n1} {n2}"));
|
let displayname = Some(format!("{n1} {n2}"));
|
||||||
let email = Some(format!("{username}@{email_domain}"));
|
let email = Some(format!("{username}@{email_domain}"));
|
||||||
let id = DbId::new();
|
|
||||||
let user = User {
|
let user = User {
|
||||||
id,
|
id: 0.into(),
|
||||||
username,
|
username,
|
||||||
displayname,
|
displayname,
|
||||||
email,
|
email,
|
||||||
|
@ -108,8 +117,8 @@ async fn gen_users(num: usize, words: &[&str], pool: &SqlitePool) -> Vec<DbId> {
|
||||||
// batch add quests
|
// batch add quests
|
||||||
//-************************************************************************
|
//-************************************************************************
|
||||||
async fn add_quests<R: Rng>(
|
async fn add_quests<R: Rng>(
|
||||||
user: DbId,
|
user: Julid,
|
||||||
movies: &[DbId],
|
movies: &[Julid],
|
||||||
w2w_db: &SqlitePool,
|
w2w_db: &SqlitePool,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
normal: Normal<f32>,
|
normal: Normal<f32>,
|
||||||
|
|
|
@ -5,6 +5,7 @@ use axum_login::{
|
||||||
axum_sessions::{PersistencePolicy, SessionLayer},
|
axum_sessions::{PersistencePolicy, SessionLayer},
|
||||||
AuthLayer, SqliteStore, SqlxStore,
|
AuthLayer, SqliteStore, SqlxStore,
|
||||||
};
|
};
|
||||||
|
use julid::Julid;
|
||||||
use session_store::SqliteSessionStore;
|
use session_store::SqliteSessionStore;
|
||||||
use sqlx::{
|
use sqlx::{
|
||||||
migrate::Migrator,
|
migrate::Migrator,
|
||||||
|
@ -12,7 +13,7 @@ use sqlx::{
|
||||||
SqlitePool,
|
SqlitePool,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{DbId, User};
|
use crate::User;
|
||||||
|
|
||||||
const MAX_CONNS: u32 = 200;
|
const MAX_CONNS: u32 = 200;
|
||||||
const MIN_CONNS: u32 = 5;
|
const MIN_CONNS: u32 = 5;
|
||||||
|
@ -111,7 +112,7 @@ pub async fn session_layer(pool: SqlitePool, secret: &[u8]) -> SessionLayer<Sqli
|
||||||
pub async fn auth_layer(
|
pub async fn auth_layer(
|
||||||
pool: SqlitePool,
|
pool: SqlitePool,
|
||||||
secret: &[u8],
|
secret: &[u8],
|
||||||
) -> AuthLayer<SqlxStore<SqlitePool, User>, DbId, User> {
|
) -> AuthLayer<SqlxStore<SqlitePool, User>, Julid, User> {
|
||||||
const QUERY: &str = "select * from users where id = $1";
|
const QUERY: &str = "select * from users where id = $1";
|
||||||
let store = SqliteStore::<User>::new(pool).with_query(QUERY);
|
let store = SqliteStore::<User>::new(pool).with_query(QUERY);
|
||||||
AuthLayer::new(store, secret)
|
AuthLayer::new(store, secret)
|
||||||
|
@ -449,14 +450,14 @@ mod session_store {
|
||||||
let mut session = Session::new();
|
let mut session = Session::new();
|
||||||
session.expire_in(Duration::from_secs(10));
|
session.expire_in(Duration::from_secs(10));
|
||||||
let original_id = session.id().to_owned();
|
let original_id = session.id().to_owned();
|
||||||
let original_expires = session.expiry().unwrap().clone();
|
let original_expires = *session.expiry().unwrap();
|
||||||
|
|
||||||
let cookie_value = store.store_session(session).await?.unwrap();
|
let cookie_value = store.store_session(session).await?.unwrap();
|
||||||
|
|
||||||
let mut session = store.load_session(cookie_value.clone()).await?.unwrap();
|
let mut session = store.load_session(cookie_value.clone()).await?.unwrap();
|
||||||
assert_eq!(session.expiry().unwrap(), &original_expires);
|
assert_eq!(session.expiry().unwrap(), &original_expires);
|
||||||
session.expire_in(Duration::from_secs(20));
|
session.expire_in(Duration::from_secs(20));
|
||||||
let new_expires = session.expiry().unwrap().clone();
|
let new_expires = *session.expiry().unwrap();
|
||||||
store.store_session(session).await?;
|
store.store_session(session).await?;
|
||||||
|
|
||||||
let session = store.load_session(cookie_value.clone()).await?.unwrap();
|
let session = store.load_session(cookie_value.clone()).await?.unwrap();
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
use julid::Julid;
|
||||||
use sqlx::{query_scalar, SqlitePool};
|
use sqlx::{query_scalar, SqlitePool};
|
||||||
|
|
||||||
use crate::{util::year_to_epoch, DbId, ShowKind, User, Watch, WatchQuest};
|
use crate::{util::year_to_epoch, ShowKind, User, Watch, WatchQuest};
|
||||||
|
|
||||||
const USER_EXISTS_QUERY: &str = "select count(*) from users where id = $1";
|
const USER_EXISTS_QUERY: &str = "select count(*) from users where id = $1";
|
||||||
|
|
||||||
const MOVIE_QUERY: &str = "select * from movies order by random() limit 10000";
|
const MOVIE_QUERY: &str = "select * from movies order by random() limit ?";
|
||||||
|
|
||||||
//-************************************************************************
|
//-************************************************************************
|
||||||
// the omega user is the system ID, but has no actual power in the app
|
// the omega user is the system ID, but has no actual power in the app
|
||||||
//-************************************************************************
|
//-************************************************************************
|
||||||
const OMEGA_ID: u128 = u128::MAX;
|
const OMEGA_ID: Julid = Julid::omega();
|
||||||
|
|
||||||
const BULK_INSERT: usize = 2_000;
|
const BULK_INSERT: usize = 2_000;
|
||||||
|
|
||||||
#[derive(Debug, sqlx::FromRow, Clone)]
|
#[derive(Debug, sqlx::FromRow, Clone)]
|
||||||
|
@ -23,13 +25,13 @@ pub struct ImportMovieOmega {
|
||||||
impl From<ImportMovieOmega> for Watch {
|
impl From<ImportMovieOmega> for Watch {
|
||||||
fn from(value: ImportMovieOmega) -> Self {
|
fn from(value: ImportMovieOmega) -> Self {
|
||||||
Watch {
|
Watch {
|
||||||
|
id: Julid::omega(), // this is ignored by the inserter
|
||||||
title: value.title,
|
title: value.title,
|
||||||
release_date: year_to_epoch(value.year.as_deref()),
|
release_date: year_to_epoch(value.year.as_deref()),
|
||||||
length: value.length.and_then(|v| v.parse::<i64>().ok()),
|
length: value.length.and_then(|v| v.parse::<i64>().ok()),
|
||||||
id: DbId::new(),
|
|
||||||
kind: ShowKind::Movie,
|
kind: ShowKind::Movie,
|
||||||
metadata_url: None,
|
metadata_url: None,
|
||||||
added_by: OMEGA_ID.into(),
|
added_by: OMEGA_ID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,13 +39,13 @@ impl From<ImportMovieOmega> for Watch {
|
||||||
impl From<&ImportMovieOmega> for Watch {
|
impl From<&ImportMovieOmega> for Watch {
|
||||||
fn from(value: &ImportMovieOmega) -> Self {
|
fn from(value: &ImportMovieOmega) -> Self {
|
||||||
Watch {
|
Watch {
|
||||||
|
id: Julid::omega(),
|
||||||
title: value.title.to_string(),
|
title: value.title.to_string(),
|
||||||
release_date: year_to_epoch(value.year.as_deref()),
|
release_date: year_to_epoch(value.year.as_deref()),
|
||||||
length: value.length.as_ref().and_then(|v| v.parse::<i64>().ok()),
|
length: value.length.as_ref().and_then(|v| v.parse::<i64>().ok()),
|
||||||
id: DbId::new(),
|
|
||||||
kind: ShowKind::Movie,
|
kind: ShowKind::Movie,
|
||||||
metadata_url: None,
|
metadata_url: None,
|
||||||
added_by: OMEGA_ID.into(),
|
added_by: OMEGA_ID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,78 +70,70 @@ pub async fn add_watch_quests(pool: &SqlitePool, quests: &[WatchQuest]) -> Resul
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn add_users(db_pool: &SqlitePool, users: &[User]) -> Result<(), ()> {
|
pub async fn add_users(db_pool: &SqlitePool, users: &[User]) -> Result<Duration, ()> {
|
||||||
let mut builder =
|
let mut builder =
|
||||||
sqlx::QueryBuilder::new("insert into users (id, username, displayname, email, pwhash) ");
|
sqlx::QueryBuilder::new("insert into users (username, displayname, email, pwhash)");
|
||||||
|
|
||||||
|
let start = Instant::now();
|
||||||
builder.push_values(users.iter(), |mut b, user| {
|
builder.push_values(users.iter(), |mut b, user| {
|
||||||
b.push_bind(user.id)
|
b.push_bind(&user.username)
|
||||||
.push_bind(&user.username)
|
|
||||||
.push_bind(&user.displayname)
|
.push_bind(&user.displayname)
|
||||||
.push_bind(&user.email)
|
.push_bind(&user.email)
|
||||||
.push_bind(&user.pwhash);
|
.push_bind(&user.pwhash);
|
||||||
});
|
});
|
||||||
let q = builder.build();
|
let q = builder.build();
|
||||||
q.execute(db_pool).await.map_err(|_| ())?;
|
q.execute(db_pool).await.map_err(|_| ())?;
|
||||||
Ok(())
|
let end = Instant::now();
|
||||||
|
let dur = end - start;
|
||||||
|
|
||||||
|
Ok(dur)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn add_omega_watches(
|
pub async fn add_omega_watches(
|
||||||
w2w_db: &SqlitePool,
|
w2w_db: &SqlitePool,
|
||||||
movie_db: &SqlitePool,
|
movie_db: &SqlitePool,
|
||||||
) -> Result<Vec<DbId>, ()> {
|
num: u32,
|
||||||
ensure_omega(w2w_db).await;
|
) -> Result<Duration, ()> {
|
||||||
|
let omega = ensure_omega(w2w_db).await;
|
||||||
|
|
||||||
let movies: Vec<ImportMovieOmega> = sqlx::query_as(MOVIE_QUERY)
|
let movies: Vec<ImportMovieOmega> = sqlx::query_as(MOVIE_QUERY)
|
||||||
|
.bind(num)
|
||||||
.fetch_all(movie_db)
|
.fetch_all(movie_db)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut ids = Vec::with_capacity(10_000);
|
let start = Instant::now();
|
||||||
let omega: DbId = OMEGA_ID.into();
|
|
||||||
|
|
||||||
for movies in movies.as_slice().chunks(BULK_INSERT) {
|
for movies in movies.as_slice().chunks(BULK_INSERT) {
|
||||||
let mut builder = sqlx::QueryBuilder::new(
|
let mut builder = sqlx::QueryBuilder::new(
|
||||||
"insert into watches (id, kind, title, length, release_date, added_by) ",
|
"insert into watches (kind, title, length, release_date, added_by) ",
|
||||||
);
|
);
|
||||||
|
|
||||||
builder.push_values(movies, |mut b, movie| {
|
builder.push_values(movies, |mut b, movie| {
|
||||||
let id = DbId::new();
|
|
||||||
ids.push(id);
|
|
||||||
let title = &movie.title;
|
let title = &movie.title;
|
||||||
|
b.push_bind(ShowKind::Movie)
|
||||||
b.push_bind(id)
|
|
||||||
.push_bind(ShowKind::Movie)
|
|
||||||
.push_bind(title)
|
.push_bind(title)
|
||||||
.push_bind(movie.length.as_ref().and_then(|l| l.parse::<i64>().ok()))
|
.push_bind(movie.length.as_ref().and_then(|l| l.parse::<i64>().ok()))
|
||||||
.push_bind(year_to_epoch(movie.year.as_deref()))
|
.push_bind(year_to_epoch(movie.year.as_deref()))
|
||||||
.push_bind(omega);
|
.push_bind(omega);
|
||||||
});
|
});
|
||||||
let q = builder.build();
|
let q = builder.build();
|
||||||
|
|
||||||
q.execute(w2w_db).await.map_err(|_| ())?;
|
q.execute(w2w_db).await.map_err(|_| ())?;
|
||||||
}
|
}
|
||||||
|
let end = Instant::now();
|
||||||
|
let dur = end - start;
|
||||||
|
|
||||||
Ok(ids)
|
Ok(dur)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn ensure_omega(db_pool: &SqlitePool) -> DbId {
|
pub async fn ensure_omega(db_pool: &SqlitePool) -> Julid {
|
||||||
if !check_omega_exists(db_pool).await {
|
if !check_omega_exists(db_pool).await {
|
||||||
let omega = User {
|
sqlx::query("insert into users (id, username, pwhash) values (?, 'the omega user', 'you shall not password')").bind(Julid::omega()).execute(db_pool).await.unwrap();
|
||||||
id: OMEGA_ID.into(),
|
|
||||||
username: "The Omega User".to_string(),
|
|
||||||
displayname: Some("I am the end of all watches".to_string()),
|
|
||||||
email: None,
|
|
||||||
last_seen: None,
|
|
||||||
pwhash: "you shall not password".to_string(),
|
|
||||||
};
|
|
||||||
add_users(db_pool, &[omega]).await.unwrap();
|
|
||||||
}
|
}
|
||||||
OMEGA_ID.into()
|
OMEGA_ID
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn check_omega_exists(db_pool: &SqlitePool) -> bool {
|
async fn check_omega_exists(db_pool: &SqlitePool) -> bool {
|
||||||
let id: DbId = OMEGA_ID.into();
|
let id = Julid::omega();
|
||||||
let count = query_scalar(USER_EXISTS_QUERY)
|
let count = query_scalar(USER_EXISTS_QUERY)
|
||||||
.bind(id)
|
.bind(id)
|
||||||
.fetch_one(db_pool)
|
.fetch_one(db_pool)
|
||||||
|
@ -165,7 +159,8 @@ mod test {
|
||||||
rt.block_on(async {
|
rt.block_on(async {
|
||||||
assert!(!check_omega_exists(&p).await);
|
assert!(!check_omega_exists(&p).await);
|
||||||
ensure_omega(&p).await;
|
ensure_omega(&p).await;
|
||||||
assert!(check_omega_exists(&p).await);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
assert!(rt.block_on(check_omega_exists(&p)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,8 +30,8 @@ use optional_optional_user::OptionalOptionalUser;
|
||||||
use templates::*;
|
use templates::*;
|
||||||
use watches::templates::*;
|
use watches::templates::*;
|
||||||
|
|
||||||
pub type DbId = julid::Julid;
|
type AuthContext =
|
||||||
type AuthContext = axum_login::extractors::AuthContext<DbId, User, axum_login::SqliteStore<User>>;
|
axum_login::extractors::AuthContext<julid::Julid, User, axum_login::SqliteStore<User>>;
|
||||||
|
|
||||||
/// Returns the router to be used as a service or test object, you do you.
|
/// Returns the router to be used as a service or test object, you do you.
|
||||||
pub async fn app(db_pool: sqlx::SqlitePool, secret: &[u8]) -> IntoMakeService<axum::Router> {
|
pub async fn app(db_pool: sqlx::SqlitePool, secret: &[u8]) -> IntoMakeService<axum::Router> {
|
||||||
|
|
10
src/login.rs
10
src/login.rs
|
@ -114,7 +114,8 @@ mod test {
|
||||||
use crate::{
|
use crate::{
|
||||||
get_db_pool,
|
get_db_pool,
|
||||||
templates::{LoginPage, LogoutPage, LogoutSuccessPage, MainPage},
|
templates::{LoginPage, LogoutPage, LogoutSuccessPage, MainPage},
|
||||||
test_utils::{get_test_user, massage, server_with_pool, FORM_CONTENT_TYPE},
|
test_utils::{massage, server_with_pool, FORM_CONTENT_TYPE},
|
||||||
|
User,
|
||||||
};
|
};
|
||||||
|
|
||||||
const LOGIN_FORM: &str = "username=test_user&password=a";
|
const LOGIN_FORM: &str = "username=test_user&password=a";
|
||||||
|
@ -257,10 +258,9 @@ mod test {
|
||||||
.await;
|
.await;
|
||||||
assert_eq!(resp.status_code(), 303);
|
assert_eq!(resp.status_code(), 303);
|
||||||
|
|
||||||
let logged_in = MainPage {
|
let user = User::try_get("test_user", &db).await.unwrap();
|
||||||
user: Some(get_test_user()),
|
|
||||||
}
|
let logged_in = MainPage { user: Some(user) }.to_string();
|
||||||
.to_string();
|
|
||||||
|
|
||||||
let main_page = s.get("/").await;
|
let main_page = s.get("/").await;
|
||||||
let body = std::str::from_utf8(main_page.bytes()).unwrap();
|
let body = std::str::from_utf8(main_page.bytes()).unwrap();
|
||||||
|
|
|
@ -7,14 +7,15 @@ use axum::{
|
||||||
http::StatusCode,
|
http::StatusCode,
|
||||||
response::{IntoResponse, Response},
|
response::{IntoResponse, Response},
|
||||||
};
|
};
|
||||||
|
use julid::Julid;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use sqlx::{query_as, SqlitePool};
|
use sqlx::{query_as, SqlitePool};
|
||||||
use unicode_segmentation::UnicodeSegmentation;
|
use unicode_segmentation::UnicodeSegmentation;
|
||||||
|
|
||||||
use crate::{util::empty_string_as_none, DbId, SignupPage, SignupSuccessPage, User};
|
use crate::{util::empty_string_as_none, SignupPage, SignupSuccessPage, User};
|
||||||
|
|
||||||
pub(crate) const CREATE_QUERY: &str =
|
pub(crate) const CREATE_QUERY: &str =
|
||||||
"insert into users (id, username, displayname, email, pwhash) values ($1, $2, $3, $4, $5)";
|
"insert into users (username, displayname, email, pwhash) values ($1, $2, $3, $4) returning *";
|
||||||
const ID_QUERY: &str = "select * from users where id = $1";
|
const ID_QUERY: &str = "select * from users where id = $1";
|
||||||
|
|
||||||
//-************************************************************************
|
//-************************************************************************
|
||||||
|
@ -107,11 +108,9 @@ pub async fn post_create_user(
|
||||||
|
|
||||||
let email = validate_optional_length(&signup.email, 5..30, CreateUserErrorKind::BadEmail)?;
|
let email = validate_optional_length(&signup.email, 5..30, CreateUserErrorKind::BadEmail)?;
|
||||||
|
|
||||||
let id = DbId::new();
|
let user = create_user(username, &displayname, &email, password, &pool).await?;
|
||||||
|
|
||||||
let user = create_user(username, &displayname, &email, password, &pool, id).await?;
|
tracing::debug!("created {user:?}");
|
||||||
let now = user.id.timestamp();
|
|
||||||
tracing::debug!("created {user:?} at {now:?}");
|
|
||||||
let id = user.id.as_string();
|
let id = user.id.as_string();
|
||||||
let location = format!("/signup_success/{id}");
|
let location = format!("/signup_success/{id}");
|
||||||
|
|
||||||
|
@ -126,7 +125,7 @@ pub async fn get_signup_success(
|
||||||
State(pool): State<SqlitePool>,
|
State(pool): State<SqlitePool>,
|
||||||
) -> Response {
|
) -> Response {
|
||||||
let id = id.trim();
|
let id = id.trim();
|
||||||
let id = DbId::from_string(id).unwrap_or_default();
|
let id = Julid::from_string(id).unwrap_or_default();
|
||||||
let user: User = {
|
let user: User = {
|
||||||
query_as(ID_QUERY)
|
query_as(ID_QUERY)
|
||||||
.bind(id)
|
.bind(id)
|
||||||
|
@ -156,7 +155,6 @@ pub(crate) async fn create_user(
|
||||||
email: &Option<String>,
|
email: &Option<String>,
|
||||||
password: &[u8],
|
password: &[u8],
|
||||||
pool: &SqlitePool,
|
pool: &SqlitePool,
|
||||||
id: DbId,
|
|
||||||
) -> Result<User, CreateUserError> {
|
) -> Result<User, CreateUserError> {
|
||||||
// Argon2 with default params (Argon2id v19)
|
// Argon2 with default params (Argon2id v19)
|
||||||
let argon2 = Argon2::default();
|
let argon2 = Argon2::default();
|
||||||
|
@ -166,27 +164,16 @@ pub(crate) async fn create_user(
|
||||||
.unwrap() // safe to unwrap, we know the salt is valid
|
.unwrap() // safe to unwrap, we know the salt is valid
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
let query = sqlx::query(CREATE_QUERY)
|
let res = sqlx::query_as(CREATE_QUERY)
|
||||||
.bind(id)
|
|
||||||
.bind(username)
|
.bind(username)
|
||||||
.bind(displayname)
|
.bind(displayname)
|
||||||
.bind(email)
|
.bind(email)
|
||||||
.bind(&pwhash);
|
.bind(&pwhash)
|
||||||
|
.fetch_one(pool)
|
||||||
let res = query.execute(pool).await;
|
.await;
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
Ok(_) => {
|
Ok(user) => Ok(user),
|
||||||
let user = User {
|
|
||||||
id,
|
|
||||||
username: username.to_string(),
|
|
||||||
displayname: displayname.to_owned(),
|
|
||||||
email: email.to_owned(),
|
|
||||||
last_seen: None,
|
|
||||||
pwhash,
|
|
||||||
};
|
|
||||||
Ok(user)
|
|
||||||
}
|
|
||||||
Err(sqlx::Error::Database(db)) => {
|
Err(sqlx::Error::Database(db)) => {
|
||||||
if let Some(exit) = db.code() {
|
if let Some(exit) = db.code() {
|
||||||
let exit = exit.parse().unwrap_or(0u32);
|
let exit = exit.parse().unwrap_or(0u32);
|
||||||
|
@ -216,11 +203,11 @@ mod test {
|
||||||
use crate::{
|
use crate::{
|
||||||
db::get_db_pool,
|
db::get_db_pool,
|
||||||
templates::{SignupPage, SignupSuccessPage},
|
templates::{SignupPage, SignupSuccessPage},
|
||||||
test_utils::{get_test_user, massage, server_with_pool, FORM_CONTENT_TYPE},
|
test_utils::{massage, server_with_pool, FORM_CONTENT_TYPE},
|
||||||
User,
|
User,
|
||||||
};
|
};
|
||||||
|
|
||||||
const GOOD_FORM: &str = "username=good_user&displayname=Test+User&password=aaaa&pw_verify=aaaa";
|
const GOOD_FORM: &str = "username=good_user&displayname=Good+User&password=aaaa&pw_verify=aaaa";
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn post_create_user() {
|
fn post_create_user() {
|
||||||
|
@ -265,10 +252,20 @@ mod test {
|
||||||
let rt = Runtime::new().unwrap();
|
let rt = Runtime::new().unwrap();
|
||||||
rt.block_on(async {
|
rt.block_on(async {
|
||||||
let server = server_with_pool(&pool).await;
|
let server = server_with_pool(&pool).await;
|
||||||
|
let body = massage(GOOD_FORM);
|
||||||
|
|
||||||
let user = get_test_user();
|
let resp = server
|
||||||
let id = user.id.to_string();
|
.post("/signup")
|
||||||
dbg!(&id);
|
.expect_failure() // 303 is "failure"
|
||||||
|
.bytes(body)
|
||||||
|
.content_type(FORM_CONTENT_TYPE)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert_eq!(StatusCode::SEE_OTHER, resp.status_code());
|
||||||
|
|
||||||
|
// get the new user from the db
|
||||||
|
let user = User::try_get("good_user", &pool).await.unwrap();
|
||||||
|
let id = user.id;
|
||||||
|
|
||||||
let path = format!("/signup_success/{id}");
|
let path = format!("/signup_success/{id}");
|
||||||
|
|
||||||
|
@ -288,15 +285,15 @@ mod test {
|
||||||
|
|
||||||
// various ways to fuck up signup
|
// various ways to fuck up signup
|
||||||
const PASSWORD_MISMATCH_FORM: &str =
|
const PASSWORD_MISMATCH_FORM: &str =
|
||||||
"username=bad_user&displayname=Test+User&password=aaaa&pw_verify=bbbb";
|
"username=bad_user&displayname=Bad+User&password=aaaa&pw_verify=bbbb";
|
||||||
const PASSWORD_SHORT_FORM: &str =
|
const PASSWORD_SHORT_FORM: &str =
|
||||||
"username=bad_user&displayname=Test+User&password=a&pw_verify=a";
|
"username=bad_user&displayname=Bad+User&password=a&pw_verify=a";
|
||||||
const PASSWORD_LONG_FORM: &str = "username=bad_user&displayname=Test+User&password=sphinx+of+black+qwartz+judge+my+vow+etc+etc+yadd+yadda&pw_verify=sphinx+of+black+qwartz+judge+my+vow+etc+etc+yadd+yadda";
|
const PASSWORD_LONG_FORM: &str = "username=bad_user&displayname=Bad+User&password=sphinx+of+black+qwartz+judge+my+vow+etc+etc+yadd+yadda&pw_verify=sphinx+of+black+qwartz+judge+my+vow+etc+etc+yadd+yadda";
|
||||||
const USERNAME_SHORT_FORM: &str =
|
const USERNAME_SHORT_FORM: &str =
|
||||||
"username=&displayname=Test+User&password=aaaa&pw_verify=aaaa";
|
"username=&displayname=Bad+User&password=aaaa&pw_verify=aaaa";
|
||||||
const USERNAME_LONG_FORM: &str =
|
const USERNAME_LONG_FORM: &str =
|
||||||
"username=bad_user12345678901234567890&displayname=Test+User&password=aaaa&pw_verify=aaaa";
|
"username=bad_user12345678901234567890&displayname=Bad+User&password=aaaa&pw_verify=aaaa";
|
||||||
const DISPLAYNAME_LONG_FORM: &str = "username=test_user&displayname=Since+time+immemorial%2C+display+names+have+been+subject+to+a+number+of+conventions%2C+restrictions%2C+usages%2C+and+even+incentives.+Have+we+finally+gone+too+far%3F+In+this+essay%2C+&password=aaaa&pw_verify=aaaa";
|
const DISPLAYNAME_LONG_FORM: &str = "username=bad_user&displayname=Since+time+immemorial%2C+display+names+have+been+subject+to+a+number+of+conventions%2C+restrictions%2C+usages%2C+and+even+incentives.+Have+we+finally+gone+too+far%3F+In+this+essay%2C+&password=aaaa&pw_verify=aaaa";
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn password_mismatch() {
|
fn password_mismatch() {
|
||||||
|
|
|
@ -1,28 +1,18 @@
|
||||||
use axum::body::Bytes;
|
use axum::body::Bytes;
|
||||||
use axum_test::{TestServer, TestServerConfig};
|
use axum_test::{TestServer, TestServerConfig};
|
||||||
|
use julid::Julid;
|
||||||
use sqlx::SqlitePool;
|
use sqlx::SqlitePool;
|
||||||
|
|
||||||
use crate::{DbId, User};
|
use crate::User;
|
||||||
|
|
||||||
pub const FORM_CONTENT_TYPE: &str = "application/x-www-form-urlencoded";
|
pub const FORM_CONTENT_TYPE: &str = "application/x-www-form-urlencoded";
|
||||||
|
|
||||||
pub fn get_test_user() -> User {
|
|
||||||
User {
|
|
||||||
username: "test_user".to_string(),
|
|
||||||
// corresponding to a password of "a":
|
|
||||||
pwhash: "$argon2id$v=19$m=19456,t=2,p=1$GWsCH1w5RYaP9WWmq+xw0g$hmOEqC+MU+vnEk3bOdkoE+z01mOmmOeX08XyPyjqua8".to_string(),
|
|
||||||
id: DbId::from_string("00041061050R3GG28A1C60T3GF").unwrap(),
|
|
||||||
displayname: Some("Test User".to_string()),
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn server_with_pool(pool: &SqlitePool) -> TestServer {
|
pub async fn server_with_pool(pool: &SqlitePool) -> TestServer {
|
||||||
let secret = [0u8; 64];
|
let secret = [0u8; 64];
|
||||||
|
|
||||||
let user = get_test_user();
|
let user = get_test_user();
|
||||||
|
|
||||||
insert_user(&user, pool).await;
|
insert_user_with_id(&user, pool).await;
|
||||||
let r: i32 = sqlx::query_scalar("select count(*) from users")
|
let r: i32 = sqlx::query_scalar("select count(*) from users")
|
||||||
.fetch_one(pool)
|
.fetch_one(pool)
|
||||||
.await
|
.await
|
||||||
|
@ -38,8 +28,21 @@ pub async fn server_with_pool(pool: &SqlitePool) -> TestServer {
|
||||||
TestServer::new_with_config(app, config).unwrap()
|
TestServer::new_with_config(app, config).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn insert_user(user: &User, pool: &SqlitePool) {
|
fn get_test_user() -> User {
|
||||||
sqlx::query(crate::signup::CREATE_QUERY)
|
User {
|
||||||
|
username: "test_user".to_string(),
|
||||||
|
// corresponding to a password of "a":
|
||||||
|
pwhash: "$argon2id$v=19$m=19456,t=2,p=1$GWsCH1w5RYaP9WWmq+xw0g$hmOEqC+MU+vnEk3bOdkoE+z01mOmmOeX08XyPyjqua8".to_string(),
|
||||||
|
id: Julid::omega(),
|
||||||
|
displayname: Some("Test User".to_string()),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn insert_user_with_id(user: &User, pool: &SqlitePool) {
|
||||||
|
sqlx::query(
|
||||||
|
"insert into users (id, username, displayname, email, pwhash) values ($1, $2, $3, $4, $5)",
|
||||||
|
)
|
||||||
.bind(user.id)
|
.bind(user.id)
|
||||||
.bind(&user.username)
|
.bind(&user.username)
|
||||||
.bind(&user.displayname)
|
.bind(&user.displayname)
|
||||||
|
|
11
src/users.rs
11
src/users.rs
|
@ -5,17 +5,18 @@ use std::{
|
||||||
|
|
||||||
use axum::{extract::State, http::Request, middleware::Next, response::IntoResponse};
|
use axum::{extract::State, http::Request, middleware::Next, response::IntoResponse};
|
||||||
use axum_login::{secrecy::SecretVec, AuthUser};
|
use axum_login::{secrecy::SecretVec, AuthUser};
|
||||||
|
use julid::Julid;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::SqlitePool;
|
use sqlx::SqlitePool;
|
||||||
|
|
||||||
use crate::{AuthContext, DbId};
|
use crate::AuthContext;
|
||||||
|
|
||||||
const USERNAME_QUERY: &str = "select * from users where username = $1";
|
const USERNAME_QUERY: &str = "select * from users where username = $1";
|
||||||
const LAST_SEEN_QUERY: &str = "update users set last_seen = (select unixepoch()) where id = $1";
|
const LAST_SEEN_QUERY: &str = "update users set last_seen = (select unixepoch()) where id = $1";
|
||||||
|
|
||||||
#[derive(Default, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)]
|
#[derive(Default, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
pub id: DbId,
|
pub id: Julid,
|
||||||
pub username: String,
|
pub username: String,
|
||||||
pub displayname: Option<String>,
|
pub displayname: Option<String>,
|
||||||
pub email: Option<String>,
|
pub email: Option<String>,
|
||||||
|
@ -49,8 +50,8 @@ impl Display for User {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AuthUser<DbId> for User {
|
impl AuthUser<Julid> for User {
|
||||||
fn get_id(&self) -> DbId {
|
fn get_id(&self) -> Julid {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +76,7 @@ impl User {
|
||||||
{
|
{
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let id = self.id.0.to_string();
|
let id = self.id.to_string();
|
||||||
tracing::error!("Could not update last_seen for user {id}; got {e:?}");
|
tracing::error!("Could not update last_seen for user {id}; got {e:?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,14 @@ use axum::{
|
||||||
http::StatusCode,
|
http::StatusCode,
|
||||||
response::{IntoResponse, Redirect, Response},
|
response::{IntoResponse, Redirect, Response},
|
||||||
};
|
};
|
||||||
|
use julid::Julid;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use sqlx::{query, query_as, SqlitePool};
|
use sqlx::{query, query_as, query_scalar, SqlitePool};
|
||||||
|
|
||||||
use super::templates::{AddNewWatchPage, GetWatchPage, SearchWatchesPage};
|
use super::templates::{AddNewWatchPage, GetWatchPage, SearchWatchesPage};
|
||||||
use crate::{
|
use crate::{
|
||||||
util::{empty_string_as_none, year_to_epoch},
|
util::{empty_string_as_none, year_to_epoch},
|
||||||
AuthContext, DbId, MyWatchesPage, ShowKind, Watch, WatchQuest,
|
AuthContext, MyWatchesPage, ShowKind, Watch, WatchQuest,
|
||||||
};
|
};
|
||||||
|
|
||||||
//-************************************************************************
|
//-************************************************************************
|
||||||
|
@ -21,7 +22,7 @@ const GET_SAVED_WATCHES_QUERY: &str =
|
||||||
|
|
||||||
const GET_WATCH_QUERY: &str = "select * from watches where id = $1";
|
const GET_WATCH_QUERY: &str = "select * from watches where id = $1";
|
||||||
|
|
||||||
const ADD_WATCH_QUERY: &str = "insert into watches (id, title, kind, release_date, metadata_url, added_by) values ($1, $2, $3, $4, $5, $6)";
|
const ADD_WATCH_QUERY: &str = "insert into watches (title, kind, release_date, metadata_url, added_by, length) values ($1, $2, $3, $4, $5, $6) returning id";
|
||||||
const ADD_WATCH_QUEST_QUERY: &str =
|
const ADD_WATCH_QUEST_QUERY: &str =
|
||||||
"insert into watch_quests (user, watch, public, watched) values ($1, $2, $3, $4)";
|
"insert into watch_quests (user, watch, public, watched) values ($1, $2, $3, $4)";
|
||||||
|
|
||||||
|
@ -109,6 +110,12 @@ pub async fn get_add_new_watch(auth: AuthContext) -> impl IntoResponse {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct QuestQuest {
|
||||||
|
pub user: Julid,
|
||||||
|
pub is_public: bool,
|
||||||
|
pub already_watched: bool,
|
||||||
|
}
|
||||||
|
|
||||||
/// Add a Watch to your watchlist (side effects system-add)
|
/// Add a Watch to your watchlist (side effects system-add)
|
||||||
pub async fn post_add_new_watch(
|
pub async fn post_add_new_watch(
|
||||||
auth: AuthContext,
|
auth: AuthContext,
|
||||||
|
@ -117,25 +124,22 @@ pub async fn post_add_new_watch(
|
||||||
) -> Result<impl IntoResponse, WatchAddError> {
|
) -> Result<impl IntoResponse, WatchAddError> {
|
||||||
if let Some(user) = auth.current_user {
|
if let Some(user) = auth.current_user {
|
||||||
{
|
{
|
||||||
let watch_id = DbId::new();
|
|
||||||
let release_date = year_to_epoch(form.year.as_deref());
|
let release_date = year_to_epoch(form.year.as_deref());
|
||||||
let watch = Watch {
|
let watch = Watch {
|
||||||
id: watch_id,
|
|
||||||
title: form.title,
|
title: form.title,
|
||||||
kind: form.kind,
|
kind: form.kind,
|
||||||
metadata_url: form.metadata_url,
|
metadata_url: form.metadata_url,
|
||||||
length: None,
|
|
||||||
release_date,
|
release_date,
|
||||||
added_by: user.id,
|
added_by: user.id,
|
||||||
|
..Default::default()
|
||||||
};
|
};
|
||||||
let quest = WatchQuest {
|
let quest = QuestQuest {
|
||||||
user: user.id,
|
user: user.id,
|
||||||
watch: watch_id,
|
|
||||||
is_public: !form.private,
|
is_public: !form.private,
|
||||||
already_watched: form.watched_already,
|
already_watched: form.watched_already,
|
||||||
};
|
};
|
||||||
|
|
||||||
add_new_watch_impl(&pool, &watch, Some(quest)).await?;
|
let watch_id = add_new_watch_impl(&pool, &watch, Some(quest)).await?;
|
||||||
|
|
||||||
let location = format!("/watch/{watch_id}");
|
let location = format!("/watch/{watch_id}");
|
||||||
Ok(Redirect::to(&location))
|
Ok(Redirect::to(&location))
|
||||||
|
@ -145,23 +149,23 @@ pub async fn post_add_new_watch(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn add_new_watch_impl(
|
async fn add_new_watch_impl(
|
||||||
db_pool: &SqlitePool,
|
db_pool: &SqlitePool,
|
||||||
watch: &Watch,
|
watch: &Watch,
|
||||||
quest: Option<WatchQuest>,
|
quest: Option<QuestQuest>,
|
||||||
) -> Result<(), WatchAddError> {
|
) -> Result<Julid, WatchAddError> {
|
||||||
let mut tx = db_pool
|
let mut tx = db_pool
|
||||||
.begin()
|
.begin()
|
||||||
.await
|
.await
|
||||||
.map_err(|_| WatchAddErrorKind::UnknownDBError)?;
|
.map_err(|_| WatchAddErrorKind::UnknownDBError)?;
|
||||||
query(ADD_WATCH_QUERY)
|
let watch_id: Julid = query_scalar(ADD_WATCH_QUERY)
|
||||||
.bind(watch.id)
|
|
||||||
.bind(&watch.title)
|
.bind(&watch.title)
|
||||||
.bind(watch.kind)
|
.bind(watch.kind)
|
||||||
.bind(watch.release_date)
|
.bind(watch.release_date)
|
||||||
.bind(&watch.metadata_url)
|
.bind(&watch.metadata_url)
|
||||||
.bind(watch.added_by)
|
.bind(watch.added_by)
|
||||||
.execute(&mut *tx)
|
.bind(watch.length)
|
||||||
|
.fetch_one(&mut *tx)
|
||||||
.await
|
.await
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
tracing::error!("Got error: {err}");
|
tracing::error!("Got error: {err}");
|
||||||
|
@ -171,7 +175,7 @@ pub(crate) async fn add_new_watch_impl(
|
||||||
if let Some(quest) = quest {
|
if let Some(quest) = quest {
|
||||||
query(ADD_WATCH_QUEST_QUERY)
|
query(ADD_WATCH_QUEST_QUERY)
|
||||||
.bind(quest.user)
|
.bind(quest.user)
|
||||||
.bind(quest.watch)
|
.bind(watch_id)
|
||||||
.bind(quest.is_public)
|
.bind(quest.is_public)
|
||||||
.bind(quest.already_watched)
|
.bind(quest.already_watched)
|
||||||
.execute(&mut *tx)
|
.execute(&mut *tx)
|
||||||
|
@ -186,7 +190,7 @@ pub(crate) async fn add_new_watch_impl(
|
||||||
WatchAddErrorKind::UnknownDBError
|
WatchAddErrorKind::UnknownDBError
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(())
|
Ok(watch_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a Watch to your watchlist by selecting it with a checkbox
|
/// Add a Watch to your watchlist by selecting it with a checkbox
|
||||||
|
@ -224,7 +228,7 @@ pub async fn get_watch(
|
||||||
"".to_string()
|
"".to_string()
|
||||||
};
|
};
|
||||||
let id = id.trim();
|
let id = id.trim();
|
||||||
let id = DbId::from_string(id).unwrap_or_default();
|
let id = Julid::from_string(id).unwrap_or_default();
|
||||||
let q = query_as(GET_WATCH_QUERY).bind(id);
|
let q = query_as(GET_WATCH_QUERY).bind(id);
|
||||||
let watch: Option<Watch> = q.fetch_one(&pool).await.ok();
|
let watch: Option<Watch> = q.fetch_one(&pool).await.ok();
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
|
use julid::Julid;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::DbId;
|
|
||||||
|
|
||||||
pub mod handlers;
|
pub mod handlers;
|
||||||
pub mod templates;
|
pub mod templates;
|
||||||
|
|
||||||
|
@ -69,13 +68,13 @@ impl From<i64> for ShowKind {
|
||||||
sqlx::FromRow,
|
sqlx::FromRow,
|
||||||
)]
|
)]
|
||||||
pub struct Watch {
|
pub struct Watch {
|
||||||
pub id: DbId,
|
pub id: Julid,
|
||||||
pub title: String,
|
pub title: String,
|
||||||
pub kind: ShowKind,
|
pub kind: ShowKind,
|
||||||
pub metadata_url: Option<String>,
|
pub metadata_url: Option<String>,
|
||||||
pub length: Option<i64>,
|
pub length: Option<i64>,
|
||||||
pub release_date: Option<i64>,
|
pub release_date: Option<i64>,
|
||||||
pub added_by: DbId, // this shouldn't be exposed to randos in the application
|
pub added_by: Julid, // this shouldn't be exposed to randos in the application
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Watch {
|
impl Watch {
|
||||||
|
@ -95,14 +94,14 @@ impl Watch {
|
||||||
//-************************************************************************
|
//-************************************************************************
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct WatchQuest {
|
pub struct WatchQuest {
|
||||||
pub user: DbId,
|
pub user: Julid,
|
||||||
pub watch: DbId,
|
pub watch: Julid,
|
||||||
pub is_public: bool,
|
pub is_public: bool,
|
||||||
pub already_watched: bool,
|
pub already_watched: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WatchQuest {
|
impl WatchQuest {
|
||||||
pub fn id(&self) -> (DbId, DbId) {
|
pub fn id(&self) -> (Julid, Julid) {
|
||||||
(self.user, self.watch)
|
(self.user, self.watch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue