custviwe
This commit is contained in:
parent
8a044653f7
commit
877a374f97
|
@ -72,7 +72,7 @@ dependencies = [
|
||||||
"actix-service",
|
"actix-service",
|
||||||
"actix-utils",
|
"actix-utils",
|
||||||
"ahash 0.8.3",
|
"ahash 0.8.3",
|
||||||
"base64",
|
"base64 0.21.2",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"brotli",
|
"brotli",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
@ -91,7 +91,7 @@ dependencies = [
|
||||||
"mime",
|
"mime",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"rand",
|
"rand 0.8.5",
|
||||||
"sha1",
|
"sha1",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
@ -281,7 +281,7 @@ version = "0.7.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
|
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom 0.2.10",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
@ -293,7 +293,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
|
checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"getrandom",
|
"getrandom 0.2.10",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
@ -322,6 +322,27 @@ dependencies = [
|
||||||
"alloc-no-stdlib",
|
"alloc-no-stdlib",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "android-tzdata"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "android_system_properties"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyhow"
|
||||||
|
version = "1.0.71"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arc-bytes"
|
name = "arc-bytes"
|
||||||
version = "0.3.5"
|
version = "0.3.5"
|
||||||
|
@ -356,6 +377,43 @@ version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
|
checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-channel"
|
||||||
|
version = "1.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833"
|
||||||
|
dependencies = [
|
||||||
|
"concurrent-queue",
|
||||||
|
"event-listener",
|
||||||
|
"futures-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-stripe"
|
||||||
|
version = "0.22.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b313de0d654c4c4c46faa737b2257ce9ed79e69926aa4c734b9816be20102b2c"
|
||||||
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
|
"futures-util",
|
||||||
|
"hex",
|
||||||
|
"hmac 0.12.1",
|
||||||
|
"http-types",
|
||||||
|
"hyper",
|
||||||
|
"hyper-tls",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serde_path_to_error",
|
||||||
|
"serde_qs 0.10.1",
|
||||||
|
"sha2 0.10.7",
|
||||||
|
"smart-default",
|
||||||
|
"smol_str",
|
||||||
|
"thiserror",
|
||||||
|
"time-core",
|
||||||
|
"tokio",
|
||||||
|
"uuid",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-trait"
|
name = "async-trait"
|
||||||
version = "0.1.68"
|
version = "0.1.68"
|
||||||
|
@ -422,6 +480,12 @@ dependencies = [
|
||||||
"rustc-demangle",
|
"rustc-demangle",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.21.2"
|
version = "0.21.2"
|
||||||
|
@ -562,7 +626,7 @@ dependencies = [
|
||||||
"p256",
|
"p256",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"pot",
|
"pot",
|
||||||
"rand",
|
"rand 0.8.5",
|
||||||
"region",
|
"region",
|
||||||
"serde",
|
"serde",
|
||||||
"sysinfo",
|
"sysinfo",
|
||||||
|
@ -683,6 +747,19 @@ dependencies = [
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chrono"
|
||||||
|
version = "0.4.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5"
|
||||||
|
dependencies = [
|
||||||
|
"android-tzdata",
|
||||||
|
"iana-time-zone",
|
||||||
|
"num-traits",
|
||||||
|
"serde",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cipher"
|
name = "cipher"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
|
@ -756,6 +833,15 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "concurrent-queue"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "const-oid"
|
name = "const-oid"
|
||||||
version = "0.6.2"
|
version = "0.6.2"
|
||||||
|
@ -785,6 +871,16 @@ dependencies = [
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-foundation"
|
||||||
|
version = "0.9.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation-sys"
|
name = "core-foundation-sys"
|
||||||
version = "0.8.4"
|
version = "0.8.4"
|
||||||
|
@ -874,7 +970,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f83bd3bb4314701c568e340cd8cf78c975aa0ca79e03d3f6d1677d5b0c9c0c03"
|
checksum = "f83bd3bb4314701c568e340cd8cf78c975aa0ca79e03d3f6d1677d5b0c9c0c03"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"generic-array",
|
"generic-array",
|
||||||
"rand_core",
|
"rand_core 0.6.4",
|
||||||
"subtle",
|
"subtle",
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
@ -1010,7 +1106,7 @@ checksum = "43ee23aa5b4f68c7a092b5c3beb25f50c406adc75e2363634f242f28ab255372"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"der",
|
"der",
|
||||||
"elliptic-curve",
|
"elliptic-curve",
|
||||||
"hmac",
|
"hmac 0.11.0",
|
||||||
"signature",
|
"signature",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1031,7 +1127,7 @@ dependencies = [
|
||||||
"generic-array",
|
"generic-array",
|
||||||
"group",
|
"group",
|
||||||
"pkcs8",
|
"pkcs8",
|
||||||
"rand_core",
|
"rand_core 0.6.4",
|
||||||
"subtle",
|
"subtle",
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
@ -1045,19 +1141,49 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "errno"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
|
||||||
|
dependencies = [
|
||||||
|
"errno-dragonfly",
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "errno-dragonfly"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "event-listener"
|
name = "event-listener"
|
||||||
version = "2.5.3"
|
version = "2.5.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fastrand"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
|
||||||
|
dependencies = [
|
||||||
|
"instant",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ff"
|
name = "ff"
|
||||||
version = "0.10.1"
|
version = "0.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f"
|
checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand_core",
|
"rand_core 0.6.4",
|
||||||
"subtle",
|
"subtle",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1090,6 +1216,21 @@ 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.0"
|
version = "1.2.0"
|
||||||
|
@ -1147,6 +1288,21 @@ version = "0.3.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
|
checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-lite"
|
||||||
|
version = "1.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce"
|
||||||
|
dependencies = [
|
||||||
|
"fastrand",
|
||||||
|
"futures-core",
|
||||||
|
"futures-io",
|
||||||
|
"memchr",
|
||||||
|
"parking",
|
||||||
|
"pin-project-lite",
|
||||||
|
"waker-fn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-macro"
|
name = "futures-macro"
|
||||||
version = "0.3.28"
|
version = "0.3.28"
|
||||||
|
@ -1199,6 +1355,17 @@ dependencies = [
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.1.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"wasi 0.9.0+wasi-snapshot-preview1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.10"
|
version = "0.2.10"
|
||||||
|
@ -1208,7 +1375,7 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1241,7 +1408,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1c363a5301b8f153d80747126a04b3c82073b9fe3130571a9d170cacdeaf7912"
|
checksum = "1c363a5301b8f153d80747126a04b3c82073b9fe3130571a9d170cacdeaf7912"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ff",
|
"ff",
|
||||||
"rand_core",
|
"rand_core 0.6.4",
|
||||||
"subtle",
|
"subtle",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1303,6 +1470,18 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hkdf"
|
name = "hkdf"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
|
@ -1310,7 +1489,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "01706d578d5c281058480e673ae4086a9f4710d8df1ad80a5b03e39ece5f886b"
|
checksum = "01706d578d5c281058480e673ae4086a9f4710d8df1ad80a5b03e39ece5f886b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"digest 0.9.0",
|
"digest 0.9.0",
|
||||||
"hmac",
|
"hmac 0.11.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1323,6 +1502,15 @@ dependencies = [
|
||||||
"digest 0.9.0",
|
"digest 0.9.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hmac"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
|
||||||
|
dependencies = [
|
||||||
|
"digest 0.10.7",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hpke"
|
name = "hpke"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
|
@ -1338,7 +1526,7 @@ dependencies = [
|
||||||
"hkdf",
|
"hkdf",
|
||||||
"p256",
|
"p256",
|
||||||
"paste",
|
"paste",
|
||||||
"rand_core",
|
"rand_core 0.6.4",
|
||||||
"serde",
|
"serde",
|
||||||
"sha2 0.9.9",
|
"sha2 0.9.9",
|
||||||
"subtle",
|
"subtle",
|
||||||
|
@ -1356,6 +1544,38 @@ dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "http-body"
|
||||||
|
version = "0.4.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"http",
|
||||||
|
"pin-project-lite",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "http-types"
|
||||||
|
version = "2.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6e9b187a72d63adbfba487f48095306ac823049cb504ee195541e91c7775f5ad"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"async-channel",
|
||||||
|
"base64 0.13.1",
|
||||||
|
"futures-lite",
|
||||||
|
"http",
|
||||||
|
"infer",
|
||||||
|
"pin-project-lite",
|
||||||
|
"rand 0.7.3",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serde_qs 0.8.5",
|
||||||
|
"serde_urlencoded",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "httparse"
|
name = "httparse"
|
||||||
version = "1.8.0"
|
version = "1.8.0"
|
||||||
|
@ -1368,6 +1588,66 @@ version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
|
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper"
|
||||||
|
version = "0.14.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4"
|
||||||
|
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]]
|
||||||
|
name = "iana-time-zone"
|
||||||
|
version = "0.1.57"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613"
|
||||||
|
dependencies = [
|
||||||
|
"android_system_properties",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"iana-time-zone-haiku",
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"windows",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iana-time-zone-haiku"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ident_case"
|
name = "ident_case"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
|
@ -1394,6 +1674,32 @@ dependencies = [
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "infer"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "64e9829a50b42bb782c1df523f78d332fe371b10c661e78b7a3c34b0198e9fac"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "instant"
|
||||||
|
version = "0.1.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "io-lifetimes"
|
||||||
|
version = "1.0.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi 0.3.1",
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.10.5"
|
version = "0.10.5"
|
||||||
|
@ -1445,12 +1751,19 @@ version = "0.2.146"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
|
checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linux-raw-sys"
|
||||||
|
version = "0.3.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lmspos"
|
name = "lmspos"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-cors",
|
"actix-cors",
|
||||||
"actix-web",
|
"actix-web",
|
||||||
|
"async-stripe",
|
||||||
"bonsaidb",
|
"bonsaidb",
|
||||||
"log",
|
"log",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -1565,7 +1878,7 @@ checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"wasi",
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1575,7 +1888,25 @@ version = "0.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3"
|
checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom 0.2.10",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[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]]
|
||||||
|
@ -1655,6 +1986,50 @@ version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl"
|
||||||
|
version = "0.10.54"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "69b3f656a17a6cbc115b5c7a40c616947d213ba182135b014d6051b73ab6f019"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"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.18",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[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.88"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c2ce0f250f34a308dcfdbb351f511359857d4ed2134ba715a4eadd46e1ffd617"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"pkg-config",
|
||||||
|
"vcpkg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ordered-varint"
|
name = "ordered-varint"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
|
@ -1684,6 +2059,12 @@ dependencies = [
|
||||||
"sha2 0.9.9",
|
"sha2 0.9.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "14f2252c834a40ed9bb5422029649578e63aa341ac401f74e719dd1afda8394e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
|
@ -1714,7 +2095,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700"
|
checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64ct",
|
"base64ct",
|
||||||
"rand_core",
|
"rand_core 0.6.4",
|
||||||
"subtle",
|
"subtle",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1874,6 +2255,19 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.7.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.1.16",
|
||||||
|
"libc",
|
||||||
|
"rand_chacha 0.2.2",
|
||||||
|
"rand_core 0.5.1",
|
||||||
|
"rand_hc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.8.5"
|
version = "0.8.5"
|
||||||
|
@ -1881,8 +2275,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"rand_chacha",
|
"rand_chacha 0.3.1",
|
||||||
"rand_core",
|
"rand_core 0.6.4",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86",
|
||||||
|
"rand_core 0.5.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1892,7 +2296,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ppv-lite86",
|
"ppv-lite86",
|
||||||
"rand_core",
|
"rand_core 0.6.4",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.1.16",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1901,7 +2314,16 @@ version = "0.6.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom 0.2.10",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_hc"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core 0.5.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1979,18 +2401,64 @@ dependencies = [
|
||||||
"semver",
|
"semver",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustix"
|
||||||
|
version = "0.37.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"errno",
|
||||||
|
"io-lifetimes",
|
||||||
|
"libc",
|
||||||
|
"linux-raw-sys",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.13"
|
version = "1.0.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
|
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "schannel"
|
||||||
|
version = "0.1.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys 0.42.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "security-framework"
|
||||||
|
version = "2.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"core-foundation",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
"security-framework-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "security-framework-sys"
|
||||||
|
version = "2.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "1.0.17"
|
version = "1.0.17"
|
||||||
|
@ -2028,6 +2496,37 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_path_to_error"
|
||||||
|
version = "0.1.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f7f05c1d5476066defcdfacce1f52fc3cae3af1d3089727100c02ae92e5abbe0"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_qs"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c7715380eec75f029a4ef7de39a9200e0a63823176b759d055b613f5a87df6a6"
|
||||||
|
dependencies = [
|
||||||
|
"percent-encoding",
|
||||||
|
"serde",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_qs"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8cac3f1e2ca2fe333923a1ae72caca910b98ed0630bb35ef6f8c8517d6e81afa"
|
||||||
|
dependencies = [
|
||||||
|
"percent-encoding",
|
||||||
|
"serde",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_urlencoded"
|
name = "serde_urlencoded"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
|
@ -2091,7 +2590,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f2807892cfa58e081aa1f1111391c7a0649d4fa127a4ffbe34bcbfb35a1171a4"
|
checksum = "f2807892cfa58e081aa1f1111391c7a0649d4fa127a4ffbe34bcbfb35a1171a4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"digest 0.9.0",
|
"digest 0.9.0",
|
||||||
"rand_core",
|
"rand_core 0.6.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2121,6 +2620,26 @@ version = "1.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
|
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "smart-default"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "133659a15339456eeeb07572eb02a91c91e9815e9cbc89566944d2c8d3efdbf6"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "smol_str"
|
||||||
|
version = "0.1.24"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fad6c857cbab2627dcf01ec85a623ca4e7dcb5691cbaa3d7fb7653671f0d09c9"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
version = "0.4.9"
|
version = "0.4.9"
|
||||||
|
@ -2203,6 +2722,20 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tempfile"
|
||||||
|
version = "3.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"cfg-if",
|
||||||
|
"fastrand",
|
||||||
|
"redox_syscall",
|
||||||
|
"rustix",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "termcolor"
|
name = "termcolor"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
|
@ -2240,9 +2773,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.3.22"
|
version = "0.3.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd"
|
checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"libc",
|
"libc",
|
||||||
|
@ -2254,15 +2787,15 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time-core"
|
name = "time-core"
|
||||||
version = "0.1.1"
|
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 = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
|
checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time-macros"
|
name = "time-macros"
|
||||||
version = "0.2.9"
|
version = "0.2.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b"
|
checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"time-core",
|
"time-core",
|
||||||
]
|
]
|
||||||
|
@ -2312,6 +2845,16 @@ dependencies = [
|
||||||
"syn 2.0.18",
|
"syn 2.0.18",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[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]]
|
||||||
name = "tokio-util"
|
name = "tokio-util"
|
||||||
version = "0.7.8"
|
version = "0.7.8"
|
||||||
|
@ -2343,6 +2886,12 @@ 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.37"
|
version = "0.1.37"
|
||||||
|
@ -2404,6 +2953,12 @@ dependencies = [
|
||||||
"transmog",
|
"transmog",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "try-lock"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "trybuild"
|
name = "trybuild"
|
||||||
version = "1.0.80"
|
version = "1.0.80"
|
||||||
|
@ -2475,14 +3030,51 @@ dependencies = [
|
||||||
"form_urlencoded",
|
"form_urlencoded",
|
||||||
"idna",
|
"idna",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uuid"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.2.10",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vcpkg"
|
||||||
|
version = "0.2.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.4"
|
version = "0.9.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "waker-fn"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "want"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
|
||||||
|
dependencies = [
|
||||||
|
"try-lock",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.9.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
@ -2586,6 +3178,15 @@ version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.42.0"
|
version = "0.42.0"
|
||||||
|
|
|
@ -11,4 +11,5 @@ simple_logger = "4"
|
||||||
actix-web = "4"
|
actix-web = "4"
|
||||||
bonsaidb = { version = "0.4", features = ["local-full"] }
|
bonsaidb = { version = "0.4", features = ["local-full"] }
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
actix-cors = "0.6.4"
|
actix-cors = "0.6.4"
|
||||||
|
async-stripe = { version = "0.22", features = ["runtime-tokio-hyper"] }
|
|
@ -0,0 +1,17 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use bonsaidb::core::schema::Collection;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Collection, Clone)]
|
||||||
|
#[collection(name = "customerviews")]
|
||||||
|
pub struct CustomerView {
|
||||||
|
pub sync_id: String,
|
||||||
|
pub products: HashMap<CustomerViewProductSlice, u64>,
|
||||||
|
pub price_total: f64
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct CustomerViewProductSlice {
|
||||||
|
pub name: String,
|
||||||
|
pub price_usd: u64
|
||||||
|
}
|
|
@ -7,11 +7,20 @@ use serde::{Deserialize, Serialize};
|
||||||
pub struct Order {
|
pub struct Order {
|
||||||
pub order_type: OrderType,
|
pub order_type: OrderType,
|
||||||
pub total_usd: f64,
|
pub total_usd: f64,
|
||||||
pub products: HashMap<u64, u64>
|
pub products: HashMap<u64, u64>,
|
||||||
|
pub stripe_status: StripeStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
pub enum OrderType {
|
pub enum OrderType {
|
||||||
Cash,
|
Cash,
|
||||||
Stripe
|
Stripe
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||||
|
pub enum StripeStatus {
|
||||||
|
SessionCreated,
|
||||||
|
Paid,
|
||||||
|
Failed,
|
||||||
|
NotStripeTransaction
|
||||||
}
|
}
|
|
@ -1,28 +1,38 @@
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use actix_cors::Cors;
|
use actix_cors::Cors;
|
||||||
use actix_web::{App, get, HttpResponse, HttpServer};
|
use actix_web::{App, get, HttpRequest, HttpResponse, HttpServer};
|
||||||
|
use actix_web::http::header::HeaderValue;
|
||||||
use actix_web::web::Data;
|
use actix_web::web::Data;
|
||||||
use bonsaidb::core::schema::Schema;
|
use bonsaidb::core::schema::Schema;
|
||||||
use bonsaidb::local::AsyncDatabase;
|
use bonsaidb::local::AsyncDatabase;
|
||||||
use bonsaidb::local::config::{Builder, StorageConfiguration};
|
use bonsaidb::local::config::{Builder, StorageConfiguration};
|
||||||
|
use stripe::Client;
|
||||||
|
|
||||||
use crate::db_products::Product;
|
use crate::db_products::Product;
|
||||||
use crate::db_orders::Order;
|
use crate::db_orders::Order;
|
||||||
use crate::route_order::{cash_order, get_orders};
|
use crate::error::APIError;
|
||||||
|
use crate::route_customer::{custview_get, custview_push};
|
||||||
|
use crate::db_custview::CustomerView;
|
||||||
|
use crate::route_order::{cash_order, get_order, get_orders, stripe_order};
|
||||||
use crate::route_products::{create_product, delete_product, get_product, get_products, update_product};
|
use crate::route_products::{create_product, delete_product, get_product, get_products, update_product};
|
||||||
|
use crate::route_stripe::{stripe_cancel, stripe_finish};
|
||||||
|
|
||||||
pub mod db_products;
|
pub mod db_products;
|
||||||
pub mod route_products;
|
pub mod route_products;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod route_order;
|
pub mod route_order;
|
||||||
pub mod db_orders;
|
pub mod db_orders;
|
||||||
|
pub mod route_stripe;
|
||||||
|
pub mod db_custview;
|
||||||
|
pub mod route_customer;
|
||||||
|
|
||||||
#[derive(Debug, Schema)]
|
#[derive(Debug, Schema)]
|
||||||
#[schema(name = "lmsposschema", collections = [Product, Order])]
|
#[schema(name = "lmsposschema", collections = [Product, Order, CustomerView])]
|
||||||
pub struct DbSchema;
|
pub struct DbSchema;
|
||||||
|
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
pub db: AsyncDatabase
|
pub db: AsyncDatabase,
|
||||||
|
pub client: Client
|
||||||
}
|
}
|
||||||
|
|
||||||
#[actix_web::main]
|
#[actix_web::main]
|
||||||
|
@ -31,8 +41,11 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
||||||
|
|
||||||
let db = AsyncDatabase::open::<DbSchema>(StorageConfiguration::new("lms.bonsaidb")).await?;
|
let db = AsyncDatabase::open::<DbSchema>(StorageConfiguration::new("lms.bonsaidb")).await?;
|
||||||
|
|
||||||
|
let client = stripe::Client::new("sk_test_51HcdjVJZz7Qxr83OUKOUmzK07dLlpzmbtlUbbxptdGxdXoECKK0BfDo0F89A7A3EFLON8xQDSPxhowVlq0UF2P7000hR3OYha7");
|
||||||
|
|
||||||
let state = Data::new(AppState {
|
let state = Data::new(AppState {
|
||||||
db
|
db,
|
||||||
|
client
|
||||||
});
|
});
|
||||||
|
|
||||||
HttpServer::new(move || {
|
HttpServer::new(move || {
|
||||||
|
@ -47,8 +60,15 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
||||||
.service(status)
|
.service(status)
|
||||||
.service(get_orders)
|
.service(get_orders)
|
||||||
.service(cash_order)
|
.service(cash_order)
|
||||||
|
.service(stripe_order)
|
||||||
|
.service(get_order)
|
||||||
|
.service(stripe_cancel)
|
||||||
|
.service(stripe_finish)
|
||||||
|
.service(auth_status)
|
||||||
|
.service(custview_push)
|
||||||
|
.service(custview_get)
|
||||||
})
|
})
|
||||||
.bind(("127.0.0.1", 8080))?
|
.bind(("0.0.0.0", 8080))?
|
||||||
.run()
|
.run()
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -57,4 +77,12 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
||||||
#[get("/status")]
|
#[get("/status")]
|
||||||
pub async fn status() -> HttpResponse {
|
pub async fn status() -> HttpResponse {
|
||||||
HttpResponse::Ok().body("{\"status\":\"ok\"}")
|
HttpResponse::Ok().body("{\"status\":\"ok\"}")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/auth_status")]
|
||||||
|
pub async fn auth_status(req_info: HttpRequest) -> HttpResponse {
|
||||||
|
if req_info.headers().get("Authorization") != Some(&HeaderValue::from_str("Bearer 65ed1563-b9a3-4923-8f5a-a0ea955adf97").unwrap()) {
|
||||||
|
return HttpResponse::Unauthorized().json(APIError { code: "UNAUTHORIZED".to_string(), message: "Unauthorized".to_string() });
|
||||||
|
}
|
||||||
|
HttpResponse::Ok().body("{\"status\":\"ok\"}")
|
||||||
}
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use actix_web::{get, HttpRequest, HttpResponse, post};
|
||||||
|
use actix_web::http::header::HeaderValue;
|
||||||
|
use actix_web::web::{Data, Json, Path};
|
||||||
|
use bonsaidb::core::Error;
|
||||||
|
use bonsaidb::core::schema::SerializedCollection;
|
||||||
|
use log::debug;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use crate::AppState;
|
||||||
|
use crate::db_custview::{CustomerView, CustomerViewProductSlice};
|
||||||
|
use crate::error::APIError;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct CustviewPushReq {
|
||||||
|
pub sync_id: String,
|
||||||
|
pub products: HashMap<u64, (CustomerViewProductSlice, u64)>,
|
||||||
|
pub price_total: f64
|
||||||
|
}
|
||||||
|
|
||||||
|
#[post("/custview")]
|
||||||
|
pub async fn custview_push(req: Json<CustviewPushReq>, db: Data<AppState>, req_info: HttpRequest) -> HttpResponse {
|
||||||
|
if req_info.headers().get("Authorization") != Some(&HeaderValue::from_str("Bearer 65ed1563-b9a3-4923-8f5a-a0ea955adf97").unwrap()) {
|
||||||
|
return HttpResponse::Unauthorized().json(APIError { code: "UNAUTHORIZED".to_string(), message: "Unauthorized".to_string() });
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut existing_db = match CustomerView::list_async(0.., &db.db).await {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(e) => {
|
||||||
|
return HttpResponse::InternalServerError().json(APIError { code: "DB_ERROR".to_string(), message: e.to_string() })
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut converted_hashmap = HashMap::new();
|
||||||
|
|
||||||
|
for (k, (v, v2)) in &req.products {
|
||||||
|
converted_hashmap.insert(v.clone(), *v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
for maybe_db in &mut existing_db {
|
||||||
|
if maybe_db.contents.sync_id == req.sync_id {
|
||||||
|
let mut definitely_db = maybe_db;
|
||||||
|
definitely_db.contents.products = converted_hashmap.clone();
|
||||||
|
definitely_db.contents.price_total = req.price_total;
|
||||||
|
match definitely_db.update_async(&db.db).await {
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(e) => {
|
||||||
|
return HttpResponse::InternalServerError().json(APIError { code: "DB_ERROR".to_string(), message: e.to_string() })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return HttpResponse::Ok().finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let doc = CustomerView {
|
||||||
|
sync_id: req.sync_id.clone(),
|
||||||
|
products: converted_hashmap.clone(),
|
||||||
|
price_total: req.price_total,
|
||||||
|
};
|
||||||
|
|
||||||
|
match doc.push_into_async(&db.db).await {
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(e) => {
|
||||||
|
return HttpResponse::InternalServerError().json(APIError { code: "DB_ERROR".to_string(), message: e.to_string() })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpResponse::Ok().finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/custview/{id}")]
|
||||||
|
pub async fn custview_get(id: Path<String>, db: Data<AppState>) -> HttpResponse {
|
||||||
|
let existing_db = match CustomerView::list_async(0.., &db.db).await {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(e) => {
|
||||||
|
return HttpResponse::InternalServerError().json(APIError { code: "DB_ERROR".to_string(), message: e.to_string() })
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for maybe_db in &existing_db {
|
||||||
|
if maybe_db.contents.sync_id == id.clone() {
|
||||||
|
let definitely_db = maybe_db;
|
||||||
|
|
||||||
|
let mut translated: HashMap<u64, (CustomerViewProductSlice, u64)> = HashMap::new();
|
||||||
|
|
||||||
|
for (k, v) in &definitely_db.contents.products {
|
||||||
|
translated.insert(translated.len() as u64, (k.clone(), *v));
|
||||||
|
}
|
||||||
|
|
||||||
|
return HttpResponse::Ok().json(translated.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpResponse::NotFound().json(APIError { code: "Sync ID not known".to_string(), message: "Missing sync ID in DB".to_string() })
|
||||||
|
}
|
|
@ -1,15 +1,18 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use actix_web::{get, HttpResponse, post};
|
use actix_web::{get, HttpRequest, HttpResponse, post};
|
||||||
use actix_web::web::{Data, Json};
|
use actix_web::http::header::HeaderValue;
|
||||||
|
use actix_web::web::{Data, Json, Path};
|
||||||
use bonsaidb::core::schema::SerializedCollection;
|
use bonsaidb::core::schema::SerializedCollection;
|
||||||
|
use log::debug;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use stripe::{CheckoutSession, CheckoutSessionMode, CreateCheckoutSession, CreateCheckoutSessionLineItems, CreateCheckoutSessionLineItemsPriceData, CreateCheckoutSessionLineItemsPriceDataProductData, Currency, Metadata};
|
||||||
use crate::AppState;
|
use crate::AppState;
|
||||||
use crate::db_orders::{Order, OrderType};
|
use crate::db_orders::{Order, OrderType, StripeStatus};
|
||||||
use crate::db_products::Product;
|
use crate::db_products::Product;
|
||||||
use crate::error::APIError;
|
use crate::error::APIError;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct CashOrderRequest {
|
pub struct OrderRequest {
|
||||||
pub products: HashMap<u64, u64>,
|
pub products: HashMap<u64, u64>,
|
||||||
pub adjust_stock: bool
|
pub adjust_stock: bool
|
||||||
}
|
}
|
||||||
|
@ -20,7 +23,10 @@ pub struct CashOrderResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/cash_order")]
|
#[post("/cash_order")]
|
||||||
pub async fn cash_order(req: Json<CashOrderRequest>, db: Data<AppState>) -> HttpResponse {
|
pub async fn cash_order(req: Json<OrderRequest>, db: Data<AppState>, req_info: HttpRequest) -> HttpResponse {
|
||||||
|
if req_info.headers().get("Authorization") != Some(&HeaderValue::from_str("Bearer 65ed1563-b9a3-4923-8f5a-a0ea955adf97").unwrap()) {
|
||||||
|
return HttpResponse::Unauthorized().json(APIError { code: "UNAUTHORIZED".to_string(), message: "Unauthorized".to_string() });
|
||||||
|
}
|
||||||
// load product data
|
// load product data
|
||||||
let mut products = match Product::get_multiple_async(req.products.keys(), &db.db).await {
|
let mut products = match Product::get_multiple_async(req.products.keys(), &db.db).await {
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
|
@ -42,6 +48,7 @@ pub async fn cash_order(req: Json<CashOrderRequest>, db: Data<AppState>) -> Http
|
||||||
order_type: OrderType::Cash,
|
order_type: OrderType::Cash,
|
||||||
total_usd: price_total,
|
total_usd: price_total,
|
||||||
products: req.products.clone(),
|
products: req.products.clone(),
|
||||||
|
stripe_status: StripeStatus::NotStripeTransaction
|
||||||
};
|
};
|
||||||
|
|
||||||
if req.adjust_stock {
|
if req.adjust_stock {
|
||||||
|
@ -95,11 +102,15 @@ pub struct OrderResponse {
|
||||||
pub id: u64,
|
pub id: u64,
|
||||||
pub order_type: OrderType,
|
pub order_type: OrderType,
|
||||||
pub total_usd: f64,
|
pub total_usd: f64,
|
||||||
pub products: HashMap<u64, u64>
|
pub products: HashMap<u64, u64>,
|
||||||
|
pub stripe_status: StripeStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/orders")]
|
#[get("/orders")]
|
||||||
pub async fn get_orders(db: Data<AppState>) -> HttpResponse {
|
pub async fn get_orders(db: Data<AppState>, req_info: HttpRequest) -> HttpResponse {
|
||||||
|
if req_info.headers().get("Authorization") != Some(&HeaderValue::from_str("Bearer 65ed1563-b9a3-4923-8f5a-a0ea955adf97").unwrap()) {
|
||||||
|
return HttpResponse::Unauthorized().json(APIError { code: "UNAUTHORIZED".to_string(), message: "Unauthorized".to_string() });
|
||||||
|
}
|
||||||
let orders = match Order::list_async(0.., &db.db).await {
|
let orders = match Order::list_async(0.., &db.db).await {
|
||||||
Ok(p) => p,
|
Ok(p) => p,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -115,7 +126,218 @@ pub async fn get_orders(db: Data<AppState>) -> HttpResponse {
|
||||||
order_type: u.contents.order_type.clone(),
|
order_type: u.contents.order_type.clone(),
|
||||||
total_usd: u.contents.total_usd,
|
total_usd: u.contents.total_usd,
|
||||||
products: u.contents.products.clone(),
|
products: u.contents.products.clone(),
|
||||||
|
stripe_status: u.contents.stripe_status.clone()
|
||||||
}).collect();
|
}).collect();
|
||||||
|
|
||||||
HttpResponse::Ok().json(OrdersResponse { orders: resp })
|
HttpResponse::Ok().json(OrdersResponse { orders: resp })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/order/{id}")]
|
||||||
|
pub async fn get_order(id: Path<u64>, db: Data<AppState>, req_info: HttpRequest) -> HttpResponse {
|
||||||
|
if req_info.headers().get("Authorization") != Some(&HeaderValue::from_str("Bearer 65ed1563-b9a3-4923-8f5a-a0ea955adf97").unwrap()) {
|
||||||
|
return HttpResponse::Unauthorized().json(APIError { code: "UNAUTHORIZED".to_string(), message: "Unauthorized".to_string() });
|
||||||
|
}
|
||||||
|
let orders = match Order::get_async(id.into_inner(), &db.db).await {
|
||||||
|
Ok(p) => p,
|
||||||
|
Err(e) => {
|
||||||
|
return HttpResponse::InternalServerError().json(APIError {
|
||||||
|
code: "DB_ERROR".to_string(),
|
||||||
|
message: e.to_string(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(u) = orders {
|
||||||
|
HttpResponse::Ok().json(OrderResponse {
|
||||||
|
id: u.header.id,
|
||||||
|
order_type: u.contents.order_type.clone(),
|
||||||
|
total_usd: u.contents.total_usd,
|
||||||
|
products: u.contents.products.clone(),
|
||||||
|
stripe_status: u.contents.stripe_status.clone()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
HttpResponse::NotFound().finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
pub struct StripeOrderResponse {
|
||||||
|
pub order_id: u64,
|
||||||
|
pub checkout_url: String
|
||||||
|
}
|
||||||
|
|
||||||
|
#[post("/stripe_order")]
|
||||||
|
pub async fn stripe_order(req: Json<OrderRequest>, db: Data<AppState>, req_info: HttpRequest) -> HttpResponse {
|
||||||
|
if req_info.headers().get("Authorization") != Some(&HeaderValue::from_str("Bearer 65ed1563-b9a3-4923-8f5a-a0ea955adf97").unwrap()) {
|
||||||
|
return HttpResponse::Unauthorized().json(APIError { code: "UNAUTHORIZED".to_string(), message: "Unauthorized".to_string() });
|
||||||
|
}
|
||||||
|
// load product data
|
||||||
|
let mut products = match Product::get_multiple_async(req.products.keys(), &db.db).await {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(e) => {
|
||||||
|
return HttpResponse::InternalServerError().json(APIError {
|
||||||
|
code: "DB_ERROR".to_string(),
|
||||||
|
message: e.to_string(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut products_map: HashMap<u64, Product> = HashMap::new();
|
||||||
|
for product in &products {
|
||||||
|
products_map.insert(product.header.id, Product {
|
||||||
|
name: product.contents.name.clone(),
|
||||||
|
price_usd: product.contents.price_usd,
|
||||||
|
stock: product.contents.stock,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut price_total: f64 = 0.0;
|
||||||
|
|
||||||
|
for product in &products {
|
||||||
|
price_total += req.products[&product.header.id] as f64 * product.contents.price_usd;
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.adjust_stock {
|
||||||
|
for product in &mut products {
|
||||||
|
if product.contents.stock < req.products[&product.header.id] {
|
||||||
|
return HttpResponse::BadRequest().json(APIError {
|
||||||
|
code: "NOT_ENOUGH_STOCK".to_string(),
|
||||||
|
message: "Cannot sell more items than are in stock backend".to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the stripe fee
|
||||||
|
let f_fixed = 0.30;
|
||||||
|
let f_percent = 0.029;
|
||||||
|
let p_charge = (price_total + f_fixed) / (1f64 - f_percent);
|
||||||
|
let stripe_fee = p_charge - price_total;
|
||||||
|
|
||||||
|
debug!("Stripe transactional fee: {} for a {} total", stripe_fee, price_total);
|
||||||
|
|
||||||
|
// Create line items
|
||||||
|
|
||||||
|
let mut products_filtered = vec![];
|
||||||
|
for (product_id, product_qty) in &req.products {
|
||||||
|
if *product_qty != 0 {
|
||||||
|
products_filtered.push((*product_id, *product_qty));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let line_items = products_filtered.iter().map(|(id, qty)| {
|
||||||
|
CreateCheckoutSessionLineItems {
|
||||||
|
adjustable_quantity: None,
|
||||||
|
dynamic_tax_rates: None,
|
||||||
|
price: None,
|
||||||
|
price_data: Some(CreateCheckoutSessionLineItemsPriceData {
|
||||||
|
currency: Currency::USD,
|
||||||
|
product: None,
|
||||||
|
product_data: Some(CreateCheckoutSessionLineItemsPriceDataProductData {
|
||||||
|
description: None,
|
||||||
|
images: None,
|
||||||
|
metadata: Metadata::from([
|
||||||
|
("X-LMSPOS-ID".to_string(), id.to_string())
|
||||||
|
]),
|
||||||
|
name: products_map[id].name.clone(),
|
||||||
|
tax_code: None,
|
||||||
|
}),
|
||||||
|
recurring: None,
|
||||||
|
tax_behavior: None,
|
||||||
|
unit_amount: Some((products_map[id].price_usd * 100f64) as i64),
|
||||||
|
unit_amount_decimal: None,
|
||||||
|
}),
|
||||||
|
quantity: Some(*qty),
|
||||||
|
tax_rates: None,
|
||||||
|
}
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
let doc = Order {
|
||||||
|
order_type: OrderType::Stripe,
|
||||||
|
total_usd: price_total,
|
||||||
|
products: req.products.clone(),
|
||||||
|
stripe_status: StripeStatus::SessionCreated
|
||||||
|
};
|
||||||
|
|
||||||
|
let order = match doc.push_into_async(&db.db).await {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(e) => {
|
||||||
|
return HttpResponse::InternalServerError().json(APIError {
|
||||||
|
code: "DB_ERROR".to_string(),
|
||||||
|
message: e.to_string(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let checkout_session = CheckoutSession::create(&db.client, CreateCheckoutSession {
|
||||||
|
after_expiration: None,
|
||||||
|
allow_promotion_codes: None,
|
||||||
|
automatic_tax: None,
|
||||||
|
billing_address_collection: None,
|
||||||
|
cancel_url: Some(&format!("http://192.168.254.201:8080/stripe_cancel?session_id={{CHECKOUT_SESSION_ID}}&order={}", order.header.id)),
|
||||||
|
client_reference_id: None,
|
||||||
|
consent_collection: None,
|
||||||
|
currency: None,
|
||||||
|
custom_fields: None,
|
||||||
|
custom_text: None,
|
||||||
|
customer: None,
|
||||||
|
customer_creation: None,
|
||||||
|
customer_email: None,
|
||||||
|
customer_update: None,
|
||||||
|
discounts: None,
|
||||||
|
expand: &[],
|
||||||
|
expires_at: None,
|
||||||
|
invoice_creation: None,
|
||||||
|
line_items: Some(line_items),
|
||||||
|
locale: None,
|
||||||
|
metadata: Some(Metadata::from([
|
||||||
|
("X-LMSPOS-Affects-Stock".to_string(), req.adjust_stock.to_string())
|
||||||
|
])),
|
||||||
|
mode: Some(CheckoutSessionMode::Payment),
|
||||||
|
payment_intent_data: None,
|
||||||
|
payment_method_collection: None,
|
||||||
|
payment_method_options: None,
|
||||||
|
payment_method_types: None,
|
||||||
|
phone_number_collection: None,
|
||||||
|
setup_intent_data: None,
|
||||||
|
shipping_address_collection: None,
|
||||||
|
shipping_options: None,
|
||||||
|
shipping_rates: None,
|
||||||
|
submit_type: None,
|
||||||
|
subscription_data: None,
|
||||||
|
success_url: &format!("http://192.168.254.201:8080/stripe_finish?session_id={{CHECKOUT_SESSION_ID}}&order={}", order.header.id),
|
||||||
|
tax_id_collection: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
let session = match checkout_session.await {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(e) => {
|
||||||
|
return HttpResponse::InternalServerError().json(APIError {
|
||||||
|
code: "STRIPE_ERR".to_string(),
|
||||||
|
message: e.to_string(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!("Payment session created! ID: {}", session.id);
|
||||||
|
|
||||||
|
if req.adjust_stock {
|
||||||
|
for product in &mut products {
|
||||||
|
product.contents.stock -= req.products[&product.header.id];
|
||||||
|
match product.update_async(&db.db).await {
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(e) => {
|
||||||
|
return HttpResponse::InternalServerError().json(APIError {
|
||||||
|
code: "DB_ERROR".to_string(),
|
||||||
|
message: e.to_string(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpResponse::Ok().json(StripeOrderResponse {
|
||||||
|
order_id: order.header.id,
|
||||||
|
checkout_url: session.url.unwrap(),
|
||||||
|
})
|
||||||
}
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
use actix_web::{get, post, HttpResponse, put, delete};
|
use actix_web::{get, post, HttpResponse, put, delete, HttpRequest};
|
||||||
|
use actix_web::http::header::HeaderValue;
|
||||||
use actix_web::web::{Data, Json, Path};
|
use actix_web::web::{Data, Json, Path};
|
||||||
use bonsaidb::core::schema::SerializedCollection;
|
use bonsaidb::core::schema::SerializedCollection;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -20,7 +21,10 @@ pub struct ProductResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/products")]
|
#[get("/products")]
|
||||||
pub async fn get_products(db: Data<AppState>) -> HttpResponse {
|
pub async fn get_products(db: Data<AppState>, req_info: HttpRequest) -> HttpResponse {
|
||||||
|
if req_info.headers().get("Authorization") != Some(&HeaderValue::from_str("Bearer 65ed1563-b9a3-4923-8f5a-a0ea955adf97").unwrap()) {
|
||||||
|
return HttpResponse::Unauthorized().json(APIError { code: "UNAUTHORIZED".to_string(), message: "Unauthorized".to_string() });
|
||||||
|
}
|
||||||
let products = match Product::list_async(0.., &db.db).await {
|
let products = match Product::list_async(0.., &db.db).await {
|
||||||
Ok(p) => p,
|
Ok(p) => p,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -37,7 +41,10 @@ pub async fn get_products(db: Data<AppState>) -> HttpResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/products/{id}")]
|
#[get("/products/{id}")]
|
||||||
pub async fn get_product(id: Path<u64>, db: Data<AppState>) -> HttpResponse {
|
pub async fn get_product(id: Path<u64>, db: Data<AppState>, req_info: HttpRequest) -> HttpResponse {
|
||||||
|
if req_info.headers().get("Authorization") != Some(&HeaderValue::from_str("Bearer 65ed1563-b9a3-4923-8f5a-a0ea955adf97").unwrap()) {
|
||||||
|
return HttpResponse::Unauthorized().json(APIError { code: "UNAUTHORIZED".to_string(), message: "Unauthorized".to_string() });
|
||||||
|
}
|
||||||
let product = match Product::get_async(id.into_inner(), &db.db).await {
|
let product = match Product::get_async(id.into_inner(), &db.db).await {
|
||||||
Ok(p) => p,
|
Ok(p) => p,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -71,7 +78,10 @@ pub struct CreateProductRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/products")]
|
#[post("/products")]
|
||||||
pub async fn create_product(req: Json<CreateProductRequest>, db: Data<AppState>) -> HttpResponse {
|
pub async fn create_product(req: Json<CreateProductRequest>, db: Data<AppState>, req_info: HttpRequest) -> HttpResponse {
|
||||||
|
if req_info.headers().get("Authorization") != Some(&HeaderValue::from_str("Bearer 65ed1563-b9a3-4923-8f5a-a0ea955adf97").unwrap()) {
|
||||||
|
return HttpResponse::Unauthorized().json(APIError { code: "UNAUTHORIZED".to_string(), message: "Unauthorized".to_string() });
|
||||||
|
}
|
||||||
let document = Product {
|
let document = Product {
|
||||||
name: req.name.clone(),
|
name: req.name.clone(),
|
||||||
price_usd: req.price_usd,
|
price_usd: req.price_usd,
|
||||||
|
@ -103,7 +113,10 @@ pub struct UpdateProductRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[put("/products/{id}")]
|
#[put("/products/{id}")]
|
||||||
pub async fn update_product(id: Path<u64>, req: Json<CreateProductRequest>, db: Data<AppState>) -> HttpResponse {
|
pub async fn update_product(id: Path<u64>, req: Json<CreateProductRequest>, db: Data<AppState>, req_info: HttpRequest) -> HttpResponse {
|
||||||
|
if req_info.headers().get("Authorization") != Some(&HeaderValue::from_str("Bearer 65ed1563-b9a3-4923-8f5a-a0ea955adf97").unwrap()) {
|
||||||
|
return HttpResponse::Unauthorized().json(APIError { code: "UNAUTHORIZED".to_string(), message: "Unauthorized".to_string() });
|
||||||
|
}
|
||||||
let document = match Product::get_async(id.into_inner(), &db.db).await {
|
let document = match Product::get_async(id.into_inner(), &db.db).await {
|
||||||
Ok(p) => p,
|
Ok(p) => p,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -144,7 +157,10 @@ pub async fn update_product(id: Path<u64>, req: Json<CreateProductRequest>, db:
|
||||||
}
|
}
|
||||||
|
|
||||||
#[delete("/products/{id}")]
|
#[delete("/products/{id}")]
|
||||||
pub async fn delete_product(id: Path<u64>, db: Data<AppState>) -> HttpResponse {
|
pub async fn delete_product(id: Path<u64>, db: Data<AppState>, req_info: HttpRequest) -> HttpResponse {
|
||||||
|
if req_info.headers().get("Authorization") != Some(&HeaderValue::from_str("Bearer 65ed1563-b9a3-4923-8f5a-a0ea955adf97").unwrap()) {
|
||||||
|
return HttpResponse::Unauthorized().json(APIError { code: "UNAUTHORIZED".to_string(), message: "Unauthorized".to_string() });
|
||||||
|
}
|
||||||
let document = match Product::get_async(id.into_inner(), &db.db).await {
|
let document = match Product::get_async(id.into_inner(), &db.db).await {
|
||||||
Ok(p) => p,
|
Ok(p) => p,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|
|
@ -0,0 +1,135 @@
|
||||||
|
use std::str::FromStr;
|
||||||
|
use actix_web::{get, HttpResponse};
|
||||||
|
use actix_web::web::{Data, Path, Query};
|
||||||
|
use bonsaidb::core::schema::SerializedCollection;
|
||||||
|
use log::error;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use stripe::{CheckoutSession, CheckoutSessionId, CheckoutSessionPaymentStatus};
|
||||||
|
use crate::AppState;
|
||||||
|
use crate::db_orders::{Order, StripeStatus};
|
||||||
|
use crate::db_products::Product;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct StripeCancelQuery {
|
||||||
|
session_id: String,
|
||||||
|
order: u64
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/stripe_cancel")]
|
||||||
|
pub async fn stripe_cancel(req: Query<StripeCancelQuery>, db: Data<AppState>) -> HttpResponse {
|
||||||
|
// lookup order ID
|
||||||
|
let order = match Order::get_async(req.order, &db.db).await {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(e) => {
|
||||||
|
error!("{}", e);
|
||||||
|
return HttpResponse::InternalServerError().body("There was an error completing your request. Please try again later.")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let order = match order {
|
||||||
|
Some(o) => o,
|
||||||
|
None => {
|
||||||
|
return HttpResponse::NotFound().body("We were unable to find your order in our systems. Please try again later.")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// make sure the order isnt over yet
|
||||||
|
if order.contents.stripe_status != StripeStatus::SessionCreated {
|
||||||
|
return HttpResponse::BadRequest().body("This transaction has already been finished or cancelled. Please try again later.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// cancel the order in our database
|
||||||
|
let mut order = order;
|
||||||
|
order.contents.stripe_status = StripeStatus::Failed;
|
||||||
|
match order.update_async(&db.db).await {
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(e) => {
|
||||||
|
error!("{}", e);
|
||||||
|
return HttpResponse::InternalServerError().body("There was an error completing your request. Please try again later.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// lookup and cancel the order in stripe - do we need to un-adjust stock?
|
||||||
|
let session = match CheckoutSession::expire(&db.client, &CheckoutSessionId::from_str(&req.session_id).unwrap()).await {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(e) => {
|
||||||
|
error!("{}", e);
|
||||||
|
return HttpResponse::InternalServerError().body("There was an error completing your request. Please try again later.")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let need_unadjust_stock = session.metadata.get("X-LMSPOS-Affects-Stock") == Some(&String::from("true"));
|
||||||
|
|
||||||
|
if need_unadjust_stock {
|
||||||
|
let mut products = match Product::get_multiple_async(order.contents.products.keys(), &db.db).await {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(e) => {
|
||||||
|
error!("{}", e);
|
||||||
|
return HttpResponse::InternalServerError().body("There was an error completing your request. Please try again later.");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for product in &mut products {
|
||||||
|
product.contents.stock += order.contents.products[&product.header.id];
|
||||||
|
match product.update_async(&db.db).await {
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(e) => {
|
||||||
|
error!("{}", e);
|
||||||
|
return HttpResponse::InternalServerError().body("There was an error completing your request. Please try again later.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpResponse::Ok().body("Your order has been cancelled. We hope to see you again soon!")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/stripe_finish")]
|
||||||
|
pub async fn stripe_finish(req: Query<StripeCancelQuery>, db: Data<AppState>) -> HttpResponse {
|
||||||
|
// lookup order ID
|
||||||
|
let order = match Order::get_async(req.order, &db.db).await {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(e) => {
|
||||||
|
error!("{}", e);
|
||||||
|
return HttpResponse::InternalServerError().body("There was an error completing your request. Please try again later.")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let order = match order {
|
||||||
|
Some(o) => o,
|
||||||
|
None => {
|
||||||
|
return HttpResponse::NotFound().body("We were unable to find your order in our systems. Please try again later.")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// make sure the order isnt over yet
|
||||||
|
if order.contents.stripe_status != StripeStatus::SessionCreated {
|
||||||
|
return HttpResponse::BadRequest().body("This transaction has already been finished or cancelled. Please try again later.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// lookup the order in stripe
|
||||||
|
let session = match CheckoutSession::retrieve(&db.client, &CheckoutSessionId::from_str(&req.session_id).unwrap(), &[]).await {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(e) => {
|
||||||
|
error!("{}", e);
|
||||||
|
return HttpResponse::InternalServerError().body("There was an error completing your request. Please try again later.")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if session.payment_status != CheckoutSessionPaymentStatus::Paid {
|
||||||
|
return HttpResponse::BadRequest().body("This transaction has not yet been paid. Please try again later.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// finish the order in our database
|
||||||
|
let mut order = order;
|
||||||
|
order.contents.stripe_status = StripeStatus::Paid;
|
||||||
|
match order.update_async(&db.db).await {
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(e) => {
|
||||||
|
error!("{}", e);
|
||||||
|
return HttpResponse::InternalServerError().body("There was an error completing your request. Please try again later.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpResponse::Ok().body("Thank you for your order! Payment has been initiated and your transaction has been completed. We hope to see you again soon!")
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
import { persist } from "$lib/PersistentStore";
|
||||||
|
|
||||||
|
export const authToken = persist("auth", "YOUR_TOKEN_HERE");
|
|
@ -11,6 +11,10 @@
|
||||||
import HelperText from "@smui/textfield/helper-text";
|
import HelperText from "@smui/textfield/helper-text";
|
||||||
import Checkbox from "@smui/checkbox";
|
import Checkbox from "@smui/checkbox";
|
||||||
import FormField from "@smui/form-field";
|
import FormField from "@smui/form-field";
|
||||||
|
import CircularProgress from "@smui/circular-progress";
|
||||||
|
import QRJS from "$lib/components/QRJS.svelte";
|
||||||
|
import {authToken} from "$lib/stores/AuthStore";
|
||||||
|
import {browser} from "$app/environment";
|
||||||
|
|
||||||
let products = [];
|
let products = [];
|
||||||
let productsCounter = {};
|
let productsCounter = {};
|
||||||
|
@ -28,7 +32,7 @@
|
||||||
async function loadProducts() {
|
async function loadProducts() {
|
||||||
loaded = false;
|
loaded = false;
|
||||||
try {
|
try {
|
||||||
let resp = await fetch(`${$serverUrl}/products`);
|
let resp = await fetch(`${$serverUrl}/products`, {headers: [["Authorization", "Bearer " + $authToken]]});
|
||||||
if (resp.ok) {
|
if (resp.ok) {
|
||||||
let json = await resp.json();
|
let json = await resp.json();
|
||||||
console.log(json);
|
console.log(json);
|
||||||
|
@ -147,7 +151,8 @@
|
||||||
let resp = await fetch(`${$serverUrl}/cash_order`, {
|
let resp = await fetch(`${$serverUrl}/cash_order`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: [
|
headers: [
|
||||||
['Content-Type', 'application/json']
|
['Content-Type', 'application/json'],
|
||||||
|
["Authorization", "Bearer " + $authToken]
|
||||||
],
|
],
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
products: productsCounter,
|
products: productsCounter,
|
||||||
|
@ -174,6 +179,222 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let stripeOpen = false;
|
||||||
|
let stripeTransactionFinished = false;
|
||||||
|
let stripeTransactionStarted = false;
|
||||||
|
|
||||||
|
let stripeProgressSpinner = false;
|
||||||
|
let stripeProgressSpinnerText = "";
|
||||||
|
let stripeProgressSpinnerClosed = false;
|
||||||
|
|
||||||
|
let stripeCanClose = false;
|
||||||
|
function updateCanClose() {
|
||||||
|
stripeCanClose = !stripeTransactionFinished;
|
||||||
|
}
|
||||||
|
$: stripeTransactionFinished, updateCanClose();
|
||||||
|
|
||||||
|
let hasStripeUrl = false;
|
||||||
|
|
||||||
|
let order_url = '';
|
||||||
|
|
||||||
|
async function startStripeTransaction() {
|
||||||
|
stripeTransactionStarted = true;
|
||||||
|
|
||||||
|
stripeProgressSpinner = true;
|
||||||
|
stripeProgressSpinnerText = "Contacting Stripe API to initiate transaction...";
|
||||||
|
|
||||||
|
let order_id = '';
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
let resp = await fetch(`${$serverUrl}/stripe_order`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: [
|
||||||
|
['Content-Type', 'application/json'],
|
||||||
|
["Authorization", "Bearer " + $authToken]
|
||||||
|
],
|
||||||
|
body: JSON.stringify({
|
||||||
|
products: productsCounter,
|
||||||
|
adjust_stock: adjustStockOnOrderFinish
|
||||||
|
})
|
||||||
|
});
|
||||||
|
if (resp.ok) {
|
||||||
|
let json = await resp.json();
|
||||||
|
loadedCashIn = true;
|
||||||
|
snackbarText = "Order started! Order ID: " + json.order_id;
|
||||||
|
console.log(json);
|
||||||
|
|
||||||
|
order_url = json.checkout_url;
|
||||||
|
order_id = json.order_id;
|
||||||
|
|
||||||
|
hasStripeUrl = true;
|
||||||
|
|
||||||
|
snackbar.open();
|
||||||
|
} else {
|
||||||
|
console.error(await resp.text());
|
||||||
|
snackbarText = "There was an error starting the order. Check the browser console for more information.";
|
||||||
|
snackbar.open();
|
||||||
|
|
||||||
|
stripeProgressSpinnerText = "Transaction failed. Check browser console for more information.";
|
||||||
|
stripeProgressSpinnerClosed = true;
|
||||||
|
stripeTransactionFinished = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
snackbarText = "There was an error starting the order. Check the browser console for more information.";
|
||||||
|
snackbar.open();
|
||||||
|
|
||||||
|
stripeProgressSpinnerText = "Transaction failed. Check browser console for more information.";
|
||||||
|
stripeProgressSpinnerClosed = true;
|
||||||
|
stripeTransactionFinished = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
stripeProgressSpinnerText = "Waiting for customer...";
|
||||||
|
|
||||||
|
async function updateOrderStatus() {
|
||||||
|
console.log('polling for updated stripe order info');
|
||||||
|
try {
|
||||||
|
let resp = await fetch(`${$serverUrl}/order/${order_id}`, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: [["Authorization", "Bearer " + $authToken]]
|
||||||
|
});
|
||||||
|
if (resp.ok) {
|
||||||
|
let json = await resp.json();
|
||||||
|
|
||||||
|
if (json.stripe_status === 'SessionCreated') {
|
||||||
|
console.log('result: SessionCreated waiting for customer');
|
||||||
|
setTimeout(updateOrderStatus, 1000);
|
||||||
|
return;
|
||||||
|
} else if (json.stripe_status === 'Paid') {
|
||||||
|
hasStripeUrl = false;
|
||||||
|
console.log('result: Paid order complete');
|
||||||
|
stripeProgressSpinnerText = 'Order complete! Payment was successful.';
|
||||||
|
stripeProgressSpinnerClosed = true;
|
||||||
|
stripeTransactionFinished = true;
|
||||||
|
snackbarText = "Order complete! Order ID: " + json.id;
|
||||||
|
snackbar.open();
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
hasStripeUrl = false;
|
||||||
|
console.log('result: Other order cancelled');
|
||||||
|
stripeProgressSpinnerText = 'Order cancelled by customer or payment provider';
|
||||||
|
stripeProgressSpinnerClosed = true;
|
||||||
|
stripeTransactionFinished = true;
|
||||||
|
snackbarText = "Order cancelled! Order ID: " + json.id;
|
||||||
|
snackbar.open();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hasStripeUrl = false;
|
||||||
|
console.error(await resp.text());
|
||||||
|
snackbarText = "There was an error checking the order status. Check the browser console for more information.";
|
||||||
|
snackbar.open();
|
||||||
|
|
||||||
|
stripeProgressSpinnerText = "Transaction failed. Check browser console for more information.";
|
||||||
|
stripeProgressSpinnerClosed = true;
|
||||||
|
stripeTransactionFinished = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
hasStripeUrl = false;
|
||||||
|
console.error(e);
|
||||||
|
snackbarText = "There was an error checking the order status. Check the browser console for more information.";
|
||||||
|
snackbar.open();
|
||||||
|
|
||||||
|
stripeProgressSpinnerText = "Transaction failed. Check browser console for more information.";
|
||||||
|
stripeProgressSpinnerClosed = true;
|
||||||
|
stripeTransactionFinished = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await updateOrderStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
function openStripe() {
|
||||||
|
stripeTransactionFinished = false;
|
||||||
|
stripeTransactionStarted = false;
|
||||||
|
|
||||||
|
stripeProgressSpinner = false;
|
||||||
|
stripeProgressSpinnerText = "";
|
||||||
|
stripeProgressSpinnerClosed = false;
|
||||||
|
|
||||||
|
stripeOpen = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function uuid() {
|
||||||
|
var uuid = "", i, random;
|
||||||
|
for (i = 0; i < 32; i++) {
|
||||||
|
random = Math.random() * 16 | 0;
|
||||||
|
|
||||||
|
if (i == 8 || i == 12 || i == 16 || i == 20) {
|
||||||
|
uuid += "-"
|
||||||
|
}
|
||||||
|
uuid += (i == 12 ? 4 : (i == 16 ? (random & 3 | 8) : random)).toString(16);
|
||||||
|
}
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
let cs_view_sync_code = uuid();
|
||||||
|
let showCsQrCode = false;
|
||||||
|
let csQrCodeUrl = "";
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
csQrCodeUrl = `${window.location}customer?cs=${cs_view_sync_code}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
async function resendCs() {
|
||||||
|
if (!browser) return;
|
||||||
|
|
||||||
|
let product_slice = {};
|
||||||
|
|
||||||
|
for (let i = 0; i < products.length; i++) {
|
||||||
|
let product = products[i];
|
||||||
|
let counter = productsCounter[product.id];
|
||||||
|
|
||||||
|
product_slice[product.id] = [
|
||||||
|
{
|
||||||
|
name: `${product.name} (#${product.id})`,
|
||||||
|
price_usd: Math.trunc(product.price_usd * 100)
|
||||||
|
},
|
||||||
|
counter
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
let resp = await fetch(`${$serverUrl}/custview`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: [
|
||||||
|
['Content-Type', 'application/json'],
|
||||||
|
["Authorization", "Bearer " + $authToken]
|
||||||
|
],
|
||||||
|
body: JSON.stringify({
|
||||||
|
sync_id: cs_view_sync_code,
|
||||||
|
products: product_slice,
|
||||||
|
price_total: total
|
||||||
|
})
|
||||||
|
});
|
||||||
|
if (!resp.ok) {
|
||||||
|
console.error(await resp.text());
|
||||||
|
snackbarText = "There was an error updating the customer view. Check the browser console for more information.";
|
||||||
|
snackbar.open();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
snackbarText = "There was an error updating the customer view. Check the browser console for more information.";
|
||||||
|
snackbar.open();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$: productsCounter, resendCs();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Header selected="pos" />
|
<Header selected="pos" />
|
||||||
|
@ -234,7 +455,7 @@
|
||||||
<Button disabled={!hasProducts} variant="outlined" on:click={() => {cashIn = total.toFixed(2); cashDialogOpen = true;}}>
|
<Button disabled={!hasProducts} variant="outlined" on:click={() => {cashIn = total.toFixed(2); cashDialogOpen = true;}}>
|
||||||
<ButtonLabel>Cash In</ButtonLabel>
|
<ButtonLabel>Cash In</ButtonLabel>
|
||||||
</Button>
|
</Button>
|
||||||
<Button disabled={!hasProducts} variant="outlined">
|
<Button disabled={!hasProducts} variant="outlined" on:click={() => {openStripe()}}>
|
||||||
<ButtonLabel>Stripe</ButtonLabel>
|
<ButtonLabel>Stripe</ButtonLabel>
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="unelevated" on:click={() => {for (let i = 0; i < products.length; i++) {productsCounter[products[i].id] = 0}}}>
|
<Button variant="unelevated" on:click={() => {for (let i = 0; i < products.length; i++) {productsCounter[products[i].id] = 0}}}>
|
||||||
|
@ -248,6 +469,19 @@
|
||||||
<LinearProgress indeterminate bind:closed={loaded} aria-label="Data is being loaded..." slot="progress" />
|
<LinearProgress indeterminate bind:closed={loaded} aria-label="Data is being loaded..." slot="progress" />
|
||||||
</DataTable>
|
</DataTable>
|
||||||
|
|
||||||
|
<Textfield label="Customer View Sync Code" bind:value={cs_view_sync_code}></Textfield>
|
||||||
|
<Button on:click={() => {showCsQrCode = true}}>
|
||||||
|
<ButtonLabel>Open Customer View</ButtonLabel>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Dialog bind:open={showCsQrCode} aria-labelledby="cs-title" aria-describedby="cs-content">
|
||||||
|
<DialogTitle id="cs-title">Customer View QR Code</DialogTitle>
|
||||||
|
<DialogContent id="cs-content">
|
||||||
|
Use this QR code on another device to open the Customer View.
|
||||||
|
<QRJS codeValue="" squareSize="200" />
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
<Dialog bind:open={cashDialogOpen} aria-labelledby="cash-title" aria-describedby="cash-content">
|
<Dialog bind:open={cashDialogOpen} aria-labelledby="cash-title" aria-describedby="cash-content">
|
||||||
<DialogTitle id="cash-title">Cash In</DialogTitle>
|
<DialogTitle id="cash-title">Cash In</DialogTitle>
|
||||||
<DialogContent id="cash-content">
|
<DialogContent id="cash-content">
|
||||||
|
@ -293,4 +527,35 @@
|
||||||
<ButtonLabel>Cancel</ButtonLabel>
|
<ButtonLabel>Cancel</ButtonLabel>
|
||||||
</Button>
|
</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
|
<Dialog bind:open={stripeOpen} aria-labelledby="stripe-title" aria-describedby="stripe-content" scrimClickAction="" escapeKeyAction="">
|
||||||
|
<DialogTitle id="stripe-title">Stripe Transaction</DialogTitle>
|
||||||
|
<DialogContent id="stripe-content">
|
||||||
|
<p>Total Price: {formatter.format(total)}</p>
|
||||||
|
<p>Stripe transactions cannot be stopped once started. Confirm with customer now before starting the transaction.</p>
|
||||||
|
<Button bind:disabled={stripeTransactionStarted} on:click={startStripeTransaction}>
|
||||||
|
<ButtonLabel>Start Transaction</ButtonLabel>
|
||||||
|
</Button>
|
||||||
|
{#if hasStripeUrl}
|
||||||
|
<QRJS squareSize="200" codeValue="{order_url}" />
|
||||||
|
<Button on:click={() => {window.open(order_url, "_blank")}}>
|
||||||
|
<ButtonLabel>Card In Hand?</ButtonLabel>
|
||||||
|
</Button>
|
||||||
|
{/if}
|
||||||
|
{#if stripeProgressSpinner}
|
||||||
|
<div style="display: flex; margin-top: 5px;">
|
||||||
|
<CircularProgress bind:closed={stripeProgressSpinnerClosed} style="height: 32px; width: 32px; margin-right: 5px;" indeterminate />
|
||||||
|
<span style="margin-top: 3px;">{stripeProgressSpinnerText}</span>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button bind:disabled={stripeCanClose}>
|
||||||
|
<ButtonLabel>Finish</ButtonLabel>
|
||||||
|
</Button>
|
||||||
|
<Button bind:disabled={stripeTransactionStarted}>
|
||||||
|
<ButtonLabel>Cancel</ButtonLabel>
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
|
@ -0,0 +1,96 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { onMount } from "svelte";
|
||||||
|
import {serverUrl} from "$lib/stores/ServerStore";
|
||||||
|
import Snackbar, {Label as SnackbarLabel} from "@smui/snackbar";
|
||||||
|
import DataTable, { Head, Body, Row, Cell } from '@smui/data-table';
|
||||||
|
import LinearProgress from "@smui/linear-progress";
|
||||||
|
|
||||||
|
let snackbar: Snackbar;
|
||||||
|
let snackbarText = "";
|
||||||
|
|
||||||
|
let csCode = '';
|
||||||
|
|
||||||
|
let csData = {};
|
||||||
|
let data = [];
|
||||||
|
|
||||||
|
const formatter = new Intl.NumberFormat('en-US', {style: 'currency', currency: 'USD'});
|
||||||
|
|
||||||
|
let loaded = false;
|
||||||
|
|
||||||
|
let total = 0.0;
|
||||||
|
|
||||||
|
async function updateData() {
|
||||||
|
try {
|
||||||
|
let resp = await fetch(`${$serverUrl}/custview/${csCode}`);
|
||||||
|
if (resp.ok) {
|
||||||
|
csData = await resp.json();
|
||||||
|
console.log(csData);
|
||||||
|
|
||||||
|
data = Object.entries(csData);
|
||||||
|
|
||||||
|
setTimeout(updateData, 500);
|
||||||
|
loaded = true;
|
||||||
|
} else {
|
||||||
|
console.error(await resp.text());
|
||||||
|
snackbarText = "There was an error updating the customer view. Check the browser console for more information.";
|
||||||
|
snackbar.open();
|
||||||
|
loaded = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
snackbarText = "There was an error updating the customer view. Check the browser console for more information.";
|
||||||
|
snackbar.open();
|
||||||
|
loaded = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
const params = new URLSearchParams(window.location.search);
|
||||||
|
if (!params.has("cs")) {
|
||||||
|
snackbarText = "CS code missing. Please scan your QR code again.";
|
||||||
|
snackbar.open();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
csCode = params.get("cs");
|
||||||
|
updateData();
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Snackbar bind:this={snackbar}>
|
||||||
|
<SnackbarLabel>{snackbarText}</SnackbarLabel>
|
||||||
|
</Snackbar>
|
||||||
|
|
||||||
|
<DataTable table$aria-label="Product list" style="width: 100%;">
|
||||||
|
<Head>
|
||||||
|
<Row>
|
||||||
|
<Cell>Name</Cell>
|
||||||
|
<Cell>Price Ea</Cell>
|
||||||
|
<Cell>Qty</Cell>
|
||||||
|
<Cell>Price</Cell>
|
||||||
|
</Row>
|
||||||
|
</Head>
|
||||||
|
<Body>
|
||||||
|
{#each data as [num, data]}
|
||||||
|
{#if data[1] !== 0}
|
||||||
|
<Row>
|
||||||
|
<Cell>{data[0].name}</Cell>
|
||||||
|
<Cell>{formatter.format(data[0].price_usd / 100)}</Cell>
|
||||||
|
<Cell>{data[1]}</Cell>
|
||||||
|
<Cell>{formatter.format(data[0].price_usd * data[1] / 100)}</Cell>
|
||||||
|
</Row>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
<Row>
|
||||||
|
<Cell numeric></Cell>
|
||||||
|
<Cell></Cell>
|
||||||
|
<Cell><b>Total</b></Cell>
|
||||||
|
<Cell>
|
||||||
|
{formatter.format(total)}
|
||||||
|
</Cell>
|
||||||
|
</Row>
|
||||||
|
</Body>
|
||||||
|
|
||||||
|
<LinearProgress indeterminate bind:closed={loaded} aria-label="Data is being loaded..." slot="progress" />
|
||||||
|
</DataTable>
|
|
@ -8,6 +8,7 @@
|
||||||
import {serverUrl} from "$lib/stores/ServerStore";
|
import {serverUrl} from "$lib/stores/ServerStore";
|
||||||
|
|
||||||
import Snackbar from "@smui/snackbar";
|
import Snackbar from "@smui/snackbar";
|
||||||
|
import {authToken} from "$lib/stores/AuthStore";
|
||||||
|
|
||||||
let snackbarTesting: Snackbar;
|
let snackbarTesting: Snackbar;
|
||||||
let snackbarTestSuccess: Snackbar;
|
let snackbarTestSuccess: Snackbar;
|
||||||
|
@ -36,6 +37,10 @@
|
||||||
snackbarTestFailure.open();
|
snackbarTestFailure.open();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
authTokenTesting.close();
|
||||||
|
authTokenTestFailure.open();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
|
@ -44,6 +49,46 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let authTokenTesting: Snackbar;
|
||||||
|
let authTokenTestSuccess: Snackbar;
|
||||||
|
let authTokenTestFailure: Snackbar;
|
||||||
|
let changeAuthTokenOpen = false;
|
||||||
|
|
||||||
|
let changeAuthTokenFocused;
|
||||||
|
let changeAuthTokenDirty;
|
||||||
|
let newAuthToken = $authToken;
|
||||||
|
let changeAuthTokenInvalid;
|
||||||
|
|
||||||
|
async function testAuthTokenConnection() {
|
||||||
|
authTokenTesting.open();
|
||||||
|
try {
|
||||||
|
let resp = await fetch(`${$serverUrl}/auth_status`, {headers: [["Authorization", "Bearer " + $authToken]]});
|
||||||
|
if (resp.ok) {
|
||||||
|
let json = await resp.json();
|
||||||
|
if (json.status === "ok") {
|
||||||
|
// ok!
|
||||||
|
authTokenTesting.close();
|
||||||
|
authTokenTestSuccess.open();
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
console.error("Response .status was not ok");
|
||||||
|
authTokenTesting.close();
|
||||||
|
authTokenTestFailure.open();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
authTokenTesting.close();
|
||||||
|
authTokenTestFailure.open();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
authTokenTesting.close();
|
||||||
|
authTokenTestFailure.open();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Header selected="manage/env" />
|
<Header selected="manage/env" />
|
||||||
|
@ -62,6 +107,20 @@
|
||||||
</PaperContent>
|
</PaperContent>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|
||||||
|
<Paper>
|
||||||
|
<PaperTitle>Authentication Token</PaperTitle>
|
||||||
|
<PaperSubtitle>Configure the token that LMSPOS uses to authenticate with the backend.</PaperSubtitle>
|
||||||
|
<PaperContent>
|
||||||
|
<p>Current: <pre>{$authToken}</pre>
|
||||||
|
<Button variant="raised" on:click={() => {changeAuthTokenOpen = true}}>
|
||||||
|
<Label>Change</Label>
|
||||||
|
</Button>
|
||||||
|
<Button variant="outlined" on:click={testAuthTokenConnection}>
|
||||||
|
<Label>Test</Label>
|
||||||
|
</Button>
|
||||||
|
</PaperContent>
|
||||||
|
</Paper>
|
||||||
|
|
||||||
<Snackbar bind:this={snackbarTesting}>
|
<Snackbar bind:this={snackbarTesting}>
|
||||||
<Label>Testing server connection, this may take a moment...</Label>
|
<Label>Testing server connection, this may take a moment...</Label>
|
||||||
</Snackbar>
|
</Snackbar>
|
||||||
|
@ -72,6 +131,16 @@
|
||||||
<Label>Connection failed. Check browser console for details.</Label>
|
<Label>Connection failed. Check browser console for details.</Label>
|
||||||
</Snackbar>
|
</Snackbar>
|
||||||
|
|
||||||
|
<Snackbar bind:this={authTokenTesting}>
|
||||||
|
<Label>Testing server connection with auth token, this may take a moment...</Label>
|
||||||
|
</Snackbar>
|
||||||
|
<Snackbar bind:this={authTokenTestSuccess}>
|
||||||
|
<Label>Connection successful!</Label>
|
||||||
|
</Snackbar>
|
||||||
|
<Snackbar bind:this={authTokenTestFailure}>
|
||||||
|
<Label>Connection failed. Check browser console for details.</Label>
|
||||||
|
</Snackbar>
|
||||||
|
|
||||||
<Dialog bind:open={changeServerUrlOpen} aria-labelledby="change-title" aria-describedby="change-content">
|
<Dialog bind:open={changeServerUrlOpen} aria-labelledby="change-title" aria-describedby="change-content">
|
||||||
<DialogTitle id="change-title">Change server URL</DialogTitle>
|
<DialogTitle id="change-title">Change server URL</DialogTitle>
|
||||||
<DialogContent id="change-content">
|
<DialogContent id="change-content">
|
||||||
|
@ -90,4 +159,20 @@
|
||||||
<Label>Cancel</Label>
|
<Label>Cancel</Label>
|
||||||
</Button>
|
</Button>
|
||||||
</Actions>
|
</Actions>
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
|
<Dialog bind:open={changeAuthTokenOpen} aria-labelledby="token-title" aria-describedby="token-content">
|
||||||
|
<DialogTitle id="token-title">Change auth token</DialogTitle>
|
||||||
|
<DialogContent id="token-content">
|
||||||
|
This is the token that LMSPOS will use to connect to it's backend. It is <i>highly recommended</i> that you use the "Test" button to ensure this is working properly before proceeding. <br>
|
||||||
|
<Textfield type="text" bind:dirty={changeAuthTokenDirty} bind:invalid={changeAuthTokenInvalid} updateInvalid bind:value={newAuthToken} label="Auth Token" on:focus={() => {changeAuthTokenFocused = true}} on:blur={() => {changeAuthTokenFocused = false}}></Textfield>
|
||||||
|
</DialogContent>
|
||||||
|
<Actions>
|
||||||
|
<Button on:click={() => {authToken.set(newAuthToken); window.location.reload();}}>
|
||||||
|
<Label>Save</Label>
|
||||||
|
</Button>
|
||||||
|
<Button on:click={() => {changeAuthTokenOpen = false; newAuthToken = $authToken;}}>
|
||||||
|
<Label>Cancel</Label>
|
||||||
|
</Button>
|
||||||
|
</Actions>
|
||||||
</Dialog>
|
</Dialog>
|
|
@ -6,6 +6,7 @@
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import {serverUrl} from "$lib/stores/ServerStore";
|
import {serverUrl} from "$lib/stores/ServerStore";
|
||||||
import Paper, { Title as PaperTitle, Content as PaperContent } from "@smui/paper";
|
import Paper, { Title as PaperTitle, Content as PaperContent } from "@smui/paper";
|
||||||
|
import {authToken} from "$lib/stores/AuthStore";
|
||||||
|
|
||||||
let loaded = false;
|
let loaded = false;
|
||||||
let orders = [];
|
let orders = [];
|
||||||
|
@ -18,7 +19,7 @@
|
||||||
async function loadOrders() {
|
async function loadOrders() {
|
||||||
loaded = false;
|
loaded = false;
|
||||||
try {
|
try {
|
||||||
let resp = await fetch(`${$serverUrl}/orders`);
|
let resp = await fetch(`${$serverUrl}/orders`, {headers: [["Authorization", "Bearer " + $authToken]]});
|
||||||
if (resp.ok) {
|
if (resp.ok) {
|
||||||
let json = await resp.json();
|
let json = await resp.json();
|
||||||
console.log(json);
|
console.log(json);
|
||||||
|
@ -45,7 +46,7 @@
|
||||||
async function loadProducts() {
|
async function loadProducts() {
|
||||||
loaded = false;
|
loaded = false;
|
||||||
try {
|
try {
|
||||||
let resp = await fetch(`${$serverUrl}/products`);
|
let resp = await fetch(`${$serverUrl}/products`, {headers: [["Authorization", "Bearer " + $authToken]]});
|
||||||
if (resp.ok) {
|
if (resp.ok) {
|
||||||
let json = await resp.json();
|
let json = await resp.json();
|
||||||
console.log(json);
|
console.log(json);
|
||||||
|
@ -108,6 +109,10 @@
|
||||||
let stripe_orders = 0;
|
let stripe_orders = 0;
|
||||||
let cash_orders = 0;
|
let cash_orders = 0;
|
||||||
|
|
||||||
|
let stripe_sessioncreated = 0;
|
||||||
|
let stripe_failed = 0;
|
||||||
|
let stripe_paid = 0;
|
||||||
|
|
||||||
function updateStats() {
|
function updateStats() {
|
||||||
for (let i = 0; i < orders.length; i++) {
|
for (let i = 0; i < orders.length; i++) {
|
||||||
if (orders[i].order_type === "Cash") {
|
if (orders[i].order_type === "Cash") {
|
||||||
|
@ -115,6 +120,13 @@
|
||||||
}
|
}
|
||||||
if (orders[i].order_type === "Stripe") {
|
if (orders[i].order_type === "Stripe") {
|
||||||
stripe_orders += 1;
|
stripe_orders += 1;
|
||||||
|
if (orders[i].stripe_status === 'SessionCreated') {
|
||||||
|
stripe_sessioncreated += 1;
|
||||||
|
} else if (orders[i].stripe_status === 'Failed') {
|
||||||
|
stripe_failed += 1;
|
||||||
|
} else if (orders[i].stripe_status === 'Paid') {
|
||||||
|
stripe_paid += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,6 +143,7 @@
|
||||||
<Cell numeric>ID</Cell>
|
<Cell numeric>ID</Cell>
|
||||||
<Cell style="width: 70%;">Products</Cell>
|
<Cell style="width: 70%;">Products</Cell>
|
||||||
<Cell>Order Type</Cell>
|
<Cell>Order Type</Cell>
|
||||||
|
<Cell>Stripe Status</Cell>
|
||||||
<Cell>Revenue</Cell>
|
<Cell>Revenue</Cell>
|
||||||
</Row>
|
</Row>
|
||||||
</Head>
|
</Head>
|
||||||
|
@ -142,6 +155,7 @@
|
||||||
{buildProductsString(order)}
|
{buildProductsString(order)}
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell>{order.order_type}</Cell>
|
<Cell>{order.order_type}</Cell>
|
||||||
|
<Cell>{order.stripe_status}</Cell>
|
||||||
<Cell>{formatter.format(order.total_usd)}</Cell>
|
<Cell>{formatter.format(order.total_usd)}</Cell>
|
||||||
</Row>
|
</Row>
|
||||||
{/each}
|
{/each}
|
||||||
|
@ -149,6 +163,7 @@
|
||||||
<Row>
|
<Row>
|
||||||
<Cell numeric></Cell>
|
<Cell numeric></Cell>
|
||||||
<Cell></Cell>
|
<Cell></Cell>
|
||||||
|
<Cell></Cell>
|
||||||
<Cell><b>Total Revenue</b></Cell>
|
<Cell><b>Total Revenue</b></Cell>
|
||||||
<Cell>{formatter.format(total.toFixed(2))}</Cell>
|
<Cell>{formatter.format(total.toFixed(2))}</Cell>
|
||||||
</Row>
|
</Row>
|
||||||
|
@ -165,6 +180,9 @@
|
||||||
<p>order_type = STRIPE: {stripe_orders}</p>
|
<p>order_type = STRIPE: {stripe_orders}</p>
|
||||||
<p>Percentage of orders using CASH: {(cash_orders / orders.length) * 100}%</p>
|
<p>Percentage of orders using CASH: {(cash_orders / orders.length) * 100}%</p>
|
||||||
<p>Percentage of orders using STRIPE: {(stripe_orders / orders.length) * 100}%</p>
|
<p>Percentage of orders using STRIPE: {(stripe_orders / orders.length) * 100}%</p>
|
||||||
|
<p>Percentage of STRIPE, stripe_status = SessionCreated: {stripe_sessioncreated} ({stripe_sessioncreated / stripe_orders * 100}%)</p>
|
||||||
|
<p>Percentage of STRIPE, stripe_status = Failed: {stripe_failed} ({stripe_failed / stripe_orders * 100}%)</p>
|
||||||
|
<p>Percentage of STRIPE, stripe_status = Paid: {stripe_paid} ({stripe_paid / stripe_orders * 100}%)</p>
|
||||||
</PaperContent>
|
</PaperContent>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
import Tooltip, { Wrapper as TooltipWrapper } from "@smui/tooltip";
|
import Tooltip, { Wrapper as TooltipWrapper } from "@smui/tooltip";
|
||||||
|
|
||||||
import "./style.scss";
|
import "./style.scss";
|
||||||
|
import {authToken} from "$lib/stores/AuthStore";
|
||||||
|
|
||||||
let loaded = false;
|
let loaded = false;
|
||||||
let products = [];
|
let products = [];
|
||||||
|
@ -26,7 +27,7 @@
|
||||||
async function loadProducts() {
|
async function loadProducts() {
|
||||||
loaded = false;
|
loaded = false;
|
||||||
try {
|
try {
|
||||||
let resp = await fetch(`${$serverUrl}/products`);
|
let resp = await fetch(`${$serverUrl}/products`, {headers: [["Authorization", "Bearer " + $authToken]]});
|
||||||
if (resp.ok) {
|
if (resp.ok) {
|
||||||
let json = await resp.json();
|
let json = await resp.json();
|
||||||
console.log(json);
|
console.log(json);
|
||||||
|
@ -86,7 +87,8 @@
|
||||||
let resp = await fetch(`${$serverUrl}/products/${editingProductID}`, {
|
let resp = await fetch(`${$serverUrl}/products/${editingProductID}`, {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
headers: [
|
headers: [
|
||||||
['Content-Type', 'application/json']
|
['Content-Type', 'application/json'],
|
||||||
|
["Authorization", "Bearer " + $authToken]
|
||||||
],
|
],
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
name: editName,
|
name: editName,
|
||||||
|
@ -126,7 +128,7 @@
|
||||||
deletingProduct = false;
|
deletingProduct = false;
|
||||||
loaded = false;
|
loaded = false;
|
||||||
try {
|
try {
|
||||||
let resp = await fetch(`${$serverUrl}/products/${id}`, {method: 'DELETE'});
|
let resp = await fetch(`${$serverUrl}/products/${id}`, {method: 'DELETE', headers: [["Authorization", "Bearer " + $authToken]]});
|
||||||
if (resp.ok) {
|
if (resp.ok) {
|
||||||
loaded = true;
|
loaded = true;
|
||||||
await loadProducts();
|
await loadProducts();
|
||||||
|
@ -177,7 +179,8 @@
|
||||||
let resp = await fetch(`${$serverUrl}/products`, {
|
let resp = await fetch(`${$serverUrl}/products`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: [
|
headers: [
|
||||||
['Content-Type', 'application/json']
|
['Content-Type', 'application/json'],
|
||||||
|
["Authorization", "Bearer " + $authToken]
|
||||||
],
|
],
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
name: createName,
|
name: createName,
|
||||||
|
|
Loading…
Reference in New Issue