Compare commits
No commits in common. "fa8ed2b5992396a92278775f75bc3c303b490850" and "52ef924f12e67a1a4388299f218a1bc8d65fb192" have entirely different histories.
fa8ed2b599
...
52ef924f12
33 changed files with 301 additions and 1270 deletions
541
Cargo.lock
generated
541
Cargo.lock
generated
|
@ -65,7 +65,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb"
|
checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.48",
|
"syn 2.0.44",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -179,7 +179,7 @@ dependencies = [
|
||||||
"actix-router",
|
"actix-router",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.48",
|
"syn 2.0.44",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -251,13 +251,13 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-trait"
|
name = "async-trait"
|
||||||
version = "0.1.77"
|
version = "0.1.76"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9"
|
checksum = "531b97fb4cd3dfdce92c35dedbfdc1f0b9d8091c8ca943d6dae340ef5012d514"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.48",
|
"syn 2.0.44",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -437,16 +437,6 @@ dependencies = [
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "core-foundation"
|
|
||||||
version = "0.9.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
|
|
||||||
dependencies = [
|
|
||||||
"core-foundation-sys",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation-sys"
|
name = "core-foundation-sys"
|
||||||
version = "0.8.6"
|
version = "0.8.6"
|
||||||
|
@ -455,9 +445,9 @@ checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cpufeatures"
|
name = "cpufeatures"
|
||||||
version = "0.2.12"
|
version = "0.2.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
|
checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
@ -527,7 +517,7 @@ dependencies = [
|
||||||
"diesel_table_macro_syntax",
|
"diesel_table_macro_syntax",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.48",
|
"syn 2.0.44",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -547,7 +537,7 @@ version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fc5557efc453706fed5e4fa85006fe9817c224c3f480a34c7e5959fd700921c5"
|
checksum = "fc5557efc453706fed5e4fa85006fe9817c224c3f480a34c7e5959fd700921c5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"syn 2.0.48",
|
"syn 2.0.44",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -576,41 +566,12 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "env_logger"
|
|
||||||
version = "0.10.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece"
|
|
||||||
dependencies = [
|
|
||||||
"humantime",
|
|
||||||
"is-terminal",
|
|
||||||
"log",
|
|
||||||
"regex",
|
|
||||||
"termcolor",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "equivalent"
|
name = "equivalent"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "errno"
|
|
||||||
version = "0.3.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"windows-sys 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fastrand"
|
|
||||||
version = "2.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flate2"
|
name = "flate2"
|
||||||
version = "1.0.28"
|
version = "1.0.28"
|
||||||
|
@ -627,21 +588,6 @@ version = "1.0.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "foreign-types"
|
|
||||||
version = "0.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
|
||||||
dependencies = [
|
|
||||||
"foreign-types-shared",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "foreign-types-shared"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "form_urlencoded"
|
name = "form_urlencoded"
|
||||||
version = "1.2.1"
|
version = "1.2.1"
|
||||||
|
@ -651,27 +597,12 @@ dependencies = [
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures-channel"
|
|
||||||
version = "0.3.30"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
|
|
||||||
dependencies = [
|
|
||||||
"futures-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-core"
|
name = "futures-core"
|
||||||
version = "0.3.30"
|
version = "0.3.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
|
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures-io"
|
|
||||||
version = "0.3.30"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-sink"
|
name = "futures-sink"
|
||||||
version = "0.3.30"
|
version = "0.3.30"
|
||||||
|
@ -691,12 +622,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-io",
|
|
||||||
"futures-task",
|
"futures-task",
|
||||||
"memchr",
|
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"pin-utils",
|
"pin-utils",
|
||||||
"slab",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -753,12 +681,6 @@ version = "0.14.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hermit-abi"
|
|
||||||
version = "0.3.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hmac"
|
name = "hmac"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
|
@ -779,17 +701,6 @@ dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "http-body"
|
|
||||||
version = "0.4.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
|
|
||||||
dependencies = [
|
|
||||||
"bytes",
|
|
||||||
"http",
|
|
||||||
"pin-project-lite",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "httparse"
|
name = "httparse"
|
||||||
version = "1.8.0"
|
version = "1.8.0"
|
||||||
|
@ -802,49 +713,6 @@ version = "1.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "humantime"
|
|
||||||
version = "2.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hyper"
|
|
||||||
version = "0.14.28"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80"
|
|
||||||
dependencies = [
|
|
||||||
"bytes",
|
|
||||||
"futures-channel",
|
|
||||||
"futures-core",
|
|
||||||
"futures-util",
|
|
||||||
"h2",
|
|
||||||
"http",
|
|
||||||
"http-body",
|
|
||||||
"httparse",
|
|
||||||
"httpdate",
|
|
||||||
"itoa",
|
|
||||||
"pin-project-lite",
|
|
||||||
"socket2",
|
|
||||||
"tokio",
|
|
||||||
"tower-service",
|
|
||||||
"tracing",
|
|
||||||
"want",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hyper-tls"
|
|
||||||
version = "0.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
|
|
||||||
dependencies = [
|
|
||||||
"bytes",
|
|
||||||
"hyper",
|
|
||||||
"native-tls",
|
|
||||||
"tokio",
|
|
||||||
"tokio-native-tls",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iana-time-zone"
|
name = "iana-time-zone"
|
||||||
version = "0.1.59"
|
version = "0.1.59"
|
||||||
|
@ -897,23 +765,6 @@ dependencies = [
|
||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ipnet"
|
|
||||||
version = "2.9.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "is-terminal"
|
|
||||||
version = "0.4.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455"
|
|
||||||
dependencies = [
|
|
||||||
"hermit-abi",
|
|
||||||
"rustix",
|
|
||||||
"windows-sys 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.10"
|
version = "1.0.10"
|
||||||
|
@ -967,15 +818,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.152"
|
version = "0.2.151"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
|
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "linux-raw-sys"
|
|
||||||
version = "0.4.12"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "local-channel"
|
name = "local-channel"
|
||||||
|
@ -1061,25 +906,7 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"wasi",
|
"wasi",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "native-tls"
|
|
||||||
version = "0.2.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"
|
|
||||||
dependencies = [
|
|
||||||
"lazy_static",
|
|
||||||
"libc",
|
|
||||||
"log",
|
|
||||||
"openssl",
|
|
||||||
"openssl-probe",
|
|
||||||
"openssl-sys",
|
|
||||||
"schannel",
|
|
||||||
"security-framework",
|
|
||||||
"security-framework-sys",
|
|
||||||
"tempfile",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1112,16 +939,6 @@ dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num_cpus"
|
|
||||||
version = "1.16.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
|
||||||
dependencies = [
|
|
||||||
"hermit-abi",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "object"
|
name = "object"
|
||||||
version = "0.32.2"
|
version = "0.32.2"
|
||||||
|
@ -1137,50 +954,6 @@ version = "1.19.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "openssl"
|
|
||||||
version = "0.10.62"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8cde4d2d9200ad5909f8dac647e29482e07c3a35de8a13fce7c9c7747ad9f671"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.4.1",
|
|
||||||
"cfg-if",
|
|
||||||
"foreign-types",
|
|
||||||
"libc",
|
|
||||||
"once_cell",
|
|
||||||
"openssl-macros",
|
|
||||||
"openssl-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "openssl-macros"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.48",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "openssl-probe"
|
|
||||||
version = "0.1.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "openssl-sys"
|
|
||||||
version = "0.9.98"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c1665caf8ab2dc9aef43d1c0023bd904633a6a05cb30b0ad59bec2ae986e57a7"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"libc",
|
|
||||||
"pkg-config",
|
|
||||||
"vcpkg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
|
@ -1267,18 +1040,18 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.76"
|
version = "1.0.73"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c"
|
checksum = "2dd5e8a1f1029c43224ad5898e50140c2aebb1705f19e67c918ebf5b9e797fe1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.35"
|
version = "1.0.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
|
checksum = "22a37c9326af5ed140c86a46655b5278de879853be5573c01df185b6f49a580a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
@ -1362,44 +1135,6 @@ version = "0.8.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "reqwest"
|
|
||||||
version = "0.11.23"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41"
|
|
||||||
dependencies = [
|
|
||||||
"base64",
|
|
||||||
"bytes",
|
|
||||||
"encoding_rs",
|
|
||||||
"futures-core",
|
|
||||||
"futures-util",
|
|
||||||
"h2",
|
|
||||||
"http",
|
|
||||||
"http-body",
|
|
||||||
"hyper",
|
|
||||||
"hyper-tls",
|
|
||||||
"ipnet",
|
|
||||||
"js-sys",
|
|
||||||
"log",
|
|
||||||
"mime",
|
|
||||||
"native-tls",
|
|
||||||
"once_cell",
|
|
||||||
"percent-encoding",
|
|
||||||
"pin-project-lite",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"serde_urlencoded",
|
|
||||||
"system-configuration",
|
|
||||||
"tokio",
|
|
||||||
"tokio-native-tls",
|
|
||||||
"tower-service",
|
|
||||||
"url",
|
|
||||||
"wasm-bindgen",
|
|
||||||
"wasm-bindgen-futures",
|
|
||||||
"web-sys",
|
|
||||||
"winreg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ring"
|
name = "ring"
|
||||||
version = "0.17.7"
|
version = "0.17.7"
|
||||||
|
@ -1411,7 +1146,7 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"spin",
|
"spin",
|
||||||
"untrusted",
|
"untrusted",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1429,34 +1164,12 @@ dependencies = [
|
||||||
"semver",
|
"semver",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustix"
|
|
||||||
version = "0.38.28"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.4.1",
|
|
||||||
"errno",
|
|
||||||
"libc",
|
|
||||||
"linux-raw-sys",
|
|
||||||
"windows-sys 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.16"
|
version = "1.0.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
|
checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "schannel"
|
|
||||||
version = "0.1.23"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534"
|
|
||||||
dependencies = [
|
|
||||||
"windows-sys 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scheduled-thread-pool"
|
name = "scheduled-thread-pool"
|
||||||
version = "0.2.7"
|
version = "0.2.7"
|
||||||
|
@ -1472,60 +1185,37 @@ version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "security-framework"
|
|
||||||
version = "2.9.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 1.3.2",
|
|
||||||
"core-foundation",
|
|
||||||
"core-foundation-sys",
|
|
||||||
"libc",
|
|
||||||
"security-framework-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "security-framework-sys"
|
|
||||||
version = "2.9.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a"
|
|
||||||
dependencies = [
|
|
||||||
"core-foundation-sys",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "1.0.21"
|
version = "1.0.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0"
|
checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.195"
|
version = "1.0.193"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02"
|
checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.195"
|
version = "1.0.193"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c"
|
checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.48",
|
"syn 2.0.44",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.111"
|
version = "1.0.109"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4"
|
checksum = "cb0652c533506ad7a2e353cce269330d6afd8bdfb6d75e0ace5b35aacbd7b9e9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
|
@ -1618,7 +1308,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
|
checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1646,76 +1336,33 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.48"
|
version = "2.0.44"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
|
checksum = "92d27c2c202598d05175a6dd3af46824b7f747f8d8e9b14c623f19fa5069735d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "system-configuration"
|
|
||||||
version = "0.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 1.3.2",
|
|
||||||
"core-foundation",
|
|
||||||
"system-configuration-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "system-configuration-sys"
|
|
||||||
version = "0.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
|
|
||||||
dependencies = [
|
|
||||||
"core-foundation-sys",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tempfile"
|
|
||||||
version = "3.9.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"fastrand",
|
|
||||||
"redox_syscall",
|
|
||||||
"rustix",
|
|
||||||
"windows-sys 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "termcolor"
|
|
||||||
version = "1.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449"
|
|
||||||
dependencies = [
|
|
||||||
"winapi-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.56"
|
version = "1.0.53"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad"
|
checksum = "b2cd5904763bad08ad5513ddbb12cf2ae273ca53fa9f68e843e236ec6dfccc09"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "1.0.56"
|
version = "1.0.53"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471"
|
checksum = "3dcf4a824cce0aeacd6f38ae6f24234c8e80d68632338ebaa1443b5df9e29e19"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.48",
|
"syn 2.0.44",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1772,22 +1419,11 @@ dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"libc",
|
"libc",
|
||||||
"mio",
|
"mio",
|
||||||
"num_cpus",
|
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
"socket2",
|
"socket2",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tokio-native-tls"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
|
|
||||||
dependencies = [
|
|
||||||
"native-tls",
|
|
||||||
"tokio",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1838,12 +1474,6 @@ dependencies = [
|
||||||
"winnow",
|
"winnow",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tower-service"
|
|
||||||
version = "0.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing"
|
name = "tracing"
|
||||||
version = "0.1.40"
|
version = "0.1.40"
|
||||||
|
@ -1864,12 +1494,6 @@ dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "try-lock"
|
|
||||||
version = "0.2.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typenum"
|
name = "typenum"
|
||||||
version = "1.17.0"
|
version = "1.17.0"
|
||||||
|
@ -1931,7 +1555,6 @@ name = "vybr-api"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-rt",
|
"actix-rt",
|
||||||
"actix-service",
|
|
||||||
"actix-web",
|
"actix-web",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"bcrypt",
|
"bcrypt",
|
||||||
|
@ -1939,26 +1562,14 @@ dependencies = [
|
||||||
"diesel",
|
"diesel",
|
||||||
"diesel_migrations",
|
"diesel_migrations",
|
||||||
"dotenvy",
|
"dotenvy",
|
||||||
"env_logger",
|
|
||||||
"hmac",
|
"hmac",
|
||||||
"jsonwebtoken",
|
"jsonwebtoken",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log",
|
|
||||||
"reqwest",
|
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha2",
|
"sha2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "want"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
|
|
||||||
dependencies = [
|
|
||||||
"try-lock",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
@ -1986,22 +1597,10 @@ dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.48",
|
"syn 2.0.44",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasm-bindgen-futures"
|
|
||||||
version = "0.4.39"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"js-sys",
|
|
||||||
"wasm-bindgen",
|
|
||||||
"web-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro"
|
name = "wasm-bindgen-macro"
|
||||||
version = "0.2.89"
|
version = "0.2.89"
|
||||||
|
@ -2020,7 +1619,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.48",
|
"syn 2.0.44",
|
||||||
"wasm-bindgen-backend",
|
"wasm-bindgen-backend",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
@ -2031,47 +1630,6 @@ version = "0.2.89"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f"
|
checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "web-sys"
|
|
||||||
version = "0.3.66"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f"
|
|
||||||
dependencies = [
|
|
||||||
"js-sys",
|
|
||||||
"wasm-bindgen",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi"
|
|
||||||
version = "0.3.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
|
||||||
dependencies = [
|
|
||||||
"winapi-i686-pc-windows-gnu",
|
|
||||||
"winapi-x86_64-pc-windows-gnu",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-i686-pc-windows-gnu"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-util"
|
|
||||||
version = "0.1.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
|
|
||||||
dependencies = [
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-x86_64-pc-windows-gnu"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-core"
|
name = "windows-core"
|
||||||
version = "0.52.0"
|
version = "0.52.0"
|
||||||
|
@ -2090,15 +1648,6 @@ dependencies = [
|
||||||
"windows-targets 0.48.5",
|
"windows-targets 0.48.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-sys"
|
|
||||||
version = "0.52.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
|
||||||
dependencies = [
|
|
||||||
"windows-targets 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-targets"
|
name = "windows-targets"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
|
@ -2215,23 +1764,13 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
version = "0.5.33"
|
version = "0.5.31"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b7520bbdec7211caa7c4e682eb1fbe07abe20cee6756b6e00f537c82c11816aa"
|
checksum = "97a4882e6b134d6c28953a387571f1acdd3496830d5e36c5e3a1075580ea641c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winreg"
|
|
||||||
version = "0.50.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"windows-sys 0.48.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
version = "0.7.32"
|
version = "0.7.32"
|
||||||
|
@ -2249,7 +1788,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.48",
|
"syn 2.0.44",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -14,13 +14,9 @@ chrono = { version = "0.4", features = ["serde"] }
|
||||||
diesel = { version = "2", features = ["r2d2", "postgres", "chrono"] }
|
diesel = { version = "2", features = ["r2d2", "postgres", "chrono"] }
|
||||||
diesel_migrations = "2"
|
diesel_migrations = "2"
|
||||||
dotenvy = "*"
|
dotenvy = "*"
|
||||||
env_logger = "0.10"
|
|
||||||
hmac = "0.12"
|
hmac = "0.12"
|
||||||
log = "0.4"
|
|
||||||
reqwest = { version = "0.11", features = ["blocking", "json"] }
|
|
||||||
sha2 = "0.10"
|
sha2 = "0.10"
|
||||||
lazy_static = "1"
|
lazy_static = "1"
|
||||||
jsonwebtoken = "9"
|
jsonwebtoken = "9"
|
||||||
serde = "1"
|
serde = "1"
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
actix-service = "2.0.2"
|
|
||||||
|
|
|
@ -34,99 +34,3 @@ BEGIN
|
||||||
RETURN NEW;
|
RETURN NEW;
|
||||||
END;
|
END;
|
||||||
$$ LANGUAGE plpgsql;
|
$$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
-- nanoid function
|
|
||||||
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
|
||||||
|
|
||||||
-- The `nanoid()` function generates a compact, URL-friendly unique identifier.
|
|
||||||
-- Based on the given size and alphabet, it creates a randomized string that's ideal for
|
|
||||||
-- use-cases requiring small, unpredictable IDs (e.g., URL shorteners, generated file names, etc.).
|
|
||||||
-- While it comes with a default configuration, the function is designed to be flexible,
|
|
||||||
-- allowing for customization to meet specific needs.
|
|
||||||
DROP FUNCTION IF EXISTS nanoid(int, text, float);
|
|
||||||
CREATE OR REPLACE FUNCTION nanoid(
|
|
||||||
size int DEFAULT 24, -- The number of symbols in the NanoId String. Must be greater than 0.
|
|
||||||
alphabet text DEFAULT '_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', -- The symbols used in the NanoId String. Must contain between 1 and 255 symbols.
|
|
||||||
additionalBytesFactor float DEFAULT 1.6 -- The additional bytes factor used for calculating the step size. Must be equal or greater then 1.
|
|
||||||
)
|
|
||||||
RETURNS text -- A randomly generated NanoId String
|
|
||||||
LANGUAGE plpgsql
|
|
||||||
VOLATILE
|
|
||||||
LEAKPROOF
|
|
||||||
PARALLEL SAFE
|
|
||||||
AS
|
|
||||||
$$
|
|
||||||
DECLARE
|
|
||||||
alphabetArray text[];
|
|
||||||
alphabetLength int := 64;
|
|
||||||
mask int := 63;
|
|
||||||
step int := 34;
|
|
||||||
BEGIN
|
|
||||||
IF size IS NULL OR size < 1 THEN
|
|
||||||
RAISE EXCEPTION 'The size must be defined and greater than 0!';
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
IF alphabet IS NULL OR length(alphabet) = 0 OR length(alphabet) > 255 THEN
|
|
||||||
RAISE EXCEPTION 'The alphabet can''t be undefined, zero or bigger than 255 symbols!';
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
IF additionalBytesFactor IS NULL OR additionalBytesFactor < 1 THEN
|
|
||||||
RAISE EXCEPTION 'The additional bytes factor can''t be less than 1!';
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
alphabetArray := regexp_split_to_array(alphabet, '');
|
|
||||||
alphabetLength := array_length(alphabetArray, 1);
|
|
||||||
mask := (2 << cast(floor(log(alphabetLength - 1) / log(2)) as int)) - 1;
|
|
||||||
step := cast(ceil(additionalBytesFactor * mask * size / alphabetLength) AS int);
|
|
||||||
|
|
||||||
IF step > 1024 THEN
|
|
||||||
step := 1024; -- The step size % can''t be bigger then 1024!
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
RETURN nanoid_optimized(size, alphabet, mask, step);
|
|
||||||
END
|
|
||||||
$$;
|
|
||||||
|
|
||||||
-- Generates an optimized random string of a specified size using the given alphabet, mask, and step.
|
|
||||||
-- This optimized version is designed for higher performance and lower memory overhead.
|
|
||||||
-- No checks are performed! Use it only if you really know what you are doing.
|
|
||||||
DROP FUNCTION IF EXISTS nanoid_optimized(int, text, int, int);
|
|
||||||
CREATE OR REPLACE FUNCTION nanoid_optimized(
|
|
||||||
size int, -- The desired length of the generated string.
|
|
||||||
alphabet text, -- The set of characters to choose from for generating the string.
|
|
||||||
mask int, -- The mask used for mapping random bytes to alphabet indices. Should be `(2^n) - 1` where `n` is a power of 2 less than or equal to the alphabet size.
|
|
||||||
step int -- The number of random bytes to generate in each iteration. A larger value may speed up the function but increase memory usage.
|
|
||||||
)
|
|
||||||
RETURNS text -- A randomly generated NanoId String
|
|
||||||
LANGUAGE plpgsql
|
|
||||||
VOLATILE
|
|
||||||
LEAKPROOF
|
|
||||||
PARALLEL SAFE
|
|
||||||
AS
|
|
||||||
$$
|
|
||||||
DECLARE
|
|
||||||
idBuilder text := '';
|
|
||||||
counter int := 0;
|
|
||||||
bytes bytea;
|
|
||||||
alphabetIndex int;
|
|
||||||
alphabetArray text[];
|
|
||||||
alphabetLength int := 64;
|
|
||||||
BEGIN
|
|
||||||
alphabetArray := regexp_split_to_array(alphabet, '');
|
|
||||||
alphabetLength := array_length(alphabetArray, 1);
|
|
||||||
|
|
||||||
LOOP
|
|
||||||
bytes := gen_random_bytes(step);
|
|
||||||
FOR counter IN 0..step - 1
|
|
||||||
LOOP
|
|
||||||
alphabetIndex := (get_byte(bytes, counter) & mask) + 1;
|
|
||||||
IF alphabetIndex <= alphabetLength THEN
|
|
||||||
idBuilder := idBuilder || alphabetArray[alphabetIndex];
|
|
||||||
IF length(idBuilder) = size THEN
|
|
||||||
RETURN idBuilder;
|
|
||||||
END IF;
|
|
||||||
END IF;
|
|
||||||
END LOOP;
|
|
||||||
END LOOP;
|
|
||||||
END
|
|
||||||
$$;
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ create table if not exists users
|
||||||
password text not null,
|
password text not null,
|
||||||
|
|
||||||
updated_at timestamp,
|
updated_at timestamp,
|
||||||
created_at timestamp default now(),
|
created_at timestamp default now() not null,
|
||||||
|
|
||||||
primary key (id)
|
primary key (id)
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,16 +1,12 @@
|
||||||
create type playlist_type as enum ('playlist', 'folder');
|
|
||||||
|
|
||||||
create table if not exists playlists
|
create table if not exists playlists
|
||||||
(
|
(
|
||||||
id varchar(24) default nanoid(24),
|
id varchar(24) default nanoid(24),
|
||||||
name varchar(255) not null,
|
name varchar(255) not null,
|
||||||
public bool default false not null,
|
public bool default false,
|
||||||
type playlist_type default 'playlist' not null,
|
|
||||||
|
|
||||||
creator_id varchar(24) not null,
|
creator_id varchar(24) not null,
|
||||||
parent_id varchar(24) references playlists (id) on delete set null,
|
|
||||||
|
|
||||||
created_at timestamp default now(),
|
created_at timestamp default now() not null,
|
||||||
updated_at timestamp,
|
updated_at timestamp,
|
||||||
|
|
||||||
primary key (id),
|
primary key (id),
|
||||||
|
|
|
@ -5,11 +5,11 @@ create table if not exists tracks
|
||||||
title varchar(255) not null,
|
title varchar(255) not null,
|
||||||
duration_ms int not null default 0,
|
duration_ms int not null default 0,
|
||||||
|
|
||||||
created_at timestamp default now(),
|
created_at timestamp default now() not null,
|
||||||
updated_at timestamp,
|
updated_at timestamp,
|
||||||
|
|
||||||
-- music services
|
-- music services
|
||||||
spotify_id varchar(22) unique,
|
spotify_id varchar(21) unique,
|
||||||
tidal_id varchar(10) unique,
|
tidal_id varchar(10) unique,
|
||||||
|
|
||||||
primary key (id)
|
primary key (id)
|
||||||
|
|
|
@ -2,6 +2,5 @@ create table if not exists playlists_tracks
|
||||||
(
|
(
|
||||||
playlist_id varchar(24) references playlists (id) on delete cascade,
|
playlist_id varchar(24) references playlists (id) on delete cascade,
|
||||||
track_id varchar(24) references tracks (id) on delete cascade,
|
track_id varchar(24) references tracks (id) on delete cascade,
|
||||||
added_at timestamp default now() not null,
|
|
||||||
primary key (playlist_id, track_id)
|
primary key (playlist_id, track_id)
|
||||||
);
|
);
|
||||||
|
|
|
@ -3,14 +3,13 @@ create table if not exists artists
|
||||||
(
|
(
|
||||||
id varchar(24) default nanoid(24),
|
id varchar(24) default nanoid(24),
|
||||||
name varchar(255) NOT NULL,
|
name varchar(255) NOT NULL,
|
||||||
slug varchar unique not null generated always as (lower(replace(name, ' ', '-'))) stored,
|
|
||||||
|
|
||||||
created_at timestamp default now(),
|
created_at TIMESTAMP DEFAULT now() NOT NULL,
|
||||||
updated_at timestamp,
|
updated_at TIMESTAMP,
|
||||||
|
|
||||||
-- music services
|
-- music services
|
||||||
spotify_id varchar(22) unique,
|
spotify_id VARCHAR(21) UNIQUE,
|
||||||
tidal_id varchar(10) unique,
|
tidal_id VARCHAR(10) UNIQUE,
|
||||||
|
|
||||||
primary key (id)
|
primary key (id)
|
||||||
);
|
);
|
||||||
|
|
|
@ -16,7 +16,6 @@ lazy_static! {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
log::info!("Initializing db pool.");
|
|
||||||
lazy_static::initialize(&POOL);
|
lazy_static::initialize(&POOL);
|
||||||
let _conn = connection().expect("Failed to get db connection.");
|
let _conn = connection().expect("Failed to get db connection.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use jsonwebtoken::{decode, DecodingKey, EncodingKey, TokenData, Validation};
|
||||||
const JWT_SECRET: &str = "secret";
|
const JWT_SECRET: &str = "secret";
|
||||||
|
|
||||||
pub fn get_token(token: &str) -> Result<TokenData<JWTClaims>, Error> {
|
pub fn get_token(token: &str) -> Result<TokenData<JWTClaims>, Error> {
|
||||||
let token = decode::<JWTClaims>(token, &get_decoding_key(), &Validation::default())?;
|
let token = decode::<JWTClaims>(&token, &get_decoding_key(), &Validation::default())?;
|
||||||
Ok(token)
|
Ok(token)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
17
src/main.rs
17
src/main.rs
|
@ -5,32 +5,23 @@ mod middlewares;
|
||||||
mod models;
|
mod models;
|
||||||
mod routes;
|
mod routes;
|
||||||
mod schema;
|
mod schema;
|
||||||
mod services;
|
|
||||||
mod utils;
|
|
||||||
|
|
||||||
use crate::helpers::db;
|
use crate::helpers::db;
|
||||||
|
use actix_web::{web, App, HttpServer};
|
||||||
|
|
||||||
#[actix_web::main]
|
#[actix_web::main]
|
||||||
async fn main() -> std::io::Result<()> {
|
async fn main() -> std::io::Result<()> {
|
||||||
use actix_web::{App, HttpServer};
|
|
||||||
|
|
||||||
dotenvy::dotenv().expect("No .env file found");
|
dotenvy::dotenv().expect("No .env file found");
|
||||||
env_logger::init();
|
std::env::set_var("RUST_LOG", "debug");
|
||||||
|
|
||||||
// Register services.
|
|
||||||
let _ = services::spotify::instance().await;
|
|
||||||
|
|
||||||
db::init();
|
db::init();
|
||||||
|
|
||||||
HttpServer::new(move || {
|
HttpServer::new(move || {
|
||||||
App::new()
|
App::new()
|
||||||
.service(routes::auth::routes())
|
.service(web::scope("/playlists").service(routes::playlists::get_playlist))
|
||||||
// .wrap(middlewares::auth::auth())
|
.service(routes::auth::login)
|
||||||
.service(routes::playlists::routes())
|
|
||||||
.service(routes::me::routes())
|
.service(routes::me::routes())
|
||||||
.service(routes::import::routes())
|
|
||||||
.service(routes::users::routes())
|
.service(routes::users::routes())
|
||||||
.service(routes::search::routes())
|
|
||||||
})
|
})
|
||||||
.bind(("127.0.0.1", 9000))?
|
.bind(("127.0.0.1", 9000))?
|
||||||
.run()
|
.run()
|
||||||
|
|
|
@ -9,15 +9,6 @@ pub struct ErrorResponse {
|
||||||
pub status: StatusCode,
|
pub status: StatusCode,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ErrorResponse {
|
|
||||||
pub fn new(message: &str, status: StatusCode) -> Self {
|
|
||||||
ErrorResponse {
|
|
||||||
message: message.to_string(),
|
|
||||||
status,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for ErrorResponse {
|
impl Display for ErrorResponse {
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||||
write!(f, "{}: {}", self.status, self.message)
|
write!(f, "{}: {}", self.status, self.message)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::helpers::jwt::get_token;
|
use crate::helpers::jwt::get_token;
|
||||||
use crate::middlewares::error::ErrorResponse;
|
use crate::middlewares::error::ErrorResponse;
|
||||||
use crate::models::users::Users;
|
use crate::models::user::Users;
|
||||||
use actix_web::http::{header, StatusCode};
|
use actix_web::http::{header, StatusCode};
|
||||||
use actix_web::HttpRequest;
|
use actix_web::HttpRequest;
|
||||||
|
|
||||||
|
@ -19,29 +19,23 @@ pub fn get_user(req: HttpRequest) -> Result<Users, ErrorResponse> {
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Err(match e.kind() {
|
return Err(match e.kind() {
|
||||||
jsonwebtoken::errors::ErrorKind::ExpiredSignature => {
|
jsonwebtoken::errors::ErrorKind::ExpiredSignature => ErrorResponse {
|
||||||
ErrorResponse::new("Not Authorized", StatusCode::UNAUTHORIZED)
|
message: "Not Authorized".to_string(),
|
||||||
}
|
status: StatusCode::UNAUTHORIZED,
|
||||||
_ => ErrorResponse::new(
|
},
|
||||||
e.to_string().as_str(),
|
_ => ErrorResponse {
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
message: e.to_string(),
|
||||||
),
|
status: StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => Err(ErrorResponse::new(
|
None => {
|
||||||
"Not Authorized",
|
return Err(ErrorResponse {
|
||||||
StatusCode::UNAUTHORIZED,
|
message: "Not Authorized".to_string(),
|
||||||
)),
|
status: StatusCode::UNAUTHORIZED,
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_user_option(req: HttpRequest) -> Option<Users> {
|
|
||||||
let user = get_user(req);
|
|
||||||
|
|
||||||
match user {
|
|
||||||
Ok(user) => Some(user),
|
|
||||||
Err(_) => None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +1,33 @@
|
||||||
use crate::helpers::db;
|
use crate::helpers::db;
|
||||||
use crate::schema::{artists, artists_tracks};
|
use crate::schema::{artists, artists_tracks};
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
use diesel::prelude::*;
|
|
||||||
use diesel::result::Error;
|
use diesel::result::Error;
|
||||||
|
use diesel::{
|
||||||
|
AsChangeset, ExpressionMethods, Insertable, QueryDsl, Queryable, RunQueryDsl, Selectable,
|
||||||
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(AsChangeset, Identifiable, Insertable, Queryable, Selectable, Deserialize, Serialize)]
|
#[derive(AsChangeset, Insertable, Queryable, Selectable, Deserialize, Serialize)]
|
||||||
#[diesel(table_name = artists)]
|
#[diesel(table_name = crate::schema::artists)]
|
||||||
pub struct Artists {
|
#[diesel(check_for_backend(diesel::pg::Pg))]
|
||||||
|
pub struct Artist {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub slug: String,
|
|
||||||
|
|
||||||
pub created_at: Option<NaiveDateTime>,
|
created_at: NaiveDateTime,
|
||||||
pub updated_at: Option<NaiveDateTime>,
|
updated_at: Option<NaiveDateTime>,
|
||||||
|
|
||||||
pub spotify_id: Option<String>,
|
pub spotify_id: Option<String>,
|
||||||
pub tidal_id: Option<String>,
|
pub tidal_id: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Insertable, Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Queryable, Serialize)]
|
||||||
#[diesel(table_name = artists)]
|
pub struct Artists {
|
||||||
pub struct NewArtist {
|
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub name: String,
|
pub title: String,
|
||||||
|
|
||||||
|
created_at: NaiveDateTime,
|
||||||
|
updated_at: Option<NaiveDateTime>,
|
||||||
|
|
||||||
pub spotify_id: Option<String>,
|
pub spotify_id: Option<String>,
|
||||||
pub tidal_id: Option<String>,
|
pub tidal_id: Option<String>,
|
||||||
|
@ -32,14 +36,14 @@ pub struct NewArtist {
|
||||||
impl Artists {
|
impl Artists {
|
||||||
pub fn find(id: String) -> Result<Self, Error> {
|
pub fn find(id: String) -> Result<Self, Error> {
|
||||||
let conn = &mut db::connection()?;
|
let conn = &mut db::connection()?;
|
||||||
let artist = artists::table.filter(artists::id.eq(id)).first(conn)?;
|
let playlist = artists::table.filter(artists::id.eq(id)).first(conn)?;
|
||||||
Ok(artist)
|
Ok(playlist)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create(artist: NewArtist) -> Result<Self, Error> {
|
pub fn create(artist: Artist) -> Result<Self, Error> {
|
||||||
let conn = &mut db::connection()?;
|
let conn = &mut db::connection()?;
|
||||||
let playlist = diesel::insert_into(artists::table)
|
let playlist = diesel::insert_into(artists::table)
|
||||||
.values(artist)
|
.values(Artist::from(artist))
|
||||||
.get_result(conn)?;
|
.get_result(conn)?;
|
||||||
Ok(playlist)
|
Ok(playlist)
|
||||||
}
|
}
|
||||||
|
@ -58,3 +62,18 @@ impl Artists {
|
||||||
Ok(artists)
|
Ok(artists)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Artist {
|
||||||
|
fn from(artist: Artist) -> Artist {
|
||||||
|
Artist {
|
||||||
|
id: artist.id,
|
||||||
|
name: artist.name,
|
||||||
|
|
||||||
|
created_at: artist.created_at,
|
||||||
|
updated_at: artist.updated_at,
|
||||||
|
|
||||||
|
spotify_id: artist.spotify_id,
|
||||||
|
tidal_id: artist.tidal_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
use diesel::prelude::*;
|
|
||||||
use diesel::result::Error;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::helpers::db;
|
|
||||||
|
|
||||||
use super::artists::Artists;
|
|
||||||
use super::tracks::Tracks;
|
|
||||||
|
|
||||||
use crate::schema::{artists, artists_tracks, tracks};
|
|
||||||
|
|
||||||
#[derive(Identifiable, Selectable, Queryable, Associations, Debug)]
|
|
||||||
#[diesel(belongs_to(Artists, foreign_key = artist_id))]
|
|
||||||
#[diesel(belongs_to(Tracks, foreign_key = track_id))]
|
|
||||||
#[diesel(table_name = artists_tracks)]
|
|
||||||
#[diesel(primary_key(artist_id, track_id))]
|
|
||||||
pub struct ArtistTracks {
|
|
||||||
pub artist_id: String,
|
|
||||||
pub track_id: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ArtistTracks {
|
|
||||||
pub fn get_tracks(artist: &Artists) -> Result<Vec<Tracks>, Error> {
|
|
||||||
let conn = &mut db::connection()?;
|
|
||||||
let track_ids = ArtistTracks::belonging_to(artist).select(artists_tracks::track_id);
|
|
||||||
|
|
||||||
let tracks: Vec<Tracks> = tracks::table
|
|
||||||
.filter(tracks::id.eq_any(track_ids))
|
|
||||||
.load::<Tracks>(conn)?;
|
|
||||||
|
|
||||||
Ok(tracks)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_artists(track: &Tracks) -> Result<Vec<TrackArtist>, Error> {
|
|
||||||
let conn = &mut db::connection()?;
|
|
||||||
let artist_ids = ArtistTracks::belonging_to(track).select(artists_tracks::artist_id);
|
|
||||||
|
|
||||||
let artists = artists::table
|
|
||||||
.select((artists::id, artists::name))
|
|
||||||
.filter(artists::id.eq_any(artist_ids))
|
|
||||||
.load::<TrackArtist>(conn)?;
|
|
||||||
|
|
||||||
Ok(artists)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, Queryable)]
|
|
||||||
#[diesel(table_name = artists)]
|
|
||||||
pub struct TrackArtist {
|
|
||||||
pub id: String,
|
|
||||||
pub name: String,
|
|
||||||
}
|
|
|
@ -1,7 +1,4 @@
|
||||||
pub mod artists;
|
pub mod artists;
|
||||||
pub mod artists_tracks;
|
|
||||||
pub mod playlists;
|
pub mod playlists;
|
||||||
pub mod playlists_tracks;
|
|
||||||
pub mod spotify;
|
|
||||||
pub mod tracks;
|
pub mod tracks;
|
||||||
pub mod users;
|
pub mod user;
|
||||||
|
|
|
@ -1,45 +1,45 @@
|
||||||
use crate::helpers::db;
|
use crate::helpers::db;
|
||||||
use crate::schema::{playlists, playlists_tracks};
|
use crate::models::tracks::{Track, Tracks, TracksWithArtists};
|
||||||
|
use crate::models::user::Users;
|
||||||
|
use crate::schema::playlists;
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
use diesel::{prelude::*, result::Error};
|
use diesel::result::Error;
|
||||||
|
use diesel::{
|
||||||
|
AsChangeset, ExpressionMethods, Insertable, QueryDsl, Queryable, RunQueryDsl, Selectable,
|
||||||
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::artists_tracks::{ArtistTracks, TrackArtist};
|
#[derive(Serialize, Deserialize)]
|
||||||
use super::{playlists_tracks::PlaylistTracks, tracks::Tracks, users::Users};
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
|
||||||
pub struct PlaylistCreator {
|
pub struct PlaylistCreator {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(
|
#[derive(AsChangeset, Insertable, Queryable, Selectable, Deserialize, Serialize)]
|
||||||
AsChangeset, Debug, Deserialize, Identifiable, Queryable, Selectable, Serialize, PartialEq,
|
#[diesel(table_name = crate::schema::playlists)]
|
||||||
)]
|
#[diesel(belongs_to(Users))]
|
||||||
#[diesel(table_name = playlists)]
|
#[diesel(check_for_backend(diesel::pg::Pg))]
|
||||||
|
pub struct Playlist {
|
||||||
|
pub id: String,
|
||||||
|
pub name: String,
|
||||||
|
pub public: bool,
|
||||||
|
pub creator_id: String,
|
||||||
|
|
||||||
|
pub created_at: NaiveDateTime,
|
||||||
|
pub updated_at: Option<NaiveDateTime>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Queryable, Serialize)]
|
||||||
pub struct Playlists {
|
pub struct Playlists {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub public: bool,
|
pub public: bool,
|
||||||
|
|
||||||
pub playlist_type: String,
|
|
||||||
pub parent_id: Option<String>,
|
|
||||||
|
|
||||||
pub creator_id: String,
|
pub creator_id: String,
|
||||||
|
|
||||||
pub created_at: Option<NaiveDateTime>,
|
pub created_at: NaiveDateTime,
|
||||||
pub updated_at: Option<NaiveDateTime>,
|
pub updated_at: Option<NaiveDateTime>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Insertable)]
|
|
||||||
#[diesel(table_name = playlists)]
|
|
||||||
pub struct NewPlaylist {
|
|
||||||
pub name: String,
|
|
||||||
pub public: bool,
|
|
||||||
// pub playlist_type: String,
|
|
||||||
pub creator_id: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Playlists {
|
impl Playlists {
|
||||||
pub fn find(id: &str) -> Result<Self, Error> {
|
pub fn find(id: &str) -> Result<Self, Error> {
|
||||||
let conn = &mut db::connection()?;
|
let conn = &mut db::connection()?;
|
||||||
|
@ -59,26 +59,23 @@ impl Playlists {
|
||||||
let conn = &mut db::connection()?;
|
let conn = &mut db::connection()?;
|
||||||
|
|
||||||
let mut playlists = playlists::table
|
let mut playlists = playlists::table
|
||||||
.distinct()
|
|
||||||
.select(Playlists::as_select())
|
|
||||||
.order((playlists::playlist_type.desc(), playlists::parent_id.desc()))
|
|
||||||
.filter(playlists::creator_id.eq(user_id))
|
.filter(playlists::creator_id.eq(user_id))
|
||||||
.into_boxed();
|
.into_boxed();
|
||||||
|
|
||||||
if filter_public {
|
if filter_public {
|
||||||
playlists = playlists.filter(
|
playlists = playlists.filter(playlists::public.eq(true));
|
||||||
playlists::public
|
|
||||||
.eq(true)
|
|
||||||
.and(playlists::playlist_type.ne("folder")),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let playlists = playlists.get_results(conn)?;
|
let playlists = playlists.get_results(conn)?;
|
||||||
Ok(playlists)
|
Ok(playlists)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_tracks(&self) -> Result<Vec<PlaylistTrack>, Error> {
|
pub fn get_tracks(&self) -> Result<Vec<TracksWithArtists>, Error> {
|
||||||
let tracks: Vec<PlaylistTrack> = PlaylistTracks::get_tracks(self)?;
|
let tracks = Tracks::find_by_playlist(&self.id)?;
|
||||||
|
let tracks: Vec<TracksWithArtists> = tracks
|
||||||
|
.into_iter()
|
||||||
|
.map(Track::with_artists)
|
||||||
|
.collect::<Result<Vec<TracksWithArtists>, _>>()?;
|
||||||
|
|
||||||
Ok(tracks)
|
Ok(tracks)
|
||||||
}
|
}
|
||||||
|
@ -87,69 +84,34 @@ impl Playlists {
|
||||||
let creator = Users::find(&self.creator_id)?;
|
let creator = Users::find(&self.creator_id)?;
|
||||||
Ok(creator)
|
Ok(creator)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_data(&self, tracks: &[PlaylistTrack]) -> (usize, usize) {
|
#[derive(Debug, Insertable, Deserialize)]
|
||||||
if tracks.is_empty() {
|
#[diesel(table_name = playlists)]
|
||||||
return (0, 0);
|
pub struct NewPlaylist {
|
||||||
|
pub name: String,
|
||||||
|
pub public: bool,
|
||||||
|
pub creator_id: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Playlist {
|
||||||
|
pub fn create(name: &str, public: bool, creator_id: &str) -> NewPlaylist {
|
||||||
|
NewPlaylist {
|
||||||
|
name: name.to_string(),
|
||||||
|
public,
|
||||||
|
creator_id: Some(creator_id.to_string()),
|
||||||
}
|
}
|
||||||
|
|
||||||
let duration = tracks
|
|
||||||
.iter()
|
|
||||||
.map(|track| track.duration_ms)
|
|
||||||
.reduce(|a, b| a + b)
|
|
||||||
.unwrap() as usize;
|
|
||||||
|
|
||||||
(duration, tracks.len())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn can_see(&self, creator: Option<Users>) -> bool {
|
fn from(playlist: Playlist) -> Playlist {
|
||||||
self.public || creator.map_or(false, |user| user.id == self.creator_id)
|
Playlist {
|
||||||
}
|
id: playlist.id,
|
||||||
}
|
name: playlist.name,
|
||||||
|
public: playlist.public,
|
||||||
|
creator_id: playlist.creator_id,
|
||||||
|
|
||||||
// // Folder
|
created_at: playlist.created_at,
|
||||||
// struct Folder {
|
updated_at: playlist.updated_at,
|
||||||
// id: String,
|
|
||||||
// name: String,
|
|
||||||
// playlists: Vec<Playlists>,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// impl Folder {
|
|
||||||
// pub fn get_playlists(&self) -> Result<Vec<Playlists>, Error> {
|
|
||||||
// let playlists = playlists::table
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
|
||||||
pub struct PlaylistTrack {
|
|
||||||
pub id: String,
|
|
||||||
pub title: String,
|
|
||||||
pub duration_ms: i32,
|
|
||||||
|
|
||||||
pub artists: Vec<TrackArtist>,
|
|
||||||
pub added_at: NaiveDateTime,
|
|
||||||
pub spotify_id: Option<String>,
|
|
||||||
pub tidal_id: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Tracks> for PlaylistTrack {
|
|
||||||
fn from(track: Tracks) -> Self {
|
|
||||||
let artists = ArtistTracks::get_artists(&track).unwrap();
|
|
||||||
|
|
||||||
let added_at = playlists_tracks::table
|
|
||||||
.filter(playlists_tracks::track_id.eq(&track.id))
|
|
||||||
.select(playlists_tracks::added_at)
|
|
||||||
.first::<NaiveDateTime>(&mut db::connection().unwrap())
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
PlaylistTrack {
|
|
||||||
id: track.id,
|
|
||||||
title: track.title,
|
|
||||||
duration_ms: track.duration_ms,
|
|
||||||
artists,
|
|
||||||
added_at,
|
|
||||||
spotify_id: track.spotify_id,
|
|
||||||
tidal_id: track.tidal_id,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
use diesel::prelude::*;
|
|
||||||
use diesel::result::Error;
|
|
||||||
|
|
||||||
use crate::helpers::db;
|
|
||||||
|
|
||||||
use super::playlists::{PlaylistTrack, Playlists};
|
|
||||||
use super::tracks::Tracks;
|
|
||||||
|
|
||||||
use crate::schema::{playlists_tracks, tracks};
|
|
||||||
|
|
||||||
#[derive(Identifiable, Selectable, Queryable, Associations, Debug)]
|
|
||||||
#[diesel(belongs_to(Playlists, foreign_key = playlist_id))]
|
|
||||||
#[diesel(belongs_to(Tracks, foreign_key = track_id))]
|
|
||||||
#[diesel(table_name = playlists_tracks)]
|
|
||||||
#[diesel(primary_key(playlist_id, track_id))]
|
|
||||||
pub struct PlaylistTracks {
|
|
||||||
pub playlist_id: String,
|
|
||||||
pub track_id: String,
|
|
||||||
pub added_at: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PlaylistTracks {
|
|
||||||
pub fn get_tracks(playlist: &Playlists) -> Result<Vec<PlaylistTrack>, Error> {
|
|
||||||
let conn = &mut db::connection()?;
|
|
||||||
let track_ids = PlaylistTracks::belonging_to(playlist).select(playlists_tracks::track_id);
|
|
||||||
|
|
||||||
let tracks: Vec<Tracks> = tracks::table
|
|
||||||
.filter(tracks::id.eq_any(track_ids))
|
|
||||||
.load::<Tracks>(conn)?;
|
|
||||||
|
|
||||||
let tracks = tracks
|
|
||||||
.into_iter()
|
|
||||||
.map(PlaylistTrack::from)
|
|
||||||
.collect::<Vec<PlaylistTrack>>();
|
|
||||||
|
|
||||||
Ok(tracks)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
|
||||||
pub struct Track {
|
|
||||||
pub id: String,
|
|
||||||
pub name: String,
|
|
||||||
pub duration_ms: i32,
|
|
||||||
pub artists: Vec<Artist>,
|
|
||||||
pub album: Album,
|
|
||||||
|
|
||||||
pub external_ids: ExternalIds,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
|
||||||
pub struct ExternalIds {
|
|
||||||
pub isrc: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
|
||||||
pub struct Artist {
|
|
||||||
pub id: String,
|
|
||||||
pub name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
|
||||||
pub struct Album {
|
|
||||||
pub id: String,
|
|
||||||
pub name: String,
|
|
||||||
pub artists: Vec<Artist>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
|
||||||
pub struct APISearchResponse {
|
|
||||||
pub albums: APISearchItems<Album>,
|
|
||||||
pub artists: APISearchItems<Artist>,
|
|
||||||
pub tracks: APISearchItems<Track>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
|
||||||
pub struct APISearchItems<T> {
|
|
||||||
pub items: Vec<T>,
|
|
||||||
}
|
|
|
@ -1,34 +1,39 @@
|
||||||
use crate::helpers::db;
|
use crate::helpers::db;
|
||||||
use crate::models::{artists::Artists, spotify};
|
use crate::models::artists::Artists;
|
||||||
use crate::schema::{playlists_tracks, tracks};
|
use crate::schema::tracks;
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
use diesel::prelude::*;
|
|
||||||
use diesel::result::Error;
|
use diesel::result::Error;
|
||||||
|
use diesel::{
|
||||||
|
AsChangeset, ExpressionMethods, Insertable, QueryDsl, Queryable, RunQueryDsl, Selectable,
|
||||||
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(
|
use crate::schema::playlists_tracks;
|
||||||
AsChangeset, Debug, Deserialize, Serialize, Queryable, Identifiable, Selectable, Clone,
|
|
||||||
)]
|
#[derive(AsChangeset, Insertable, Queryable, Selectable, Deserialize, Serialize)]
|
||||||
#[diesel(table_name = tracks)]
|
#[diesel(table_name = crate::schema::tracks)]
|
||||||
pub struct Tracks {
|
#[diesel(check_for_backend(diesel::pg::Pg))]
|
||||||
|
pub struct Track {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub title: String,
|
pub title: String,
|
||||||
pub duration_ms: i32,
|
pub duration_ms: i32,
|
||||||
|
|
||||||
pub created_at: Option<NaiveDateTime>,
|
pub created_at: NaiveDateTime,
|
||||||
pub updated_at: Option<NaiveDateTime>,
|
pub updated_at: Option<NaiveDateTime>,
|
||||||
|
|
||||||
pub spotify_id: Option<String>,
|
pub spotify_id: Option<String>,
|
||||||
pub tidal_id: Option<String>,
|
pub tidal_id: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(AsChangeset, Clone, Debug, Deserialize, Insertable)]
|
#[derive(Debug, Deserialize, Queryable, Serialize)]
|
||||||
#[diesel(table_name = tracks)]
|
pub struct Tracks {
|
||||||
pub struct NewTrack {
|
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub title: String,
|
pub title: String,
|
||||||
pub duration_ms: i32,
|
pub duration_ms: i32,
|
||||||
|
|
||||||
|
pub created_at: NaiveDateTime,
|
||||||
|
pub updated_at: Option<NaiveDateTime>,
|
||||||
|
|
||||||
pub spotify_id: Option<String>,
|
pub spotify_id: Option<String>,
|
||||||
pub tidal_id: Option<String>,
|
pub tidal_id: Option<String>,
|
||||||
}
|
}
|
||||||
|
@ -40,29 +45,51 @@ impl Tracks {
|
||||||
Ok(playlist)
|
Ok(playlist)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create(track: NewTrack) -> Result<Self, Error> {
|
pub fn create(track: Track) -> Result<Self, Error> {
|
||||||
let conn = &mut db::connection()?;
|
let conn = &mut db::connection()?;
|
||||||
let playlist = diesel::insert_into(tracks::table)
|
let playlist = diesel::insert_into(tracks::table)
|
||||||
.values(track)
|
.values(Track::from(track))
|
||||||
.get_result(conn)?;
|
.get_result(conn)?;
|
||||||
Ok(playlist)
|
Ok(playlist)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_or_update(track: NewTrack) -> Result<Self, Error> {
|
pub fn find_by_playlist(playlist_id: &str) -> Result<Vec<Tracks>, Error> {
|
||||||
let conn = &mut db::connection()?;
|
let conn = &mut db::connection()?;
|
||||||
let playlist = diesel::insert_into(tracks::table)
|
let tracks: Vec<(String, String)> = playlists_tracks::table
|
||||||
.values(track.clone())
|
.filter(playlists_tracks::playlist_id.eq(playlist_id))
|
||||||
.on_conflict(tracks::id)
|
.get_results::<(String, String)>(conn)?;
|
||||||
.do_update()
|
|
||||||
.set(track)
|
let tracks = tracks
|
||||||
.get_result(conn)?;
|
.into_iter()
|
||||||
Ok(playlist)
|
.map(|(playlist_id, track_id)| {
|
||||||
|
println!("{}: {}", playlist_id, track_id);
|
||||||
|
Tracks::find(track_id).unwrap()
|
||||||
|
})
|
||||||
|
.collect::<Vec<Tracks>>();
|
||||||
|
|
||||||
|
Ok(tracks)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_artists(&self) -> Result<Vec<Artists>, Error> {
|
pub fn get_artists(&self) -> Result<Vec<Artists>, Error> {
|
||||||
let artists = Artists::find_by_track(&self.id)?;
|
let artists = Artists::find_by_track(&self.id)?;
|
||||||
Ok(artists)
|
Ok(artists)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Track {
|
||||||
|
fn from(track: Track) -> Track {
|
||||||
|
Track {
|
||||||
|
id: track.id,
|
||||||
|
title: track.title,
|
||||||
|
duration_ms: track.duration_ms,
|
||||||
|
|
||||||
|
created_at: track.created_at,
|
||||||
|
updated_at: track.updated_at,
|
||||||
|
|
||||||
|
spotify_id: track.spotify_id,
|
||||||
|
tidal_id: track.tidal_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn with_artists(track: Tracks) -> Result<TracksWithArtists, Error> {
|
pub fn with_artists(track: Tracks) -> Result<TracksWithArtists, Error> {
|
||||||
let artists = track.get_artists()?;
|
let artists = track.get_artists()?;
|
||||||
|
@ -80,20 +107,6 @@ impl Tracks {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<spotify::Track> for Tracks {
|
|
||||||
fn from(value: spotify::Track) -> Tracks {
|
|
||||||
Tracks {
|
|
||||||
id: value.external_ids.isrc,
|
|
||||||
title: value.name,
|
|
||||||
duration_ms: value.duration_ms,
|
|
||||||
spotify_id: Some(value.id),
|
|
||||||
tidal_id: None,
|
|
||||||
created_at: None,
|
|
||||||
updated_at: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub struct TracksWithArtists {
|
pub struct TracksWithArtists {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
|
|
|
@ -11,6 +11,18 @@ use serde::{Deserialize, Serialize};
|
||||||
#[derive(AsChangeset, Insertable, Queryable, Selectable, Deserialize, Serialize)]
|
#[derive(AsChangeset, Insertable, Queryable, Selectable, Deserialize, Serialize)]
|
||||||
#[diesel(table_name = crate::schema::users)]
|
#[diesel(table_name = crate::schema::users)]
|
||||||
#[diesel(check_for_backend(diesel::pg::Pg))]
|
#[diesel(check_for_backend(diesel::pg::Pg))]
|
||||||
|
pub struct User {
|
||||||
|
pub id: String,
|
||||||
|
pub name: String,
|
||||||
|
pub email: String,
|
||||||
|
|
||||||
|
pub password: String,
|
||||||
|
|
||||||
|
pub updated_at: Option<NaiveDateTime>,
|
||||||
|
pub created_at: NaiveDateTime,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Queryable, Serialize)]
|
||||||
pub struct Users {
|
pub struct Users {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
@ -18,8 +30,8 @@ pub struct Users {
|
||||||
|
|
||||||
pub password: String,
|
pub password: String,
|
||||||
|
|
||||||
pub created_at: Option<NaiveDateTime>,
|
|
||||||
pub updated_at: Option<NaiveDateTime>,
|
pub updated_at: Option<NaiveDateTime>,
|
||||||
|
pub created_at: NaiveDateTime,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Users {
|
impl Users {
|
||||||
|
@ -29,6 +41,14 @@ impl Users {
|
||||||
Ok(user)
|
Ok(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn create(user: User) -> Result<Self, Error> {
|
||||||
|
let conn = &mut db::connection()?;
|
||||||
|
let user = diesel::insert_into(users::table)
|
||||||
|
.values(User::from(user))
|
||||||
|
.get_result(conn)?;
|
||||||
|
Ok(user)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn find_by_email(email: &str) -> Result<Self, Error> {
|
pub fn find_by_email(email: &str) -> Result<Self, Error> {
|
||||||
let conn = &mut db::connection()?;
|
let conn = &mut db::connection()?;
|
||||||
let user = users::table.filter(users::email.eq(email)).first(conn)?;
|
let user = users::table.filter(users::email.eq(email)).first(conn)?;
|
||||||
|
@ -39,3 +59,16 @@ impl Users {
|
||||||
bcrypt::verify(password, hash)
|
bcrypt::verify(password, hash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl User {
|
||||||
|
fn from(user: User) -> User {
|
||||||
|
User {
|
||||||
|
id: user.id,
|
||||||
|
name: user.name,
|
||||||
|
email: user.email,
|
||||||
|
password: user.password,
|
||||||
|
created_at: user.created_at,
|
||||||
|
updated_at: user.updated_at,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,28 +1,24 @@
|
||||||
use crate::helpers::jwt::get_encoding_key;
|
use crate::helpers::jwt::get_encoding_key;
|
||||||
use crate::middlewares::error::ErrorResponse;
|
use crate::middlewares::error::ErrorResponse;
|
||||||
use crate::models::users::Users;
|
use crate::models::user::Users;
|
||||||
use actix_web::http::StatusCode;
|
use actix_web::http::StatusCode;
|
||||||
use actix_web::{post, web, HttpResponse, Scope};
|
use actix_web::{post, web, HttpResponse};
|
||||||
use chrono::{Days, Utc};
|
use chrono::{Days, Utc};
|
||||||
use jsonwebtoken::{encode, Header};
|
use jsonwebtoken::{encode, Header};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub fn routes() -> Scope {
|
|
||||||
web::scope("/auth").service(login)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
pub struct JWTClaims {
|
pub struct JWTClaims {
|
||||||
pub user_id: String,
|
pub user_id: String,
|
||||||
pub exp: i64,
|
pub exp: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/login")]
|
#[post("/auth/login")]
|
||||||
async fn login(body: web::Json<LoginBody>) -> Result<HttpResponse, ErrorResponse> {
|
async fn login(body: web::Json<LoginBody>) -> Result<HttpResponse, ErrorResponse> {
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
struct Response {
|
struct Response {
|
||||||
access_token: String,
|
access_token: String,
|
||||||
exp: i64,
|
exp: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
let user = Users::find_by_email(&body.email);
|
let user = Users::find_by_email(&body.email);
|
||||||
|
@ -36,24 +32,28 @@ async fn login(body: web::Json<LoginBody>) -> Result<HttpResponse, ErrorResponse
|
||||||
|
|
||||||
let claims = JWTClaims {
|
let claims = JWTClaims {
|
||||||
user_id: user.id.to_string(),
|
user_id: user.id.to_string(),
|
||||||
exp,
|
exp: exp as usize,
|
||||||
};
|
};
|
||||||
let token = encode(&Header::default(), &claims, &get_encoding_key()).unwrap();
|
let token = encode(&Header::default(), &claims, &get_encoding_key()).unwrap();
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(Response {
|
Ok(HttpResponse::Ok().json(Response {
|
||||||
access_token: token,
|
access_token: token,
|
||||||
exp,
|
exp: exp as usize,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
Err(_e) => Err(ErrorResponse::new(
|
Err(_e) => {
|
||||||
"Invalid credentials",
|
return Err(ErrorResponse {
|
||||||
StatusCode::BAD_REQUEST,
|
message: "Invalid credentials.".to_string(),
|
||||||
)),
|
status: StatusCode::BAD_REQUEST,
|
||||||
|
})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Err(_err) => Err(ErrorResponse::new(
|
Err(_err) => {
|
||||||
"Invalid credentials",
|
return Err(ErrorResponse {
|
||||||
StatusCode::BAD_REQUEST,
|
message: "Invalid credentials.".to_string(),
|
||||||
)),
|
status: StatusCode::BAD_REQUEST,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
use actix_web::{get, web, HttpResponse, Result, Scope};
|
|
||||||
|
|
||||||
use crate::middlewares::error::ErrorResponse;
|
|
||||||
|
|
||||||
pub fn routes() -> Scope {
|
|
||||||
web::scope("/import")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[get("/spotify/{playlist_id}")]
|
|
||||||
async fn import_spotify() -> Result<HttpResponse, ErrorResponse> {
|
|
||||||
Ok(HttpResponse::Ok().finish())
|
|
||||||
}
|
|
|
@ -1,7 +1,6 @@
|
||||||
use crate::middlewares::error::ErrorResponse;
|
use crate::middlewares::error::ErrorResponse;
|
||||||
use crate::middlewares::user::get_user;
|
use crate::middlewares::user::get_user;
|
||||||
use crate::models::playlists::{NewPlaylist, PlaylistCreator, Playlists};
|
use crate::models::playlists::{NewPlaylist, Playlists};
|
||||||
use crate::routes::playlists::GetPlaylistResponse;
|
|
||||||
use actix_web::{get, post, web, HttpRequest, HttpResponse, Scope};
|
use actix_web::{get, post, web, HttpRequest, HttpResponse, Scope};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
|
@ -34,32 +33,14 @@ async fn me(req: HttpRequest) -> Result<HttpResponse, ErrorResponse> {
|
||||||
async fn me_playlists(req: HttpRequest) -> Result<HttpResponse, ErrorResponse> {
|
async fn me_playlists(req: HttpRequest) -> Result<HttpResponse, ErrorResponse> {
|
||||||
let user = get_user(req)?;
|
let user = get_user(req)?;
|
||||||
|
|
||||||
let playlists = Playlists::find_for_user(&user.id, false)?;
|
#[derive(Serialize)]
|
||||||
let playlists = playlists
|
struct Response {
|
||||||
.into_iter()
|
playlists: Vec<Playlists>,
|
||||||
.map(|playlist| {
|
}
|
||||||
let creator = playlist.get_creator().unwrap();
|
|
||||||
|
|
||||||
let tracks = playlist.get_tracks().unwrap();
|
Ok(HttpResponse::Ok().json(Response {
|
||||||
let (duration, tracks_count) = playlist.get_data(&tracks);
|
playlists: Playlists::find_for_user(&user.id, false)?,
|
||||||
|
}))
|
||||||
GetPlaylistResponse {
|
|
||||||
id: playlist.id.to_string(),
|
|
||||||
name: playlist.name.to_string(),
|
|
||||||
playlist_type: playlist.playlist_type.to_string(),
|
|
||||||
parent_id: playlist.parent_id,
|
|
||||||
creator: PlaylistCreator {
|
|
||||||
id: creator.id,
|
|
||||||
name: creator.name,
|
|
||||||
},
|
|
||||||
tracks,
|
|
||||||
tracks_count,
|
|
||||||
duration,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<GetPlaylistResponse>>();
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(playlists))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/playlists")]
|
#[post("/playlists")]
|
||||||
|
@ -69,7 +50,7 @@ async fn create_playlist(
|
||||||
) -> Result<HttpResponse, ErrorResponse> {
|
) -> Result<HttpResponse, ErrorResponse> {
|
||||||
let user = get_user(req)?;
|
let user = get_user(req)?;
|
||||||
|
|
||||||
playlist.creator_id = user.id;
|
playlist.creator_id = Option::from(user.id);
|
||||||
|
|
||||||
Playlists::create(playlist.into_inner())?;
|
Playlists::create(playlist.into_inner())?;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
pub mod auth;
|
pub mod auth;
|
||||||
pub mod import;
|
|
||||||
pub mod me;
|
pub mod me;
|
||||||
pub mod playlists;
|
pub mod playlists;
|
||||||
pub mod search;
|
|
||||||
pub mod users;
|
pub mod users;
|
||||||
|
|
|
@ -1,51 +1,37 @@
|
||||||
use crate::middlewares::error::ErrorResponse;
|
use crate::middlewares::error::ErrorResponse;
|
||||||
use crate::middlewares::user::get_user_option;
|
use crate::models::playlists::{PlaylistCreator, Playlists};
|
||||||
use crate::models::playlists::{PlaylistCreator, PlaylistTrack, Playlists};
|
use crate::models::tracks::TracksWithArtists;
|
||||||
use actix_web::{get, web, HttpRequest, HttpResponse, Scope};
|
use actix_web::{get, web, HttpResponse};
|
||||||
use reqwest::StatusCode;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub fn routes() -> Scope {
|
|
||||||
web::scope("/playlists").service(get_playlist)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub struct GetPlaylistResponse {
|
struct GetPlaylistResponse {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub playlist_type: String,
|
|
||||||
pub parent_id: Option<String>,
|
|
||||||
pub creator: PlaylistCreator,
|
pub creator: PlaylistCreator,
|
||||||
pub tracks: Vec<PlaylistTrack>,
|
pub tracks: Vec<TracksWithArtists>,
|
||||||
pub tracks_count: usize,
|
pub tracks_count: usize,
|
||||||
pub duration: usize,
|
pub duration: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/{playlist_id}")]
|
#[get("/{playlist_id}")]
|
||||||
async fn get_playlist(
|
pub async fn get_playlist(path: web::Path<String>) -> Result<HttpResponse, ErrorResponse> {
|
||||||
req: HttpRequest,
|
|
||||||
path: web::Path<String>,
|
|
||||||
) -> Result<HttpResponse, ErrorResponse> {
|
|
||||||
let playlist_id = path.into_inner();
|
let playlist_id = path.into_inner();
|
||||||
let playlist = Playlists::find(playlist_id.as_str())?;
|
let playlist = Playlists::find(playlist_id.as_str())?;
|
||||||
|
|
||||||
if !playlist.can_see(get_user_option(req)) {
|
|
||||||
return Err(ErrorResponse::new(
|
|
||||||
"Playlist not found",
|
|
||||||
StatusCode::NOT_FOUND,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let creator = playlist.get_creator()?;
|
let creator = playlist.get_creator()?;
|
||||||
|
|
||||||
let tracks = playlist.get_tracks()?;
|
let tracks = playlist.get_tracks()?;
|
||||||
let (duration, tracks_count) = playlist.get_data(&tracks);
|
let tracks_count = tracks.len();
|
||||||
|
let duration = tracks
|
||||||
|
.iter()
|
||||||
|
.map(|track| track.duration_ms)
|
||||||
|
.reduce(|a, b| a + b)
|
||||||
|
.unwrap() as usize;
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(GetPlaylistResponse {
|
Ok(HttpResponse::Ok().json(GetPlaylistResponse {
|
||||||
id: playlist.id.to_string(),
|
id: playlist.id.to_string(),
|
||||||
name: playlist.name.to_string(),
|
name: playlist.name.to_string(),
|
||||||
playlist_type: playlist.playlist_type.to_string(),
|
|
||||||
parent_id: playlist.parent_id,
|
|
||||||
creator: PlaylistCreator {
|
creator: PlaylistCreator {
|
||||||
id: creator.id,
|
id: creator.id,
|
||||||
name: creator.name,
|
name: creator.name,
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
use crate::middlewares::error::ErrorResponse;
|
|
||||||
use crate::models::spotify;
|
|
||||||
use crate::services::spotify as Spotify;
|
|
||||||
use actix_web::{get, web, HttpResponse, Result, Scope};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
pub fn routes() -> Scope {
|
|
||||||
web::scope("/search").service(search)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct SearchQuery {
|
|
||||||
q: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize)]
|
|
||||||
struct SearchResponse {
|
|
||||||
tracks: Vec<SearchTracks>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize)]
|
|
||||||
struct SearchTracks {
|
|
||||||
pub id: String,
|
|
||||||
pub title: String,
|
|
||||||
// pub artists: String,
|
|
||||||
pub duration_ms: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<spotify::Track> for SearchTracks {
|
|
||||||
fn from(value: spotify::Track) -> SearchTracks {
|
|
||||||
SearchTracks {
|
|
||||||
id: value.id,
|
|
||||||
title: value.name,
|
|
||||||
duration_ms: value.duration_ms,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[get("")]
|
|
||||||
async fn search(query: web::Query<SearchQuery>) -> Result<HttpResponse, ErrorResponse> {
|
|
||||||
let spotify = Spotify::instance().await;
|
|
||||||
let search = spotify.search(&query.q).await.unwrap();
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(SearchResponse {
|
|
||||||
tracks: search
|
|
||||||
.tracks
|
|
||||||
.items
|
|
||||||
.into_iter()
|
|
||||||
.map(SearchTracks::from)
|
|
||||||
.collect::<Vec<SearchTracks>>(),
|
|
||||||
}))
|
|
||||||
}
|
|
|
@ -1,9 +1,6 @@
|
||||||
use crate::middlewares::error::ErrorResponse;
|
use crate::middlewares::error::ErrorResponse;
|
||||||
use crate::models::{
|
use crate::models::playlists::Playlists;
|
||||||
playlists::{PlaylistCreator, Playlists},
|
use crate::models::user::Users;
|
||||||
users::Users,
|
|
||||||
};
|
|
||||||
use crate::routes::playlists::GetPlaylistResponse;
|
|
||||||
use actix_web::http::StatusCode;
|
use actix_web::http::StatusCode;
|
||||||
use actix_web::{get, web, HttpResponse, Result, Scope};
|
use actix_web::{get, web, HttpResponse, Result, Scope};
|
||||||
use diesel::result::Error as DBError;
|
use diesel::result::Error as DBError;
|
||||||
|
@ -27,11 +24,18 @@ fn get_a_user(user_id: &str) -> Result<Users, ErrorResponse> {
|
||||||
|
|
||||||
match user {
|
match user {
|
||||||
Ok(user) => Ok(user),
|
Ok(user) => Ok(user),
|
||||||
Err(DBError::NotFound) => Err(ErrorResponse::new("User not found", StatusCode::NOT_FOUND)),
|
Err(DBError::NotFound) => {
|
||||||
_ => Err(ErrorResponse::new(
|
return Err(ErrorResponse {
|
||||||
"Unknown error",
|
message: "User not found".to_string(),
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
status: StatusCode::NOT_FOUND,
|
||||||
)),
|
})
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(ErrorResponse {
|
||||||
|
message: "Unknown error".to_string(),
|
||||||
|
status: StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,29 +56,6 @@ async fn get_user_playlists(path: web::Path<String>) -> Result<HttpResponse, Err
|
||||||
let user = get_a_user(&path.into_inner())?;
|
let user = get_a_user(&path.into_inner())?;
|
||||||
|
|
||||||
let playlists = Playlists::find_for_user(&user.id, true)?;
|
let playlists = Playlists::find_for_user(&user.id, true)?;
|
||||||
let playlists = playlists
|
|
||||||
.into_iter()
|
|
||||||
.map(|playlist| {
|
|
||||||
let creator = playlist.get_creator().unwrap();
|
|
||||||
|
|
||||||
let tracks = playlist.get_tracks().unwrap();
|
|
||||||
let (duration, tracks_count) = playlist.get_data(&tracks);
|
|
||||||
|
|
||||||
GetPlaylistResponse {
|
|
||||||
id: playlist.id.to_string(),
|
|
||||||
name: playlist.name.to_string(),
|
|
||||||
playlist_type: playlist.playlist_type.to_string(),
|
|
||||||
parent_id: playlist.parent_id,
|
|
||||||
creator: PlaylistCreator {
|
|
||||||
id: creator.id,
|
|
||||||
name: creator.name,
|
|
||||||
},
|
|
||||||
tracks,
|
|
||||||
tracks_count,
|
|
||||||
duration,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<GetPlaylistResponse>>();
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().json(playlists))
|
Ok(HttpResponse::Ok().json(playlists))
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,9 @@ diesel::table! {
|
||||||
id -> Varchar,
|
id -> Varchar,
|
||||||
#[max_length = 255]
|
#[max_length = 255]
|
||||||
name -> Varchar,
|
name -> Varchar,
|
||||||
slug -> Varchar,
|
created_at -> Timestamp,
|
||||||
created_at -> Nullable<Timestamp>,
|
|
||||||
updated_at -> Nullable<Timestamp>,
|
updated_at -> Nullable<Timestamp>,
|
||||||
#[max_length = 22]
|
#[max_length = 21]
|
||||||
spotify_id -> Nullable<Varchar>,
|
spotify_id -> Nullable<Varchar>,
|
||||||
#[max_length = 10]
|
#[max_length = 10]
|
||||||
tidal_id -> Nullable<Varchar>,
|
tidal_id -> Nullable<Varchar>,
|
||||||
|
@ -33,12 +32,8 @@ diesel::table! {
|
||||||
name -> Varchar,
|
name -> Varchar,
|
||||||
public -> Bool,
|
public -> Bool,
|
||||||
#[max_length = 24]
|
#[max_length = 24]
|
||||||
playlist_type -> Varchar,
|
|
||||||
#[max_length = 24]
|
|
||||||
parent_id -> Nullable<Varchar>,
|
|
||||||
#[max_length = 24]
|
|
||||||
creator_id -> Varchar,
|
creator_id -> Varchar,
|
||||||
created_at -> Nullable<Timestamp>,
|
created_at -> Timestamp,
|
||||||
updated_at -> Nullable<Timestamp>,
|
updated_at -> Nullable<Timestamp>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,7 +44,6 @@ diesel::table! {
|
||||||
playlist_id -> Varchar,
|
playlist_id -> Varchar,
|
||||||
#[max_length = 24]
|
#[max_length = 24]
|
||||||
track_id -> Varchar,
|
track_id -> Varchar,
|
||||||
added_at -> Timestamp,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,9 +54,9 @@ diesel::table! {
|
||||||
#[max_length = 255]
|
#[max_length = 255]
|
||||||
title -> Varchar,
|
title -> Varchar,
|
||||||
duration_ms -> Int4,
|
duration_ms -> Int4,
|
||||||
created_at -> Nullable<Timestamp>,
|
created_at -> Timestamp,
|
||||||
updated_at -> Nullable<Timestamp>,
|
updated_at -> Nullable<Timestamp>,
|
||||||
#[max_length = 22]
|
#[max_length = 21]
|
||||||
spotify_id -> Nullable<Varchar>,
|
spotify_id -> Nullable<Varchar>,
|
||||||
#[max_length = 10]
|
#[max_length = 10]
|
||||||
tidal_id -> Nullable<Varchar>,
|
tidal_id -> Nullable<Varchar>,
|
||||||
|
@ -79,7 +73,7 @@ diesel::table! {
|
||||||
email -> Varchar,
|
email -> Varchar,
|
||||||
password -> Text,
|
password -> Text,
|
||||||
updated_at -> Nullable<Timestamp>,
|
updated_at -> Nullable<Timestamp>,
|
||||||
created_at -> Nullable<Timestamp>,
|
created_at -> Timestamp,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
mod service;
|
|
||||||
pub mod spotify;
|
|
|
@ -1,11 +0,0 @@
|
||||||
use async_trait::async_trait;
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
pub trait Service: Send + Sync {
|
|
||||||
fn get_token(&self) -> &String;
|
|
||||||
|
|
||||||
async fn fetch_token(&mut self);
|
|
||||||
// async fn get_track_by_isrc(&self, isrc: &str);
|
|
||||||
|
|
||||||
fn is_expired(&self) -> bool;
|
|
||||||
}
|
|
|
@ -1,129 +0,0 @@
|
||||||
use crate::{models::spotify::APISearchResponse, services::service::Service, utils::get_env};
|
|
||||||
use actix_web::http::Method;
|
|
||||||
use async_trait::async_trait;
|
|
||||||
use chrono::{Duration, Utc};
|
|
||||||
use lazy_static::lazy_static;
|
|
||||||
use reqwest::{Client, RequestBuilder};
|
|
||||||
use serde::Deserialize;
|
|
||||||
use std::sync::Mutex;
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct SpotifyResponse {
|
|
||||||
access_token: String,
|
|
||||||
expires_in: i64,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Spotify {
|
|
||||||
token: String,
|
|
||||||
expires_at: i64,
|
|
||||||
}
|
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
static ref SPOTIFY_INSTANCE: Mutex<Spotify> = Mutex::new(Spotify::new());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn instance() -> Spotify {
|
|
||||||
let mut spotify = SPOTIFY_INSTANCE.lock().unwrap().clone();
|
|
||||||
|
|
||||||
// Fetch token if expired
|
|
||||||
spotify.fetch_token().await;
|
|
||||||
|
|
||||||
spotify
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Spotify {
|
|
||||||
pub fn new() -> Spotify {
|
|
||||||
Spotify {
|
|
||||||
token: String::new(),
|
|
||||||
expires_at: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn api(&self, url: &str, method: Method) -> RequestBuilder {
|
|
||||||
let client = Client::new();
|
|
||||||
|
|
||||||
client
|
|
||||||
.request(method, format!("https://api.spotify.com/v1{url}"))
|
|
||||||
.bearer_auth(self.get_token())
|
|
||||||
}
|
|
||||||
|
|
||||||
// pub async fn get_track(self, spotify_id: &str) {
|
|
||||||
// let spotify = &SPOTIFY;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub async fn get_artist(self, spotify_id: &str) {}
|
|
||||||
|
|
||||||
// pub async fn get_track_by_isrc(self, isrc: &str) {}
|
|
||||||
|
|
||||||
pub async fn search(&self, search: &str) -> Result<APISearchResponse, ()> {
|
|
||||||
let response = self
|
|
||||||
.api("/search", Method::GET)
|
|
||||||
.query(&[("q", search), ("type", "album,artist,track")])
|
|
||||||
.send()
|
|
||||||
.await;
|
|
||||||
|
|
||||||
match response {
|
|
||||||
Ok(res) => {
|
|
||||||
let data = res.json::<APISearchResponse>().await;
|
|
||||||
|
|
||||||
match data {
|
|
||||||
Ok(data) => Ok(data),
|
|
||||||
Err(_) => {
|
|
||||||
panic!("Invalid response (Spotify Search)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
panic!("Invalid response (Spotify Search)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl Service for Spotify {
|
|
||||||
fn get_token(&self) -> &String {
|
|
||||||
&self.token
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_expired(&self) -> bool {
|
|
||||||
self.expires_at < chrono::Utc::now().timestamp()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn fetch_token(&mut self) {
|
|
||||||
if !self.is_expired() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let response = Client::new()
|
|
||||||
.post("https://accounts.spotify.com/api/token")
|
|
||||||
.basic_auth(
|
|
||||||
get_env("SPOTIFY_CLIENT_ID"),
|
|
||||||
Some(get_env("SPOTIFY_CLIENT_SECRET")),
|
|
||||||
)
|
|
||||||
.form(&[("grant_type", "client_credentials")])
|
|
||||||
.send()
|
|
||||||
.await;
|
|
||||||
|
|
||||||
match response {
|
|
||||||
Ok(res) => {
|
|
||||||
let data = res.json::<SpotifyResponse>().await;
|
|
||||||
|
|
||||||
match data {
|
|
||||||
Ok(data) => {
|
|
||||||
self.token = data.access_token;
|
|
||||||
self.expires_at =
|
|
||||||
(Utc::now() + Duration::seconds(data.expires_in)).timestamp();
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
panic!("Invalid response (Spotify Token)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
panic!("Invalid response (Spotify Token)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
pub fn get_env(key: &str) -> String {
|
|
||||||
std::env::var(key).unwrap()
|
|
||||||
}
|
|
Loading…
Reference in a new issue