Compare commits
10 commits
714274659e
...
97623afd8d
Author | SHA1 | Date | |
---|---|---|---|
|
97623afd8d | ||
|
4d8706d6bf | ||
|
0e170c0428 | ||
|
a45ca8d3a5 | ||
|
4e2e8e585f | ||
|
ba1f9119e8 | ||
|
9179395aee | ||
|
def08b69b8 | ||
|
a7104e54aa | ||
|
51427ecdb5 |
38 changed files with 280 additions and 307 deletions
247
Cargo.lock
generated
247
Cargo.lock
generated
|
@ -32,9 +32,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
|
||||
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
@ -163,7 +163,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"syn 2.0.52",
|
||||
"syn 2.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -183,13 +183,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.77"
|
||||
version = "0.1.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9"
|
||||
checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.52",
|
||||
"syn 2.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -209,15 +209,15 @@ checksum = "3c1e7e457ea78e524f48639f551fd79703ac3f2237f5ecccdf4708f8a75ad373"
|
|||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
|
||||
|
||||
[[package]]
|
||||
name = "axum"
|
||||
version = "0.7.4"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1236b4b292f6c4d6dc34604bb5120d85c3fe1d1aa596bd5cc52ca054d13e7b9e"
|
||||
checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum-core",
|
||||
|
@ -240,7 +240,7 @@ dependencies = [
|
|||
"serde_json",
|
||||
"serde_path_to_error",
|
||||
"serde_urlencoded",
|
||||
"sync_wrapper",
|
||||
"sync_wrapper 1.0.1",
|
||||
"tokio",
|
||||
"tower",
|
||||
"tower-layer",
|
||||
|
@ -263,7 +263,7 @@ dependencies = [
|
|||
"mime",
|
||||
"pin-project-lite",
|
||||
"rustversion",
|
||||
"sync_wrapper",
|
||||
"sync_wrapper 0.1.2",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
|
@ -295,17 +295,17 @@ version = "0.4.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00c055ee2d014ae5981ce1016374e8213682aa14d9bf40e48ab48b5f3ef20eaa"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"heck 0.4.1",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.52",
|
||||
"syn 2.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum-test"
|
||||
version = "14.4.0"
|
||||
version = "14.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "673f937bbc7eaadff359e2797c0de2c20e02c9db5bd6f2aed457c7ae93559b9b"
|
||||
checksum = "db705caa0b050aa7247c4748293b09e4cddaf7a3c4a87faf145859c11ce501e3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
|
@ -332,9 +332,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.69"
|
||||
version = "0.3.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
|
||||
checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
|
@ -380,9 +380,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.4.2"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
|
||||
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
@ -407,9 +407,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.15.4"
|
||||
version = "3.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa"
|
||||
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
|
@ -419,15 +419,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
|||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.5.0"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
|
||||
checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.90"
|
||||
version = "1.0.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5"
|
||||
checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
|
@ -444,15 +444,16 @@ dependencies = [
|
|||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"time 0.1.45",
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.2"
|
||||
version = "4.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b230ab84b0ffdf890d5a10abdbc8b83ae1c4918275daea1ab8801f71536b2651"
|
||||
checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
|
@ -474,14 +475,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.0"
|
||||
version = "4.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47"
|
||||
checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.52",
|
||||
"syn 2.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -516,9 +517,9 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
|
|||
|
||||
[[package]]
|
||||
name = "cookie"
|
||||
version = "0.18.0"
|
||||
version = "0.18.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3cd91cf61412820176e137621345ee43b3f4423e589e7ae4e50d601d93e35ef8"
|
||||
checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
"time 0.3.34",
|
||||
|
@ -542,9 +543,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "crc"
|
||||
version = "3.0.1"
|
||||
version = "3.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe"
|
||||
checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636"
|
||||
dependencies = [
|
||||
"crc-catalog",
|
||||
]
|
||||
|
@ -582,9 +583,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "der"
|
||||
version = "0.7.8"
|
||||
version = "0.7.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c"
|
||||
checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0"
|
||||
dependencies = [
|
||||
"const-oid",
|
||||
"pem-rfc7468",
|
||||
|
@ -699,9 +700,9 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
|||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.0.1"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
|
||||
checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984"
|
||||
|
||||
[[package]]
|
||||
name = "finl_unicode"
|
||||
|
@ -801,7 +802,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.52",
|
||||
"syn 2.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -845,9 +846,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.12"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
|
||||
checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
|
@ -862,25 +863,6 @@ version = "0.28.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31d030e59af851932b72ceebadf4a2b5986dba4c3b99dd2493f8273a0f151943"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
"indexmap",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.3"
|
||||
|
@ -909,6 +891,12 @@ dependencies = [
|
|||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.9"
|
||||
|
@ -1029,7 +1017,6 @@ dependencies = [
|
|||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"http 1.1.0",
|
||||
"http-body",
|
||||
"httparse",
|
||||
|
@ -1096,9 +1083,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.2.5"
|
||||
version = "2.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4"
|
||||
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
|
@ -1115,9 +1102,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.10"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
|
||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
|
@ -1130,9 +1117,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "julid-rs"
|
||||
version = "1.6.1803398"
|
||||
version = "1.6.18033988"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "98270c2a07b60873e7b164cebea22f83bbe42632c9774c5360e0f7ef0a63986d"
|
||||
checksum = "82f75e4d7184b798c5b8e3b9ead1a3d1ea121091a84089bb39138e6a5500ca61"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
|
@ -1175,13 +1162,12 @@ checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
|
|||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
version = "0.0.1"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8"
|
||||
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
|
||||
dependencies = [
|
||||
"bitflags 2.4.2",
|
||||
"bitflags 2.5.0",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1245,9 +1231,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.1"
|
||||
version = "2.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
|
||||
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
|
@ -1447,7 +1433,7 @@ name = "optional_optional_user"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.52",
|
||||
"syn 2.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1551,14 +1537,14 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.52",
|
||||
"syn 2.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.13"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
|
||||
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
|
@ -1674,9 +1660,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.4.4"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4"
|
||||
checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"libredox",
|
||||
|
@ -1685,14 +1671,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.3"
|
||||
version = "1.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15"
|
||||
checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata 0.4.6",
|
||||
"regex-syntax 0.8.2",
|
||||
"regex-syntax 0.8.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1712,7 +1698,7 @@ checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
|
|||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax 0.8.2",
|
||||
"regex-syntax 0.8.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1723,9 +1709,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
|
|||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.2"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||
checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
|
||||
|
||||
[[package]]
|
||||
name = "reserve-port"
|
||||
|
@ -1818,11 +1804,11 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
|||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.31"
|
||||
version = "0.38.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949"
|
||||
checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89"
|
||||
dependencies = [
|
||||
"bitflags 2.4.2",
|
||||
"bitflags 2.5.0",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
|
@ -1831,9 +1817,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.14"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
|
||||
checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
|
@ -1864,14 +1850,14 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.52",
|
||||
"syn 2.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.114"
|
||||
version = "1.0.115"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0"
|
||||
checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
|
@ -1982,9 +1968,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.13.1"
|
||||
version = "1.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
|
||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
|
@ -2055,6 +2041,7 @@ dependencies = [
|
|||
"atoi",
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"chrono",
|
||||
"crc",
|
||||
"crossbeam-queue",
|
||||
"either",
|
||||
|
@ -2106,7 +2093,7 @@ checksum = "5833ef53aaa16d860e92123292f1f6a3d53c34ba8b1969f152ef1a7bb803f3c8"
|
|||
dependencies = [
|
||||
"dotenvy",
|
||||
"either",
|
||||
"heck",
|
||||
"heck 0.4.1",
|
||||
"hex",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
|
@ -2132,9 +2119,10 @@ checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418"
|
|||
dependencies = [
|
||||
"atoi",
|
||||
"base64 0.21.7",
|
||||
"bitflags 2.4.2",
|
||||
"bitflags 2.5.0",
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"chrono",
|
||||
"crc",
|
||||
"digest",
|
||||
"dotenvy",
|
||||
|
@ -2175,8 +2163,9 @@ checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e"
|
|||
dependencies = [
|
||||
"atoi",
|
||||
"base64 0.21.7",
|
||||
"bitflags 2.4.2",
|
||||
"bitflags 2.5.0",
|
||||
"byteorder",
|
||||
"chrono",
|
||||
"crc",
|
||||
"dotenvy",
|
||||
"etcetera",
|
||||
|
@ -2213,6 +2202,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "b244ef0a8414da0bed4bb1910426e890b19e5e9bccc27ada6b797d05c55ae0aa"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"chrono",
|
||||
"flume",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
|
@ -2243,9 +2233,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.0"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
|
@ -2266,9 +2256,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.52"
|
||||
version = "2.0.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07"
|
||||
checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -2281,6 +2271,12 @@ version = "0.1.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
|
||||
|
||||
[[package]]
|
||||
name = "sync_wrapper"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.10.1"
|
||||
|
@ -2310,7 +2306,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.52",
|
||||
"syn 2.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2382,9 +2378,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
|||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.36.0"
|
||||
version = "1.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931"
|
||||
checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
|
@ -2407,14 +2403,14 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.52",
|
||||
"syn 2.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-stream"
|
||||
version = "0.1.14"
|
||||
version = "0.1.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842"
|
||||
checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
|
@ -2432,14 +2428,13 @@ dependencies = [
|
|||
"futures-sink",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.8.11"
|
||||
version = "0.8.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af06656561d28735e9c1cd63dfd57132c8155426aa6af24f36a00a351f88c48e"
|
||||
checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
|
@ -2458,9 +2453,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.22.7"
|
||||
version = "0.22.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18769cd1cec395d70860ceb4d932812a0b4d06b1a4bb336745a4d21b9496e992"
|
||||
checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
|
@ -2508,7 +2503,7 @@ version = "0.5.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5"
|
||||
dependencies = [
|
||||
"bitflags 2.4.2",
|
||||
"bitflags 2.5.0",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
|
@ -2541,9 +2536,9 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
|
|||
|
||||
[[package]]
|
||||
name = "tower-sessions"
|
||||
version = "0.11.0"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "989b4d77286a7fb96b094b9e62c4524cebe7bb720769b41588ebaac5d9a787ca"
|
||||
checksum = "b27326208b21807803c5f5aa1020d30ca0432b78cfe251b51a67a05e0baea102"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"http 1.1.0",
|
||||
|
@ -2559,9 +2554,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tower-sessions-core"
|
||||
version = "0.11.0"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0a9049748900860b01f92d3decf5fec71b9d75008f07732956288b003a2282f"
|
||||
checksum = "afd1c5040577134115d8cc758d7757da29e171f83102de3ed1b86e3a2405533f"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum-core",
|
||||
|
@ -2580,9 +2575,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tower-sessions-memory-store"
|
||||
version = "0.11.0"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36baf499920bb861ec9fa929a1f879cec0759af987c6360bd65226bc484ab846"
|
||||
checksum = "88ac75309918b8f6ba16d09865a2a64f81e01b05cf42d5e88e5d3c6cbf775486"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"time 0.3.34",
|
||||
|
@ -2624,7 +2619,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.52",
|
||||
"syn 2.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2821,7 +2816,7 @@ dependencies = [
|
|||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.52",
|
||||
"syn 2.0.58",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
|
@ -2843,7 +2838,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.52",
|
||||
"syn 2.0.58",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
@ -3097,7 +3092,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.52",
|
||||
"syn 2.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -16,7 +16,7 @@ async-trait = "0.1"
|
|||
axum = { version = "0.7", features = ["macros"] }
|
||||
axum-login = "0.14"
|
||||
axum-macros = "0.4"
|
||||
chrono = { version = "0.4", default-features = false, features = ["std", "clock"] }
|
||||
chrono = { version = "0.4", default-features = false, features = ["std", "clock", "serde"] }
|
||||
clap = { version = "4", features = ["derive", "env", "unicode", "suggestions", "usage"] }
|
||||
confy = "0.6"
|
||||
dirs = "5"
|
||||
|
@ -29,7 +29,7 @@ password-hash = { version = "0.5", features = ["std", "getrandom"] }
|
|||
rand = "0.8"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
sha256 = { version = "1", default-features = false }
|
||||
sqlx = { version = "0.7", default-features = false, features = ["runtime-tokio", "sqlite", "tls-none", "migrate"] }
|
||||
sqlx = { version = "0.7", default-features = false, features = ["runtime-tokio", "sqlite", "tls-none", "migrate", "chrono"] }
|
||||
thiserror = "1"
|
||||
tokio = { version = "1", features = ["rt-multi-thread", "signal", "tracing"], default-features = false }
|
||||
tower = { version = "0.4", features = ["util", "timeout"], default-features = false }
|
||||
|
|
2
julid
2
julid
|
@ -1 +1 @@
|
|||
Subproject commit 705afc19e953133aadf811a0a51597e169f7aa62
|
||||
Subproject commit 1e93d0b1e4bc76ff19e1ce8e638c60204f458604
|
|
@ -3,11 +3,11 @@ create table if not exists users (
|
|||
username text not null unique,
|
||||
displayname text,
|
||||
email text,
|
||||
last_seen int,
|
||||
last_seen text,
|
||||
pwhash blob not null,
|
||||
invited_by blob not null,
|
||||
is_active boolean not null default true,
|
||||
last_updated int not null default (unixepoch()),
|
||||
last_updated text not null default CURRENT_TIMESTAMP,
|
||||
foreign key (invited_by) references users (id)
|
||||
);
|
||||
create index if not exists users_username_dex on users (lower(username));
|
||||
|
@ -18,16 +18,16 @@ create trigger if not exists update_last_updated_users
|
|||
after update on users
|
||||
when OLD.last_updated = NEW.last_updated or OLD.last_updated is null
|
||||
BEGIN
|
||||
update users set last_updated = (select unixepoch()) where id=NEW.id;
|
||||
update users set last_updated = CURRENT_TIMESTAMP where id=NEW.id;
|
||||
END;
|
||||
|
||||
-- invitations
|
||||
create table if not exists invites (
|
||||
id blob not null primary key default (julid_new()),
|
||||
owner blob not null,
|
||||
expires_at int,
|
||||
expires_at text,
|
||||
remaining int not null default 1,
|
||||
last_updated int not null default (unixepoch()),
|
||||
last_updated text not null default CURRENT_TIMESTAMP,
|
||||
foreign key (owner) references users (id) on delete cascade on update no action
|
||||
);
|
||||
create index if not exists invites_owner_dex on invites (owner);
|
||||
|
@ -36,6 +36,6 @@ create trigger if not exists update_last_updated_invites
|
|||
after update on invites
|
||||
when OLD.last_updated = NEW.last_updated or OLD.last_updated is null
|
||||
BEGIN
|
||||
update invites set last_updated = (select unixepoch()) where id=NEW.id;
|
||||
update invites set last_updated = CURRENT_TIMESTAMP where id=NEW.id;
|
||||
END;
|
||||
|
||||
|
|
|
@ -5,9 +5,9 @@ create table if not exists watches (
|
|||
title text not null,
|
||||
metadata_url text, -- possible url for imdb or other metadata-esque site to show the user
|
||||
length int,
|
||||
release_date int,
|
||||
release_date text,
|
||||
added_by blob not null, -- ID of the user that added it
|
||||
last_updated int not null default (unixepoch()),
|
||||
last_updated text not null default CURRENT_TIMESTAMP,
|
||||
foreign key (added_by) references users (id)
|
||||
);
|
||||
create index if not exists watches_title_dex on watches (lower(title));
|
||||
|
@ -16,7 +16,7 @@ create trigger if not exists update_last_updated_watches
|
|||
after update on watches
|
||||
when OLD.last_updated = NEW.last_updated or OLD.last_updated is null
|
||||
BEGIN
|
||||
update watches set last_updated = (select unixepoch()) where id=NEW.id;
|
||||
update watches set last_updated = CURRENT_TIMESTAMP where id=NEW.id;
|
||||
END;
|
||||
|
||||
-- table of what people want to watch
|
||||
|
@ -26,9 +26,9 @@ create table if not exists watch_quests (
|
|||
priority int, -- 1-5 how much do you want to watch it
|
||||
public boolean not null default true,
|
||||
watched boolean not null default false,
|
||||
when_watched int,
|
||||
created_at int not null default (unixepoch()),
|
||||
last_updated int not null default (unixepoch()),
|
||||
when_watched text,
|
||||
created_at text not null default CURRENT_TIMESTAMP,
|
||||
last_updated text not null default CURRENT_TIMESTAMP,
|
||||
foreign key (user) references users (id) on delete cascade on update no action,
|
||||
foreign key (watch) references watches (id) on delete cascade on update no action,
|
||||
primary key (user, watch)
|
||||
|
@ -40,7 +40,7 @@ create trigger if not exists update_last_updated_watch_quests
|
|||
after update on watch_quests
|
||||
when OLD.last_updated = NEW.last_updated or OLD.last_updated is null
|
||||
BEGIN
|
||||
update watch_quests set last_updated = (select unixepoch()) where watch=NEW.watch and user=NEW.user;
|
||||
update watch_quests set last_updated = CURRENT_TIMESTAMP where watch=NEW.watch and user=NEW.user;
|
||||
END;
|
||||
|
||||
-- notes on stuff to watch
|
||||
|
@ -50,7 +50,7 @@ create table if not exists watch_notes (
|
|||
watch blob not null,
|
||||
note blob,
|
||||
public boolean not null,
|
||||
last_updated int not null default (unixepoch()),
|
||||
last_updated text not null default CURRENT_TIMESTAMP,
|
||||
foreign key (user) references users (id) on delete cascade on update no action,
|
||||
foreign key (watch) references watches (id) on delete cascade on update no action
|
||||
);
|
||||
|
@ -61,5 +61,5 @@ create trigger if not exists update_last_updated_watch_notes
|
|||
after update on watch_notes
|
||||
when OLD.last_updated = NEW.last_updated or OLD.last_updated is null
|
||||
BEGIN
|
||||
update watch_notes set last_updated = (select unixepoch()) where id=NEW.id;
|
||||
update watch_notes set last_updated = CURRENT_TIMESTAMP where id=NEW.id;
|
||||
END;
|
||||
|
|
|
@ -2,8 +2,8 @@ create table if not exists stars (
|
|||
id blob not null primary key default (julid_new()),
|
||||
name text not null,
|
||||
metadata_url text,
|
||||
born int,
|
||||
died int
|
||||
born text,
|
||||
died text
|
||||
);
|
||||
create index if not exists stars_name_dex on stars (lower(name));
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
create table if not exists follows (
|
||||
follower blob not null,
|
||||
followee blob not null,
|
||||
created_at int not null default (unixepoch()),
|
||||
created_at text not null default CURRENT_TIMESTAMP,
|
||||
foreign key (follower) references users (id) on delete cascade on update no action,
|
||||
foreign key (followee) references users (id) on delete cascade on update no action,
|
||||
unique (follower, followee)
|
||||
|
|
5
migrations/20240409233522_views.down.sql
Normal file
5
migrations/20240409233522_views.down.sql
Normal file
|
@ -0,0 +1,5 @@
|
|||
drop view if exists q;
|
||||
drop view if exists i;
|
||||
drop view if exists u;
|
||||
drop view if exists s;
|
||||
drop view if exists w;
|
6
migrations/20240409233522_views.up.sql
Normal file
6
migrations/20240409233522_views.up.sql
Normal file
|
@ -0,0 +1,6 @@
|
|||
-- human-friendly views with joined fields and string julids
|
||||
create view if not exists w as select julid_string(id) id, kind, title, metadata_url, length, release_date, last_updated from watches;
|
||||
create view if not exists s as select julid_string(id) id, name, born, died from stars;
|
||||
create view if not exists u as select julid_string(id) id, username, displayname, email, (select username from users where id = invited_by) invited_by, last_seen, last_updated from users;
|
||||
create view if not exists i as select julid_string(invites.id) id, users.username, expires_at, remaining, invites.last_updated from invites inner join users on users.id = owner;
|
||||
create view if not exists q as select users.username, watches.title, julid_string(watch) from watch_quests inner join users on users.id = user inner join watches on watch = watches.id;
|
|
@ -50,9 +50,10 @@ impl AuthnBackend for AuthStore {
|
|||
let username = creds.username.trim();
|
||||
let password = creds.password.trim();
|
||||
|
||||
let user = User::try_get(username, &self.0)
|
||||
.await
|
||||
.map_err(|_| AuthErrorKind::Internal)?;
|
||||
let user = User::try_get(username, &self.0).await.map_err(|e| {
|
||||
tracing::debug!("Got error getting {username}: {e:?}");
|
||||
AuthErrorKind::Internal
|
||||
})?;
|
||||
|
||||
Ok(user.filter(|user| verify_password(password, &user.pwhash).is_ok()))
|
||||
}
|
||||
|
|
|
@ -33,8 +33,18 @@ fn main() {
|
|||
.unwrap();
|
||||
|
||||
let cli = Cli::parse();
|
||||
let now = std::time::Instant::now();
|
||||
let ids = rt.block_on(import_watches(&w2w_db, &cli));
|
||||
let dur = std::time::Instant::now() - now;
|
||||
println!(
|
||||
"Imported {} watches in {} seconds",
|
||||
ids.len(),
|
||||
dur.as_secs()
|
||||
);
|
||||
let now = std::time::Instant::now();
|
||||
rt.block_on(save_ids(&cli.db_path, ids));
|
||||
let dur = std::time::Instant::now() - now;
|
||||
println!("Saved the IDs in {} seconds", dur.as_secs());
|
||||
}
|
||||
|
||||
async fn import_watches(w2w_db: &SqlitePool, cli: &Cli) -> IdMap {
|
||||
|
@ -64,6 +74,7 @@ async fn save_ids(path: &OsStr, ids: IdMap) {
|
|||
let file = path.file_name().unwrap();
|
||||
let file = file.to_str().unwrap();
|
||||
let path = format!("{}/w2w-{file}", path.parent().unwrap().to_str().unwrap());
|
||||
println!("Writing IDs to {path}");
|
||||
|
||||
let conn_opts = SqliteConnectOptions::new()
|
||||
.journal_mode(sqlx::sqlite::SqliteJournalMode::Wal)
|
||||
|
|
|
@ -7,6 +7,7 @@ const CONFIG_NAME: Option<&str> = Some("config");
|
|||
pub struct Config {
|
||||
pub base_url: String,
|
||||
pub db_file: String,
|
||||
pub julid_plugin: String,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
|
@ -14,9 +15,14 @@ impl Default for Config {
|
|||
let mut datadir = dirs::data_dir().unwrap();
|
||||
datadir.push(APP_NAME);
|
||||
datadir.push("what2watch.db");
|
||||
let db_file = datadir.as_os_str().to_string_lossy().to_string();
|
||||
datadir.pop();
|
||||
datadir.push("libjulid"); // don't have the '.so' extension here
|
||||
let julid_plugin = datadir.as_os_str().to_string_lossy().to_string();
|
||||
Self {
|
||||
base_url: "http://localhost:3000".into(),
|
||||
db_file: datadir.as_os_str().to_string_lossy().to_string(),
|
||||
db_file,
|
||||
julid_plugin,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,14 +8,15 @@ use sqlx::{
|
|||
|
||||
const MAX_CONNS: u32 = 200;
|
||||
const MIN_CONNS: u32 = 5;
|
||||
const TIMEOUT: u64 = 3;
|
||||
const TIMEOUT: u64 = 20;
|
||||
|
||||
pub fn get_db_pool() -> SqlitePool {
|
||||
let conf = crate::conf::Config::get();
|
||||
let db_filename = {
|
||||
std::env::var("DATABASE_FILE").unwrap_or_else(|_| {
|
||||
#[cfg(not(test))]
|
||||
{
|
||||
let f = crate::conf::Config::get().db_file;
|
||||
let f = conf.db_file;
|
||||
let p = std::path::Path::new(&f);
|
||||
let p = p.parent().unwrap();
|
||||
std::fs::create_dir_all(p).expect("couldn't create data dir");
|
||||
|
@ -36,13 +37,15 @@ pub fn get_db_pool() -> SqlitePool {
|
|||
|
||||
tracing::info!("Connecting to DB at {db_filename}");
|
||||
|
||||
let plugin = conf.julid_plugin;
|
||||
|
||||
let conn_opts = SqliteConnectOptions::new()
|
||||
.foreign_keys(true)
|
||||
.journal_mode(SqliteJournalMode::Wal)
|
||||
.synchronous(sqlx::sqlite::SqliteSynchronous::Normal)
|
||||
.filename(&db_filename)
|
||||
// be sure to have run `make` so that the libjulid extension is built
|
||||
.extension("./libjulid")
|
||||
.extension(plugin)
|
||||
.busy_timeout(Duration::from_secs(TIMEOUT))
|
||||
.create_if_missing(true)
|
||||
.optimize_on_close(true, None)
|
||||
|
|
|
@ -6,6 +6,7 @@ pub async fn handle_slash_redir() -> impl IntoResponse {
|
|||
Redirect::to("/")
|
||||
}
|
||||
|
||||
#[axum::debug_handler]
|
||||
pub async fn handle_slash(auth: AuthSession) -> impl IntoResponse {
|
||||
if let Some(ref user) = auth.user {
|
||||
let name = &user.username;
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
use julid::Julid;
|
||||
use sqlx::{Connection, Sqlite, SqlitePool};
|
||||
use sqlx::{Sqlite, SqlitePool};
|
||||
|
||||
use crate::{
|
||||
import_utils::{insert_credit, insert_star, insert_watch},
|
||||
misc_util::year_to_epoch,
|
||||
Credit, ShowKind, Star, Watch,
|
||||
};
|
||||
|
||||
|
@ -25,7 +24,7 @@ impl From<ImportImdbMovie> for Watch {
|
|||
Watch {
|
||||
id: OMEGA_ID, // this is ignored by the inserter
|
||||
title: value.title,
|
||||
release_date: year_to_epoch(value.year.as_deref()),
|
||||
release_date: value.year,
|
||||
length: value.length.and_then(|v| v.parse::<i64>().ok()),
|
||||
kind: ShowKind::Movie,
|
||||
metadata_url: Some(format!("https://imdb.com/title/{}/", &value.id)),
|
||||
|
@ -39,7 +38,7 @@ impl From<&ImportImdbMovie> for Watch {
|
|||
Watch {
|
||||
id: OMEGA_ID,
|
||||
title: value.title.to_string(),
|
||||
release_date: year_to_epoch(value.year.as_deref()),
|
||||
release_date: value.year.clone(),
|
||||
length: value.length.as_ref().and_then(|v| v.parse::<i64>().ok()),
|
||||
kind: ShowKind::Movie,
|
||||
metadata_url: Some(format!("https://imdb.com/title/{}/", value.id)),
|
||||
|
@ -66,8 +65,8 @@ impl From<&ImdbStar> for Star {
|
|||
Self {
|
||||
name: value.name.clone(),
|
||||
metadata_url,
|
||||
born: year_to_epoch(value.born.as_deref()),
|
||||
died: year_to_epoch(value.died.as_deref()),
|
||||
born: value.born.clone(),
|
||||
died: value.died.clone(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
@ -83,8 +82,7 @@ pub async fn import_imdb_data(w2w_db: &SqlitePool, imdb: &SqlitePool, ids: &mut
|
|||
.unwrap();
|
||||
|
||||
for batch in iwatches.chunks(5_000) {
|
||||
let mut tx = w2w_db.acquire().await.unwrap();
|
||||
let mut tx = tx.begin().await.unwrap();
|
||||
let mut tx = w2w_db.begin().await.unwrap();
|
||||
for iwatch in batch {
|
||||
let aid = iwatch.id.clone();
|
||||
let kind = show_kind(iwatch.kind.as_ref().unwrap());
|
||||
|
|
|
@ -31,8 +31,8 @@ pub async fn insert_star(star: &Star, db: &mut SqliteConnection) -> Julid {
|
|||
sqlx::query_scalar(q)
|
||||
.bind(&star.name)
|
||||
.bind(&star.metadata_url)
|
||||
.bind(star.born)
|
||||
.bind(star.died)
|
||||
.bind(&star.born)
|
||||
.bind(&star.died)
|
||||
.fetch_one(db)
|
||||
.await
|
||||
.unwrap()
|
||||
|
|
|
@ -22,6 +22,7 @@ pub use users::User;
|
|||
pub use watches::{ShowKind, Watch, WatchQuest};
|
||||
|
||||
pub type WWRouter = axum::Router<SqlitePool>;
|
||||
pub type WatchDate = chrono::DateTime<chrono::Utc>;
|
||||
|
||||
// everything else is private to the crate
|
||||
mod auth;
|
||||
|
@ -55,6 +56,9 @@ pub async fn app(db_pool: sqlx::SqlitePool) -> IntoMakeService<axum::Router> {
|
|||
post_add_watch_quest,
|
||||
};
|
||||
|
||||
let conf = crate::conf::Config::get();
|
||||
tracing::info!("Using config: {conf:#?}");
|
||||
|
||||
let auth_layer = {
|
||||
let session_layer = session_layer(db_pool.clone()).await;
|
||||
let store = AuthStore::new(db_pool.clone());
|
||||
|
|
|
@ -7,7 +7,7 @@ fn main() {
|
|||
tracing_subscriber::registry()
|
||||
.with(
|
||||
tracing_subscriber::EnvFilter::try_from_default_env()
|
||||
.unwrap_or_else(|_| "what2watch=debug,axum::routing=debug".into()),
|
||||
.unwrap_or_else(|_| "what2watch=debug,axum=debug".into()),
|
||||
)
|
||||
.with(tracing_subscriber::fmt::layer())
|
||||
.init();
|
||||
|
|
|
@ -35,17 +35,3 @@ where
|
|||
.map(Some),
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a stringy number like "1999" to a 64-bit signed unix epoch-based
|
||||
/// timestamp
|
||||
pub fn year_to_epoch(year: Option<&str>) -> Option<i64> {
|
||||
year?
|
||||
.trim()
|
||||
.parse::<i32>()
|
||||
.map(|year| {
|
||||
let years = (year - 1970) as f32;
|
||||
let days = (years * 365.2425) as i64;
|
||||
days * 24 * 60 * 60
|
||||
})
|
||||
.ok()
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use axum::{
|
|||
response::IntoResponse,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::{query_as, SqlitePool};
|
||||
use sqlx::SqlitePool;
|
||||
|
||||
use crate::{
|
||||
misc_util::empty_string_as_none, AuthSession, OptionalOptionalUser, Star, User, Watch,
|
||||
|
@ -25,44 +25,29 @@ pub enum SearchResult {
|
|||
|
||||
#[derive(Debug, Default, Clone, Deserialize, PartialEq, Eq)]
|
||||
pub struct SearchQuery {
|
||||
#[serde(default, deserialize_with = "empty_string_as_none")]
|
||||
pub search: Option<String>,
|
||||
#[serde(default, deserialize_with = "empty_string_as_none")]
|
||||
pub title: Option<String>,
|
||||
#[serde(default, deserialize_with = "empty_string_as_none")]
|
||||
pub kind: Option<String>,
|
||||
#[serde(default, deserialize_with = "empty_string_as_none")]
|
||||
pub year: Option<i64>,
|
||||
pub year: Option<String>,
|
||||
}
|
||||
|
||||
pub async fn get_search_watch(
|
||||
auth: AuthSession,
|
||||
State(pool): State<SqlitePool>,
|
||||
search: Query<SearchQuery>,
|
||||
Query(search): Query<SearchQuery>,
|
||||
) -> impl IntoResponse {
|
||||
const DEFAULT_WATCHES_QUERY: &str =
|
||||
"select * from (select * from watches order by random() limit 50) order by release_date asc";
|
||||
|
||||
let user = auth.user;
|
||||
let search_query = search.0;
|
||||
let SearchQuery { title, year } = &search;
|
||||
|
||||
let query = if search_query == SearchQuery::default() {
|
||||
query_as(DEFAULT_WATCHES_QUERY)
|
||||
} else if let Some(title) = search_query.title {
|
||||
query_as(
|
||||
"select * from watches where id in (select id from watch_search where title match ? order by rank)",
|
||||
)
|
||||
.bind(title)
|
||||
} else if let Some(ref search) = search_query.search {
|
||||
query_as("select * from watches where id in (select id from watch_search where title match ?) outer join (select * from stars where id in (select id from star_search where name match ?)) s")
|
||||
.bind(search).bind(search)
|
||||
} else {
|
||||
query_as(DEFAULT_WATCHES_QUERY)
|
||||
let watches: Vec<Watch> = match (title, year) {
|
||||
(Some(title), None) => sqlx::query_as(
|
||||
"select * from watches where id in (select id from watch_search where title match ? order by rank)").bind(
|
||||
title.trim()).fetch_all(&pool).await.unwrap_or_default(),
|
||||
(Some(title), Some(year)) => sqlx::query_as("select * from watches where id in (select id from watch_search where title match ? order by rank) and release_date = ?").bind(title.trim()).bind(year.trim()).fetch_all(&pool).await.unwrap_or_default(),
|
||||
(None, Some(year)) => sqlx::query_as("select * from watches where release_date = ? order by title").bind(year.trim()).fetch_all(&pool).await.unwrap_or_default(),
|
||||
_ => sqlx::query_as("select * from (select * from watches order by random() limit 50) order by release_date asc").fetch_all(&pool).await.unwrap_or_default()
|
||||
};
|
||||
|
||||
// until tantivy search
|
||||
let watches: Vec<Watch> = query.fetch_all(&pool).await.unwrap();
|
||||
|
||||
SearchPage {
|
||||
results: watches,
|
||||
user,
|
||||
|
|
|
@ -250,7 +250,7 @@ async fn validate_invitation(
|
|||
}
|
||||
|
||||
if let Some(ts) = invitation.expires_at {
|
||||
let now = chrono::Utc::now().timestamp();
|
||||
let now = chrono::Utc::now();
|
||||
if ts < now {
|
||||
return Err(CreateUserErrorKind::BadInvitation);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ use julid::Julid;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::SqlitePool;
|
||||
|
||||
use crate::WatchDate;
|
||||
|
||||
pub mod handlers;
|
||||
pub mod templates;
|
||||
|
||||
|
@ -25,7 +27,7 @@ pub enum CreateInviteErrorKind {
|
|||
pub struct Invitation {
|
||||
id: Julid,
|
||||
owner: Julid,
|
||||
expires_at: Option<i64>,
|
||||
expires_at: Option<WatchDate>,
|
||||
remaining: i16,
|
||||
}
|
||||
|
||||
|
@ -85,8 +87,9 @@ impl Invitation {
|
|||
}
|
||||
|
||||
pub fn with_expires_in(&self, expires_in: Duration) -> Self {
|
||||
let now = chrono::Utc::now();
|
||||
Self {
|
||||
expires_at: Some((chrono::Utc::now() + expires_in).timestamp()),
|
||||
expires_at: Some(now + expires_in),
|
||||
..*self
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@ pub struct Star {
|
|||
pub id: Julid,
|
||||
pub name: String,
|
||||
pub metadata_url: Option<String>,
|
||||
pub born: Option<i64>,
|
||||
pub died: Option<i64>,
|
||||
pub born: Option<String>,
|
||||
pub died: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize, FromRow)]
|
||||
|
|
57
src/users.rs
57
src/users.rs
|
@ -9,12 +9,7 @@ use julid::Julid;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::{sqlite::SqliteRow, Row, SqlitePool};
|
||||
|
||||
use crate::AuthSession;
|
||||
|
||||
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 INSERT_QUERY: &str =
|
||||
"insert into users (id, username, displayname, email, pwhash, invited_by) values ($1, $2, $3, $4, $5, $6)";
|
||||
use crate::{AuthSession, WatchDate};
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct User {
|
||||
|
@ -22,7 +17,7 @@ pub struct User {
|
|||
pub username: String,
|
||||
pub displayname: Option<String>,
|
||||
pub email: Option<String>,
|
||||
pub last_seen: Option<i64>,
|
||||
pub last_seen: Option<WatchDate>,
|
||||
pub pwhash: String,
|
||||
pub invited_by: Julid,
|
||||
pub is_active: bool,
|
||||
|
@ -81,42 +76,43 @@ impl Debug for User {
|
|||
impl Display for User {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let uname = &self.username;
|
||||
let dname = if let Some(ref n) = self.displayname {
|
||||
n
|
||||
} else {
|
||||
""
|
||||
};
|
||||
let email = if let Some(ref e) = self.email { e } else { "" };
|
||||
let dname = self.displayname.as_deref().unwrap_or("");
|
||||
let email = self.email.as_deref().unwrap_or("");
|
||||
write!(f, "Username: {uname}\nDisplayname: {dname}\nEmail: {email}")
|
||||
}
|
||||
}
|
||||
|
||||
impl User {
|
||||
pub async fn try_get(username: &str, db: &SqlitePool) -> Result<Option<Self>, sqlx::Error> {
|
||||
sqlx::query_as(USERNAME_QUERY)
|
||||
sqlx::query_as("select * from users where username = ?")
|
||||
.bind(username)
|
||||
.fetch_optional(db)
|
||||
.await
|
||||
}
|
||||
|
||||
/// This is mostly for tests and to ensure that the system accounts are
|
||||
/// present. Most of the time, users should not be inserted with an ID, but
|
||||
/// should let the DB assign them an ID.
|
||||
pub async fn try_insert(&self, db: &SqlitePool) -> Result<(), sqlx::Error> {
|
||||
sqlx::query(INSERT_QUERY)
|
||||
.bind(self.id)
|
||||
.bind(&self.username)
|
||||
.bind(&self.displayname)
|
||||
.bind(&self.email)
|
||||
.bind(&self.pwhash)
|
||||
.bind(self.invited_by)
|
||||
sqlx::query!("insert into users (id, username, displayname, email, pwhash, invited_by) values (?, ?, ?, ?, ?, ?)",
|
||||
self.id,
|
||||
self.username,
|
||||
self.displayname,
|
||||
self.email,
|
||||
self.pwhash,
|
||||
self.invited_by)
|
||||
.execute(db)
|
||||
.await
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
pub async fn update_last_seen(&self, pool: &SqlitePool) {
|
||||
match sqlx::query(LAST_SEEN_QUERY)
|
||||
.bind(self.id)
|
||||
.execute(pool)
|
||||
.await
|
||||
match sqlx::query!(
|
||||
"update users set last_seen = CURRENT_TIMESTAMP where id = ?",
|
||||
self.id
|
||||
)
|
||||
.execute(pool)
|
||||
.await
|
||||
{
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
|
@ -147,15 +143,12 @@ pub async fn handle_update_last_seen(
|
|||
request: Request,
|
||||
next: Next,
|
||||
) -> impl IntoResponse {
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
if let Some(user) = auth.user {
|
||||
if let Some(then) = user.last_seen {
|
||||
let now = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_secs() as i64;
|
||||
if let Some(then) = &user.last_seen {
|
||||
let now = chrono::Utc::now();
|
||||
// The Nyquist frequency for 1-day tracking resolution is 12 hours.
|
||||
if now - then > 12 * 3600 {
|
||||
let dur = chrono::Duration::hours(12);
|
||||
if (now - then) > dur {
|
||||
user.update_last_seen(&pool).await;
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -10,8 +10,7 @@ use sqlx::{query, query_as, query_scalar, SqlitePool};
|
|||
|
||||
use super::templates::{AddNewWatchPage, AddWatchButton, GetWatchPage};
|
||||
use crate::{
|
||||
misc_util::{empty_string_as_none, year_to_epoch},
|
||||
AuthSession, MyWatchesPage, ShowKind, Watch, WatchQuest,
|
||||
misc_util::empty_string_as_none, AuthSession, MyWatchesPage, ShowKind, Watch, WatchQuest,
|
||||
};
|
||||
|
||||
//-************************************************************************
|
||||
|
@ -99,12 +98,11 @@ pub async fn post_add_new_watch(
|
|||
) -> Result<impl IntoResponse, AddError> {
|
||||
if let Some(user) = auth.user {
|
||||
{
|
||||
let release_date = year_to_epoch(form.year.as_deref());
|
||||
let watch = Watch {
|
||||
title: form.title,
|
||||
kind: form.kind,
|
||||
metadata_url: form.metadata_url,
|
||||
release_date,
|
||||
release_date: form.year,
|
||||
added_by: user.id,
|
||||
..Default::default()
|
||||
};
|
||||
|
@ -132,7 +130,7 @@ async fn add_new_watch_impl(db_pool: &SqlitePool, watch: &Watch) -> Result<Julid
|
|||
let watch_id: Julid = query_scalar(ADD_WATCH_QUERY)
|
||||
.bind(&watch.title)
|
||||
.bind(watch.kind)
|
||||
.bind(watch.release_date)
|
||||
.bind(&watch.release_date)
|
||||
.bind(&watch.metadata_url)
|
||||
.bind(watch.added_by)
|
||||
.bind(watch.length)
|
||||
|
|
|
@ -73,22 +73,10 @@ pub struct Watch {
|
|||
pub kind: ShowKind,
|
||||
pub metadata_url: Option<String>,
|
||||
pub length: Option<i64>,
|
||||
pub release_date: Option<i64>,
|
||||
pub release_date: Option<String>,
|
||||
pub added_by: Julid, // this shouldn't be exposed to randos in the application
|
||||
}
|
||||
|
||||
impl Watch {
|
||||
pub fn year(&self) -> Option<String> {
|
||||
if let Some(year) = self.release_date {
|
||||
let date = chrono::NaiveDateTime::from_timestamp_opt(year, 0)?;
|
||||
let year = format!("{}", date.format("%Y"));
|
||||
Some(year)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-************************************************************************
|
||||
/// Something a user wants to watch
|
||||
//-************************************************************************
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{% extends "base.html" %}
|
||||
{% import "macros.html" as m %}
|
||||
|
||||
{% block title %}Welcome to What 2 Watch, Bish{% endblock %}
|
||||
{% block title %}Welcome to What 2 Watch, Buddy{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{% extends "base.html" %}
|
||||
{% import "macros.html" as m %}
|
||||
|
||||
{% block title %}Welcome to What 2 Watch, Bish{% endblock %}
|
||||
{% block title %}Welcome to What 2 Watch, Buddy{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
|||
{% when Some with (watch) %}
|
||||
|
||||
<div class="watch">
|
||||
<span class="watchtitle">{{watch.title}}</span> -- {% call m::get_or_default(watch.year(), "when??") %}
|
||||
<span class="watchtitle">{{watch.title}}</span> -- {% call m::get_or_default(watch.release_date, "when??") %}
|
||||
</div>
|
||||
|
||||
{% else %}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Welcome to What 2 Watch, Bish{% endblock %}
|
||||
{% block title %}Welcome to What 2 Watch, Buddy{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Login to What 2 Watch, Bish{% endblock %}
|
||||
{% block title %}Login to What 2 Watch, Buddy{% endblock %}
|
||||
|
||||
{% block header %}{% endblock %}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Logout of What 2 Watch, Bish{% endblock %}
|
||||
{% block title %}Logout of What 2 Watch, Buddy{% endblock %}
|
||||
|
||||
{% block header %}{% endblock %}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Thanks for Signing Up for What 2 Watch, Bish{% endblock %}
|
||||
{% block title %}Thanks for Signing Up for What 2 Watch, Buddy{% endblock %}
|
||||
|
||||
{% block header %}{% endblock %}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{% extends "base.html" %}
|
||||
{% import "macros.html" as m %}
|
||||
|
||||
{% block title %}Welcome to What 2 Watch, Bish{% endblock %}
|
||||
{% block title %}Welcome to What 2 Watch, Buddy{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
|
@ -28,7 +28,8 @@
|
|||
<div class="watchlist">
|
||||
<ul>
|
||||
{% for watch in watches %}
|
||||
<li><span class="watchtitle">{{watch.title}}</span> -- {% call m::get_or_default(watch.year(), "when??") %}
|
||||
<li><span class="watchtitle">{{watch.title}}</span> -- {% call m::get_or_default(watch.release_date, "when??")
|
||||
%}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
|
|
@ -1,11 +1,33 @@
|
|||
{% extends "base.html" %}
|
||||
{% import "macros.html" as m %}
|
||||
|
||||
{% block title %}Welcome to What 2 Watch, Bish{% endblock %}
|
||||
{% block title %}Welcome to What 2 Watch, Buddy{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<h1>Whatcha Watchin?</h1>
|
||||
|
||||
<div class="fullsearch">
|
||||
<form action="/search" enctype="application/x-www-form-urlencoded" method="get">
|
||||
<h2>Search</h2>
|
||||
|
||||
<label for="title">Title</label>
|
||||
<input type="text" name="title" id="title-search"></br>
|
||||
|
||||
<label for="year">Release Year</label>
|
||||
<input type="text" name="year" id="title-year-search"></br>
|
||||
|
||||
<hr>
|
||||
|
||||
<label for="person">Person</label>
|
||||
<input type="text" name="person" id="person-search"></br>
|
||||
|
||||
<input type="submit" value="Let's go!">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="watchlist">
|
||||
<table>
|
||||
<thead>
|
||||
|
@ -23,39 +45,6 @@
|
|||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
<h2>Simple Search</h2>
|
||||
<div class="simplesearch">
|
||||
<form action="/search" enctype="application/x-www-form-urlencoded" method="get">
|
||||
<label for="search">Looking for something else to watch?</label>
|
||||
<input type="text" name="search" id="search"></br>
|
||||
<input type="submit" value="Let's go!">
|
||||
</div>
|
||||
|
||||
<h2>Fussy Search</h2>
|
||||
<div class="fullsearch">
|
||||
<label for="title">Title</label>
|
||||
<input type="text" name="title" id="title"></br>
|
||||
|
||||
<label for="year">Release Year</label>
|
||||
<input type="text" name="year" id="year"></br>
|
||||
|
||||
<label for="kind">Type</label>
|
||||
<select id="kind" name="kind">
|
||||
<option value="">Unknown</option>
|
||||
<option value="0">Movie</option>
|
||||
<option value="1">Series</option>
|
||||
<option value="2">Limited Series</option>
|
||||
<option value="3">Short</option>
|
||||
<option value="4">Other</option>
|
||||
</select>
|
||||
|
||||
<input type="submit" value="Let's go!">
|
||||
</form>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Sign Up for What 2 Watch, Bish{% endblock %}
|
||||
{% block title %}Sign Up for What 2 Watch, Buddy{% endblock %}
|
||||
|
||||
{% block header %} {% endblock %}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Dang, Bish{% endblock %}
|
||||
{% block title %}Dang, Buddy{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% block header %}{% endblock %}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Thanks for Signing Up for What 2 Watch, Bish{% endblock %}
|
||||
{% block title %}Thanks for Signing Up for What 2 Watch, Buddy{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% block header %}{% endblock %}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
</span>
|
||||
</td>
|
||||
<td>{{res.kind}}</td>
|
||||
<td> {% call m::get_or_default(res.year(), "when??") -%}</td>
|
||||
<td> {% call m::get_or_default(res.release_date, "when??") -%}</td>
|
||||
<td>
|
||||
<span id="add-watch-{{res.id}}">
|
||||
<span hx-get="/watch/status/{{res.id}}" hx-target="this" hx-trigger="load, reveal"
|
||||
|
|
Loading…
Reference in a new issue