Compare commits

...
17 changed files with 619 additions and 38 deletions
Generated
+406 -27
View File
@@ -721,7 +721,7 @@ dependencies = [
"openai_sora_client",
"os_info",
"primitives",
"rand 0.9.1",
"rand 0.9.2",
"reqwest 0.12.23",
"serde",
"serde_derive",
@@ -2984,6 +2984,20 @@ dependencies = [
"syn 2.0.106",
]
[[package]]
name = "dashmap"
version = "6.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf"
dependencies = [
"cfg-if",
"crossbeam-utils",
"hashbrown 0.14.5",
"lock_api",
"once_cell",
"parking_lot_core 0.9.10",
]
[[package]]
name = "data-encoding"
version = "2.5.0"
@@ -3219,7 +3233,7 @@ dependencies = [
"log",
"mimetypes",
"mysql_queries",
"rand 0.9.1",
"rand 0.9.2",
"sqlx",
"storyteller_root",
"tokens",
@@ -3468,7 +3482,7 @@ checksum = "f2646c2bb4993c86006961293208b69d86a2b254356889ddad826e9df3f684f9"
dependencies = [
"bit-set",
"cssparser 0.35.0",
"foldhash",
"foldhash 0.1.5",
"html5ever 0.35.0",
"precomputed-hash",
"selectors 0.30.0",
@@ -3641,6 +3655,15 @@ dependencies = [
"spki",
]
[[package]]
name = "ecow"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78e4f79b296fbaab6ce2e22d52cb4c7f010fe0ebe7a32e34fa25885fd797bd02"
dependencies = [
"serde",
]
[[package]]
name = "ed25519-compact"
version = "2.1.1"
@@ -4242,6 +4265,12 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]]
name = "foldhash"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
[[package]]
name = "foreign-types"
version = "0.3.2"
@@ -4454,6 +4483,12 @@ version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
[[package]]
name = "futures-timer"
version = "3.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24"
[[package]]
name = "futures-util"
version = "0.3.31"
@@ -4646,11 +4681,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
dependencies = [
"cfg-if",
"js-sys",
"libc",
"wasi 0.13.3+wasi-0.2.2",
"wasm-bindgen",
"windows-targets 0.52.6",
]
[[package]]
name = "getrandom"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec"
dependencies = [
"cfg-if",
"js-sys",
"libc",
"r-efi",
"wasip2",
"wasip3",
"wasm-bindgen",
]
[[package]]
name = "gif"
version = "0.13.1"
@@ -4805,6 +4857,29 @@ dependencies = [
"workspace-build-acceleration",
]
[[package]]
name = "governor"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9efcab3c1958580ff1f25a2a41be1668f7603d849bb63af523b208a3cc1223b8"
dependencies = [
"cfg-if",
"dashmap",
"futures-sink",
"futures-timer",
"futures-util",
"getrandom 0.3.1",
"hashbrown 0.16.1",
"nonzero_ext",
"parking_lot 0.12.2",
"portable-atomic",
"quanta",
"rand 0.9.2",
"smallvec",
"spinning_top",
"web-time",
]
[[package]]
name = "grok_client"
version = "0.0.1"
@@ -4981,6 +5056,20 @@ name = "hashbrown"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
dependencies = [
"foldhash 0.1.5",
]
[[package]]
name = "hashbrown"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
dependencies = [
"allocator-api2",
"equivalent",
"foldhash 0.2.0",
]
[[package]]
name = "hashing"
@@ -5613,6 +5702,12 @@ dependencies = [
"syn 2.0.106",
]
[[package]]
name = "id-arena"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
[[package]]
name = "idempotency"
version = "0.0.1"
@@ -6239,6 +6334,12 @@ dependencies = [
"spin 0.5.2",
]
[[package]]
name = "leb128fmt"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
[[package]]
name = "lebe"
version = "0.5.2"
@@ -6566,7 +6667,7 @@ dependencies = [
"log-mdc",
"mock_instant",
"parking_lot 0.12.2",
"rand 0.9.1",
"rand 0.9.2",
"serde",
"serde-value",
"serde_json",
@@ -6747,13 +6848,13 @@ checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
[[package]]
name = "maybe-async"
version = "0.2.7"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f1b8c13cb1f814b634a96b2c725449fe7ed464a7b8781de8688be5ffbd3f305"
checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
"syn 2.0.106",
]
[[package]]
@@ -7122,7 +7223,7 @@ dependencies = [
"log",
"num-traits",
"once_cell",
"rand 0.9.1",
"rand 0.9.2",
"regex",
"reusable_types",
"serde",
@@ -7296,6 +7397,12 @@ dependencies = [
"minimal-lexical",
]
[[package]]
name = "nonzero_ext"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21"
[[package]]
name = "noop_proc_macro"
version = "0.3.0"
@@ -7840,7 +7947,7 @@ dependencies = [
"idempotency",
"log",
"once_cell",
"rand 0.9.1",
"rand 0.9.2",
"serde",
"serde_derive",
"serde_json",
@@ -7870,7 +7977,7 @@ dependencies = [
"idempotency",
"log",
"once_cell",
"rand 0.9.1",
"rand 0.9.2",
"reqwest 0.12.23",
"serde",
"serde_derive",
@@ -8589,6 +8696,16 @@ dependencies = [
"log",
]
[[package]]
name = "prettyplease"
version = "0.2.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
dependencies = [
"proc-macro2",
"syn 2.0.106",
]
[[package]]
name = "primeorder"
version = "0.13.6"
@@ -8832,6 +8949,21 @@ dependencies = [
"bytemuck",
]
[[package]]
name = "quanta"
version = "0.12.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3ab5a9d756f0d97bdc89019bd2e4ea098cf9cde50ee7564dde6b81ccc8f06c7"
dependencies = [
"crossbeam-utils",
"libc",
"once_cell",
"raw-cpuid",
"wasi 0.11.0+wasi-snapshot-preview1",
"web-sys",
"winapi",
]
[[package]]
name = "quick-error"
version = "1.2.3"
@@ -8946,6 +9078,12 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79ec282e887b434b68c18fe5c121d38e72a5cf35119b59e54ec5b992ea9c8eb0"
[[package]]
name = "r-efi"
version = "5.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
[[package]]
name = "r2d2"
version = "0.8.10"
@@ -9013,9 +9151,9 @@ dependencies = [
[[package]]
name = "rand"
version = "0.9.1"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
dependencies = [
"rand_chacha 0.9.0",
"rand_core 0.9.3",
@@ -9161,6 +9299,15 @@ dependencies = [
"rgb",
]
[[package]]
name = "raw-cpuid"
version = "11.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186"
dependencies = [
"bitflags 2.5.0",
]
[[package]]
name = "raw-window-handle"
version = "0.6.2"
@@ -9246,7 +9393,7 @@ dependencies = [
"percent-encoding",
"pin-project-lite",
"r2d2",
"rand 0.9.1",
"rand 0.9.2",
"rustls 0.23.13",
"rustls-native-certs 0.8.0",
"ryu",
@@ -9488,6 +9635,61 @@ dependencies = [
"webpki-roots 1.0.2",
]
[[package]]
name = "reqwest"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801"
dependencies = [
"base64 0.22.1",
"bytes",
"futures-core",
"h2 0.4.5",
"http 1.3.1",
"http-body 1.0.1",
"http-body-util",
"hyper 1.6.0",
"hyper-rustls 0.27.3",
"hyper-tls",
"hyper-util",
"js-sys",
"log",
"native-tls",
"percent-encoding",
"pin-project-lite",
"rustls-pki-types",
"serde",
"serde_json",
"serde_urlencoded",
"sync_wrapper 1.0.2",
"tokio",
"tokio-native-tls",
"tower 0.5.2",
"tower-http",
"tower-service",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
]
[[package]]
name = "resend-rs"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47209b1b50ed58522cd0084c581df21967616b98308c636d96d81ef24da63566"
dependencies = [
"ecow",
"getrandom 0.4.1",
"governor",
"maybe-async",
"rand 0.9.2",
"reqwest 0.13.2",
"serde",
"serde_json",
"thiserror 2.0.12",
]
[[package]]
name = "reusable_types"
version = "0.0.1"
@@ -9633,7 +9835,7 @@ dependencies = [
"jwt_light",
"log",
"once_cell",
"rand 0.9.1",
"rand 0.9.2",
"reqwest 0.12.23",
"serde",
"serde_derive",
@@ -10233,10 +10435,11 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "serde"
version = "1.0.219"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
"serde_derive",
]
@@ -10262,10 +10465,19 @@ dependencies = [
]
[[package]]
name = "serde_derive"
version = "1.0.219"
name = "serde_core"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
@@ -10298,15 +10510,16 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.140"
version = "1.0.149"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
dependencies = [
"indexmap 2.9.0",
"itoa 1.0.11",
"memchr",
"ryu",
"serde",
"serde_core",
"zmij",
]
[[package]]
@@ -10841,6 +11054,15 @@ dependencies = [
"lock_api",
]
[[package]]
name = "spinning_top"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300"
dependencies = [
"lock_api",
]
[[package]]
name = "spki"
version = "0.7.3"
@@ -11198,13 +11420,14 @@ dependencies = [
"primitives",
"prompt_engineering",
"r2d2",
"rand 0.9.1",
"rand 0.9.2",
"redis 1.0.2",
"redis_caching",
"redis_common",
"redis_schema",
"regex",
"reqwest 0.12.23",
"resend-rs",
"reusable_types",
"rust-s3",
"serde",
@@ -12655,9 +12878,9 @@ dependencies = [
[[package]]
name = "tower-http"
version = "0.6.6"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2"
checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8"
dependencies = [
"async-compression",
"bitflags 2.5.0",
@@ -12873,7 +13096,7 @@ dependencies = [
"http 1.3.1",
"httparse",
"log",
"rand 0.9.1",
"rand 0.9.2",
"sha1 0.10.6",
"thiserror 2.0.12",
"utf-8",
@@ -13126,7 +13349,7 @@ dependencies = [
"md-5 0.10.6",
"once_cell",
"primitives",
"rand 0.9.1",
"rand 0.9.2",
"workspace-build-acceleration",
]
@@ -13425,6 +13648,24 @@ dependencies = [
"wit-bindgen-rt",
]
[[package]]
name = "wasip2"
version = "1.0.2+wasi-0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5"
dependencies = [
"wit-bindgen",
]
[[package]]
name = "wasip3"
version = "0.4.0+wasi-0.3.0-rc-2026-01-06"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"
dependencies = [
"wit-bindgen",
]
[[package]]
name = "wasite"
version = "0.1.0"
@@ -13510,6 +13751,28 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "wasm-encoder"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319"
dependencies = [
"leb128fmt",
"wasmparser",
]
[[package]]
name = "wasm-metadata"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909"
dependencies = [
"anyhow",
"indexmap 2.9.0",
"wasm-encoder",
"wasmparser",
]
[[package]]
name = "wasm-streams"
version = "0.4.0"
@@ -13523,6 +13786,18 @@ dependencies = [
"web-sys",
]
[[package]]
name = "wasmparser"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
dependencies = [
"bitflags 2.5.0",
"hashbrown 0.15.2",
"indexmap 2.9.0",
"semver 1.0.23",
]
[[package]]
name = "wayland-backend"
version = "0.3.10"
@@ -13593,6 +13868,16 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "web-time"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "web_atoms"
version = "0.1.3"
@@ -14357,6 +14642,26 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "wit-bindgen"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
dependencies = [
"wit-bindgen-rust-macro",
]
[[package]]
name = "wit-bindgen-core"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc"
dependencies = [
"anyhow",
"heck 0.5.0",
"wit-parser",
]
[[package]]
name = "wit-bindgen-rt"
version = "0.33.0"
@@ -14366,6 +14671,74 @@ dependencies = [
"bitflags 2.5.0",
]
[[package]]
name = "wit-bindgen-rust"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21"
dependencies = [
"anyhow",
"heck 0.5.0",
"indexmap 2.9.0",
"prettyplease",
"syn 2.0.106",
"wasm-metadata",
"wit-bindgen-core",
"wit-component",
]
[[package]]
name = "wit-bindgen-rust-macro"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a"
dependencies = [
"anyhow",
"prettyplease",
"proc-macro2",
"quote",
"syn 2.0.106",
"wit-bindgen-core",
"wit-bindgen-rust",
]
[[package]]
name = "wit-component"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
dependencies = [
"anyhow",
"bitflags 2.5.0",
"indexmap 2.9.0",
"log",
"serde",
"serde_derive",
"serde_json",
"wasm-encoder",
"wasm-metadata",
"wasmparser",
"wit-parser",
]
[[package]]
name = "wit-parser"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736"
dependencies = [
"anyhow",
"id-arena",
"indexmap 2.9.0",
"log",
"semver 1.0.23",
"serde",
"serde_derive",
"serde_json",
"unicode-xid",
"wasmparser",
]
[[package]]
name = "workspace-build-acceleration"
version = "0.1.0"
@@ -14918,6 +15291,12 @@ dependencies = [
"zstd 0.13.3",
]
[[package]]
name = "zmij"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
[[package]]
name = "zopfli"
version = "0.8.1"
+1 -1
View File
@@ -276,7 +276,7 @@ r2d2 = "0.8.10"
rand = "0.9.1"
redis = { version = "1.0.2", features = ["r2d2", "tokio-rustls-comp", "tokio-comp", "cluster-async", "aio"] }
regex = "1.12.2"
reqwest = { version = "0.12.23", default-features = false, features = [ "charset", "http2", "system-proxy", "json", "cookies", "rustls-tls" ] }
reqwest = { version = "0.12.23", default-features = false, features = [ "charset", "http2", "system-proxy", "json", "cookies", "rustls-tls", "gzip" ] }
reqwest-websocket = { version = "0.5.0" }
serde = { version = "1.0.219", features = ["derive"] }
serde_derive = "1.0.219"
@@ -22,9 +22,11 @@ pub async fn change_password_from_password_reset<'a, 'b>(
UPDATE users
SET
email_confirmed = true,
email_is_synthetic = false,
is_without_password = false,
is_temporary = false,
password_hash = ?,
ip_address_last_update = ?,
is_without_password = false,
password_version = password_version + 1,
version = version + 1
WHERE
@@ -113,6 +113,9 @@ language-tags = "0.3.2" # Parsing single tags richly
# TODO/NB: This is just for Twitch, but we might need it later.
reqwest.workspace = true
# Email
resend-rs = "0.21.0"
# Runtime
tokio.workspace = true
@@ -37,6 +37,7 @@ pub mod threads;
pub mod util;
pub mod docs;
mod email;
#[actix_web::main]
async fn main() -> Result<(), impl Error> {
@@ -552,7 +552,6 @@ use tokens::tokens::zs_voice_datasets::*;
EnqueueVoiceConversionInferenceError,
EnqueueVoiceConversionInferenceRequest,
EnqueueVoiceConversionInferenceSuccessResponse,
FakeYouPlan,
FeaturedMediaFile,
FeaturedModelWeightForList,
FundamentalFrequencyMethod,
@@ -728,10 +727,8 @@ use tokens::tokens::zs_voice_datasets::*;
SearchModelWeightsSortField,
SearchModelWeightsSuccessResponse,
SessionInfoError,
SessionInfoSuccessResponse,
SessionTokenInfoError,
SessionTokenInfoSuccessResponse,
SessionUserInfo,
SetMediaFileCoverImageError,
SetMediaFileCoverImageRequest,
SetModelWeightCoverImageError,
@@ -750,7 +747,6 @@ use tokens::tokens::zs_voice_datasets::*;
StatusAlertInfo,
StatusAlertResponse,
StatusDetailsResponse,
StorytellerStreamPlan,
SubscriptionProductKey,
TerminateInferenceJobError,
TerminateInferenceJobPathInfo,
@@ -0,0 +1,26 @@
use std::fmt::format;
use server_environment::ServerEnvironment;
use crate::http_server::requests::get_request_domain_branding::DomainBranding;
#[derive(Clone)]
pub enum PasswordResetLocation {
FakeYouProduction,
FakeYouDevelopment,
ArtCraftProduction,
ArtCraftDevelopment,
CustomUrl(String)
}
pub fn get_password_reset_url(reset_token: &str, location: PasswordResetLocation) -> String {
let url = match location {
PasswordResetLocation::ArtCraftProduction => "https://getartcraft.com/password-reset/verify",
PasswordResetLocation::FakeYouProduction => "https://fakeyou.com/password-reset/verify",
PasswordResetLocation::ArtCraftDevelopment |
PasswordResetLocation::FakeYouDevelopment => {
"http://localhost:7000/password-reset/verify"
},
PasswordResetLocation::CustomUrl(ref url) => url,
};
format!("{url}?token={reset_token}")
}
@@ -0,0 +1,2 @@
pub mod send_password_reset_email;
pub mod get_password_reset_url;
@@ -0,0 +1,82 @@
use crate::email::get_password_reset_url::{get_password_reset_url, PasswordResetLocation};
use crate::http_server::requests::get_request_domain_branding::DomainBranding;
use errors::AnyhowResult;
use resend_rs::types::CreateEmailBaseOptions;
use resend_rs::Resend;
use server_environment::ServerEnvironment;
pub struct SendPasswordResetEmailArgs<'a> {
pub email_address_destination: &'a str,
pub verification_token: &'a str,
pub resend_api_key: &'a str,
pub server_environment: ServerEnvironment,
pub domain_branding: DomainBranding,
}
pub async fn send_password_reset_email(
args: SendPasswordResetEmailArgs<'_>
) -> AnyhowResult<()> {
let resend = Resend::new(&args.resend_api_key);
let to = [args.email_address_destination];
let subject = "ArtCraft Password Reset";
let from_address = match args.domain_branding {
DomainBranding::ArtCraftDotAi |
DomainBranding::GetArtCraft => "ArtCraft <noreply@getartcraft.com>",
DomainBranding::FakeYou => "FakeYou <noreply@fakeyou.com>",
DomainBranding::Storyteller => "FakeYou <noreply@fakeyou.com>",
};
let platform = match args.domain_branding {
DomainBranding::ArtCraftDotAi |
DomainBranding::GetArtCraft => "ArtCraft",
DomainBranding::FakeYou => "FakeYou",
DomainBranding::Storyteller => "Storyteller.ai",
};
let team_name = match args.domain_branding {
DomainBranding::ArtCraftDotAi |
DomainBranding::GetArtCraft => "ArtCraft Team",
DomainBranding::FakeYou => "FakeYou Team",
DomainBranding::Storyteller => "Storyteller.ai Team",
};
let url = match (args.domain_branding, args.server_environment) {
// Legacy FakeYou
(DomainBranding::FakeYou, ServerEnvironment::Development) => PasswordResetLocation::FakeYouDevelopment,
(DomainBranding::FakeYou, ServerEnvironment::Production) => PasswordResetLocation::FakeYouProduction,
// Everything else "development" is ArtCraft Development
(_, ServerEnvironment::Development) => PasswordResetLocation::ArtCraftDevelopment,
// Everything else "production" is ArtCraft Production
(_, ServerEnvironment::Production) => PasswordResetLocation::ArtCraftProduction,
};
let link = get_password_reset_url(args.verification_token, url);
let code = args.verification_token;
let html_message = format!(r#"
We received a request to reset your password on {platform}.
If this wasn't you, you can safely ignore this email.
<br />
<br />
<a href="{link}">Click here to reset your password!</a>
<br />
<br />
If you can't click the link, here's the secret reset code: {code}
<br />
<br />
Thank You,
<br />
<br />
{team_name}
"#);
let email = CreateEmailBaseOptions::new(from_address, to, subject)
.with_html(&html_message);
let _email = resend.emails.send(email).await?;
Ok(())
}
@@ -224,6 +224,7 @@ pub async fn enqueue_face_fusion_workflow_handler(
let mut watermark_type = match branding {
Some(DomainBranding::FakeYou) => Some(WatermarkType::FakeYou),
Some(DomainBranding::Storyteller) => Some(WatermarkType::Storyteller),
Some(_) => Some(WatermarkType::Storyteller),
None => Some(WatermarkType::Storyteller),
};
@@ -232,6 +232,7 @@ pub async fn enqueue_live_portrait_workflow_handler(
let mut watermark_type = match branding {
Some(DomainBranding::FakeYou) => Some(WatermarkType::FakeYou),
Some(DomainBranding::Storyteller) => Some(WatermarkType::Storyteller),
Some(_) => Some(WatermarkType::Storyteller),
None => Some(WatermarkType::Storyteller),
};
@@ -253,6 +253,7 @@ pub async fn enqueue_video_style_transfer_workflow_handler(
let mut watermark_type = match branding {
Some(DomainBranding::FakeYou) => Some(WatermarkType::FakeYou),
Some(DomainBranding::Storyteller) => Some(WatermarkType::Storyteller),
Some(_) => Some(WatermarkType::Storyteller),
None => Some(WatermarkType::Storyteller),
};
@@ -8,6 +8,8 @@ pub fn get_media_domain(http_request: &HttpRequest) -> MediaDomain {
.map(|domain| match domain {
DomainBranding::FakeYou => MediaDomain::FakeYou,
DomainBranding::Storyteller => MediaDomain::Storyteller,
DomainBranding::ArtCraftDotAi => MediaDomain::Storyteller,
DomainBranding::GetArtCraft => MediaDomain::Storyteller,
})
.unwrap_or(MediaDomain::FakeYou)
}
@@ -1,8 +1,8 @@
use std::fmt::Display;
use std::sync::Arc;
use actix_web::http::StatusCode;
use actix_web::{web, HttpRequest, HttpResponse, ResponseError};
use log::{error, warn};
use log::{error, info, warn};
use serde::Deserialize;
use sqlx::MySqlPool;
use strum_macros::Display;
@@ -20,6 +20,9 @@ use mysql_queries::queries::users::user::get::lookup_user_for_login_by_email::lo
use mysql_queries::queries::users::user::get::lookup_user_for_login_by_username::lookup_user_for_login_by_username;
use mysql_queries::queries::users::user_password_resets::create_password_reset_request::create_password_reset;
use server_environment::ServerEnvironment;
use crate::email::send_password_reset_email::{send_password_reset_email, SendPasswordResetEmailArgs};
use crate::http_server::requests::get_request_domain_branding::{get_request_domain_branding, DomainBranding};
use crate::state::server_state::ServerState;
#[derive(Deserialize)]
pub struct PasswordResetRequestedRequest {
@@ -81,7 +84,8 @@ pub async fn password_reset_request_handler(
http_request: HttpRequest,
request: web::Json<PasswordResetRequestedRequest>,
mysql_pool: web::Data<MySqlPool>,
_server_environment: web::Data<ServerEnvironment>,
server_environment: web::Data<ServerEnvironment>,
server_state: web::Data<Arc<ServerState>>,
_sender: web::Data<SmtpEmailSender>,
) -> Result<HttpResponse, PasswordResetRequestedErrorResponse> {
@@ -134,7 +138,7 @@ pub async fn password_reset_request_handler(
email_category: EmailCategory::PasswordReset,
maybe_email_args: Some(EmailSenderJobArgs {
args: Some(PolymorphicEmailSenderJobArgs::Pr(EmailJobPasswordResetArgs {
password_reset_secret_key: Some(secret_key),
password_reset_secret_key: Some(secret_key.clone()),
})),
}),
ietf_language_tag,
@@ -153,6 +157,21 @@ pub async fn password_reset_request_handler(
PasswordResetRequestedRequestError::Internal
})?;
let domain_branding = get_request_domain_branding(&http_request)
.unwrap_or(DomainBranding::GetArtCraft);
let server_environment = **server_environment;
info!("Sending password reset email...");
send_password_reset_email(SendPasswordResetEmailArgs {
email_address_destination: &user.email_address,
verification_token: &secret_key,
resend_api_key: &server_state.resend.api_key,
server_environment,
domain_branding,
}).await?;
success_response()
}
@@ -5,6 +5,8 @@ use log::{debug, warn};
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum DomainBranding {
ArtCraftDotAi,
GetArtCraft,
FakeYou,
Storyteller,
}
@@ -59,6 +61,8 @@ fn match_possible_hostname(maybe_hostname: Option<&str>) -> Option<DomainBrandin
None => return None,
};
match hostname {
host if host.contains("artcraft.ai") => Some(DomainBranding::ArtCraftDotAi),
host if host.contains("getartcraft") => Some(DomainBranding::GetArtCraft),
host if host.contains("fakeyou") => Some(DomainBranding::FakeYou),
host if host.contains("storyteller") => Some(DomainBranding::Storyteller),
_ => None,
@@ -73,6 +77,39 @@ mod tests {
mod origin_header {
use super::*;
#[test]
fn getartcraft_dot_com() {
let request = TestRequest::get()
.insert_header(("origin", "https://getartcraft.com"))
.to_http_request();
assert_eq!(get_request_domain_branding(&request), Some(DomainBranding::GetArtCraft));
}
#[test]
fn api_dot_getartcraft_dot_com() {
let request = TestRequest::get()
.insert_header(("origin", "https://api.getartcraft.com"))
.to_http_request();
assert_eq!(get_request_domain_branding(&request), Some(DomainBranding::GetArtCraft));
}
#[test]
fn artcraft_dot_ai() {
let request = TestRequest::get()
.insert_header(("origin", "https://artcraft.ai"))
.to_http_request();
assert_eq!(get_request_domain_branding(&request), Some(DomainBranding::ArtCraftDotAi));
}
#[test]
fn api_dot_artcraft_dot_ai() {
let request = TestRequest::get()
.insert_header(("origin", "https://api.artcraft.ai"))
.to_http_request();
assert_eq!(get_request_domain_branding(&request), Some(DomainBranding::ArtCraftDotAi));
}
#[test]
fn fakeyou_dot_com() {
@@ -110,6 +147,21 @@ mod tests {
mod host_header {
use super::*;
fn getartcraft_dot_com() {
let request = TestRequest::get()
.insert_header(("host", "getartcraft.com"))
.to_http_request();
assert_eq!(get_request_domain_branding(&request), Some(DomainBranding::GetArtCraft));
}
#[test]
fn api_dot_getartcraft_dot_com() {
let request = TestRequest::get()
.insert_header(("host", "api.getartcraft.com"))
.to_http_request();
assert_eq!(get_request_domain_branding(&request), Some(DomainBranding::GetArtCraft));
}
#[test]
fn fakeyou_dot_com() {
let request = TestRequest::get()
@@ -80,7 +80,7 @@ use crate::http_server::web_utils::handle_multipart_error::handle_multipart_erro
use crate::http_server::web_utils::scoped_temp_dir_creator::ScopedTempDirCreator;
use crate::state::certs::google_sign_in_cert::GoogleSignInCert;
use crate::state::memory_cache::model_token_to_info_cache::ModelTokenToInfoCache;
use crate::state::server_state::{DurableInMemoryCaches, EnvConfig, EphemeralInMemoryCaches, FalData, InMemoryCaches, OpenAiData, ServerInfo, ServerState, StaticFeatureFlags, StripeSettings, TrollBans};
use crate::state::server_state::{DurableInMemoryCaches, EnvConfig, EphemeralInMemoryCaches, FalData, InMemoryCaches, OpenAiData, ResendData, ServerInfo, ServerState, StaticFeatureFlags, StripeSettings, TrollBans};
use crate::threads::db_health_checker_thread::db_health_check_status::HealthCheckStatus;
use crate::threads::db_health_checker_thread::db_health_checker_thread::db_health_checker_thread;
use crate::threads::poll_ip_banlist_thread::poll_ip_bans;
@@ -91,6 +91,7 @@ use crate::util::troll_user_bans::troll_user_ban_list::TrollUserBanList;
pub mod billing;
pub mod configs;
pub mod email;
pub mod error;
pub mod http_server;
pub mod state;
@@ -401,6 +402,8 @@ async fn main() -> AnyhowResult<()> {
let openai_api_key= easyenv::get_env_string_required("OPENAI_API_KEY")?;
let resend_api_key = easyenv::get_env_string_required("RESEND_API_KEY")?;
let startup_time = Utc::now();
let server_state = ServerState {
@@ -459,6 +462,9 @@ async fn main() -> AnyhowResult<()> {
openai: OpenAiData {
api_key: openai_api_key,
},
resend: ResendData {
api_key: resend_api_key,
},
caches: InMemoryCaches {
durable: DurableInMemoryCaches {
model_token_info: model_token_info_cache,
@@ -95,6 +95,8 @@ pub struct ServerState {
pub openai: OpenAiData,
pub resend: ResendData,
/// Where to store audio uploads for w2l
pub audio_uploads_bucket_root: String,
@@ -314,3 +316,9 @@ pub struct FalData {
pub struct OpenAiData {
pub api_key: String,
}
/// Resend integration
#[derive(Clone)]
pub struct ResendData {
pub api_key: String,
}