diff --git a/.github/workflows/demo-ci.yml b/.github/workflows/demo-ci.yml deleted file mode 100644 index e2d9097b9..000000000 --- a/.github/workflows/demo-ci.yml +++ /dev/null @@ -1,82 +0,0 @@ -name: "[demo:ci]" - -on: - push: - branches: - - master - pull_request: - -env: - RUST_TOOLCHAIN: stable - TOOLCHAIN_PROFILE: minimal - -jobs: - style: - runs-on: ubuntu-latest - - permissions: - contents: read - - steps: - - name: Checkout the code - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - with: - toolchain: ${{ env.RUST_TOOLCHAIN }} - components: rustfmt - - name: Setup Rust cache - uses: Swatinem/rust-cache@v2 - - run: cargo fmt --all -- --check - working-directory: ./examples/demo - - name: Run cargo clippy - run: cargo clippy -- -W clippy::nursery -W clippy::pedantic -W rust-2018-idioms -W rust-2021-compatibility - working-directory: ./examples/demo - - test: - needs: [style] - runs-on: ubuntu-latest - - permissions: - contents: read - - services: - redis: - image: redis - options: >- - --health-cmd "redis-cli ping" - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - - "6379:6379" - postgres: - image: postgres - env: - POSTGRES_DB: postgres_test - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - ports: - - "5432:5432" - # Set health checks to wait until postgres has started - options: --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - - steps: - - name: Checkout the code - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - with: - toolchain: ${{ env.RUST_TOOLCHAIN }} - - name: Setup Rust cache - uses: Swatinem/rust-cache@v2 - - name: Install seaorm cli - run: cargo install sea-orm-cli - - name: Run cargo test - run: cargo test --all-features --all - working-directory: ./examples/demo - env: - LOCO_CI_MODE: 1 - REDIS_URL: redis://localhost:${{job.services.redis.ports[6379]}} - DATABASE_URL: postgres://postgres:postgres@localhost:5432/postgres_test diff --git a/examples/demo/.cargo/config.toml b/examples/demo/.cargo/config.toml deleted file mode 100644 index fb921ea85..000000000 --- a/examples/demo/.cargo/config.toml +++ /dev/null @@ -1,4 +0,0 @@ -[alias] -loco = "run --" -loco-tool = "run --bin tool --" -playground = "run --example playground" diff --git a/examples/demo/.rustfmt.toml b/examples/demo/.rustfmt.toml deleted file mode 100644 index 777ca6821..000000000 --- a/examples/demo/.rustfmt.toml +++ /dev/null @@ -1,8 +0,0 @@ -max_width = 100 -comment_width = 80 -wrap_comments = true -imports_granularity = "Crate" -use_small_heuristics = "Default" -group_imports = "StdExternalCrate" -format_strings = true -edition = "2021" diff --git a/examples/demo/.vscode/settings.json b/examples/demo/.vscode/settings.json deleted file mode 100644 index b48948abd..000000000 --- a/examples/demo/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "rust-analyzer.showUnlinkedFileNotification": false -} diff --git a/examples/demo/Cargo.lock b/examples/demo/Cargo.lock deleted file mode 100644 index e91a236a9..000000000 --- a/examples/demo/Cargo.lock +++ /dev/null @@ -1,6527 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" - -[[package]] -name = "aead" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" -dependencies = [ - "crypto-common", - "generic-array", -] - -[[package]] -name = "aes" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - -[[package]] -name = "aes-gcm" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" -dependencies = [ - "aead", - "aes", - "cipher", - "ctr", - "ghash", - "subtle", -] - -[[package]] -name = "ahash" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" -dependencies = [ - "getrandom", - "once_cell", - "version_check", -] - -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "getrandom", - "once_cell", - "version_check", - "zerocopy", -] - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "aliasable" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" - -[[package]] -name = "alloc-no-stdlib" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" - -[[package]] -name = "alloc-stdlib" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" -dependencies = [ - "alloc-no-stdlib", -] - -[[package]] -name = "allocator-api2" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" - -[[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 = "anstream" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" - -[[package]] -name = "anstyle-parse" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" -dependencies = [ - "anstyle", - "windows-sys 0.59.0", -] - -[[package]] -name = "anyhow" -version = "1.0.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" - -[[package]] -name = "arc-swap" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" - -[[package]] -name = "argon2" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" -dependencies = [ - "base64ct", - "blake2", - "cpufeatures", - "password-hash", -] - -[[package]] -name = "arrayvec" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" - -[[package]] -name = "assert-json-diff" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12" -dependencies = [ - "serde", - "serde_json", -] - -[[package]] -name = "async-attributes" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" -dependencies = [ - "quote", - "syn 1.0.109", -] - -[[package]] -name = "async-channel" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" -dependencies = [ - "concurrent-queue", - "event-listener 2.5.3", - "futures-core", -] - -[[package]] -name = "async-channel" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" -dependencies = [ - "concurrent-queue", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-compression" -version = "0.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df895a515f70646414f4b45c0b79082783b80552b373a68283012928df56f522" -dependencies = [ - "brotli", - "flate2", - "futures-core", - "memchr", - "pin-project-lite", - "tokio", - "zstd", - "zstd-safe", -] - -[[package]] -name = "async-executor" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", - "slab", -] - -[[package]] -name = "async-global-executor" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" -dependencies = [ - "async-channel 2.3.1", - "async-executor", - "async-io", - "async-lock", - "blocking", - "futures-lite", - "once_cell", - "tokio", -] - -[[package]] -name = "async-io" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" -dependencies = [ - "async-lock", - "cfg-if", - "concurrent-queue", - "futures-io", - "futures-lite", - "parking", - "polling", - "rustix", - "slab", - "tracing", - "windows-sys 0.59.0", -] - -[[package]] -name = "async-lock" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" -dependencies = [ - "event-listener 5.3.1", - "event-listener-strategy", - "pin-project-lite", -] - -[[package]] -name = "async-std" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c634475f29802fde2b8f0b505b1bd00dfe4df7d4a000f0b36f7671197d5c3615" -dependencies = [ - "async-attributes", - "async-channel 1.9.0", - "async-global-executor", - "async-io", - "async-lock", - "crossbeam-utils", - "futures-channel", - "futures-core", - "futures-io", - "futures-lite", - "gloo-timers", - "kv-log-macro", - "log", - "memchr", - "once_cell", - "pin-project-lite", - "pin-utils", - "slab", - "wasm-bindgen-futures", -] - -[[package]] -name = "async-stream" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.95", -] - -[[package]] -name = "async-task" -version = "4.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" - -[[package]] -name = "async-trait" -version = "0.1.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1244b10dcd56c92219da4e14caa97e312079e185f04ba3eea25061561dc0a0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.95", -] - -[[package]] -name = "atoi" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" -dependencies = [ - "num-traits", -] - -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - -[[package]] -name = "auto-future" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c1e7e457ea78e524f48639f551fd79703ac3f2237f5ecccdf4708f8a75ad373" - -[[package]] -name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" - -[[package]] -name = "axum" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d6fd624c75e18b3b4c6b9caf42b1afe24437daaee904069137d8bab077be8b8" -dependencies = [ - "axum-core", - "axum-macros", - "bytes", - "form_urlencoded", - "futures-util", - "http 1.2.0", - "http-body", - "http-body-util", - "hyper", - "hyper-util", - "itoa", - "matchit", - "memchr", - "mime", - "multer", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "serde_json", - "serde_path_to_error", - "serde_urlencoded", - "sync_wrapper", - "tokio", - "tower 0.5.2", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "axum-core" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1362f362fd16024ae199c1970ce98f9661bf5ef94b9808fee734bc3698b733" -dependencies = [ - "bytes", - "futures-util", - "http 1.2.0", - "http-body", - "http-body-util", - "mime", - "pin-project-lite", - "rustversion", - "sync_wrapper", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "axum-extra" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "460fc6f625a1f7705c6cf62d0d070794e94668988b1c38111baeec177c715f7b" -dependencies = [ - "axum", - "axum-core", - "bytes", - "cookie", - "futures-util", - "http 1.2.0", - "http-body", - "http-body-util", - "mime", - "pin-project-lite", - "serde", - "tower 0.5.2", - "tower-layer", - "tower-service", -] - -[[package]] -name = "axum-macros" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.95", -] - -[[package]] -name = "axum-test" -version = "17.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53f1009889890a439cbf67a4071a2593d027c65209da4faeac5582f28ca9e6c3" -dependencies = [ - "anyhow", - "assert-json-diff", - "auto-future", - "axum", - "bytes", - "bytesize", - "cookie", - "http 1.2.0", - "http-body-util", - "hyper", - "hyper-util", - "mime", - "pretty_assertions", - "reserve-port", - "rust-multipart-rfc7578_2", - "serde", - "serde_json", - "serde_urlencoded", - "smallvec", - "tokio", - "tower 0.5.2", - "url", -] - -[[package]] -name = "axum_session" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bcd5d9395b53d6a7054f599f4fe6f519d374a5b84fa758d1163af0d278b9213" -dependencies = [ - "aes-gcm", - "async-trait", - "axum", - "base64 0.22.1", - "bytes", - "chrono", - "cookie", - "dashmap", - "forwarded-header-value", - "futures", - "hmac", - "http 1.2.0", - "http-body", - "rand", - "serde", - "serde_json", - "sha2", - "thiserror 2.0.9", - "tokio", - "tower-layer", - "tower-service", - "tracing", - "uuid", -] - -[[package]] -name = "backon" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5289ec98f68f28dd809fd601059e6aa908bb8f6108620930828283d4ee23d7" -dependencies = [ - "fastrand", - "gloo-timers", - "tokio", -] - -[[package]] -name = "backtrace" -version = "0.3.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] - -[[package]] -name = "backtrace_printer" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8d28de81c708c843640982b66573df0f0168d87e42854b563971f326745aab7" -dependencies = [ - "btparse-stable", - "colored", - "regex", - "thiserror 1.0.69", -] - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "base64ct" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" - -[[package]] -name = "bb8" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89aabfae550a5c44b43ab941844ffcd2e993cb6900b342debf59e9ea74acdb8" -dependencies = [ - "async-trait", - "futures-util", - "parking_lot", - "tokio", -] - -[[package]] -name = "bigdecimal" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f31f3af01c5c65a07985c804d3366560e6fa7883d640a122819b14ec327482c" -dependencies = [ - "autocfg", - "libm", - "num-bigint", - "num-integer", - "num-traits", - "serde", -] - -[[package]] -name = "bitflags" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" -dependencies = [ - "serde", -] - -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - -[[package]] -name = "blake2" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" -dependencies = [ - "digest", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "blocking" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" -dependencies = [ - "async-channel 2.3.1", - "async-task", - "futures-io", - "futures-lite", - "piper", -] - -[[package]] -name = "borsh" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2506947f73ad44e344215ccd6403ac2ae18cd8e046e581a441bf8d199f257f03" -dependencies = [ - "borsh-derive", - "cfg_aliases", -] - -[[package]] -name = "borsh-derive" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2593a3b8b938bd68373196c9832f516be11fa487ef4ae745eb282e6a56a7244" -dependencies = [ - "once_cell", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.95", -] - -[[package]] -name = "brotli" -version = "7.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor", -] - -[[package]] -name = "brotli-decompressor" -version = "4.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", -] - -[[package]] -name = "bstr" -version = "1.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0" -dependencies = [ - "memchr", - "serde", -] - -[[package]] -name = "btparse-stable" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d75b8252ed252f881d1dc4482ae3c3854df6ee8183c1906bac50ff358f4f89f" - -[[package]] -name = "bumpalo" -version = "3.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - -[[package]] -name = "byte-unit" -version = "4.0.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da78b32057b8fdfc352504708feeba7216dcd65a2c9ab02978cbd288d1279b6c" -dependencies = [ - "serde", - "utf8-width", -] - -[[package]] -name = "bytecheck" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" -dependencies = [ - "bytecheck_derive", - "ptr_meta", - "simdutf8", -] - -[[package]] -name = "bytecheck_derive" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" - -[[package]] -name = "bytesize" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc" - -[[package]] -name = "cc" -version = "1.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a012a0df96dd6d06ba9a1b29d6402d1a5d77c6befd2566afdc26e10603dc93d7" -dependencies = [ - "jobserver", - "libc", - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - -[[package]] -name = "chrono" -version = "0.4.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "serde", - "wasm-bindgen", - "windows-targets 0.52.6", -] - -[[package]] -name = "chrono-tz" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93698b29de5e97ad0ae26447b344c482a7284c737d9ddc5f9e52b74a336671bb" -dependencies = [ - "chrono", - "chrono-tz-build", - "phf", -] - -[[package]] -name = "chrono-tz-build" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c088aee841df9c3041febbb73934cfc39708749bf96dc827e3359cd39ef11b1" -dependencies = [ - "parse-zoneinfo", - "phf", - "phf_codegen", -] - -[[package]] -name = "chumsky" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eebd66744a15ded14960ab4ccdbfb51ad3b81f51f3f04a80adac98c985396c9" -dependencies = [ - "hashbrown 0.14.5", - "stacker", -] - -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", -] - -[[package]] -name = "clap" -version = "4.5.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.5.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "syn 2.0.95", -] - -[[package]] -name = "clap_lex" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" - -[[package]] -name = "colorchoice" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" - -[[package]] -name = "colored" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" -dependencies = [ - "lazy_static", - "windows-sys 0.59.0", -] - -[[package]] -name = "combine" -version = "4.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" -dependencies = [ - "bytes", - "futures-core", - "memchr", - "pin-project-lite", - "tokio", - "tokio-util", -] - -[[package]] -name = "concurrent-queue" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "console" -version = "0.15.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b" -dependencies = [ - "encode_unicode", - "libc", - "once_cell", - "windows-sys 0.59.0", -] - -[[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - -[[package]] -name = "content_inspector" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7bda66e858c683005a53a9a60c69a4aca7eeaa45d124526e389f7aec8e62f38" -dependencies = [ - "memchr", -] - -[[package]] -name = "convert_case" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "cookie" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" -dependencies = [ - "aes-gcm", - "base64 0.22.1", - "percent-encoding", - "rand", - "subtle", - "time", - "version_check", -] - -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "cpufeatures" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" -dependencies = [ - "libc", -] - -[[package]] -name = "crc" -version = "3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" -dependencies = [ - "crc-catalog", -] - -[[package]] -name = "crc-catalog" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" - -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "cron" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f8c3e73077b4b4a6ab1ea5047c37c57aee77657bc8ecd6f29b0af082d0b0c07" -dependencies = [ - "chrono", - "nom", - "once_cell", -] - -[[package]] -name = "cron_clock" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a8699d8ed16e3db689f8ae04d8dc3c6666a4ba7e724e5a157884b7cc385d16b" -dependencies = [ - "chrono", - "nom", - "once_cell", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-queue" -version = "0.3.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "cruet" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "113a9e83d8f614be76de8df1f25bf9d0ea6e85ea573710a3d3f3abe1438ae49c" -dependencies = [ - "once_cell", - "regex", -] - -[[package]] -name = "cruet" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6132609543972496bc97b1e01f1ce6586768870aeb4cabeb3385f4e05b5caead" -dependencies = [ - "once_cell", - "regex", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "rand_core", - "typenum", -] - -[[package]] -name = "cssparser" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c66d1cd8ed61bf80b38432613a7a2f09401ab8d0501110655f8b341484a3e3" -dependencies = [ - "cssparser-macros", - "dtoa-short", - "itoa", - "phf", - "smallvec", -] - -[[package]] -name = "cssparser-macros" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" -dependencies = [ - "quote", - "syn 2.0.95", -] - -[[package]] -name = "ctr" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" -dependencies = [ - "cipher", -] - -[[package]] -name = "darling" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.95", -] - -[[package]] -name = "darling_macro" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" -dependencies = [ - "darling_core", - "quote", - "syn 2.0.95", -] - -[[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", -] - -[[package]] -name = "demo_app" -version = "0.1.0" -dependencies = [ - "async-trait", - "axum", - "axum-extra", - "axum-test", - "axum_session", - "chrono", - "fluent-templates", - "futures-util", - "include_dir", - "insta", - "loco-rs", - "migration", - "rstest", - "sea-orm", - "serde", - "serde_json", - "serial_test", - "tera", - "tokio", - "tower 0.4.13", - "tracing", - "tracing-subscriber", - "trycmd", - "unic-langid", - "utoipa", - "uuid", - "validator", -] - -[[package]] -name = "der" -version = "0.7.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" -dependencies = [ - "const-oid", - "pem-rfc7468", - "zeroize", -] - -[[package]] -name = "deranged" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" -dependencies = [ - "powerfmt", - "serde", -] - -[[package]] -name = "derive_more" -version = "0.99.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.95", -] - -[[package]] -name = "deunicode" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "339544cc9e2c4dc3fc7149fd630c5f22263a4fdf18a98afd0075784968b5cf00" - -[[package]] -name = "diff" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", - "subtle", -] - -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.95", -] - -[[package]] -name = "doc-comment" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" - -[[package]] -name = "dotenvy" -version = "0.15.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" - -[[package]] -name = "dtoa" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" - -[[package]] -name = "dtoa-short" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" -dependencies = [ - "dtoa", -] - -[[package]] -name = "duct" -version = "0.13.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ab5718d1224b63252cd0c6f74f6480f9ffeb117438a2e0f5cf6d9a4798929c" -dependencies = [ - "libc", - "once_cell", - "os_pipe", - "shared_child", -] - -[[package]] -name = "duct_sh" -version = "0.13.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a6633cadba557545fbbe0299a2f9adc4bb2fc5fb238773f5e841e0c23d62146" -dependencies = [ - "duct", -] - -[[package]] -name = "dunce" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" - -[[package]] -name = "ego-tree" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c6ba7d4eec39eaa9ab24d44a0e73a7949a1095a8b3f3abb11eddf27dbb56a53" - -[[package]] -name = "either" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" -dependencies = [ - "serde", -] - -[[package]] -name = "email-encoding" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea3d894bbbab314476b265f9b2d46bf24b123a36dd0e96b06a1b49545b9d9dcc" -dependencies = [ - "base64 0.22.1", - "memchr", -] - -[[package]] -name = "email_address" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e079f19b08ca6239f47f8ba8509c11cf3ea30095831f7fed61441475edd8c449" - -[[package]] -name = "encode_unicode" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" - -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "english-to-cron" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c16423ac933fee80f05a52b435a912d5b08edbbbfe936e0042ebb3accdf303da" -dependencies = [ - "lazy_static", - "regex", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "errno" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - -[[package]] -name = "etcetera" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" -dependencies = [ - "cfg-if", - "home", - "windows-sys 0.48.0", -] - -[[package]] -name = "event-listener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - -[[package]] -name = "event-listener" -version = "5.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener-strategy" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" -dependencies = [ - "event-listener 5.3.1", - "pin-project-lite", -] - -[[package]] -name = "fastrand" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - -[[package]] -name = "filetime" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" -dependencies = [ - "cfg-if", - "libc", - "libredox", - "windows-sys 0.59.0", -] - -[[package]] -name = "flagset" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3ea1ec5f8307826a5b71094dd91fc04d4ae75d5709b20ad351c7fb4815c86ec" - -[[package]] -name = "flate2" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "fluent" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb74634707bebd0ce645a981148e8fb8c7bccd4c33c652aeffd28bf2f96d555a" -dependencies = [ - "fluent-bundle", - "unic-langid", -] - -[[package]] -name = "fluent-bundle" -version = "0.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe0a21ee80050c678013f82edf4b705fe2f26f1f9877593d13198612503f493" -dependencies = [ - "fluent-langneg", - "fluent-syntax", - "intl-memoizer", - "intl_pluralrules", - "rustc-hash 1.1.0", - "self_cell 0.10.3", - "smallvec", - "unic-langid", -] - -[[package]] -name = "fluent-langneg" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c4ad0989667548f06ccd0e306ed56b61bd4d35458d54df5ec7587c0e8ed5e94" -dependencies = [ - "unic-langid", -] - -[[package]] -name = "fluent-syntax" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a530c4694a6a8d528794ee9bbd8ba0122e779629ac908d15ad5a7ae7763a33d" -dependencies = [ - "thiserror 1.0.69", -] - -[[package]] -name = "fluent-template-macros" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec7592cd1f45c1afe9084ce59c62a3a7c266c125c4c2ec97e95b0563c4aa914" -dependencies = [ - "flume 0.10.14", - "ignore", - "once_cell", - "proc-macro2", - "quote", - "syn 1.0.109", - "unic-langid", -] - -[[package]] -name = "fluent-templates" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c3ef2c2152757885365abce32ddf682746062f1b6b3c0824a29fbed6ee4d080" -dependencies = [ - "arc-swap", - "fluent", - "fluent-bundle", - "fluent-langneg", - "fluent-syntax", - "fluent-template-macros", - "flume 0.10.14", - "heck 0.4.1", - "ignore", - "intl-memoizer", - "lazy_static", - "log", - "once_cell", - "serde_json", - "snafu", - "tera", - "unic-langid", -] - -[[package]] -name = "flume" -version = "0.10.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" -dependencies = [ - "spin", -] - -[[package]] -name = "flume" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" -dependencies = [ - "futures-core", - "futures-sink", - "spin", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foldhash" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "forwarded-header-value" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8835f84f38484cc86f110a805655697908257fb9a7af005234060891557198e9" -dependencies = [ - "nonempty", - "thiserror 1.0.69", -] - -[[package]] -name = "fs-err" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" -dependencies = [ - "autocfg", -] - -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - -[[package]] -name = "futf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" -dependencies = [ - "mac", - "new_debug_unreachable", -] - -[[package]] -name = "futures" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-executor" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-intrusive" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" -dependencies = [ - "futures-core", - "lock_api", - "parking_lot", -] - -[[package]] -name = "futures-io" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" - -[[package]] -name = "futures-lite" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cef40d21ae2c515b51041df9ed313ed21e572df340ea58a922a0aefe7e8891a1" -dependencies = [ - "fastrand", - "futures-core", - "futures-io", - "parking", - "pin-project-lite", -] - -[[package]] -name = "futures-macro" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.95", -] - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "futures-task" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - -[[package]] -name = "generator" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6bd114ceda131d3b1d665eba35788690ad37f5916457286b32ab6fd3c438dd" -dependencies = [ - "cfg-if", - "libc", - "log", - "rustversion", - "windows 0.58.0", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "gethostname" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ebd34e35c46e00bb73e81363248d627782724609fe1b6396f553f68fe3862e" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "getopts" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" -dependencies = [ - "unicode-width", -] - -[[package]] -name = "getrandom" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi", - "wasm-bindgen", -] - -[[package]] -name = "ghash" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" -dependencies = [ - "opaque-debug", - "polyval", -] - -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - -[[package]] -name = "glob" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" - -[[package]] -name = "globset" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19" -dependencies = [ - "aho-corasick", - "bstr", - "log", - "regex-automata 0.4.9", - "regex-syntax 0.8.5", -] - -[[package]] -name = "globwalk" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf760ebf69878d9fd8f110c89703d90ce35095324d1f1edcb595c63945ee757" -dependencies = [ - "bitflags", - "ignore", - "walkdir", -] - -[[package]] -name = "gloo-timers" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "h2" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http 1.2.0", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash 0.7.8", -] - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash 0.8.11", - "allocator-api2", -] - -[[package]] -name = "hashbrown" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" -dependencies = [ - "allocator-api2", - "equivalent", - "foldhash", -] - -[[package]] -name = "hashlink" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" -dependencies = [ - "hashbrown 0.15.2", -] - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - -[[package]] -name = "hermit-abi" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hkdf" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" -dependencies = [ - "hmac", -] - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "home" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "hostname" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9c7c7c8ac16c798734b8a24560c1362120597c40d5e1459f09498f8f6c8f2ba" -dependencies = [ - "cfg-if", - "libc", - "windows 0.52.0", -] - -[[package]] -name = "html5ever" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e15626aaf9c351bc696217cbe29cb9b5e86c43f8a46b5e2f5c6c5cf7cb904ce" -dependencies = [ - "log", - "mac", - "markup5ever", - "proc-macro2", - "quote", - "syn 2.0.95", -] - -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" -dependencies = [ - "bytes", - "http 1.2.0", -] - -[[package]] -name = "http-body-util" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" -dependencies = [ - "bytes", - "futures-util", - "http 1.2.0", - "http-body", - "pin-project-lite", -] - -[[package]] -name = "http-range-header" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c" - -[[package]] -name = "httparse" -version = "1.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "humansize" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" -dependencies = [ - "libm", -] - -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - -[[package]] -name = "humantime-serde" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a3db5ea5923d99402c94e9feb261dc5ee9b4efa158b0315f788cf549cc200c" -dependencies = [ - "humantime", - "serde", -] - -[[package]] -name = "hyper" -version = "1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "h2", - "http 1.2.0", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "smallvec", - "tokio", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.27.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" -dependencies = [ - "futures-util", - "http 1.2.0", - "hyper", - "hyper-util", - "rustls", - "rustls-pki-types", - "tokio", - "tokio-rustls", - "tower-service", - "webpki-roots", -] - -[[package]] -name = "hyper-util" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "http 1.2.0", - "http-body", - "hyper", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core 0.52.0", -] - -[[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]] -name = "icu_collections" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locid" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" - -[[package]] -name = "icu_normalizer" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "utf16_iter", - "utf8_iter", - "write16", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" - -[[package]] -name = "icu_properties" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_locid_transform", - "icu_properties_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" - -[[package]] -name = "icu_provider" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_provider_macros", - "stable_deref_trait", - "tinystr", - "writeable", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.95", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "idna" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] -name = "ignore" -version = "0.4.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b" -dependencies = [ - "crossbeam-deque", - "globset", - "log", - "memchr", - "regex-automata 0.4.9", - "same-file", - "walkdir", - "winapi-util", -] - -[[package]] -name = "include_dir" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd" -dependencies = [ - "include_dir_macros", -] - -[[package]] -name = "include_dir_macros" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75" -dependencies = [ - "proc-macro2", - "quote", -] - -[[package]] -name = "indexmap" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" -dependencies = [ - "equivalent", - "hashbrown 0.15.2", - "serde", -] - -[[package]] -name = "inherent" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0122b7114117e64a63ac49f752a5ca4624d534c7b1c7de796ac196381cd2d947" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.95", -] - -[[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "generic-array", -] - -[[package]] -name = "insta" -version = "1.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513e4067e16e69ed1db5ab56048ed65db32d10ba5fc1217f5393f8f17d8b5a5" -dependencies = [ - "console", - "linked-hash-map", - "once_cell", - "pest", - "pest_derive", - "regex", - "serde", - "similar", -] - -[[package]] -name = "intl-memoizer" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe22e020fce238ae18a6d5d8c502ee76a52a6e880d99477657e6acc30ec57bda" -dependencies = [ - "type-map", - "unic-langid", -] - -[[package]] -name = "intl_pluralrules" -version = "7.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "078ea7b7c29a2b4df841a7f6ac8775ff6074020c6776d48491ce2268e068f972" -dependencies = [ - "unic-langid", -] - -[[package]] -name = "ipnet" -version = "2.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" - -[[package]] -name = "ipnetwork" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e" -dependencies = [ - "serde", -] - -[[package]] -name = "is-terminal" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" -dependencies = [ - "hermit-abi 0.4.0", - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" - -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" - -[[package]] -name = "jobserver" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" -dependencies = [ - "libc", -] - -[[package]] -name = "js-sys" -version = "0.3.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - -[[package]] -name = "jsonwebtoken" -version = "9.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ae10193d25051e74945f1ea2d0b42e03cc3b890f7e4cc5faa44997d808193f" -dependencies = [ - "base64 0.21.7", - "js-sys", - "pem", - "ring", - "serde", - "serde_json", - "simple_asn1", -] - -[[package]] -name = "kv-log-macro" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" -dependencies = [ - "log", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -dependencies = [ - "spin", -] - -[[package]] -name = "lettre" -version = "0.11.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab4c9a167ff73df98a5ecc07e8bf5ce90b583665da3d1762eb1f775ad4d0d6f5" -dependencies = [ - "async-trait", - "base64 0.22.1", - "chumsky", - "email-encoding", - "email_address", - "fastrand", - "futures-io", - "futures-util", - "hostname", - "httpdate", - "idna", - "mime", - "nom", - "percent-encoding", - "quoted_printable", - "rustls", - "rustls-pemfile", - "rustls-pki-types", - "socket2", - "tokio", - "tokio-rustls", - "url", - "webpki-roots", -] - -[[package]] -name = "libc" -version = "0.2.169" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" - -[[package]] -name = "libm" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" - -[[package]] -name = "libredox" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" -dependencies = [ - "bitflags", - "libc", - "redox_syscall", -] - -[[package]] -name = "libsqlite3-sys" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" -dependencies = [ - "cc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" - -[[package]] -name = "linux-raw-sys" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" - -[[package]] -name = "litemap" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" - -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "loco-gen" -version = "0.14.0" -dependencies = [ - "chrono", - "clap", - "colored", - "cruet 0.14.0", - "duct", - "include_dir", - "regex", - "rrgen", - "serde", - "serde_json", - "thiserror 1.0.69", - "tracing", -] - -[[package]] -name = "loco-rs" -version = "0.14.0" -dependencies = [ - "argon2", - "async-trait", - "axum", - "axum-extra", - "axum-test", - "backtrace_printer", - "bb8", - "byte-unit", - "bytes", - "cfg-if", - "chrono", - "clap", - "colored", - "cruet 0.13.3", - "duct", - "duct_sh", - "english-to-cron", - "fs-err", - "futures-util", - "heck 0.4.1", - "hyper", - "include_dir", - "ipnetwork", - "jsonwebtoken", - "lettre", - "loco-gen", - "mime", - "moka", - "opendal", - "rand", - "regex", - "reqwest", - "rusty-sidekiq", - "scraper", - "sea-orm", - "sea-orm-migration", - "semver", - "serde", - "serde_json", - "serde_variant", - "serde_yaml", - "sqlx", - "tera", - "thiserror 1.0.69", - "thousands", - "tokio", - "tokio-cron-scheduler", - "tokio-util", - "toml", - "tower 0.4.13", - "tower-http", - "tracing", - "tracing-appender", - "tracing-subscriber", - "ulid", - "uuid", - "validator", -] - -[[package]] -name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" -dependencies = [ - "value-bag", -] - -[[package]] -name = "loom" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" -dependencies = [ - "cfg-if", - "generator", - "scoped-tls", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "mac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" - -[[package]] -name = "markup5ever" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82c88c6129bd24319e62a0359cb6b958fa7e8be6e19bb1663bc396b90883aca5" -dependencies = [ - "log", - "phf", - "phf_codegen", - "string_cache", - "string_cache_codegen", - "tendril", -] - -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata 0.1.10", -] - -[[package]] -name = "matchit" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" - -[[package]] -name = "md-5" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" -dependencies = [ - "cfg-if", - "digest", -] - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "migration" -version = "0.1.0" -dependencies = [ - "async-std", - "loco-rs", - "sea-orm-migration", -] - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "mime_guess" -version = "2.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" -dependencies = [ - "mime", - "unicase", -] - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "miniz_oxide" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" -dependencies = [ - "adler2", -] - -[[package]] -name = "mio" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" -dependencies = [ - "libc", - "wasi", - "windows-sys 0.52.0", -] - -[[package]] -name = "moka" -version = "0.12.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23db87a7f248211f6a7c8644a1b750541f8a4c68ae7de0f908860e44c0c201f6" -dependencies = [ - "crossbeam-channel", - "crossbeam-epoch", - "crossbeam-utils", - "loom", - "parking_lot", - "quanta", - "rustc_version", - "smallvec", - "tagptr", - "thiserror 1.0.69", - "uuid", -] - -[[package]] -name = "multer" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83e87776546dc87511aa5ee218730c92b666d7264ab6ed41f9d215af9cd5224b" -dependencies = [ - "bytes", - "encoding_rs", - "futures-util", - "http 1.2.0", - "httparse", - "memchr", - "mime", - "spin", - "version_check", -] - -[[package]] -name = "new_debug_unreachable" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "nonempty" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9e591e719385e6ebaeb5ce5d3887f7d5676fceca6411d1925ccc95745f3d6f7" - -[[package]] -name = "normalize-line-endings" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" - -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-bigint-dig" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" -dependencies = [ - "byteorder", - "lazy_static", - "libm", - "num-integer", - "num-iter", - "num-traits", - "rand", - "smallvec", - "zeroize", -] - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "num-derive" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.95", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", - "libm", -] - -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi 0.3.9", - "libc", -] - -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" - -[[package]] -name = "opaque-debug" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" - -[[package]] -name = "opendal" -version = "0.50.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb28bb6c64e116ceaf8dd4e87099d3cfea4a58e85e62b104fef74c91afba0f44" -dependencies = [ - "anyhow", - "async-trait", - "backon", - "base64 0.22.1", - "bytes", - "chrono", - "flagset", - "futures", - "getrandom", - "http 1.2.0", - "log", - "md-5", - "once_cell", - "percent-encoding", - "quick-xml", - "reqwest", - "serde", - "serde_json", - "tokio", - "uuid", -] - -[[package]] -name = "ordered-float" -version = "3.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1e1c390732d15f1d48471625cd92d154e66db2c56645e29a9cd26f4699f72dc" -dependencies = [ - "num-traits", -] - -[[package]] -name = "os_pipe" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - -[[package]] -name = "ouroboros" -version = "0.18.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "944fa20996a25aded6b4795c6d63f10014a7a83f8be9828a11860b08c5fc4a67" -dependencies = [ - "aliasable", - "ouroboros_macro", - "static_assertions", -] - -[[package]] -name = "ouroboros_macro" -version = "0.18.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39b0deead1528fd0e5947a8546a9642a9777c25f6e1e26f34c97b204bbb465bd" -dependencies = [ - "heck 0.4.1", - "itertools", - "proc-macro2", - "proc-macro2-diagnostics", - "quote", - "syn 2.0.95", -] - -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - -[[package]] -name = "parking" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" - -[[package]] -name = "parking_lot" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.52.6", -] - -[[package]] -name = "parse-zoneinfo" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f2a05b18d44e2957b88f96ba460715e295bc1d7510468a2f3d3b44535d26c24" -dependencies = [ - "regex", -] - -[[package]] -name = "password-hash" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" -dependencies = [ - "base64ct", - "rand_core", - "subtle", -] - -[[package]] -name = "pem" -version = "3.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" -dependencies = [ - "base64 0.22.1", - "serde", -] - -[[package]] -name = "pem-rfc7468" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" -dependencies = [ - "base64ct", -] - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "pest" -version = "2.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" -dependencies = [ - "memchr", - "thiserror 2.0.9", - "ucd-trie", -] - -[[package]] -name = "pest_derive" -version = "2.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "816518421cfc6887a0d62bf441b6ffb4536fcc926395a69e1a85852d4363f57e" -dependencies = [ - "pest", - "pest_generator", -] - -[[package]] -name = "pest_generator" -version = "2.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d1396fd3a870fc7838768d171b4616d5c91f6cc25e377b673d714567d99377b" -dependencies = [ - "pest", - "pest_meta", - "proc-macro2", - "quote", - "syn 2.0.95", -] - -[[package]] -name = "pest_meta" -version = "2.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e58089ea25d717bfd31fb534e4f3afcc2cc569c70de3e239778991ea3b7dea" -dependencies = [ - "once_cell", - "pest", - "sha2", -] - -[[package]] -name = "phf" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" -dependencies = [ - "phf_macros", - "phf_shared 0.11.2", -] - -[[package]] -name = "phf_codegen" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" -dependencies = [ - "phf_generator 0.11.2", - "phf_shared 0.11.2", -] - -[[package]] -name = "phf_generator" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" -dependencies = [ - "phf_shared 0.10.0", - "rand", -] - -[[package]] -name = "phf_generator" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" -dependencies = [ - "phf_shared 0.11.2", - "rand", -] - -[[package]] -name = "phf_macros" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" -dependencies = [ - "phf_generator 0.11.2", - "phf_shared 0.11.2", - "proc-macro2", - "quote", - "syn 2.0.95", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher", -] - -[[package]] -name = "phf_shared" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "piper" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" -dependencies = [ - "atomic-waker", - "fastrand", - "futures-io", -] - -[[package]] -name = "pkcs1" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" -dependencies = [ - "der", - "pkcs8", - "spki", -] - -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der", - "spki", -] - -[[package]] -name = "pkg-config" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" - -[[package]] -name = "polling" -version = "3.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" -dependencies = [ - "cfg-if", - "concurrent-queue", - "hermit-abi 0.4.0", - "pin-project-lite", - "rustix", - "tracing", - "windows-sys 0.59.0", -] - -[[package]] -name = "polyval" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" -dependencies = [ - "cfg-if", - "cpufeatures", - "opaque-debug", - "universal-hash", -] - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - -[[package]] -name = "pretty_assertions" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" -dependencies = [ - "diff", - "yansi", -] - -[[package]] -name = "proc-macro-crate" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" -dependencies = [ - "toml_edit", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" -dependencies = [ - "proc-macro2", - "quote", -] - -[[package]] -name = "proc-macro-error2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" -dependencies = [ - "proc-macro-error-attr2", - "proc-macro2", - "quote", - "syn 2.0.95", -] - -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - -[[package]] -name = "proc-macro2" -version = "1.0.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "proc-macro2-diagnostics" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.95", - "version_check", - "yansi", -] - -[[package]] -name = "psm" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200b9ff220857e53e184257720a14553b2f4aa02577d2ed9842d45d4b9654810" -dependencies = [ - "cc", -] - -[[package]] -name = "ptr_meta" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" -dependencies = [ - "ptr_meta_derive", -] - -[[package]] -name = "ptr_meta_derive" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "quanta" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bd1fe6824cea6538803de3ff1bc0cf3949024db3d43c9643024bfb33a807c0e" -dependencies = [ - "crossbeam-utils", - "libc", - "once_cell", - "raw-cpuid", - "wasi", - "web-sys", - "winapi", -] - -[[package]] -name = "quick-xml" -version = "0.36.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe" -dependencies = [ - "memchr", - "serde", -] - -[[package]] -name = "quinn" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" -dependencies = [ - "bytes", - "pin-project-lite", - "quinn-proto", - "quinn-udp", - "rustc-hash 2.1.0", - "rustls", - "socket2", - "thiserror 2.0.9", - "tokio", - "tracing", -] - -[[package]] -name = "quinn-proto" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" -dependencies = [ - "bytes", - "getrandom", - "rand", - "ring", - "rustc-hash 2.1.0", - "rustls", - "rustls-pki-types", - "slab", - "thiserror 2.0.9", - "tinyvec", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-udp" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904" -dependencies = [ - "cfg_aliases", - "libc", - "once_cell", - "socket2", - "tracing", - "windows-sys 0.59.0", -] - -[[package]] -name = "quote" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "quoted_printable" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "640c9bd8497b02465aeef5375144c26062e0dcd5939dfcbb0f5db76cb8c17c73" - -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "raw-cpuid" -version = "11.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ab240315c661615f2ee9f0f2cd32d5a7343a84d5ebcccb99d46e6637565e7b0" -dependencies = [ - "bitflags", -] - -[[package]] -name = "rayon" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - -[[package]] -name = "redis" -version = "0.22.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa8455fa3621f6b41c514946de66ea0531f57ca017b2e6c7cc368035ea5b46df" -dependencies = [ - "async-trait", - "bytes", - "combine", - "futures-util", - "itoa", - "percent-encoding", - "pin-project-lite", - "ryu", - "sha1_smol", - "tokio", - "tokio-util", - "url", -] - -[[package]] -name = "redox_syscall" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_users" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" -dependencies = [ - "getrandom", - "libredox", - "thiserror 1.0.69", -] - -[[package]] -name = "regex" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata 0.4.9", - "regex-syntax 0.8.5", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", -] - -[[package]] -name = "regex-automata" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax 0.8.5", -] - -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" - -[[package]] -name = "relative-path" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" - -[[package]] -name = "rend" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" -dependencies = [ - "bytecheck", -] - -[[package]] -name = "reqwest" -version = "0.12.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" -dependencies = [ - "base64 0.22.1", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http 1.2.0", - "http-body", - "http-body-util", - "hyper", - "hyper-rustls", - "hyper-util", - "ipnet", - "js-sys", - "log", - "mime", - "once_cell", - "percent-encoding", - "pin-project-lite", - "quinn", - "rustls", - "rustls-pemfile", - "rustls-pki-types", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "system-configuration", - "tokio", - "tokio-rustls", - "tokio-util", - "tower 0.5.2", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-streams", - "web-sys", - "webpki-roots", - "windows-registry", -] - -[[package]] -name = "reserve-port" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9838134a2bfaa8e1f40738fcc972ac799de6e0e06b5157acb95fc2b05a0ea283" -dependencies = [ - "lazy_static", - "thiserror 1.0.69", -] - -[[package]] -name = "ring" -version = "0.17.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" -dependencies = [ - "cc", - "cfg-if", - "getrandom", - "libc", - "spin", - "untrusted", - "windows-sys 0.52.0", -] - -[[package]] -name = "rkyv" -version = "0.7.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" -dependencies = [ - "bitvec", - "bytecheck", - "bytes", - "hashbrown 0.12.3", - "ptr_meta", - "rend", - "rkyv_derive", - "seahash", - "tinyvec", - "uuid", -] - -[[package]] -name = "rkyv_derive" -version = "0.7.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "rrgen" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18e27f5f254d89b0b5b76445442e5c935b63a566ee5a735c9d877ca2029b4ce9" -dependencies = [ - "cruet 0.13.3", - "fs-err", - "glob", - "heck 0.4.1", - "regex", - "serde", - "serde_json", - "serde_regex", - "serde_yaml", - "tera", - "thiserror 1.0.69", -] - -[[package]] -name = "rsa" -version = "0.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47c75d7c5c6b673e58bf54d8544a9f432e3a925b0e80f7cd3602ab5c50c55519" -dependencies = [ - "const-oid", - "digest", - "num-bigint-dig", - "num-integer", - "num-traits", - "pkcs1", - "pkcs8", - "rand_core", - "signature", - "spki", - "subtle", - "zeroize", -] - -[[package]] -name = "rstest" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afd55a67069d6e434a95161415f5beeada95a01c7b815508a82dcb0e1593682" -dependencies = [ - "futures", - "futures-timer", - "rstest_macros", - "rustc_version", -] - -[[package]] -name = "rstest_macros" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4165dfae59a39dd41d8dec720d3cbfbc71f69744efb480a3920f5d4e0cc6798d" -dependencies = [ - "cfg-if", - "glob", - "proc-macro-crate", - "proc-macro2", - "quote", - "regex", - "relative-path", - "rustc_version", - "syn 2.0.95", - "unicode-ident", -] - -[[package]] -name = "rust-multipart-rfc7578_2" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b748410c0afdef2ebbe3685a6a862e2ee937127cdaae623336a459451c8d57" -dependencies = [ - "bytes", - "futures-core", - "futures-util", - "http 0.2.12", - "mime", - "mime_guess", - "rand", - "thiserror 1.0.69", -] - -[[package]] -name = "rust_decimal" -version = "1.36.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b082d80e3e3cc52b2ed634388d436fe1f4de6af5786cc2de9ba9737527bdf555" -dependencies = [ - "arrayvec", - "borsh", - "bytes", - "num-traits", - "rand", - "rkyv", - "serde", - "serde_json", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustc-hash" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" - -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - -[[package]] -name = "rustix" -version = "0.38.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.59.0", -] - -[[package]] -name = "rustls" -version = "0.23.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" -dependencies = [ - "log", - "once_cell", - "ring", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-pemfile" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "rustls-pki-types" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" -dependencies = [ - "web-time", -] - -[[package]] -name = "rustls-webpki" -version = "0.102.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" -dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", -] - -[[package]] -name = "rustversion" -version = "1.0.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" - -[[package]] -name = "rusty-sidekiq" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15544f047600b602c7b11ff7ee0882f9034f9cbe2c205693edd5615e2a6c03ee" -dependencies = [ - "async-trait", - "bb8", - "chrono", - "convert_case", - "cron_clock", - "gethostname", - "hex", - "num_cpus", - "rand", - "redis", - "serde", - "serde_json", - "serial_test", - "sha2", - "slog-term", - "thiserror 1.0.69", - "tokio", - "tokio-util", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "ryu" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "scc" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28e1c91382686d21b5ac7959341fcb9780fa7c03773646995a87c950fa7be640" -dependencies = [ - "sdd", -] - -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "scraper" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0e749d29b2064585327af5038a5a8eb73aeebad4a3472e83531a436563f7208" -dependencies = [ - "ahash 0.8.11", - "cssparser", - "ego-tree", - "getopts", - "html5ever", - "indexmap", - "precomputed-hash", - "selectors", - "tendril", -] - -[[package]] -name = "sdd" -version = "3.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478f121bb72bbf63c52c93011ea1791dca40140dfe13f8336c4c5ac952c33aa9" - -[[package]] -name = "sea-bae" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f694a6ab48f14bc063cfadff30ab551d3c7e46d8f81836c51989d548f44a2a25" -dependencies = [ - "heck 0.4.1", - "proc-macro-error2", - "proc-macro2", - "quote", - "syn 2.0.95", -] - -[[package]] -name = "sea-orm" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dbcf83248860dc632c46c7e81a221e041b50d0006191756cb001d9e8afc60a9" -dependencies = [ - "async-stream", - "async-trait", - "bigdecimal", - "chrono", - "futures", - "log", - "ouroboros", - "rust_decimal", - "sea-orm-macros", - "sea-query", - "sea-query-binder", - "serde", - "serde_json", - "sqlx", - "strum", - "thiserror 1.0.69", - "time", - "tracing", - "url", - "uuid", -] - -[[package]] -name = "sea-orm-cli" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a8dbef29c7e534a8e9afb49abfa946c7a9df3d85f610dfed9140215ff8bff17" -dependencies = [ - "chrono", - "clap", - "dotenvy", - "glob", - "regex", - "sea-schema", - "tracing", - "tracing-subscriber", - "url", -] - -[[package]] -name = "sea-orm-macros" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49ce6f08134f3681b1ca92185b96fac898f26d9b4f5538d13f7032ef243d14b2" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "sea-bae", - "syn 2.0.95", - "unicode-ident", -] - -[[package]] -name = "sea-orm-migration" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e53f46fe9874161ba57b15ff45d2589d754d7cbbbaab9470cb79cbada149ca7" -dependencies = [ - "async-trait", - "clap", - "dotenvy", - "futures", - "sea-orm", - "sea-orm-cli", - "sea-schema", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "sea-query" -version = "0.32.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "085e94f7d7271c0393ac2d164a39994b1dff1b06bc40cd9a0da04f3d672b0fee" -dependencies = [ - "bigdecimal", - "chrono", - "inherent", - "ordered-float", - "rust_decimal", - "sea-query-derive", - "serde_json", - "time", - "uuid", -] - -[[package]] -name = "sea-query-binder" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0019f47430f7995af63deda77e238c17323359af241233ec768aba1faea7608" -dependencies = [ - "bigdecimal", - "chrono", - "rust_decimal", - "sea-query", - "serde_json", - "sqlx", - "time", - "uuid", -] - -[[package]] -name = "sea-query-derive" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9834af2c4bd8c5162f00c89f1701fb6886119a88062cf76fe842ea9e232b9839" -dependencies = [ - "darling", - "heck 0.4.1", - "proc-macro2", - "quote", - "syn 2.0.95", - "thiserror 1.0.69", -] - -[[package]] -name = "sea-schema" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef5dd7848c993f3789d09a2616484c72c9330cae2b048df59d8c9b8c0343e95" -dependencies = [ - "futures", - "sea-query", - "sea-schema-derive", -] - -[[package]] -name = "sea-schema-derive" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "debdc8729c37fdbf88472f97fd470393089f997a909e535ff67c544d18cfccf0" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "syn 2.0.95", -] - -[[package]] -name = "seahash" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" - -[[package]] -name = "selectors" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd568a4c9bb598e291a08244a5c1f5a8a6650bee243b5b0f8dbb3d9cc1d87fe8" -dependencies = [ - "bitflags", - "cssparser", - "derive_more", - "fxhash", - "log", - "new_debug_unreachable", - "phf", - "phf_codegen", - "precomputed-hash", - "servo_arc", - "smallvec", -] - -[[package]] -name = "self_cell" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14e4d63b804dc0c7ec4a1e52bcb63f02c7ac94476755aa579edac21e01f915d" -dependencies = [ - "self_cell 1.1.0", -] - -[[package]] -name = "self_cell" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2fdfc24bc566f839a2da4c4295b82db7d25a24253867d5c64355abb5799bdbe" - -[[package]] -name = "semver" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" - -[[package]] -name = "serde" -version = "1.0.217" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.217" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.95", -] - -[[package]] -name = "serde_json" -version = "1.0.134" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "serde_path_to_error" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" -dependencies = [ - "itoa", - "serde", -] - -[[package]] -name = "serde_regex" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8136f1a4ea815d7eac4101cfd0b16dc0cb5e1fe1b8609dfd728058656b7badf" -dependencies = [ - "regex", - "serde", -] - -[[package]] -name = "serde_spanned" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_variant" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a0068df419f9d9b6488fdded3f1c818522cdea328e02ce9d9f147380265a432" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_yaml" -version = "0.9.34+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" -dependencies = [ - "indexmap", - "itoa", - "ryu", - "serde", - "unsafe-libyaml", -] - -[[package]] -name = "serial_test" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b258109f244e1d6891bf1053a55d63a5cd4f8f4c30cf9a1280989f80e7a1fa9" -dependencies = [ - "futures", - "log", - "once_cell", - "parking_lot", - "scc", - "serial_test_derive", -] - -[[package]] -name = "serial_test_derive" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.95", -] - -[[package]] -name = "servo_arc" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae65c4249478a2647db249fb43e23cec56a2c8974a427e7bd8cb5a1d0964921a" -dependencies = [ - "stable_deref_trait", -] - -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha1_smol" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" - -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "shared_child" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09fa9338aed9a1df411814a5b2252f7cd206c55ae9bf2fa763f8de84603aa60c" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "signal-hook-registry" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" -dependencies = [ - "libc", -] - -[[package]] -name = "signature" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" -dependencies = [ - "digest", - "rand_core", -] - -[[package]] -name = "simdutf8" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" - -[[package]] -name = "similar" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" - -[[package]] -name = "simple_asn1" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" -dependencies = [ - "num-bigint", - "num-traits", - "thiserror 1.0.69", - "time", -] - -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "slog" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8347046d4ebd943127157b94d63abb990fcf729dc4e9978927fdf4ac3c998d06" - -[[package]] -name = "slog-term" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6e022d0b998abfe5c3782c1f03551a596269450ccd677ea51c56f8b214610e8" -dependencies = [ - "is-terminal", - "slog", - "term", - "thread_local", - "time", -] - -[[package]] -name = "slug" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "882a80f72ee45de3cc9a5afeb2da0331d58df69e4e7d8eeb5d3c7784ae67e724" -dependencies = [ - "deunicode", - "wasm-bindgen", -] - -[[package]] -name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" -dependencies = [ - "serde", -] - -[[package]] -name = "snafu" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4de37ad025c587a29e8f3f5605c00f70b98715ef90b9061a815b9e59e9042d6" -dependencies = [ - "doc-comment", - "snafu-derive", -] - -[[package]] -name = "snafu-derive" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990079665f075b699031e9c08fd3ab99be5029b96f3b78dc0709e8f77e4efebf" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "snapbox" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b831b6e80fbcd2889efa75b185d24005f85981431495f995292b25836519d84" -dependencies = [ - "anstream", - "anstyle", - "content_inspector", - "dunce", - "filetime", - "libc", - "normalize-line-endings", - "os_pipe", - "similar", - "snapbox-macros", - "tempfile", - "wait-timeout", - "walkdir", - "windows-sys 0.52.0", -] - -[[package]] -name = "snapbox-macros" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16569f53ca23a41bb6f62e0a5084aa1661f4814a67fa33696a79073e03a664af" -dependencies = [ - "anstream", -] - -[[package]] -name = "socket2" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] - -[[package]] -name = "spki" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" -dependencies = [ - "base64ct", - "der", -] - -[[package]] -name = "sqlx" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4410e73b3c0d8442c5f99b425d7a435b5ee0ae4167b3196771dd3f7a01be745f" -dependencies = [ - "sqlx-core", - "sqlx-macros", - "sqlx-mysql", - "sqlx-postgres", - "sqlx-sqlite", -] - -[[package]] -name = "sqlx-core" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a007b6936676aa9ab40207cde35daab0a04b823be8ae004368c0793b96a61e0" -dependencies = [ - "bigdecimal", - "bytes", - "chrono", - "crc", - "crossbeam-queue", - "either", - "event-listener 5.3.1", - "futures-core", - "futures-intrusive", - "futures-io", - "futures-util", - "hashbrown 0.15.2", - "hashlink", - "indexmap", - "log", - "memchr", - "once_cell", - "percent-encoding", - "rust_decimal", - "rustls", - "rustls-pemfile", - "serde", - "serde_json", - "sha2", - "smallvec", - "thiserror 2.0.9", - "time", - "tokio", - "tokio-stream", - "tracing", - "url", - "uuid", - "webpki-roots", -] - -[[package]] -name = "sqlx-macros" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3112e2ad78643fef903618d78cf0aec1cb3134b019730edb039b69eaf531f310" -dependencies = [ - "proc-macro2", - "quote", - "sqlx-core", - "sqlx-macros-core", - "syn 2.0.95", -] - -[[package]] -name = "sqlx-macros-core" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e9f90acc5ab146a99bf5061a7eb4976b573f560bc898ef3bf8435448dd5e7ad" -dependencies = [ - "dotenvy", - "either", - "heck 0.5.0", - "hex", - "once_cell", - "proc-macro2", - "quote", - "serde", - "serde_json", - "sha2", - "sqlx-core", - "sqlx-mysql", - "sqlx-postgres", - "sqlx-sqlite", - "syn 2.0.95", - "tempfile", - "tokio", - "url", -] - -[[package]] -name = "sqlx-mysql" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4560278f0e00ce64938540546f59f590d60beee33fffbd3b9cd47851e5fff233" -dependencies = [ - "atoi", - "base64 0.22.1", - "bigdecimal", - "bitflags", - "byteorder", - "bytes", - "chrono", - "crc", - "digest", - "dotenvy", - "either", - "futures-channel", - "futures-core", - "futures-io", - "futures-util", - "generic-array", - "hex", - "hkdf", - "hmac", - "itoa", - "log", - "md-5", - "memchr", - "once_cell", - "percent-encoding", - "rand", - "rsa", - "rust_decimal", - "serde", - "sha1", - "sha2", - "smallvec", - "sqlx-core", - "stringprep", - "thiserror 2.0.9", - "time", - "tracing", - "uuid", - "whoami", -] - -[[package]] -name = "sqlx-postgres" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5b98a57f363ed6764d5b3a12bfedf62f07aa16e1856a7ddc2a0bb190a959613" -dependencies = [ - "atoi", - "base64 0.22.1", - "bigdecimal", - "bitflags", - "byteorder", - "chrono", - "crc", - "dotenvy", - "etcetera", - "futures-channel", - "futures-core", - "futures-util", - "hex", - "hkdf", - "hmac", - "home", - "itoa", - "log", - "md-5", - "memchr", - "num-bigint", - "once_cell", - "rand", - "rust_decimal", - "serde", - "serde_json", - "sha2", - "smallvec", - "sqlx-core", - "stringprep", - "thiserror 2.0.9", - "time", - "tracing", - "uuid", - "whoami", -] - -[[package]] -name = "sqlx-sqlite" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f85ca71d3a5b24e64e1d08dd8fe36c6c95c339a896cc33068148906784620540" -dependencies = [ - "atoi", - "chrono", - "flume 0.11.1", - "futures-channel", - "futures-core", - "futures-executor", - "futures-intrusive", - "futures-util", - "libsqlite3-sys", - "log", - "percent-encoding", - "serde", - "serde_urlencoded", - "sqlx-core", - "time", - "tracing", - "url", - "uuid", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "stacker" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799c883d55abdb5e98af1a7b3f23b9b6de8ecada0ecac058672d7635eb48ca7b" -dependencies = [ - "cc", - "cfg-if", - "libc", - "psm", - "windows-sys 0.59.0", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "string_cache" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" -dependencies = [ - "new_debug_unreachable", - "once_cell", - "parking_lot", - "phf_shared 0.10.0", - "precomputed-hash", - "serde", -] - -[[package]] -name = "string_cache_codegen" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" -dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", - "proc-macro2", - "quote", -] - -[[package]] -name = "stringprep" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" -dependencies = [ - "unicode-bidi", - "unicode-normalization", - "unicode-properties", -] - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "strum" -version = "0.26.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f71c0377baf4ef1cc3e3402ded576dccc315800fbc62dfc7fe04b009773b4a" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" -dependencies = [ - "futures-core", -] - -[[package]] -name = "synstructure" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.95", -] - -[[package]] -name = "system-configuration" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" -dependencies = [ - "bitflags", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "tagptr" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "tempfile" -version = "3.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" -dependencies = [ - "cfg-if", - "fastrand", - "getrandom", - "once_cell", - "rustix", - "windows-sys 0.59.0", -] - -[[package]] -name = "tendril" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" -dependencies = [ - "futf", - "mac", - "utf-8", -] - -[[package]] -name = "tera" -version = "1.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab9d851b45e865f178319da0abdbfe6acbc4328759ff18dafc3a41c16b4cd2ee" -dependencies = [ - "chrono", - "chrono-tz", - "globwalk", - "humansize", - "lazy_static", - "percent-encoding", - "pest", - "pest_derive", - "rand", - "regex", - "serde", - "serde_json", - "slug", - "unic-segment", -] - -[[package]] -name = "term" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" -dependencies = [ - "dirs-next", - "rustversion", - "winapi", -] - -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl 1.0.69", -] - -[[package]] -name = "thiserror" -version = "2.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc" -dependencies = [ - "thiserror-impl 2.0.9", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.95", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.95", -] - -[[package]] -name = "thousands" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bf63baf9f5039dadc247375c29eb13706706cfde997d0330d05aa63a77d8820" - -[[package]] -name = "thread_local" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "time" -version = "0.3.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" -dependencies = [ - "deranged", - "itoa", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] -name = "time-macros" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "tinystr" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "tinyvec" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tokio" -version = "1.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys 0.52.0", -] - -[[package]] -name = "tokio-cron-scheduler" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2594dd7c2abbbafbb1c78d167fd10860dc7bd75f814cb051a1e0d3e796b9702" -dependencies = [ - "chrono", - "cron", - "num-derive", - "num-traits", - "tokio", - "tracing", - "uuid", -] - -[[package]] -name = "tokio-macros" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.95", -] - -[[package]] -name = "tokio-rustls" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" -dependencies = [ - "rustls", - "tokio", -] - -[[package]] -name = "tokio-stream" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "toml" -version = "0.8.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "toml_datetime" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.22.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", -] - -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" -dependencies = [ - "futures-core", - "futures-util", - "pin-project-lite", - "sync_wrapper", - "tokio", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-http" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403fa3b783d4b626a8ad51d766ab03cb6d2dbfc46b1c5d4448395e6628dc9697" -dependencies = [ - "async-compression", - "bitflags", - "bytes", - "futures-core", - "futures-util", - "http 1.2.0", - "http-body", - "http-body-util", - "http-range-header", - "httpdate", - "mime", - "mime_guess", - "percent-encoding", - "pin-project-lite", - "tokio", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-layer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" - -[[package]] -name = "tower-service" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" - -[[package]] -name = "tracing" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" -dependencies = [ - "log", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-appender" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" -dependencies = [ - "crossbeam-channel", - "thiserror 1.0.69", - "time", - "tracing-subscriber", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.95", -] - -[[package]] -name = "tracing-core" -version = "0.1.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-serde" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" -dependencies = [ - "serde", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex", - "serde", - "serde_json", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", - "tracing-serde", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "trycmd" -version = "0.14.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d41014f614932fff67cd3b780e0eb0ecb14e698a831a0e555ef2a5137be968d5" -dependencies = [ - "glob", - "humantime", - "humantime-serde", - "rayon", - "serde", - "shlex", - "snapbox", - "toml_edit", -] - -[[package]] -name = "type-map" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deb68604048ff8fa93347f02441e4487594adc20bb8a084f9e564d2b827a0a9f" -dependencies = [ - "rustc-hash 1.1.0", -] - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "ucd-trie" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" - -[[package]] -name = "ulid" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04f903f293d11f31c0c29e4148f6dc0d033a7f80cebc0282bea147611667d289" -dependencies = [ - "getrandom", - "rand", - "web-time", -] - -[[package]] -name = "unic-char-property" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" -dependencies = [ - "unic-char-range", -] - -[[package]] -name = "unic-char-range" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" - -[[package]] -name = "unic-common" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" - -[[package]] -name = "unic-langid" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23dd9d1e72a73b25e07123a80776aae3e7b0ec461ef94f9151eed6ec88005a44" -dependencies = [ - "unic-langid-impl", - "unic-langid-macros", -] - -[[package]] -name = "unic-langid-impl" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a5422c1f65949306c99240b81de9f3f15929f5a8bfe05bb44b034cc8bf593e5" -dependencies = [ - "tinystr", -] - -[[package]] -name = "unic-langid-macros" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0da1cd2c042d3c7569a1008806b02039e7a4a2bdf8f8e96bd3c792434a0e275e" -dependencies = [ - "proc-macro-hack", - "tinystr", - "unic-langid-impl", - "unic-langid-macros-impl", -] - -[[package]] -name = "unic-langid-macros-impl" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ed7f4237ba393424195053097c1516bd4590dc82b84f2f97c5c69e12704555b" -dependencies = [ - "proc-macro-hack", - "quote", - "syn 2.0.95", - "unic-langid-impl", -] - -[[package]] -name = "unic-segment" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ed5d26be57f84f176157270c112ef57b86debac9cd21daaabbe56db0f88f23" -dependencies = [ - "unic-ucd-segment", -] - -[[package]] -name = "unic-ucd-segment" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2079c122a62205b421f499da10f3ee0f7697f012f55b675e002483c73ea34700" -dependencies = [ - "unic-char-property", - "unic-char-range", - "unic-ucd-version", -] - -[[package]] -name = "unic-ucd-version" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" -dependencies = [ - "unic-common", -] - -[[package]] -name = "unicase" -version = "2.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" - -[[package]] -name = "unicode-bidi" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" - -[[package]] -name = "unicode-ident" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" - -[[package]] -name = "unicode-normalization" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-properties" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" - -[[package]] -name = "unicode-segmentation" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" - -[[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" - -[[package]] -name = "universal-hash" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" -dependencies = [ - "crypto-common", - "subtle", -] - -[[package]] -name = "unsafe-libyaml" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - -[[package]] -name = "utf8-width" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "utoipa" -version = "4.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5afb1a60e207dca502682537fefcfd9921e71d0b83e9576060f09abc6efab23" -dependencies = [ - "indexmap", - "serde", - "serde_json", - "utoipa-gen", -] - -[[package]] -name = "utoipa-gen" -version = "4.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20c24e8ab68ff9ee746aad22d39b5535601e6416d1b0feeabf78be986a5c4392" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.95", -] - -[[package]] -name = "uuid" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" -dependencies = [ - "getrandom", - "rand", - "serde", -] - -[[package]] -name = "validator" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43fb22e1a008ece370ce08a3e9e4447a910e92621bb49b85d6e48a45397e7cfa" -dependencies = [ - "idna", - "once_cell", - "regex", - "serde", - "serde_derive", - "serde_json", - "url", - "validator_derive", -] - -[[package]] -name = "validator_derive" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7df16e474ef958526d1205f6dda359fdfab79d9aa6d54bafcb92dcd07673dca" -dependencies = [ - "darling", - "once_cell", - "proc-macro-error2", - "proc-macro2", - "quote", - "syn 2.0.95", -] - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "value-bag" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ef4c4aa54d5d05a279399bfa921ec387b7aba77caf7a682ae8d86785b8fdad2" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "wait-timeout" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" -dependencies = [ - "libc", -] - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[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.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasite" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" - -[[package]] -name = "wasm-bindgen" -version = "0.2.99" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" -dependencies = [ - "cfg-if", - "once_cell", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.99" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.95", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.49" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2" -dependencies = [ - "cfg-if", - "js-sys", - "once_cell", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.99" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.99" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.95", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.99" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" - -[[package]] -name = "wasm-streams" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" -dependencies = [ - "futures-util", - "js-sys", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "web-sys" -version = "0.3.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" -dependencies = [ - "js-sys", - "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 = "webpki-roots" -version = "0.26.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "whoami" -version = "1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" -dependencies = [ - "redox_syscall", - "wasite", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" -dependencies = [ - "windows-core 0.52.0", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" -dependencies = [ - "windows-core 0.58.0", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-core" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-result", - "windows-strings", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-implement" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.95", -] - -[[package]] -name = "windows-interface" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.95", -] - -[[package]] -name = "windows-registry" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" -dependencies = [ - "windows-result", - "windows-strings", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-result" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-strings" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" -dependencies = [ - "windows-result", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "winnow" -version = "0.6.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39281189af81c07ec09db316b302a3e67bf9bd7cbf6c820b50e35fee9c2fa980" -dependencies = [ - "memchr", -] - -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - -[[package]] -name = "writeable" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" - -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] - -[[package]] -name = "yansi" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" - -[[package]] -name = "yoke" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" -dependencies = [ - "serde", - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.95", - "synstructure", -] - -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "byteorder", - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.95", -] - -[[package]] -name = "zerofrom" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.95", - "synstructure", -] - -[[package]] -name = "zeroize" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" - -[[package]] -name = "zerovec" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.95", -] - -[[package]] -name = "zstd" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "7.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" -dependencies = [ - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "2.0.13+zstd.1.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" -dependencies = [ - "cc", - "pkg-config", -] diff --git a/examples/demo/Cargo.toml b/examples/demo/Cargo.toml deleted file mode 100644 index d48b8f62d..000000000 --- a/examples/demo/Cargo.toml +++ /dev/null @@ -1,62 +0,0 @@ -[workspace] -# this empty pragma excludes this project from workspaces - -[package] -name = "demo_app" -version = "0.1.0" -edition = "2021" -default-run = "demo_app-cli" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] - -loco-rs = { path = "../../", version = "*" } -migration = { path = "migration" } - -serde = { version = "1", features = ["derive"] } -serde_json = "1" -tokio = { version = "1.33.0", features = ["full"] } -async-trait = "0.1.74" -tracing = "0.1.40" -chrono = "0.4" -validator = { version = "0.20" } -sea-orm = { version = "1.1.0", features = [ - "sqlx-sqlite", - "sqlx-postgres", - "runtime-tokio-rustls", - "macros", -] } - -axum = { version = "0.8.1", features = ["multipart"] } -axum_session = { version = "0.15.0", default-features = false } -axum-extra = { version = "0.10", features = ["cookie"] } - -include_dir = "0.7" -uuid = { version = "1.6.0", features = ["v4"] } -tracing-subscriber = { version = "0.3.17", features = ["env-filter", "json"] } - -fluent-templates = { version = "0.8.0", features = ["tera"] } -unic-langid = "0.9.4" -tera = "1.19.1" -tower = "0.4.13" -futures-util = "0.3.30" -utoipa = "4.2.3" - -[[bin]] -name = "demo_app-cli" -path = "src/bin/main.rs" -required-features = [] - -[[bin]] -name = "tool" -path = "src/bin/tool.rs" -required-features = [] - -[dev-dependencies] -serial_test = "3.1.1" -rstest = "0.21.0" -loco-rs = { path = "../../", version = "*", features = ["testing"] } -trycmd = "0.14.19" -insta = { version = "1.34.0", features = ["redactions", "yaml", "filters"] } -axum-test = { version = "17.0.1" } diff --git a/examples/demo/README.md b/examples/demo/README.md deleted file mode 100644 index 52561c753..000000000 --- a/examples/demo/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# Demo - -This app is a kitchensink for various capabilities and examples of the [Loco](https://loco.rs) project. - -# Example Listings - -## OpenAPI with `utoipa` - -See [src/controllers/responses.rs](src/controllers/responses.rs) diff --git a/examples/demo/assets/i18n/de-DE/main.ftl b/examples/demo/assets/i18n/de-DE/main.ftl deleted file mode 100644 index ced609fe4..000000000 --- a/examples/demo/assets/i18n/de-DE/main.ftl +++ /dev/null @@ -1,4 +0,0 @@ -hello-world = Hallo Welt! -greeting = Hallochen { $name }! - .placeholder = Hallo Freund! -about = Uber diff --git a/examples/demo/assets/i18n/en-US/main.ftl b/examples/demo/assets/i18n/en-US/main.ftl deleted file mode 100644 index 9d4d5e7c4..000000000 --- a/examples/demo/assets/i18n/en-US/main.ftl +++ /dev/null @@ -1,10 +0,0 @@ -hello-world = Hello World! -greeting = Hello { $name }! - .placeholder = Hello Friend! -about = About -simple = simple text -reference = simple text with a reference: { -something } -parameter = text with a { $param } -parameter2 = text one { $param } second { $multi-word-param } -email = text with an EMAIL("example@example.org") -fallback = this should fall back diff --git a/examples/demo/assets/i18n/shared.ftl b/examples/demo/assets/i18n/shared.ftl deleted file mode 100644 index f169eca9d..000000000 --- a/examples/demo/assets/i18n/shared.ftl +++ /dev/null @@ -1 +0,0 @@ --something = foo diff --git a/examples/demo/assets/static/404.html b/examples/demo/assets/static/404.html deleted file mode 100644 index 66e78fb22..000000000 --- a/examples/demo/assets/static/404.html +++ /dev/null @@ -1,3 +0,0 @@ - -not found :-( - diff --git a/examples/demo/assets/static/image.png b/examples/demo/assets/static/image.png deleted file mode 100644 index fa5a09508..000000000 Binary files a/examples/demo/assets/static/image.png and /dev/null differ diff --git a/examples/demo/assets/views/home/hello.html b/examples/demo/assets/views/home/hello.html deleted file mode 100644 index 6b97c398e..000000000 --- a/examples/demo/assets/views/home/hello.html +++ /dev/null @@ -1,12 +0,0 @@ - - -
- find this tera template at assets/views/home/hello.html: -
-
- {{ t(key="hello-world", lang="en-US") }}, -
- {{ t(key="hello-world", lang="de-DE") }} - - - \ No newline at end of file diff --git a/examples/demo/config/development.yaml b/examples/demo/config/development.yaml deleted file mode 100644 index ac3c78131..000000000 --- a/examples/demo/config/development.yaml +++ /dev/null @@ -1,139 +0,0 @@ -# Loco configuration file documentation - -# -settings: - allow_list: - - google.com - - apple.com -# - -# -# Application logging configuration -logger: - # Enable or disable logging. - enable: true - # Enable pretty backtrace (sets RUST_BACKTRACE=1) - pretty_backtrace: true - # Log level, options: trace, debug, info, warn or error. - level: debug - # Define the logging format. options: compact, pretty or json - format: compact - # By default the logger has filtering only logs that came from your code or logs that came from `loco` framework. to see all third party libraries - # Uncomment the line below to override to see all third party libraries you can enable this config and override the logger filters. - # override_filter: trace -# - -# Web server configuration -# -server: - # Port on which the server will listen. the server binding is 0.0.0.0:{PORT} - port: {{ get_env(name="NODE_PORT", default=5150) }} - # The UI hostname or IP address that mailers will point to. - host: http://localhost -# - -# Worker Configuration -workers: - # specifies the worker mode. Options: - # - BackgroundQueue - Workers operate asynchronously in the background, processing queued. - # - ForegroundBlocking - Workers operate in the foreground and block until tasks are completed. - # - BackgroundAsync - Workers operate asynchronously in the background, processing tasks with async capabilities. - mode: BackgroundQueue - -# Mailer Configuration. -# -mailer: - # SMTP mailer configuration. - smtp: - # Enable/Disable smtp mailer. - enable: true - # SMTP server host. e.x localhost, smtp.gmail.com - host: {{ get_env(name="MAILER_HOST", default="localhost") }} - # SMTP server port - port: 1025 - # Use secure connection (SSL/TLS). - secure: false - # auth: - # user: - # password: -# - -# Initializers Configuration -# initializers: -# oauth2: -# authorization_code: # Authorization code grant type -# - client_identifier: google # Identifier for the OAuth2 provider. Replace 'google' with your provider's name if different, must be unique within the oauth2 config. -# ... other fields - -# Database Configuration -# -database: - # Database connection URI - uri: {{get_env(name="DATABASE_URL", default="postgres://loco:loco@localhost:5432/loco_app")}} - # When enabled, the sql query will be logged. - enable_logging: false - # Set the timeout duration when acquiring a connection. - connect_timeout: 500 - # Set the idle duration before closing a connection. - idle_timeout: 500 - # Minimum number of connections for a pool. - min_connections: 1 - # Maximum number of connections for a pool. - max_connections: 1 - # Run migration up when application loaded - auto_migrate: true - # Truncate database when application loaded. This is a dangerous operation, make sure that you using this flag only on dev environments or test mode - dangerously_truncate: false - # Recreating schema when application loaded. This is a dangerous operation, make sure that you using this flag only on dev environments or test mode - dangerously_recreate: false -# - -# Queue Configuration -# -queue: - kind: Redis - # Redis connection URI - uri: {{ get_env(name="REDIS_URL", default="redis://127.0.0.1") }} - # Dangerously flush all data in Redis on startup. dangerous operation, make sure that you using this flag only on dev environments or test mode - dangerously_flush: false -# - -# Authentication Configuration -# -auth: - # JWT authentication - jwt: - # Secret key for token generation and verification - secret: PqRwLF2rhHe8J22oBeHy - # Token expiration time in seconds - expiration: 604800 # 7 days -# - -# Scheduler Jobs Configuration -# -scheduler: - # Location of shipping the command stdout and stderr. - output: stdout - # A list of jobs to be scheduled. - jobs: - # The name of the job. - write_content: - # by default false meaning executing the the run value as a task. if true execute the run value as shell command - shell: true - # command to run - run: "echo loco >> ./scheduler.txt" - # The cron expression that defines the job's schedule. - schedule: run every 1 second - output: silent - tags: ['base', 'infra'] - - run_task: - run: "foo" - schedule: "at 10:00 am" - - list_if_users: - run: "user_report" - shell: true - schedule: "* 2 * * * *" - tags: ['base', 'users'] -# \ No newline at end of file diff --git a/examples/demo/config/production.yaml b/examples/demo/config/production.yaml deleted file mode 100644 index e69de29bb..000000000 diff --git a/examples/demo/config/scheduler.yaml b/examples/demo/config/scheduler.yaml deleted file mode 100644 index 48421987a..000000000 --- a/examples/demo/config/scheduler.yaml +++ /dev/null @@ -1,18 +0,0 @@ -output: stdout -jobs: - write_content: - shell: true - run: "echo loco >> ./scheduler.txt" - schedule: run every 1 second - output: silent - tags: ['base', 'infra'] - - run_task: - run: "foo" - schedule: "at 10:00 am" - - list_if_users: - run: "user_report" - shell: true - schedule: "* 2 * * * *" - tags: ['base', 'users'] \ No newline at end of file diff --git a/examples/demo/config/test.yaml b/examples/demo/config/test.yaml deleted file mode 100644 index 6d3121a51..000000000 --- a/examples/demo/config/test.yaml +++ /dev/null @@ -1,154 +0,0 @@ -# Loco configuration file documentation - -# Application logging configuration -logger: - # Enable or disable logging. - enable: false - # Log level, options: trace, debug, info, warn or error. - level: error - # Define the logging format. options: compact, pretty or json - format: compact - # By default the logger has filtering only logs that came from your code or logs that came from `loco` framework. to see all third party libraries - # Uncomment the line below to override to see all third party libraries you can enable this config and override the logger filters. - # override_filter: trace - -# Web server configuration -server: - # Port on which the server will listen. the server binding is 0.0.0.0:{PORT} - port: 5150 - # The UI hostname or IP address that mailers will point to. - host: http://localhost - # Out of the box middleware configuration. to disable middleware you can changed the `enable` field to `false` of comment the middleware block - middlewares: - # Allows to limit the payload size request. payload that bigger than this file will blocked the request. - limit_payload: - # Enable/Disable the middleware. - enable: true - # the limit size. can be b,kb,kib,mb,mib,gb,gib - body_limit: 5mb - # Generating a unique request ID and enhancing logging with additional information such as the start and completion of request processing, latency, status code, and other request details. - logger: - # Enable/Disable the middleware. - enable: true - # when your code is panicked, the request still returns 500 status code. - catch_panic: - # Enable/Disable the middleware. - enable: true - # Timeout for incoming requests middleware. requests that take more time from the configuration will cute and 408 status code will returned. - timeout_request: - # Enable/Disable the middleware. - enable: true - # Duration time in milliseconds. - timeout: 5000 - static_assets: - enable: true - must_exist: true - precompressed: true - folder: - path: assets - fallback: index.html - compression: - enable: true - cors: - enable: true - # Set the value of the [`Access-Control-Allow-Origin`][mdn] header - # allow_origins: - # - https://loco.rs - # Set the value of the [`Access-Control-Allow-Headers`][mdn] header - # allow_headers: - # - Content-Type - # Set the value of the [`Access-Control-Allow-Methods`][mdn] header - # allow_methods: - # - POST - # Set the value of the [`Access-Control-Max-Age`][mdn] header in seconds - # max_age: 3600 - -# Worker Configuration -workers: - # specifies the worker mode. Options: - # - BackgroundQueue - Workers operate asynchronously in the background, processing queued. - # - ForegroundBlocking - Workers operate in the foreground and block until tasks are completed. - # - BackgroundAsync - Workers operate asynchronously in the background, processing tasks with async capabilities. - mode: ForegroundBlocking - -# Mailer Configuration. -mailer: - # SMTP mailer configuration. - smtp: - # Enable/Disable smtp mailer. - enable: true - # SMTP server host. e.x localhost, smtp.gmail.com - host: localhost - # SMTP server port - port: 1025 - # Use secure connection (SSL/TLS). - secure: false - # auth: - # user: - # password: - stub: true - -# Initializers Configuration -# initializers: -# oauth2: -# authorization_code: # Authorization code grant type -# - client_identifier: google # Identifier for the OAuth2 provider. Replace 'google' with your provider's name if different, must be unique within the oauth2 config. -# ... other fields - -# Database Configuration -database: - # Database connection URI - uri: {{get_env(name="DATABASE_URL", default="postgres://loco:loco@localhost:5432/loco_app")}} - # When enabled, the sql query will be logged. - enable_logging: false - # Set the timeout duration when acquiring a connection. - connect_timeout: 500 - # Set the idle duration before closing a connection. - idle_timeout: 500 - # Minimum number of connections for a pool. - min_connections: 1 - # Maximum number of connections for a pool. - max_connections: 1 - # Run migration up when application loaded - auto_migrate: true - # Truncate database when application loaded. This is a dangerous operation, make sure that you using this flag only on dev environments or test mode - dangerously_truncate: true - # Recreating schema when application loaded. This is a dangerous operation, make sure that you using this flag only on dev environments or test mode - dangerously_recreate: true - -# Queue Configuration -queue: - kind: Redis - # Redis connection URI - uri: {{get_env(name="REDIS_URL", default="redis://127.0.0.1")}} - # Dangerously flush all data in Redis on startup. dangerous operation, make sure that you using this flag only on dev environments or test mode - dangerously_flush: false - -# Authentication Configuration -auth: - # JWT authentication - jwt: - # Secret key for token generation and verification - secret: PqRwLF2rhHe8J22oBeHy - # Token expiration time in seconds - expiration: 604800 # 7 days - -scheduler: - output: stdout - jobs: - write_content: - shell: true - run: "echo loco >> ./scheduler.txt" - schedule: run every 1 second - output: silent - tags: ['base', 'infra'] - - run_task: - run: "foo" - schedule: "at 10:00 am" - - list_if_users: - run: "user_report" - shell: true - schedule: "* 2 * * * *" - tags: ['base', 'users'] \ No newline at end of file diff --git a/examples/demo/config/teste2e.yaml b/examples/demo/config/teste2e.yaml deleted file mode 100644 index 68d3e40de..000000000 --- a/examples/demo/config/teste2e.yaml +++ /dev/null @@ -1,113 +0,0 @@ -# Loco configuration file documentation - -# Application logging configuration -logger: - # Enable or disable logging. - enable: true - # Log level, options: trace, debug, info, warn or error. - level: debug - # Define the logging format. options: compact, pretty or json - format: compact - # By default the logger has filtering only logs that came from your code or logs that came from `loco` framework. to see all third party libraries - # Uncomment the line below to override to see all third party libraries you can enable this config and override the logger filters. - # override_filter: trace - -# Web server configuration -server: - # Port on which the server will listen. the server binding is 0.0.0.0:{PORT} - port: 5150 - # The UI hostname or IP address that mailers will point to. - host: http://localhost - # Out of the box middleware configuration. to disable middleware you can changed the `enable` field to `false` of comment the middleware block - middlewares: - # Allows to limit the payload size request. payload that bigger than this file will blocked the request. - limit_payload: - # Enable/Disable the middleware. - enable: true - # the limit size. can be b,kb,kib,mb,mib,gb,gib - body_limit: 5mb - # Generating a unique request ID and enhancing logging with additional information such as the start and completion of request processing, latency, status code, and other request details. - logger: - # Enable/Disable the middleware. - enable: true - # when your code is panicked, the request still returns 500 status code. - catch_panic: - # Enable/Disable the middleware. - enable: true - # Timeout for incoming requests middleware. requests that take more time from the configuration will cute and 408 status code will returned. - timeout_request: - # Enable/Disable the middleware. - enable: true - # Duration time in milliseconds. - timeout: 5000 - -# Worker Configuration -workers: - # specifies the worker mode. Options: - # - BackgroundQueue - Workers operate asynchronously in the background, processing queued. - # - ForegroundBlocking - Workers operate in the foreground and block until tasks are completed. - # - BackgroundAsync - Workers operate asynchronously in the background, processing tasks with async capabilities. - mode: ForegroundBlocking - -# Mailer Configuration. -mailer: - # SMTP mailer configuration. - smtp: - # Enable/Disable smtp mailer. - enable: true - # SMTP server host. e.x localhost, smtp.gmail.com - host: localhost - # SMTP server port - port: 1025 - # Use secure connection (SSL/TLS). - secure: false - # auth: - # user: - # password: - stub: true - -# Initializers Configuration -# initializers: -# oauth2: -# authorization_code: # Authorization code grant type -# - client_identifier: google # Identifier for the OAuth2 provider. Replace 'google' with your provider's name if different, must be unique within the oauth2 config. -# ... other fields - - -# Database Configuration -database: - # Database connection URI - uri: {{get_env(name="DATABASE_URL", default="postgres://localhost:5432/loco_app")}} - # When enabled, the sql query will be logged. - enable_logging: false - # Set the timeout duration when acquiring a connection. - connect_timeout: 500 - # Set the idle duration before closing a connection. - idle_timeout: 500 - # Minimum number of connections for a pool. - min_connections: 1 - # Maximum number of connections for a pool. - max_connections: 1 - # Run migration up when application loaded - auto_migrate: true - # Truncate database when application loaded. This is a dangerous operation, make sure that you using this flag only on dev environments or test mode - dangerously_truncate: true - # Recreating schema when application loaded. This is a dangerous operation, make sure that you using this flag only on dev environments or test mode - dangerously_recreate: true - -# Queue Configuration -queue: - kind: Redis - # Redis connection URI - uri: {{get_env(name="APP_REDIS_URI", default="redis://127.0.0.1")}} - # Dangerously flush all data in Redis on startup. dangerous operation, make sure that you using this flag only on dev environments or test mode - dangerously_flush: false - -# Authentication Configuration -auth: - # JWT authentication - jwt: - # Secret key for token generation and verification - secret: PqRwLF2rhHe8J22oBeHy - # Token expiration time in seconds - expiration: 604800 # 7 days diff --git a/examples/demo/examples/playground.rs b/examples/demo/examples/playground.rs deleted file mode 100644 index c9501a325..000000000 --- a/examples/demo/examples/playground.rs +++ /dev/null @@ -1,21 +0,0 @@ -use demo_app::app::App; -#[allow(unused_imports)] -use loco_rs::{cli::playground, prelude::*}; - -#[tokio::main] -async fn main() -> loco_rs::Result<()> { - let _ctx = playground::().await?; - - // let active_model: articles::ActiveModel = ActiveModel { - // title: Set(Some("how to build apps in 3 steps".to_string())), - // content: Set(Some("use Loco: https://loco.rs".to_string())), - // ..Default::default() - // }; - // active_model.insert(&ctx.db).await.unwrap(); - - // let res = articles::Entity::find().all(&ctx.db).await.unwrap(); - // println!("{:?}", res); - println!("welcome to playground. edit me at `examples/playground.rs`"); - - Ok(()) -} diff --git a/examples/demo/examples/start.rs b/examples/demo/examples/start.rs deleted file mode 100644 index 0f398b08c..000000000 --- a/examples/demo/examples/start.rs +++ /dev/null @@ -1,21 +0,0 @@ -use demo_app::app::App; -use loco_rs::{ - boot::{create_app, start, ServeParams, StartMode}, - environment::{resolve_from_env, Environment}, -}; -use migration::Migrator; - -#[tokio::main] -async fn main() -> loco_rs::Result<()> { - let environment: Environment = resolve_from_env().into(); - let config = environment.load()?; - - let boot_result = - create_app::(StartMode::ServerAndWorker, &environment, config).await?; - let serve_params = ServeParams { - port: boot_result.app_context.config.server.port, - binding: boot_result.app_context.config.server.binding.to_string(), - }; - start::(boot_result, serve_params, false).await?; - Ok(()) -} diff --git a/examples/demo/examples/task.rs b/examples/demo/examples/task.rs deleted file mode 100644 index 3807cea5a..000000000 --- a/examples/demo/examples/task.rs +++ /dev/null @@ -1,21 +0,0 @@ -use std::env; - -use demo_app::app::App; -use loco_rs::{ - boot::{create_context, run_task}, - environment::{resolve_from_env, Environment}, - task, -}; - -#[tokio::main] -async fn main() -> loco_rs::Result<()> { - let environment: Environment = resolve_from_env().into(); - let config = environment.load()?; - - let args = env::args().collect::>(); - let cmd = args.get(1); - let app_context = create_context::(&environment, config).await?; - run_task::(&app_context, cmd, &task::Vars::default()).await?; - - Ok(()) -} diff --git a/examples/demo/examples/workers.rs b/examples/demo/examples/workers.rs deleted file mode 100644 index b36f4c676..000000000 --- a/examples/demo/examples/workers.rs +++ /dev/null @@ -1,21 +0,0 @@ -use demo_app::app::App; -use loco_rs::{ - boot::{create_app, start, ServeParams, StartMode}, - environment::{resolve_from_env, Environment}, -}; -use migration::Migrator; - -#[tokio::main] -async fn main() -> loco_rs::Result<()> { - let environment: Environment = resolve_from_env().into(); - let config = environment.load()?; - - let boot_result = - create_app::(StartMode::WorkerOnly, &environment, config).await?; - let serve_params = ServeParams { - port: boot_result.app_context.config.server.port, - binding: boot_result.app_context.config.server.binding.to_string(), - }; - start::(boot_result, serve_params, false).await?; - Ok(()) -} diff --git a/examples/demo/migration/Cargo.toml b/examples/demo/migration/Cargo.toml deleted file mode 100644 index fd31e14f5..000000000 --- a/examples/demo/migration/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "migration" -version = "0.1.0" -edition = "2021" -publish = false - -[lib] -name = "migration" -path = "src/lib.rs" - -[dependencies] -async-std = { version = "1", features = ["attributes", "tokio1"] } -loco-rs = { path = "../../../", version = "*" } - -[dependencies.sea-orm-migration] -version = "1.1.0" -features = [ - # Enable at least one `ASYNC_RUNTIME` and `DATABASE_DRIVER` feature if you want to run migration via CLI. - # View the list of supported features at https://www.sea-ql.org/SeaORM/docs/install-and-config/database-and-async-runtime. - # e.g. - "runtime-tokio-rustls", # `ASYNC_RUNTIME` feature -] diff --git a/examples/demo/migration/src/lib.rs b/examples/demo/migration/src/lib.rs deleted file mode 100644 index f7072b696..000000000 --- a/examples/demo/migration/src/lib.rs +++ /dev/null @@ -1,20 +0,0 @@ -pub use sea_orm_migration::prelude::*; - -mod m20220101_000001_users; -mod m20231103_114510_notes; -mod m20240416_071825_roles; -mod m20240416_082115_users_roles; -pub struct Migrator; - -#[async_trait::async_trait] -impl MigratorTrait for Migrator { - fn migrations() -> Vec> { - vec![ - Box::new(m20220101_000001_users::Migration), - Box::new(m20231103_114510_notes::Migration), - Box::new(m20240416_071825_roles::Migration), - Box::new(m20240416_082115_users_roles::Migration), - // inject-above (do not remove this comment) - ] - } -} diff --git a/examples/demo/migration/src/m20220101_000001_users.rs b/examples/demo/migration/src/m20220101_000001_users.rs deleted file mode 100644 index 888ca8434..000000000 --- a/examples/demo/migration/src/m20220101_000001_users.rs +++ /dev/null @@ -1,48 +0,0 @@ -use sea_orm_migration::{prelude::*, schema::*}; - -#[derive(DeriveMigrationName)] -pub struct Migration; - -#[async_trait::async_trait] -impl MigrationTrait for Migration { - async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - let table = table_auto(Users::Table) - .col(pk_auto(Users::Id)) - .col(uuid(Users::Pid)) - .col(string_uniq(Users::Email)) - .col(string(Users::Password)) - .col(string(Users::ApiKey).unique_key()) - .col(string(Users::Name)) - .col(string_null(Users::ResetToken)) - .col(timestamp_null(Users::ResetSentAt)) - .col(string_null(Users::EmailVerificationToken)) - .col(timestamp_null(Users::EmailVerificationSentAt)) - .col(timestamp_null(Users::EmailVerifiedAt)) - .to_owned(); - manager.create_table(table).await?; - Ok(()) - } - - async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .drop_table(Table::drop().table(Users::Table).to_owned()) - .await - } -} - -/// Learn more at https://docs.rs/sea-query#iden -#[derive(Iden)] -pub enum Users { - Table, - Id, - Pid, - Email, - Name, - Password, - ApiKey, - ResetToken, - ResetSentAt, - EmailVerificationToken, - EmailVerificationSentAt, - EmailVerifiedAt, -} diff --git a/examples/demo/migration/src/m20231103_114510_notes.rs b/examples/demo/migration/src/m20231103_114510_notes.rs deleted file mode 100644 index d99a30875..000000000 --- a/examples/demo/migration/src/m20231103_114510_notes.rs +++ /dev/null @@ -1,33 +0,0 @@ -use sea_orm_migration::{prelude::*, schema::*}; - -#[derive(DeriveMigrationName)] -pub struct Migration; - -#[async_trait::async_trait] -impl MigrationTrait for Migration { - async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .create_table( - table_auto(Notes::Table) - .col(pk_auto(Notes::Id)) - .col(string_null(Notes::Title)) - .col(string_null(Notes::Content)) - .to_owned(), - ) - .await - } - - async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .drop_table(Table::drop().table(Notes::Table).to_owned()) - .await - } -} - -#[derive(DeriveIden)] -enum Notes { - Table, - Id, - Title, - Content, -} diff --git a/examples/demo/migration/src/m20240416_071825_roles.rs b/examples/demo/migration/src/m20240416_071825_roles.rs deleted file mode 100644 index f1cd57e79..000000000 --- a/examples/demo/migration/src/m20240416_071825_roles.rs +++ /dev/null @@ -1,74 +0,0 @@ -use sea_orm_migration::{prelude::*, schema::*}; - -use crate::{ - extension::postgres::Type, - sea_orm::{DbBackend, DeriveActiveEnum, EnumIter, Schema}, -}; - -#[derive(DeriveMigrationName)] -pub struct Migration; - -#[async_trait::async_trait] -impl MigrationTrait for Migration { - async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - // Create a new enum type `roles_name` with the values `Admin` and `User` - let schema = Schema::new(DbBackend::Postgres); - manager - .create_type(schema.create_enum_from_active_enum::()) - .await?; - // Create a new table `roles` with the columns `id`, `pid`, and `name` - manager - .create_table( - table_auto(Roles::Table) - .col(pk_auto(Roles::Id)) - .col(uuid_uniq(Roles::Pid)) - .col( - ColumnDef::new(Roles::Name) - .custom(Alias::new("roles_name")) // Use the enum type name - .not_null() - .to_owned(), - ) - .to_owned(), - ) - .await?; - - Ok(()) - } - - async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - // Drop the table `roles` - manager - .drop_table(Table::drop().table(Roles::Table).to_owned()) - .await?; - - // Drop the enum type `roles_name` - manager - .drop_type( - Type::drop() - .if_exists() - .name(RolesNameEnum) - .restrict() - .to_owned(), - ) - .await?; - Ok(()) - } -} - -#[derive(DeriveIden)] -enum Roles { - Table, - Id, - Pid, - Name, -} - -// Create a new enum for the roles_name -#[derive(EnumIter, DeriveActiveEnum)] -#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "roles_name")] -pub enum RolesName { - #[sea_orm(string_value = "Admin")] - Admin, - #[sea_orm(string_value = "User")] - User, -} diff --git a/examples/demo/migration/src/m20240416_082115_users_roles.rs b/examples/demo/migration/src/m20240416_082115_users_roles.rs deleted file mode 100644 index 2592e2f8e..000000000 --- a/examples/demo/migration/src/m20240416_082115_users_roles.rs +++ /dev/null @@ -1,65 +0,0 @@ -use sea_orm_migration::{prelude::*, schema::*}; - -#[derive(DeriveMigrationName)] -pub struct Migration; - -#[async_trait::async_trait] -impl MigrationTrait for Migration { - async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .create_table( - table_auto(UsersRoles::Table) - .primary_key( - Index::create() - .name("idx-users_roles-refs-pk") - .table(UsersRoles::Table) - .col(UsersRoles::UsersId) - .col(UsersRoles::RolesId), - ) - .col(integer(UsersRoles::UsersId)) - .col(integer(UsersRoles::RolesId)) - .foreign_key( - ForeignKey::create() - .name("fk-users_roles-users") - .from(UsersRoles::Table, UsersRoles::UsersId) - .to(Users::Table, Users::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .foreign_key( - ForeignKey::create() - .name("fk-users_roles-roles") - .from(UsersRoles::Table, UsersRoles::RolesId) - .to(Roles::Table, Roles::Id) - .on_delete(ForeignKeyAction::Cascade) - .on_update(ForeignKeyAction::Cascade), - ) - .to_owned(), - ) - .await - } - - async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - manager - .drop_table(Table::drop().table(UsersRoles::Table).to_owned()) - .await - } -} - -#[derive(DeriveIden)] -enum UsersRoles { - Table, - UsersId, - RolesId, -} - -#[derive(DeriveIden)] -enum Users { - Table, - Id, -} -#[derive(DeriveIden)] -enum Roles { - Table, - Id, -} diff --git a/examples/demo/src/app.rs b/examples/demo/src/app.rs deleted file mode 100644 index 724c54d53..000000000 --- a/examples/demo/src/app.rs +++ /dev/null @@ -1,123 +0,0 @@ -use std::path::Path; - -use async_trait::async_trait; -use loco_rs::{ - app::{AppContext, Hooks, Initializer}, - boot::{create_app, BootResult, StartMode}, - cache, - config::Config, - controller::AppRoutes, - db::{self, truncate_table}, - environment::Environment, - prelude::*, - storage::{self, Storage}, - task::Tasks, - Result, -}; -use migration::Migrator; - -use crate::{ - controllers::{self, middlewares}, - initializers, - models::_entities::{notes, roles, users, users_roles}, - tasks, - workers::downloader::DownloadWorker, -}; - -pub struct App; -#[async_trait] -impl Hooks for App { - fn app_version() -> String { - format!( - "{} ({})", - env!("CARGO_PKG_VERSION"), - option_env!("BUILD_SHA") - .or(option_env!("GITHUB_SHA")) - .unwrap_or("dev") - ) - } - - fn app_name() -> &'static str { - env!("CARGO_CRATE_NAME") - } - - // - async fn initializers(_ctx: &AppContext) -> Result>> { - let initializers: Vec> = vec![ - Box::new(initializers::axum_session::AxumSessionInitializer), - Box::new(initializers::view_engine::ViewEngineInitializer), - Box::new(initializers::hello_view_engine::HelloViewEngineInitializer), - ]; - - Ok(initializers) - } - // - - fn routes(ctx: &AppContext) -> AppRoutes { - AppRoutes::with_default_routes() - .add_route( - controllers::mylayer::routes(ctx.clone()) - .layer(middlewares::routes::role::RoleRouteLayer::new(ctx.clone())), - ) - .add_route(controllers::notes::routes()) - .add_route(controllers::auth::routes()) - .add_route(controllers::mysession::routes()) - .add_route(controllers::view_engine::routes()) - .add_route(controllers::user::routes()) - .add_route(controllers::upload::routes()) - .add_route(controllers::responses::routes()) - .add_route(controllers::cache::routes()) - } - - async fn boot( - mode: StartMode, - environment: &Environment, - config: Config, - ) -> Result { - create_app::(mode, environment, config).await - } - - async fn after_context(ctx: AppContext) -> Result { - let store = if ctx.environment == Environment::Test { - storage::drivers::mem::new() - } else { - storage::drivers::local::new_with_prefix("storage-uploads").map_err(Box::from)? - }; - - Ok(AppContext { - storage: Storage::single(store).into(), - cache: cache::Cache::new(cache::drivers::inmem::new()).into(), - ..ctx - }) - - // Ok(ctx) - } - - async fn connect_workers(ctx: &AppContext, queue: &Queue) -> Result<()> { - queue.register(DownloadWorker::build(ctx)).await?; - Ok(()) - } - - fn register_tasks(tasks: &mut Tasks) { - tasks.register(tasks::user_report::UserReport); - tasks.register(tasks::seed::SeedData); - tasks.register(tasks::foo::Foo); - // tasks-inject (do not remove) - } - - async fn truncate(ctx: &AppContext) -> Result<()> { - truncate_table(&ctx.db, users_roles::Entity).await?; - truncate_table(&ctx.db, roles::Entity).await?; - truncate_table(&ctx.db, users::Entity).await?; - truncate_table(&ctx.db, notes::Entity).await?; - Ok(()) - } - - async fn seed(ctx: &AppContext, base: &Path) -> Result<()> { - db::seed::(&ctx.db, &base.join("users.yaml").display().to_string()) - .await?; - db::seed::(&ctx.db, &base.join("notes.yaml").display().to_string()) - .await?; - Ok(()) - } -} diff --git a/examples/demo/src/bin/main.rs b/examples/demo/src/bin/main.rs deleted file mode 100644 index 8eb2a0306..000000000 --- a/examples/demo/src/bin/main.rs +++ /dev/null @@ -1,8 +0,0 @@ -use demo_app::app::App; -use loco_rs::cli; -use migration::Migrator; - -#[tokio::main] -async fn main() -> loco_rs::Result<()> { - cli::main::().await -} diff --git a/examples/demo/src/bin/tool.rs b/examples/demo/src/bin/tool.rs deleted file mode 100644 index 8eb2a0306..000000000 --- a/examples/demo/src/bin/tool.rs +++ /dev/null @@ -1,8 +0,0 @@ -use demo_app::app::App; -use loco_rs::cli; -use migration::Migrator; - -#[tokio::main] -async fn main() -> loco_rs::Result<()> { - cli::main::().await -} diff --git a/examples/demo/src/common/mod.rs b/examples/demo/src/common/mod.rs deleted file mode 100644 index 6e98cefd0..000000000 --- a/examples/demo/src/common/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod settings; diff --git a/examples/demo/src/common/settings.rs b/examples/demo/src/common/settings.rs deleted file mode 100644 index 79db3d10b..000000000 --- a/examples/demo/src/common/settings.rs +++ /dev/null @@ -1,18 +0,0 @@ -use loco_rs::Result; -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize, Default, Debug)] -pub struct Settings { - pub allow_list: Option>, -} - -impl Settings { - /// Deserialize a strongly typed settings - /// - /// # Errors - /// - /// This function will return an error if deserialization fails - pub fn from_json(value: &serde_json::Value) -> Result { - Ok(serde_json::from_value(value.clone())?) - } -} diff --git a/examples/demo/src/controllers/auth.rs b/examples/demo/src/controllers/auth.rs deleted file mode 100644 index d6de58b40..000000000 --- a/examples/demo/src/controllers/auth.rs +++ /dev/null @@ -1,147 +0,0 @@ -use loco_rs::{controller::bad_request, prelude::*}; -use serde::{Deserialize, Serialize}; - -use crate::{ - mailers::auth::AuthMailer, - models::{ - _entities::users, - users::{LoginParams, RegisterParams}, - }, - views::auth::UserSession, -}; -#[derive(Debug, Deserialize, Serialize)] -pub struct VerifyParams { - pub token: String, -} - -#[derive(Debug, Deserialize, Serialize)] -pub struct ForgotParams { - pub email: String, -} - -#[derive(Debug, Deserialize, Serialize)] -pub struct ResetParams { - pub token: String, - pub password: String, -} - -/// Register function creates a new user with the given parameters and sends a -/// welcome email to the user -async fn register( - State(ctx): State, - Json(params): Json, -) -> Result { - let res = users::Model::create_with_password(&ctx.db, ¶ms).await; - - let user = match res { - Ok(user) => user, - Err(err) => { - let msg = "could not register user"; - - tracing::info!(message = err.to_string(), user_email = ¶ms.email, msg,); - return bad_request(msg); - } - }; - - let user = user - .into_active_model() - .set_email_verification_sent(&ctx.db) - .await?; - - AuthMailer::send_welcome(&ctx, &user).await?; - - let jwt_secret = ctx.config.get_jwt_config()?; - - let token = user - .generate_jwt(&jwt_secret.secret, jwt_secret.expiration) - .or_else(|_| unauthorized("unauthorized!"))?; - format::json(UserSession::new(&user, &token)) -} - -/// Verify register user. if the user not verified his email, he can't login to -/// the system. -async fn verify( - State(ctx): State, - Json(params): Json, -) -> Result { - let user = users::Model::find_by_verification_token(&ctx.db, ¶ms.token).await?; - - if user.email_verified_at.is_some() { - tracing::info!(pid = user.pid.to_string(), "user already verified"); - } else { - let active_model = user.into_active_model(); - let user = active_model.verified(&ctx.db).await?; - tracing::info!(pid = user.pid.to_string(), "user verified"); - } - - format::empty_json() -} - -/// In case the user forgot his password this endpoints generate a forgot token -/// and send email to the user. In case the email not found in our DB, we are -/// returning a valid request for for security reasons (not exposing users DB -/// list). -async fn forgot( - State(ctx): State, - Json(params): Json, -) -> Result { - let Ok(user) = users::Model::find_by_email(&ctx.db, ¶ms.email).await else { - // we don't want to expose our users email. if the email is invalid we still - // returning success to the caller - return format::empty_json(); - }; - - let user = user - .into_active_model() - .set_forgot_password_sent(&ctx.db) - .await?; - - AuthMailer::forgot_password(&ctx, &user).await?; - - format::empty_json() -} - -/// reset user password by the given parameters -async fn reset(State(ctx): State, Json(params): Json) -> Result { - let Ok(user) = users::Model::find_by_reset_token(&ctx.db, ¶ms.token).await else { - // we don't want to expose our users email. if the email is invalid we still - // returning success to the caller - tracing::info!("reset token not found"); - - return format::empty_json(); - }; - user.into_active_model() - .reset_password(&ctx.db, ¶ms.password) - .await?; - - format::empty_json() -} - -/// Creates a user login and returns a token -async fn login(State(ctx): State, Json(params): Json) -> Result { - let user = users::Model::find_by_email(&ctx.db, ¶ms.email).await?; - - let valid = user.verify_password(¶ms.password); - - if !valid { - return unauthorized("unauthorized!"); - } - - let jwt_secret = ctx.config.get_jwt_config()?; - - let token = user - .generate_jwt(&jwt_secret.secret, jwt_secret.expiration) - .or_else(|_| unauthorized("unauthorized!"))?; - - format::json(UserSession::new(&user, &token)) -} - -pub fn routes() -> Routes { - Routes::new() - .prefix("auth") - .add("/register", post(register)) - .add("/verify", post(verify)) - .add("/login", post(login)) - .add("/forgot", post(forgot)) - .add("/reset", post(reset)) -} diff --git a/examples/demo/src/controllers/cache.rs b/examples/demo/src/controllers/cache.rs deleted file mode 100644 index 90c95fe4c..000000000 --- a/examples/demo/src/controllers/cache.rs +++ /dev/null @@ -1,42 +0,0 @@ -use loco_rs::prelude::*; -use serde::{Deserialize, Serialize}; - -use crate::models::users; -#[derive(Serialize, Deserialize)] -pub struct CacheResponse { - value: Option, -} - -async fn get_cache(State(ctx): State) -> Result { - format::json(CacheResponse { - value: ctx.cache.get("value").await.unwrap(), - }) -} - -async fn insert(State(ctx): State) -> Result { - ctx.cache.insert("value", "loco cache value").await.unwrap(); - format::empty() -} - -async fn get_or_insert(State(ctx): State) -> Result { - let res = ctx - .cache - .get_or_insert("user", async { - let user = users::Model::find_by_email(&ctx.db, "user1@example.com").await?; - Ok(user.name) - }) - .await; - - match res { - Ok(username) => format::text(&username), - Err(_e) => format::text("not found"), - } -} - -pub fn routes() -> Routes { - Routes::new() - .prefix("cache") - .add("/", get(get_cache)) - .add("/insert", post(insert)) - .add("/get_or_insert", get(get_or_insert)) -} diff --git a/examples/demo/src/controllers/middlewares/handlers/admin.rs b/examples/demo/src/controllers/middlewares/handlers/admin.rs deleted file mode 100644 index 489ff1272..000000000 --- a/examples/demo/src/controllers/middlewares/handlers/admin.rs +++ /dev/null @@ -1,109 +0,0 @@ -use std::{ - convert::Infallible, - task::{Context, Poll}, -}; - -use axum::{ - body::Body, - extract::{FromRequestParts, Request}, - response::Response, -}; -use futures_util::future::BoxFuture; -use loco_rs::prelude::{auth::JWTWithUser, *}; -use tower::{Layer, Service}; - -use crate::models::{roles, sea_orm_active_enums::RolesName, users}; - -#[derive(Clone)] -pub struct AdminHandlerLayer { - state: AppContext, -} - -impl AdminHandlerLayer { - pub fn new(state: AppContext) -> Self { - Self { state } - } -} - -impl Layer for AdminHandlerLayer { - type Service = AdminHandlerService; - - fn layer(&self, inner: S) -> Self::Service { - Self::Service { - inner, - state: self.state.clone(), - } - } -} - -#[derive(Clone)] -pub struct AdminHandlerService { - inner: S, - state: AppContext, -} - -impl Service> for AdminHandlerService -where - S: Service, Response = Response, Error = Infallible> + Clone + Send + 'static, /* Inner Service must return Response and never error */ - S::Future: Send + 'static, - B: Send + 'static, -{ - // Response type is the same as the inner service / handler - type Response = S::Response; - // Error type is the same as the inner service / handler - type Error = S::Error; - // Future type is the same as the inner service / handler - type Future = BoxFuture<'static, Result>; - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_ready(cx) - } - - fn call(&mut self, req: Request) -> Self::Future { - let state = self.state.clone(); - let clone = self.inner.clone(); - // take the service that was ready - let mut inner = std::mem::replace(&mut self.inner, clone); - Box::pin(async move { - // Example of extracting JWT and checking roles - let (mut parts, body) = req.into_parts(); - let auth = JWTWithUser::::from_request_parts(&mut parts, &state).await; - - match auth { - Ok(auth) => { - // Check user roles here - // If the user has the required role, proceed with the inner service - let _admin = match roles::Model::find_by_user(&state.db, &auth.user).await { - Ok(role) => match role.name { - RolesName::User => { - return Ok(Response::builder() - .status(401) - .body(Body::empty()) - .unwrap() - .into_response()) - } - RolesName::Admin => role, - }, - Err(_) => { - return Ok(Response::builder() - .status(401) - .body(Body::empty()) - .unwrap() - .into_response()) - } - }; - - let req = Request::from_parts(parts, body); - inner.call(req).await - } - Err(_) => { - // Handle error, e.g., return an unauthorized response - Ok(Response::builder() - .status(401) - .body(Body::empty()) - .unwrap() - .into_response()) - } - } - }) - } -} diff --git a/examples/demo/src/controllers/middlewares/handlers/mod.rs b/examples/demo/src/controllers/middlewares/handlers/mod.rs deleted file mode 100644 index 1e6bf65ba..000000000 --- a/examples/demo/src/controllers/middlewares/handlers/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod admin; -pub mod user; diff --git a/examples/demo/src/controllers/middlewares/handlers/user.rs b/examples/demo/src/controllers/middlewares/handlers/user.rs deleted file mode 100644 index e6c458c84..000000000 --- a/examples/demo/src/controllers/middlewares/handlers/user.rs +++ /dev/null @@ -1,112 +0,0 @@ -use std::{ - convert::Infallible, - task::{Context, Poll}, -}; - -use axum::{ - body::Body, - extract::{FromRequestParts, Request}, - response::Response, -}; -use futures_util::future::BoxFuture; -use loco_rs::prelude::{auth::JWTWithUser, *}; -use tower::{Layer, Service}; - -use crate::models::{roles, sea_orm_active_enums::RolesName, users}; - -#[derive(Clone)] -pub struct UserHandlerLayer { - state: AppContext, -} - -impl UserHandlerLayer { - pub fn new(state: AppContext) -> Self { - Self { state } - } -} - -impl Layer for UserHandlerLayer { - type Service = UserHandlerService; - - fn layer(&self, inner: S) -> Self::Service { - Self::Service { - inner, - state: self.state.clone(), - } - } -} - -#[derive(Clone)] -pub struct UserHandlerService { - inner: S, - state: AppContext, -} - -/// Service that checks if the user has the required user role before calling -/// the inner service If the user has the required role, the inner service is -/// called Otherwise, an unauthorized response is returned -impl Service> for UserHandlerService -where - S: Service, Response = Response, Error = Infallible> + Clone + Send + 'static, - S::Future: Send + 'static, - B: Send + 'static, -{ - // Response type is the same as the inner service / handler - type Response = S::Response; - // Error type is the same as the inner service / handler - type Error = S::Error; - // Future type is the same as the inner service / handler - type Future = BoxFuture<'static, Result>; - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_ready(cx) - } - - fn call(&mut self, req: Request) -> Self::Future { - let state = self.state.clone(); - let clone = self.inner.clone(); - // take the service that was ready - let mut inner = std::mem::replace(&mut self.inner, clone); - Box::pin(async move { - // Example of extracting JWT and checking roles - let (mut parts, body) = req.into_parts(); - let auth = JWTWithUser::::from_request_parts(&mut parts, &state).await; - - match auth { - Ok(auth) => { - // Check user roles here - // If the user has the required role, proceed with the inner service - let _user = match roles::Model::find_by_user(&state.db, &auth.user).await { - Ok(role) => match role.name { - RolesName::Admin => { - return Ok(Response::builder() - .status(401) - .body(Body::empty()) - .unwrap() - .into_response()) - } - RolesName::User => role, - }, - Err(_) => { - return Ok(Response::builder() - .status(401) - .body(Body::empty()) - .unwrap() - .into_response()) - } - }; - - let req = Request::from_parts(parts, body); - inner.call(req).await - } - Err(_) => { - // Return an unauthorized response - Ok(Response::builder() - .status(401) - .body(Body::empty()) - .unwrap() - .into_response()) - } - } - }) - } -} diff --git a/examples/demo/src/controllers/middlewares/mod.rs b/examples/demo/src/controllers/middlewares/mod.rs deleted file mode 100644 index c0c696a55..000000000 --- a/examples/demo/src/controllers/middlewares/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod handlers; -pub mod routes; diff --git a/examples/demo/src/controllers/middlewares/routes/mod.rs b/examples/demo/src/controllers/middlewares/routes/mod.rs deleted file mode 100644 index f5b70d333..000000000 --- a/examples/demo/src/controllers/middlewares/routes/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod role; diff --git a/examples/demo/src/controllers/middlewares/routes/role.rs b/examples/demo/src/controllers/middlewares/routes/role.rs deleted file mode 100644 index 8403547aa..000000000 --- a/examples/demo/src/controllers/middlewares/routes/role.rs +++ /dev/null @@ -1,99 +0,0 @@ -use std::{ - convert::Infallible, - task::{Context, Poll}, -}; - -use axum::{ - body::Body, - extract::{FromRequestParts, Request}, - response::Response, -}; -use futures_util::future::BoxFuture; -use loco_rs::prelude::{auth::JWTWithUser, *}; -use tower::{Layer, Service}; - -use crate::models::{roles, users}; - -#[derive(Clone)] -pub struct RoleRouteLayer { - state: AppContext, -} - -impl RoleRouteLayer { - pub fn new(state: AppContext) -> Self { - Self { state } - } -} - -impl Layer for RoleRouteLayer { - type Service = RoleRouteService; - - fn layer(&self, inner: S) -> Self::Service { - Self::Service { - inner, - state: self.state.clone(), - } - } -} -#[derive(Clone)] -pub struct RoleRouteService { - inner: S, - state: AppContext, -} - -impl Service> for RoleRouteService -where - S: Service, Response = Response, Error = Infallible> + Clone + Send + 'static, /* Inner Service must return Response and never error */ - S::Future: Send + 'static, - B: Send + 'static, -{ - // Response type is the same as the inner service / handler - type Response = S::Response; - // Error type is the same as the inner service / handler - type Error = S::Error; - // Future type is the same as the inner service / handler - type Future = BoxFuture<'static, Result>; - - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_ready(cx) - } - - fn call(&mut self, req: Request) -> Self::Future { - let state = self.state.clone(); - let clone = self.inner.clone(); - // take the service that was ready - let mut inner = std::mem::replace(&mut self.inner, clone); - Box::pin(async move { - // Example of extracting JWT and checking roles - let (mut parts, body) = req.into_parts(); - let auth = JWTWithUser::::from_request_parts(&mut parts, &state).await; - - match auth { - Ok(auth) => { - // Check user roles here - // If the user has the required role, proceed with the inner service - let _role = match roles::Model::find_by_user(&state.db, &auth.user).await { - Ok(role) => role, - Err(_) => { - return Ok(Response::builder() - .status(401) - .body(Body::empty()) - .unwrap() - .into_response()) - } - }; - let req = Request::from_parts(parts, body); - inner.call(req).await - } - Err(_) => { - // Handle error, e.g., return an unauthorized response - Ok(Response::builder() - .status(401) - .body(Body::empty()) - .unwrap() - .into_response()) - } - } - }) - } -} diff --git a/examples/demo/src/controllers/mod.rs b/examples/demo/src/controllers/mod.rs deleted file mode 100644 index 40e04b872..000000000 --- a/examples/demo/src/controllers/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -pub mod auth; -pub mod cache; -pub mod middlewares; -pub mod mylayer; -pub mod mysession; -pub mod notes; -pub mod responses; -pub mod upload; -pub mod user; -pub mod view_engine; diff --git a/examples/demo/src/controllers/mylayer.rs b/examples/demo/src/controllers/mylayer.rs deleted file mode 100644 index b9428a4dc..000000000 --- a/examples/demo/src/controllers/mylayer.rs +++ /dev/null @@ -1,32 +0,0 @@ -#![allow(clippy::unused_async)] -use loco_rs::prelude::*; - -use crate::controllers::middlewares::handlers; - -async fn user() -> Result { - format::json("Hello, user!") -} - -async fn admin() -> Result { - format::json("Hello, admin!") -} - -async fn echo() -> Result { - format::json("Hello, World!") -} - -pub fn routes(ctx: AppContext) -> Routes { - Routes::new() - .prefix("mylayer") - // Only users with the RoleName::Admin can access this route - .add( - "/admin", - get(admin).layer(handlers::admin::AdminHandlerLayer::new(ctx.clone())), - ) - // Only users with the RoleName::User can access this route - .add( - "/user", - get(user).layer(handlers::user::UserHandlerLayer::new(ctx.clone())), - ) - .add("/echo", get(echo)) -} diff --git a/examples/demo/src/controllers/mysession.rs b/examples/demo/src/controllers/mysession.rs deleted file mode 100644 index f8b948ebb..000000000 --- a/examples/demo/src/controllers/mysession.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![allow(clippy::unused_async)] -use axum_session::{Session, SessionNullPool}; -use loco_rs::prelude::*; - -/// Get a session -/// -/// # Errors -/// -/// This function will return an error if result fails -pub async fn get_session(_session: Session) -> Result { - format::empty() -} - -pub fn routes() -> Routes { - Routes::new().prefix("mysession").add("/", get(get_session)) -} diff --git a/examples/demo/src/controllers/notes.rs b/examples/demo/src/controllers/notes.rs deleted file mode 100644 index 9dd9e6977..000000000 --- a/examples/demo/src/controllers/notes.rs +++ /dev/null @@ -1,161 +0,0 @@ -#![allow(clippy::missing_errors_doc)] -#![allow(clippy::unnecessary_struct_initialization)] -#![allow(clippy::unused_async)] -use axum::extract::Query; -use loco_rs::{controller::bad_request, model::ModelError, prelude::*}; -use sea_orm::Condition; -use serde::{Deserialize, Serialize}; - -use crate::{ - models::_entities::notes::{ActiveModel, Column, Entity, Model}, - views::notes::PaginationResponse, -}; - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Params { - pub title: Option, - pub content: Option, -} - -#[derive(Debug, Deserialize)] -pub struct ListQueryParams { - pub title: Option, - pub content: Option, - #[serde(flatten)] - pub pagination: query::PaginationQuery, -} - -impl Params { - fn update(&self, item: &mut ActiveModel) { - item.title = Set(self.title.clone()); - item.content = Set(self.content.clone()); - } -} - -async fn load_item(ctx: &AppContext, id: i32) -> Result { - let item = Entity::find_by_id(id).one(&ctx.db).await?; - item.ok_or_else(|| Error::NotFound) -} - -pub async fn list( - State(ctx): State, - Query(params): Query, -) -> Result { - let pagination_query = query::PaginationQuery { - page_size: params.pagination.page_size, - page: params.pagination.page, - }; - - let paginated_notes = query::paginate( - &ctx.db, - Entity::find(), - Some(query::with(params.into_query()).build()), - &pagination_query, - ) - .await?; - - /* - if let Some(settings) = &ctx.config.settings { - let settings = common::settings::Settings::from_json(settings)?; - println!("allow list: {:?}", settings.allow_list); - }*/ - - format::render() - .cookies(&[ - cookie::Cookie::new("foo", "bar"), - cookie::Cookie::new("baz", "qux"), - ])? - .etag("foobar")? - .json(PaginationResponse::response( - paginated_notes, - &pagination_query, - )) -} - -pub async fn add(State(ctx): State, Json(params): Json) -> Result { - let mut item = ActiveModel { - ..Default::default() - }; - params.update(&mut item); - let item = item.insert(&ctx.db).await?; - format::json(item) -} - -pub async fn update( - Path(id): Path, - State(ctx): State, - Json(params): Json, -) -> Result { - let item = load_item(&ctx, id).await?; - let mut item = item.into_active_model(); - params.update(&mut item); - let item = item.update(&ctx.db).await?; - format::json(item) -} - -pub async fn remove(Path(id): Path, State(ctx): State) -> Result { - load_item(&ctx, id).await?.delete(&ctx.db).await?; - format::empty() -} - -pub async fn get_one( - Format(respond_to): Format, - Path(id): Path, - State(ctx): State, -) -> Result { - // having `load_item` is useful because inside the function you can call and use - // '?' to bubble up errors, then, in here, we centralize handling of errors. - // if you want to freely use code statements with no wrapping function, you can - // use the experimental `try` feature in Rust where you can do: - // ``` - // let res = try { - // ... - // ... - // } - // - // match res { ..} - // ``` - let res = load_item(&ctx, id).await; - - match res { - // we're good, let's render the item based on content type - Ok(item) => match respond_to { - RespondTo::Html => format::html(&format!("{:?}", item.title)), - _ => format::json(item), - }, - // we have an opinion how to render out validation errors, only in HTML content - Err(Error::Model(ModelError::ModelValidation { errors })) => match respond_to { - RespondTo::Html => { - format::html(&format!("errors: {errors:?}")) - } - _ => bad_request("opaque message: cannot respond!"), - }, - // we have no clue what this is, let the framework render default errors - Err(err) => Err(err), - } -} - -impl ListQueryParams { - #[must_use] - pub fn into_query(&self) -> Condition { - let mut condition = query::condition(); - - if let Some(title) = &self.title { - condition = condition.like(Column::Title, title); - } - if let Some(content) = &self.content { - condition = condition.like(Column::Content, content); - } - condition.build() - } -} - -pub fn routes() -> Routes { - Routes::new() - .prefix("notes") - .add("/", get(list)) - .add("/", post(add)) - .add("/{id}", get(get_one)) - .add("/{id}", delete(remove)) - .add("/{id}", post(update)) -} diff --git a/examples/demo/src/controllers/responses.rs b/examples/demo/src/controllers/responses.rs deleted file mode 100644 index 43e0ea505..000000000 --- a/examples/demo/src/controllers/responses.rs +++ /dev/null @@ -1,147 +0,0 @@ -#![allow(clippy::unused_async)] -use axum_extra::extract::cookie::Cookie; -use loco_rs::prelude::*; -use serde::Serialize; -use utoipa::{openapi, OpenApi, ToSchema}; - -#[derive(Serialize)] -pub struct Health { - pub ok: bool, -} - -/// return an empty response -/// -/// # Errors -/// -/// This function will return an error if result fails -pub async fn empty() -> Result { - format::empty() -} - -/// return an text response -/// -/// # Errors -/// -/// This function will return an error if result fails -pub async fn text() -> Result { - format::text("Loco") -} - -/// return an JSON response -/// -/// # Errors -/// -/// This function will return an error if result fails -pub async fn json() -> Result { - format::json(Health { ok: true }) -} - -/// return an empty JSON response -/// -/// # Errors -/// -/// This function will return an error if result fails -pub async fn empty_json() -> Result { - format::empty_json() -} - -/// return an HTML response -/// -/// # Errors -/// -/// This function will return an error if result fails -pub async fn html() -> Result { - format::html("hello, world") -} - -/// return an redirect response -/// -/// # Errors -/// -/// This function will return an error if result fails -pub async fn redirect() -> Result { - format::redirect("/dashboard") -} - -/// return an custom status code response -/// -/// # Errors -/// -/// This function will return an error if result fails -pub async fn render_with_status_code() -> Result { - format::render().status(201).empty() -} - -/// return response with ETag header -/// -/// # Errors -/// -/// This function will return an error if result fails -pub async fn etag() -> Result { - format::render().etag("loco-etag")?.empty() -} - -/// return response with cookie -/// -/// # Errors -/// -/// This function will return an error if result fails -pub async fn set_cookie() -> Result { - let cookie = Cookie::build(("loco-cookie-name", "loco-cookie-value")) - // .domain("localhost:5173") - .path("/") - .same_site(cookie::SameSite::Strict) - .secure(true) - .http_only(true) - .build(); - - format::render().cookies(&[cookie])?.json(()) -} - -#[derive(Serialize, Debug, ToSchema)] -pub struct Album { - title: String, - rating: u32, -} - -// -// OpenAPI spec with `utoipa` -// -#[derive(OpenApi)] -#[openapi(paths(album))] -struct Spec; - -/// Return an OpenAPI-spec'd response -/// -/// # Errors -/// -/// This function will return an error if it fails -#[utoipa::path( - get, - path = "/response/album", - responses( - (status = 200, description = "Album found", body = Album), - ), -)] -pub async fn album() -> Result { - println!("{}", Spec::openapi().to_pretty_json().unwrap()); - - format::json(Album { - title: "VH II".to_string(), - rating: 10, - }) -} -pub fn routes() -> Routes { - Routes::new() - .prefix("response") - .add("/empty", get(empty)) - .add("/text", get(text)) - .add("/json", get(json)) - .add("/empty_json", get(empty_json)) - .add("/html", get(html)) - .add("/redirect", get(redirect)) - .add("/render_with_status_code", get(render_with_status_code)) - .add("/etag", get(etag)) - .add("/album", get(album)) - .add("/set_cookie", get(set_cookie)) -} diff --git a/examples/demo/src/controllers/upload.rs b/examples/demo/src/controllers/upload.rs deleted file mode 100644 index b04d0cd89..000000000 --- a/examples/demo/src/controllers/upload.rs +++ /dev/null @@ -1,48 +0,0 @@ -use std::path::PathBuf; - -use axum::extract::Multipart; -use loco_rs::prelude::*; - -use crate::views; - -/// File upload example -/// -/// ## Request Example -/// -/// curl -H "Content-Type: multipart/form-data" -F "file=@./test-2.json" -/// 127.0.0.1:5150/upload/file -async fn upload_file(State(ctx): State, mut multipart: Multipart) -> Result { - let mut file = None; - while let Some(field) = multipart.next_field().await.map_err(|err| { - tracing::error!(error = ?err,"could not readd multipart"); - Error::BadRequest("could not readd multipart".into()) - })? { - let file_name = match field.file_name() { - Some(file_name) => file_name.to_string(), - _ => return Err(Error::BadRequest("file name not found".into())), - }; - - let content = field.bytes().await.map_err(|err| { - tracing::error!(error = ?err,"could not readd bytes"); - Error::BadRequest("could not readd bytes".into()) - })?; - - let path = PathBuf::from("folder").join(file_name); - ctx.storage - .as_ref() - .upload(path.as_path(), &content) - .await?; - - file = Some(path); - } - - file.map_or_else(not_found, |path| { - format::json(views::upload::Response::new(path.as_path())) - }) -} - -pub fn routes() -> Routes { - Routes::new() - .prefix("upload") - .add("/file", post(upload_file)) -} diff --git a/examples/demo/src/controllers/user.rs b/examples/demo/src/controllers/user.rs deleted file mode 100644 index 48365d48c..000000000 --- a/examples/demo/src/controllers/user.rs +++ /dev/null @@ -1,45 +0,0 @@ -use loco_rs::prelude::*; - -use crate::{ - models::{_entities::users, roles}, - views::user::{CurrentResponse, UserResponse}, -}; - -async fn current( - auth: auth::JWTWithUser, - State(_ctx): State, -) -> Result { - format::json(CurrentResponse::new(&auth.user)) -} - -async fn current_by_api_key( - auth: auth::ApiToken, - State(_ctx): State, -) -> Result { - format::json(CurrentResponse::new(&auth.user)) -} - -async fn convert_to_admin( - auth: auth::JWTWithUser, - State(ctx): State, -) -> Result { - let roles = roles::Model::add_user_to_admin_role(&ctx.db, &auth.user).await?; - format::json(UserResponse::new(&auth.user, &roles)) -} - -async fn convert_to_user( - auth: auth::JWTWithUser, - State(ctx): State, -) -> Result { - let roles = roles::Model::add_user_to_user_role(&ctx.db, &auth.user).await?; - format::json(UserResponse::new(&auth.user, &roles)) -} - -pub fn routes() -> Routes { - Routes::new() - .prefix("user") - .add("/current", get(current)) - .add("/current_api_key", get(current_by_api_key)) - .add("/convert/admin", post(convert_to_admin)) - .add("/convert/user", post(convert_to_user)) -} diff --git a/examples/demo/src/controllers/view_engine.rs b/examples/demo/src/controllers/view_engine.rs deleted file mode 100644 index fc89d2b75..000000000 --- a/examples/demo/src/controllers/view_engine.rs +++ /dev/null @@ -1,38 +0,0 @@ -#![allow(clippy::unused_async)] -use loco_rs::prelude::*; -use serde_json::json; - -use crate::{initializers::hello_view_engine::HelloView, views}; - -/// Renders the dashboard home page -/// -/// # Errors -/// -/// This function will return an error if render fails -pub async fn render_home(ViewEngine(v): ViewEngine) -> Result { - views::engine::home(&v) -} - -/// Hello -/// -/// # Errors -/// -/// This function will return an error if render fails -pub async fn render_hello(ViewEngine(v): ViewEngine) -> Result { - // NOTE: v is a hello engine, which always returns 'hello', params dont matter. - // it's a funky behavior that we use for demonstrating how easy it is - // to build a custom view engine. - format::render().view(&v, "foobar", ()) -} - -pub async fn render_simple() -> Result { - format::render().template("{{name}} website", json!({"name": "Loco"})) -} - -pub fn routes() -> Routes { - Routes::new() - .prefix("view-engine") - .add("/home", get(render_home)) - .add("/hello", get(render_hello)) - .add("/simple", get(render_simple)) -} diff --git a/examples/demo/src/fixtures/notes.yaml b/examples/demo/src/fixtures/notes.yaml deleted file mode 100644 index 25cd13444..000000000 --- a/examples/demo/src/fixtures/notes.yaml +++ /dev/null @@ -1,54 +0,0 @@ ---- -- id: 1 - content: content 1 - created_at: "2023-11-12T12:34:56.789" - updated_at: "2023-11-12T12:34:56.789" -- id: 2 - title: Loco note 2 - created_at: "2023-11-12T12:34:56.789" - updated_at: "2023-11-12T12:34:56.789" -- id: 3 - title: Loco note 3 - content: content 3 - created_at: "2023-11-12T12:34:56.789" - updated_at: "2023-11-12T12:34:56.789" -- id: 4 - title: Loco note 4 - content: content 4 - created_at: "2023-11-12T12:34:56.789" - updated_at: "2023-11-12T12:34:56.789" -- id: 5 - title: Loco note 5 - content: content 5 - created_at: "2023-11-12T12:34:56.789" - updated_at: "2023-11-12T12:34:56.789" -- id: 6 - title: Loco 6 - content: content 6 - created_at: "2023-11-12T12:34:56.789" - updated_at: "2023-11-12T12:34:56.789" -- id: 7 - title: Loco 7 - content: content 7 - created_at: "2023-11-12T12:34:56.789" - updated_at: "2023-11-12T12:34:56.789" -- id: 8 - title: Loco 8 - content: content 8 - created_at: "2023-11-12T12:34:56.789" - updated_at: "2023-11-12T12:34:56.789" -- id: 9 - title: Loco 9 - content: content 9 - created_at: "2023-11-12T12:34:56.789" - updated_at: "2023-11-12T12:34:56.789" -- id: 10 - title: Loco 10 - content: content 10 - created_at: "2023-11-12T12:34:56.789" - updated_at: "2023-11-12T12:34:56.789" -- id: 11 - title: Loco 11 - content: content 11 - created_at: "2023-11-12T12:34:56.789" - updated_at: "2023-11-12T12:34:56.789" diff --git a/examples/demo/src/fixtures/users.yaml b/examples/demo/src/fixtures/users.yaml deleted file mode 100644 index 32ebc95ca..000000000 --- a/examples/demo/src/fixtures/users.yaml +++ /dev/null @@ -1,17 +0,0 @@ ---- -- id: 1 - pid: 11111111-1111-1111-1111-111111111111 - email: user1@example.com - password: "$argon2id$v=19$m=19456,t=2,p=1$JkBeJfBWoNlj4D684c568g$bKRQ+Ud8qwYGIaAu+x+4flGHPS4WJh3ylUUV4sEtDBY" - api_key: lo-95ec80d7-cb60-4b70-9b4b-9ef74cb88758 - name: user1 - created_at: "2023-11-12T12:34:56.789" - updated_at: "2023-11-12T12:34:56.789" -- id: 2 - pid: 22222222-2222-2222-2222-222222222222 - email: user2@example.com - password: "$argon2id$v=19$m=19456,t=2,p=1$JkBeJfBWoNlj4D684c568g$bKRQ+Ud8qwYGIaAu+x+4flGHPS4WJh3ylUUV4sEtDBY" - api_key: lo-153561ca-fa84-4e1b-813a-c62526d0a77e - name: user2 - created_at: "2023-11-12T12:34:56.789" - updated_at: "2023-11-12T12:34:56.789" diff --git a/examples/demo/src/initializers/axum_session.rs b/examples/demo/src/initializers/axum_session.rs deleted file mode 100644 index fb01bbee5..000000000 --- a/examples/demo/src/initializers/axum_session.rs +++ /dev/null @@ -1,26 +0,0 @@ -use async_trait::async_trait; -use axum::Router as AxumRouter; -use loco_rs::prelude::*; - -pub struct AxumSessionInitializer; - -#[async_trait] -impl Initializer for AxumSessionInitializer { - fn name(&self) -> String { - "axum-session".to_string() - } - - async fn after_routes(&self, router: AxumRouter, _ctx: &AppContext) -> Result { - let session_config = - axum_session::SessionConfig::default().with_table_name("sessions_table"); - - let session_store = - axum_session::SessionStore::::new(None, session_config) - .await - .unwrap(); - - let router = router.layer(axum_session::SessionLayer::new(session_store)); - - Ok(router) - } -} diff --git a/examples/demo/src/initializers/hello_view_engine.rs b/examples/demo/src/initializers/hello_view_engine.rs deleted file mode 100644 index 19161f4ad..000000000 --- a/examples/demo/src/initializers/hello_view_engine.rs +++ /dev/null @@ -1,28 +0,0 @@ -use async_trait::async_trait; -use axum::{Extension, Router as AxumRouter}; -use loco_rs::{ - app::{AppContext, Initializer}, - controller::views::{ViewEngine, ViewRenderer}, - Result, -}; -use serde::Serialize; - -#[derive(Clone)] -pub struct HelloView; -impl ViewRenderer for HelloView { - fn render(&self, _key: &str, _data: S) -> Result { - Ok("hello".to_string()) - } -} - -pub struct HelloViewEngineInitializer; -#[async_trait] -impl Initializer for HelloViewEngineInitializer { - fn name(&self) -> String { - "custom-view-engine".to_string() - } - - async fn after_routes(&self, router: AxumRouter, _ctx: &AppContext) -> Result { - Ok(router.layer(Extension(ViewEngine::from(HelloView)))) - } -} diff --git a/examples/demo/src/initializers/mod.rs b/examples/demo/src/initializers/mod.rs deleted file mode 100644 index c289cb97d..000000000 --- a/examples/demo/src/initializers/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -#![allow(clippy::module_name_repetitions)] -pub mod axum_session; -pub mod hello_view_engine; -pub mod view_engine; diff --git a/examples/demo/src/initializers/view_engine.rs b/examples/demo/src/initializers/view_engine.rs deleted file mode 100644 index f3ba9e6a9..000000000 --- a/examples/demo/src/initializers/view_engine.rs +++ /dev/null @@ -1,46 +0,0 @@ -use async_trait::async_trait; -use axum::{Extension, Router as AxumRouter}; -use fluent_templates::{ArcLoader, FluentLoader}; -use loco_rs::{ - app::{AppContext, Initializer}, - controller::views::{engines, ViewEngine}, - Error, Result, -}; -use tracing::info; - -const I18N_DIR: &str = "assets/i18n"; -const I18N_SHARED: &str = "assets/i18n/shared.ftl"; - -pub struct ViewEngineInitializer; -#[async_trait] -impl Initializer for ViewEngineInitializer { - fn name(&self) -> String { - "view-engine".to_string() - } - - async fn after_routes(&self, router: AxumRouter, _ctx: &AppContext) -> Result { - #[allow(unused_mut)] - let mut tera_engine = engines::TeraView::build()?; - if std::path::Path::new(I18N_DIR).exists() { - let arc = ArcLoader::builder(&I18N_DIR, unic_langid::langid!("en-US")) - .shared_resources(Some(&[I18N_SHARED.into()])) - .customize(|bundle| bundle.set_use_isolating(false)) - .build() - .map_err(|e| Error::string(&e.to_string()))?; - #[cfg(debug_assertions)] - tera_engine - .tera - .lock() - .expect("lock") - .register_function("t", FluentLoader::new(arc)); - - #[cfg(not(debug_assertions))] - tera_engine - .tera - .register_function("t", FluentLoader::new(arc)); - info!("locales loaded"); - } - - Ok(router.layer(Extension(ViewEngine::from(tera_engine)))) - } -} diff --git a/examples/demo/src/lib.rs b/examples/demo/src/lib.rs deleted file mode 100644 index d0eea6a3b..000000000 --- a/examples/demo/src/lib.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub mod app; -pub mod common; -pub mod controllers; -pub mod initializers; -pub mod mailers; -pub mod models; -pub mod tasks; -pub mod views; -pub mod workers; diff --git a/examples/demo/src/mailers/auth.rs b/examples/demo/src/mailers/auth.rs deleted file mode 100644 index 28a8991aa..000000000 --- a/examples/demo/src/mailers/auth.rs +++ /dev/null @@ -1,65 +0,0 @@ -// auth mailer -#![allow(non_upper_case_globals)] - -use loco_rs::prelude::*; -use serde_json::json; - -use crate::models::users; - -static welcome: Dir<'_> = include_dir!("src/mailers/auth/welcome"); -static forgot: Dir<'_> = include_dir!("src/mailers/auth/forgot"); -// #[derive(Mailer)] // -- disabled for faster build speed. it works. but lets -// move on for now. - -#[allow(clippy::module_name_repetitions)] -pub struct AuthMailer {} -impl Mailer for AuthMailer {} -impl AuthMailer { - /// Sending welcome email the the given user - /// - /// # Errors - /// - /// When email sending is failed - pub async fn send_welcome(ctx: &AppContext, user: &users::Model) -> Result<()> { - Self::mail_template( - ctx, - &welcome, - mailer::Args { - to: user.email.to_string(), - locals: json!({ - "name": user.name, - "verifyToken": user.email_verification_token, - "host": ctx.config.server.host - }), - ..Default::default() - }, - ) - .await?; - - Ok(()) - } - - /// Sending forgot password email - /// - /// # Errors - /// - /// When email sending is failed - pub async fn forgot_password(ctx: &AppContext, user: &users::Model) -> Result<()> { - Self::mail_template( - ctx, - &forgot, - mailer::Args { - to: user.email.to_string(), - locals: json!({ - "name": user.name, - "resetToken": user.reset_token, - "host": ctx.config.server.host - }), - ..Default::default() - }, - ) - .await?; - - Ok(()) - } -} diff --git a/examples/demo/src/mailers/auth/forgot/html.t b/examples/demo/src/mailers/auth/forgot/html.t deleted file mode 100644 index 4662b57c8..000000000 --- a/examples/demo/src/mailers/auth/forgot/html.t +++ /dev/null @@ -1,11 +0,0 @@ - - - - Hey {{name}}, - Forgot your password? No worries! You can reset it by clicking the link below: - Reset Your Password - If you didn't request a password reset, please ignore this email. - Best regards,
The Loco Team
- - - diff --git a/examples/demo/src/mailers/auth/forgot/subject.t b/examples/demo/src/mailers/auth/forgot/subject.t deleted file mode 100644 index 4938df1e3..000000000 --- a/examples/demo/src/mailers/auth/forgot/subject.t +++ /dev/null @@ -1 +0,0 @@ -Your reset password link diff --git a/examples/demo/src/mailers/auth/forgot/text.t b/examples/demo/src/mailers/auth/forgot/text.t deleted file mode 100644 index a6ab4968b..000000000 --- a/examples/demo/src/mailers/auth/forgot/text.t +++ /dev/null @@ -1,3 +0,0 @@ -Reset your password with this link: - -{{host}}/reset/{{resetToken}} diff --git a/examples/demo/src/mailers/auth/welcome/html.t b/examples/demo/src/mailers/auth/welcome/html.t deleted file mode 100644 index 33eca5261..000000000 --- a/examples/demo/src/mailers/auth/welcome/html.t +++ /dev/null @@ -1,13 +0,0 @@ -; - - - Dear {{name}}, - Welcome to Loco! You can now log in to your account. - Before you get started, please verify your account by clicking the link below: - - Verify Your Account - -

Best regards,
The Loco Team

- - - diff --git a/examples/demo/src/mailers/auth/welcome/subject.t b/examples/demo/src/mailers/auth/welcome/subject.t deleted file mode 100644 index 82cc6fbf7..000000000 --- a/examples/demo/src/mailers/auth/welcome/subject.t +++ /dev/null @@ -1 +0,0 @@ -Welcome {{name}} diff --git a/examples/demo/src/mailers/auth/welcome/text.t b/examples/demo/src/mailers/auth/welcome/text.t deleted file mode 100644 index 291ba0009..000000000 --- a/examples/demo/src/mailers/auth/welcome/text.t +++ /dev/null @@ -1,4 +0,0 @@ -Welcome {{name}}, you can now log in. - Verify your account with the link below: - -{{host}}/verify/{{verifyToken}} diff --git a/examples/demo/src/mailers/mod.rs b/examples/demo/src/mailers/mod.rs deleted file mode 100644 index 0e4a05d59..000000000 --- a/examples/demo/src/mailers/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod auth; diff --git a/examples/demo/src/models/_entities/mod.rs b/examples/demo/src/models/_entities/mod.rs deleted file mode 100644 index 2a1e4f725..000000000 --- a/examples/demo/src/models/_entities/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.15 - -pub mod prelude; - -pub mod notes; -pub mod roles; -pub mod sea_orm_active_enums; -pub mod users; -pub mod users_roles; diff --git a/examples/demo/src/models/_entities/notes.rs b/examples/demo/src/models/_entities/notes.rs deleted file mode 100644 index 3fa02a044..000000000 --- a/examples/demo/src/models/_entities/notes.rs +++ /dev/null @@ -1,18 +0,0 @@ -//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.15 - -use sea_orm::entity::prelude::*; -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)] -#[sea_orm(table_name = "notes")] -pub struct Model { - pub created_at: DateTime, - pub updated_at: DateTime, - #[sea_orm(primary_key)] - pub id: i32, - pub title: Option, - pub content: Option, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation {} diff --git a/examples/demo/src/models/_entities/prelude.rs b/examples/demo/src/models/_entities/prelude.rs deleted file mode 100644 index 202b05606..000000000 --- a/examples/demo/src/models/_entities/prelude.rs +++ /dev/null @@ -1,6 +0,0 @@ -//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.15 - -pub use super::{ - notes::Entity as Notes, roles::Entity as Roles, users::Entity as Users, - users_roles::Entity as UsersRoles, -}; diff --git a/examples/demo/src/models/_entities/roles.rs b/examples/demo/src/models/_entities/roles.rs deleted file mode 100644 index b3475c7ea..000000000 --- a/examples/demo/src/models/_entities/roles.rs +++ /dev/null @@ -1,39 +0,0 @@ -//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.15 - -use sea_orm::entity::prelude::*; -use serde::{Deserialize, Serialize}; - -use super::sea_orm_active_enums::RolesName; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)] -#[sea_orm(table_name = "roles")] -pub struct Model { - pub created_at: DateTime, - pub updated_at: DateTime, - #[sea_orm(primary_key)] - pub id: i32, - #[sea_orm(unique)] - pub pid: Uuid, - pub name: RolesName, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm(has_many = "super::users_roles::Entity")] - UsersRoles, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::UsersRoles.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - super::users_roles::Relation::Users.def() - } - fn via() -> Option { - Some(super::users_roles::Relation::Roles.def().rev()) - } -} diff --git a/examples/demo/src/models/_entities/sea_orm_active_enums.rs b/examples/demo/src/models/_entities/sea_orm_active_enums.rs deleted file mode 100644 index ae91241b3..000000000 --- a/examples/demo/src/models/_entities/sea_orm_active_enums.rs +++ /dev/null @@ -1,13 +0,0 @@ -//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.15 - -use sea_orm::entity::prelude::*; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Serialize, Deserialize)] -#[sea_orm(rs_type = "String", db_type = "Enum", enum_name = "roles_name")] -pub enum RolesName { - #[sea_orm(string_value = "Admin")] - Admin, - #[sea_orm(string_value = "User")] - User, -} diff --git a/examples/demo/src/models/_entities/users.rs b/examples/demo/src/models/_entities/users.rs deleted file mode 100644 index 3b7f1cce4..000000000 --- a/examples/demo/src/models/_entities/users.rs +++ /dev/null @@ -1,46 +0,0 @@ -//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.15 - -use sea_orm::entity::prelude::*; -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)] -#[sea_orm(table_name = "users")] -pub struct Model { - pub created_at: DateTime, - pub updated_at: DateTime, - #[sea_orm(primary_key)] - pub id: i32, - pub pid: Uuid, - #[sea_orm(unique)] - pub email: String, - pub password: String, - #[sea_orm(unique)] - pub api_key: String, - pub name: String, - pub reset_token: Option, - pub reset_sent_at: Option, - pub email_verification_token: Option, - pub email_verification_sent_at: Option, - pub email_verified_at: Option, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm(has_many = "super::users_roles::Entity")] - UsersRoles, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::UsersRoles.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - super::users_roles::Relation::Roles.def() - } - fn via() -> Option { - Some(super::users_roles::Relation::Users.def().rev()) - } -} diff --git a/examples/demo/src/models/_entities/users_roles.rs b/examples/demo/src/models/_entities/users_roles.rs deleted file mode 100644 index 8efb42283..000000000 --- a/examples/demo/src/models/_entities/users_roles.rs +++ /dev/null @@ -1,47 +0,0 @@ -//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.15 - -use sea_orm::entity::prelude::*; -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)] -#[sea_orm(table_name = "users_roles")] -pub struct Model { - pub created_at: DateTime, - pub updated_at: DateTime, - #[sea_orm(primary_key, auto_increment = false)] - pub users_id: i32, - #[sea_orm(primary_key, auto_increment = false)] - pub roles_id: i32, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm( - belongs_to = "super::roles::Entity", - from = "Column::RolesId", - to = "super::roles::Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - Roles, - #[sea_orm( - belongs_to = "super::users::Entity", - from = "Column::UsersId", - to = "super::users::Column::Id", - on_update = "Cascade", - on_delete = "Cascade" - )] - Users, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::Roles.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::Users.def() - } -} diff --git a/examples/demo/src/models/mod.rs b/examples/demo/src/models/mod.rs deleted file mode 100644 index 7eaaf3b59..000000000 --- a/examples/demo/src/models/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub mod _entities; -pub mod notes; -pub mod roles; -pub mod sea_orm_active_enums; -pub mod users; -pub mod users_roles; diff --git a/examples/demo/src/models/notes.rs b/examples/demo/src/models/notes.rs deleted file mode 100644 index 110259823..000000000 --- a/examples/demo/src/models/notes.rs +++ /dev/null @@ -1,7 +0,0 @@ -use sea_orm::entity::prelude::*; - -use super::_entities::notes::ActiveModel; - -impl ActiveModelBehavior for ActiveModel { - // extend activemodel below (keep comment for generators) -} diff --git a/examples/demo/src/models/roles.rs b/examples/demo/src/models/roles.rs deleted file mode 100644 index 8c45bf9aa..000000000 --- a/examples/demo/src/models/roles.rs +++ /dev/null @@ -1,73 +0,0 @@ -use loco_rs::prelude::*; - -pub use super::_entities::roles::{self, ActiveModel, Entity, Model}; -use crate::models::{_entities::sea_orm_active_enums::RolesName, users, users_roles}; - -#[async_trait] -impl ActiveModelBehavior for ActiveModel { - // extend activemodel below (keep comment for generators) - async fn before_save(self, _db: &C, insert: bool) -> std::result::Result - where - C: ConnectionTrait, - { - if insert { - let mut this = self; - this.pid = ActiveValue::Set(Uuid::new_v4()); - Ok(this) - } else { - Ok(self) - } - } -} - -impl super::_entities::roles::Model { - pub async fn add_user_to_admin_role( - db: &DatabaseConnection, - user: &users::Model, - ) -> ModelResult { - // Find the admin role - let role = Self::upsert_by_name(db, RolesName::Admin).await?; - // Connect the user to the admin role - users_roles::Model::connect_user_to_role(db, user, &role).await?; - Ok(role) - } - - pub async fn add_user_to_user_role( - db: &DatabaseConnection, - user: &users::Model, - ) -> ModelResult { - // Find the user role - let role = Self::upsert_by_name(db, RolesName::User).await?; - // Connect the user to the user role - users_roles::Model::connect_user_to_role(db, user, &role).await?; - Ok(role) - } - - pub async fn upsert_by_name(db: &DatabaseConnection, name: RolesName) -> ModelResult { - let role = roles::Entity::find() - .filter(roles::Column::Name.eq(name.clone())) - .one(db) - .await?; - match role { - Some(role) => Ok(role), - None => { - let role = roles::ActiveModel { - name: Set(name), - ..Default::default() - } - .insert(db) - .await?; - Ok(role) - } - } - } - - pub async fn find_by_user(db: &DatabaseConnection, user: &users::Model) -> ModelResult { - let role = roles::Entity::find() - .inner_join(users_roles::Entity) - .filter(users_roles::Column::UsersId.eq(user.id.clone())) - .one(db) - .await?; - role.ok_or_else(|| ModelError::EntityNotFound) - } -} diff --git a/examples/demo/src/models/sea_orm_active_enums.rs b/examples/demo/src/models/sea_orm_active_enums.rs deleted file mode 100644 index f761755f5..000000000 --- a/examples/demo/src/models/sea_orm_active_enums.rs +++ /dev/null @@ -1,13 +0,0 @@ -use std::fmt::Display; - -pub use crate::models::_entities::sea_orm_active_enums::RolesName; - -impl Display for RolesName { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let str = match self { - Self::Admin => "Admin".to_string(), - Self::User => "User".to_string(), - }; - write!(f, "{}", str) - } -} diff --git a/examples/demo/src/models/users.rs b/examples/demo/src/models/users.rs deleted file mode 100644 index d9762d3a8..000000000 --- a/examples/demo/src/models/users.rs +++ /dev/null @@ -1,303 +0,0 @@ -use async_trait::async_trait; -use chrono::offset::Local; -use loco_rs::{auth::jwt, hash, prelude::*}; -use serde::{Deserialize, Serialize}; -use serde_json::Map; -use uuid::Uuid; - -pub use super::_entities::users::{self, ActiveModel, Entity, Model}; - -#[derive(Debug, Deserialize, Serialize)] -pub struct LoginParams { - pub email: String, - pub password: String, -} - -#[derive(Debug, Deserialize, Serialize)] -pub struct RegisterParams { - pub email: String, - pub password: String, - pub name: String, -} - -// -#[derive(Debug, Validate, Deserialize)] -pub struct Validator { - #[validate(length(min = 2, message = "Name must be at least 2 characters long."))] - pub name: String, - #[validate(custom(function = "validation::is_valid_email"))] - pub email: String, -} - -impl Validatable for super::_entities::users::ActiveModel { - fn validator(&self) -> Box { - Box::new(Validator { - name: self.name.as_ref().to_owned(), - email: self.email.as_ref().to_owned(), - }) - } -} -// - -#[async_trait::async_trait] -impl ActiveModelBehavior for super::_entities::users::ActiveModel { - async fn before_save(self, _db: &C, insert: bool) -> Result - where - C: ConnectionTrait, - { - { - self.validate()?; - if insert { - let mut this = self; - this.pid = ActiveValue::Set(Uuid::new_v4()); - this.api_key = ActiveValue::Set(format!("lo-{}", Uuid::new_v4())); - Ok(this) - } else { - Ok(self) - } - } - } -} - -#[async_trait] -impl Authenticable for super::_entities::users::Model { - async fn find_by_api_key(db: &DatabaseConnection, api_key: &str) -> ModelResult { - let user = users::Entity::find() - .filter( - query::condition() - .eq(users::Column::ApiKey, api_key) - .build(), - ) - .one(db) - .await?; - user.ok_or_else(|| ModelError::EntityNotFound) - } - - async fn find_by_claims_key(db: &DatabaseConnection, claims_key: &str) -> ModelResult { - Self::find_by_pid(db, claims_key).await - } -} - -impl super::_entities::users::Model { - /// finds a user by the provided email - /// - /// # Errors - /// - /// When could not find user by the given token or DB query error - pub async fn find_by_email(db: &DatabaseConnection, email: &str) -> ModelResult { - let user = users::Entity::find() - .filter(query::condition().eq(users::Column::Email, email).build()) - .one(db) - .await?; - user.ok_or_else(|| ModelError::EntityNotFound) - } - - /// finds a user by the provided verification token - /// - /// # Errors - /// - /// When could not find user by the given token or DB query error - pub async fn find_by_verification_token( - db: &DatabaseConnection, - token: &str, - ) -> ModelResult { - let user = users::Entity::find() - .filter( - query::condition() - .eq(users::Column::EmailVerificationToken, token) - .build(), - ) - .one(db) - .await?; - user.ok_or_else(|| ModelError::EntityNotFound) - } - - /// finds a user by the provided reset token - /// - /// # Errors - /// - /// When could not find user by the given token or DB query error - pub async fn find_by_reset_token(db: &DatabaseConnection, token: &str) -> ModelResult { - let user = users::Entity::find() - .filter( - query::condition() - .eq(users::Column::ResetToken, token) - .build(), - ) - .one(db) - .await?; - user.ok_or_else(|| ModelError::EntityNotFound) - } - - /// finds a user by the provided pid - /// - /// # Errors - /// - /// When could not find user or DB query error - pub async fn find_by_pid(db: &DatabaseConnection, pid: &str) -> ModelResult { - let parse_uuid = Uuid::parse_str(pid).map_err(|e| ModelError::Any(e.into()))?; - let user = users::Entity::find() - .filter( - query::condition() - .eq(users::Column::Pid, parse_uuid) - .build(), - ) - .one(db) - .await?; - user.ok_or_else(|| ModelError::EntityNotFound) - } - - /// finds a user by the provided api key - /// - /// # Errors - /// - /// When could not find user by the given token or DB query error - pub async fn find_by_api_key(db: &DatabaseConnection, api_key: &str) -> ModelResult { - let user = users::Entity::find() - .filter( - query::condition() - .eq(users::Column::ApiKey, api_key) - .build(), - ) - .one(db) - .await?; - user.ok_or_else(|| ModelError::EntityNotFound) - } - - /// Verifies whether the provided plain password matches the hashed password - #[must_use] - pub fn verify_password(&self, password: &str) -> bool { - hash::verify_password(password, &self.password) - } - - /// Asynchronously creates a user with a password and saves it to the - /// database. - /// - /// # Errors - /// - /// When could not save the user into the DB - pub async fn create_with_password( - db: &DatabaseConnection, - params: &RegisterParams, - ) -> ModelResult { - let txn = db.begin().await?; - - if users::Entity::find() - .filter( - query::condition() - .eq(users::Column::Email, ¶ms.email) - .build(), - ) - .one(&txn) - .await? - .is_some() - { - return Err(ModelError::EntityAlreadyExists {}); - } - - let password_hash = - hash::hash_password(¶ms.password).map_err(|e| ModelError::Any(e.into()))?; - let user = users::ActiveModel { - email: ActiveValue::set(params.email.to_string()), - password: ActiveValue::set(password_hash), - name: ActiveValue::set(params.name.to_string()), - ..Default::default() - } - .insert(&txn) - .await?; - - txn.commit().await?; - - Ok(user) - } - - /// Creates a JWT - /// - /// # Errors - /// - /// when could not convert user claims to jwt token - pub fn generate_jwt(&self, secret: &str, expiration: u64) -> ModelResult { - let mut claims = Map::new(); - claims.insert("Role".to_string(), "Administrator".into()); - Ok(jwt::JWT::new(secret).generate_token(expiration, self.pid.to_string(), claims)?) - } -} - -impl super::_entities::users::ActiveModel { - /// Validate user schema - /// - /// # Errors - /// - /// when the active model is not valid - - /// Sets the email verification information for the user and - /// updates it in the database. - /// - /// This method is used to record the timestamp when the email verification - /// was sent and generate a unique verification token for the user. - /// - /// # Errors - /// - /// when has DB query error - pub async fn set_email_verification_sent( - mut self, - db: &DatabaseConnection, - ) -> ModelResult { - self.email_verification_sent_at = ActiveValue::set(Some(Local::now().naive_local())); - self.email_verification_token = ActiveValue::Set(Some(Uuid::new_v4().to_string())); - Ok(self.update(db).await?) - } - - /// Sets the information for a reset password request, - /// generates a unique reset password token, and updates it in the - /// database. - /// - /// This method records the timestamp when the reset password token is sent - /// and generates a unique token for the user. - /// - /// # Arguments - /// - /// # Errors - /// - /// when has DB query error - pub async fn set_forgot_password_sent(mut self, db: &DatabaseConnection) -> ModelResult { - self.reset_sent_at = ActiveValue::set(Some(Local::now().naive_local())); - self.reset_token = ActiveValue::Set(Some(Uuid::new_v4().to_string())); - Ok(self.update(db).await?) - } - - /// Records the verification time when a user verifies their - /// email and updates it in the database. - /// - /// This method sets the timestamp when the user successfully verifies their - /// email. - /// - /// # Errors - /// - /// when has DB query error - pub async fn verified(mut self, db: &DatabaseConnection) -> ModelResult { - self.email_verified_at = ActiveValue::set(Some(Local::now().naive_local())); - Ok(self.update(db).await?) - } - - /// Resets the current user password with a new password and - /// updates it in the database. - /// - /// This method hashes the provided password and sets it as the new password - /// for the user. - /// - /// # Errors - /// - /// when has DB query error or could not hashed the given password - pub async fn reset_password( - mut self, - db: &DatabaseConnection, - password: &str, - ) -> ModelResult { - self.password = - ActiveValue::set(hash::hash_password(password).map_err(|e| ModelError::Any(e.into()))?); - self.reset_token = ActiveValue::Set(None); - self.reset_sent_at = ActiveValue::Set(None); - Ok(self.update(db).await?) - } -} diff --git a/examples/demo/src/models/users_roles.rs b/examples/demo/src/models/users_roles.rs deleted file mode 100644 index 0a4b38ca9..000000000 --- a/examples/demo/src/models/users_roles.rs +++ /dev/null @@ -1,40 +0,0 @@ -use loco_rs::prelude::*; -use sea_orm::ActiveValue; - -pub use super::_entities::users_roles::{self, ActiveModel, Column, Entity, Model}; - -impl ActiveModelBehavior for ActiveModel { - // extend activemodel below (keep comment for generators) -} - -impl super::_entities::users_roles::Model { - pub async fn connect_user_to_role( - db: &DatabaseConnection, - user: &super::users::Model, - role: &super::roles::Model, - ) -> ModelResult { - // Find the user role if it exists - let user_role = users_roles::Entity::find() - .filter(Column::UsersId.eq(user.id)) - .one(db) - .await?; - // Update the user role if it exists, otherwise create it - if let Some(user_role) = user_role { - // Delete the user role if the role is different - if user_role.roles_id == role.id { - return Ok(user_role); - } - // Delete the user role, cannot update since it is a composite key - user_role.delete(db).await?; - } - // Create the user role - let user_role = users_roles::ActiveModel { - users_id: ActiveValue::set(user.id), - roles_id: ActiveValue::set(role.id), - ..Default::default() - } - .insert(db) - .await?; - Ok(user_role) - } -} diff --git a/examples/demo/src/tasks/foo.rs b/examples/demo/src/tasks/foo.rs deleted file mode 100644 index 43193b49d..000000000 --- a/examples/demo/src/tasks/foo.rs +++ /dev/null @@ -1,17 +0,0 @@ -// -use loco_rs::prelude::*; - -pub struct Foo; -#[async_trait] -impl Task for Foo { - fn task(&self) -> TaskInfo { - TaskInfo { - name: "foo".to_string(), - detail: "run foo task".to_string(), - } - } - async fn run(&self, _app_context: &AppContext, _vars: &task::Vars) -> Result<()> { - Ok(()) - } -} -// diff --git a/examples/demo/src/tasks/mod.rs b/examples/demo/src/tasks/mod.rs deleted file mode 100644 index 6428f4119..000000000 --- a/examples/demo/src/tasks/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod foo; -pub mod seed; -pub mod user_report; diff --git a/examples/demo/src/tasks/seed.rs b/examples/demo/src/tasks/seed.rs deleted file mode 100644 index ec782ef7a..000000000 --- a/examples/demo/src/tasks/seed.rs +++ /dev/null @@ -1,42 +0,0 @@ -//! This task implements data seeding functionality for initializing new -//! development/demo environments. -//! -//! # Example -//! -//! Run the task with the following command: -//! ```sh -//! cargo run task -//! ``` -//! -//! To override existing data and reset the data structure, use the following -//! command with the `refresh:true` argument: ```sh -//! cargo run task seed_data refresh:true -//! ``` -use loco_rs::{db, prelude::*}; -use migration::Migrator; - -use crate::app::App; - -#[allow(clippy::module_name_repetitions)] -pub struct SeedData; -#[async_trait] -impl Task for SeedData { - fn task(&self) -> TaskInfo { - TaskInfo { - name: "seed_data".to_string(), - detail: "Task for seeding data".to_string(), - } - } - async fn run(&self, app_context: &AppContext, vars: &task::Vars) -> Result<()> { - let refresh = vars - .cli_arg("refresh") - .is_ok_and(|refresh| refresh == "true"); - - if refresh { - db::reset::(&app_context.db).await?; - } - let path = std::path::Path::new("src/fixtures"); - db::run_app_seed::(&app_context, path).await?; - Ok(()) - } -} diff --git a/examples/demo/src/tasks/user_report.rs b/examples/demo/src/tasks/user_report.rs deleted file mode 100644 index 4440fe404..000000000 --- a/examples/demo/src/tasks/user_report.rs +++ /dev/null @@ -1,25 +0,0 @@ -use loco_rs::prelude::*; - -use crate::models::_entities::users; - -pub struct UserReport; -#[async_trait] -impl Task for UserReport { - fn task(&self) -> TaskInfo { - TaskInfo { - name: "user_report".to_string(), - detail: "output a user report".to_string(), - } - } - async fn run(&self, app_context: &AppContext, vars: &task::Vars) -> Result<()> { - let users = users::Entity::find().all(&app_context.db).await?; - println!("args: {vars:?}"); - println!("!!! user_report: listing users !!!"); - println!("------------------------"); - for user in &users { - println!("user: {}", user.email); - } - println!("done: {} users", users.len()); - Ok(()) - } -} diff --git a/examples/demo/src/views/auth.rs b/examples/demo/src/views/auth.rs deleted file mode 100644 index efbf956fe..000000000 --- a/examples/demo/src/views/auth.rs +++ /dev/null @@ -1,31 +0,0 @@ -use serde::{Deserialize, Serialize}; - -use crate::models::_entities::users; - -#[derive(Debug, Deserialize, Serialize)] -pub struct UserSession { - pub token: String, - pub user: UserDetail, -} -#[derive(Debug, Deserialize, Serialize)] -pub struct UserDetail { - pub pid: String, - pub email: String, - pub name: String, - pub last_login: String, -} - -impl UserSession { - #[must_use] - pub fn new(user: &users::Model, token: &String) -> Self { - Self { - token: token.to_string(), - user: UserDetail { - pid: user.pid.to_string(), - email: user.email.to_string(), - name: user.name.to_string(), - last_login: "n/a".to_string(), - }, - } - } -} diff --git a/examples/demo/src/views/engine.rs b/examples/demo/src/views/engine.rs deleted file mode 100644 index b043e7f39..000000000 --- a/examples/demo/src/views/engine.rs +++ /dev/null @@ -1,11 +0,0 @@ -use loco_rs::prelude::*; -use serde_json::json; - -/// Home view -/// -/// # Errors -/// -/// This function will return an error if render fails -pub fn home(v: &impl ViewRenderer) -> Result { - format::render().view(v, "home/hello.html", json!({})) -} diff --git a/examples/demo/src/views/mod.rs b/examples/demo/src/views/mod.rs deleted file mode 100644 index ef05a6aa2..000000000 --- a/examples/demo/src/views/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod auth; -pub mod engine; -pub mod notes; -pub mod upload; -pub mod user; diff --git a/examples/demo/src/views/notes.rs b/examples/demo/src/views/notes.rs deleted file mode 100644 index a10ec320e..000000000 --- a/examples/demo/src/views/notes.rs +++ /dev/null @@ -1,49 +0,0 @@ -use loco_rs::{ - controller::views::pagination::{Pager, PagerMeta}, - prelude::model::query::{PageResponse, PaginationQuery}, -}; -use serde::{Deserialize, Serialize}; - -use crate::models::_entities::notes; - -#[derive(Debug, Deserialize, Serialize)] -pub struct ListResponse { - id: i32, - title: Option, - content: Option, -} - -#[derive(Debug, Deserialize, Serialize)] -pub struct PaginationResponse {} - -impl From for ListResponse { - fn from(note: notes::Model) -> Self { - Self { - id: note.id, - title: note.title.clone(), - content: note.content, - } - } -} - -impl PaginationResponse { - #[must_use] - pub fn response( - data: PageResponse, - pagination_query: &PaginationQuery, - ) -> Pager> { - Pager { - results: data - .page - .into_iter() - .map(ListResponse::from) - .collect::>(), - info: PagerMeta { - page: pagination_query.page, - page_size: pagination_query.page_size, - total_pages: data.total_pages, - total_items: data.total_items, - }, - } - } -} diff --git a/examples/demo/src/views/upload.rs b/examples/demo/src/views/upload.rs deleted file mode 100644 index e6b7c0026..000000000 --- a/examples/demo/src/views/upload.rs +++ /dev/null @@ -1,17 +0,0 @@ -use std::path::{Path, PathBuf}; - -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Deserialize, Serialize)] -pub struct Response { - pub path: PathBuf, -} - -impl Response { - #[must_use] - pub fn new(path: &Path) -> Self { - Self { - path: path.to_path_buf(), - } - } -} diff --git a/examples/demo/src/views/user.rs b/examples/demo/src/views/user.rs deleted file mode 100644 index 086daa13f..000000000 --- a/examples/demo/src/views/user.rs +++ /dev/null @@ -1,40 +0,0 @@ -use serde::{Deserialize, Serialize}; - -use crate::models::{_entities::users, roles}; - -#[derive(Debug, Deserialize, Serialize)] -pub struct CurrentResponse { - pub pid: String, - pub name: String, - pub email: String, -} - -impl CurrentResponse { - #[must_use] - pub fn new(user: &users::Model) -> Self { - Self { - pid: user.pid.to_string(), - name: user.name.clone(), - email: user.email.clone(), - } - } -} -#[derive(Debug, Deserialize, Serialize)] -pub struct UserResponse { - pub pid: String, - pub name: String, - pub email: String, - pub role: String, -} - -impl UserResponse { - #[must_use] - pub fn new(user: &users::Model, role: &roles::Model) -> Self { - Self { - pid: user.pid.to_string(), - name: user.name.clone(), - email: user.email.clone(), - role: role.name.clone().to_string(), - } - } -} diff --git a/examples/demo/src/workers/downloader.rs b/examples/demo/src/workers/downloader.rs deleted file mode 100644 index fa094d5b4..000000000 --- a/examples/demo/src/workers/downloader.rs +++ /dev/null @@ -1,40 +0,0 @@ -use std::time::Duration; - -use loco_rs::prelude::*; -use serde::{Deserialize, Serialize}; -use tokio::time::sleep; - -use crate::models::users; - -pub struct DownloadWorker { - pub ctx: AppContext, -} - -#[derive(Deserialize, Debug, Serialize)] -pub struct DownloadWorkerArgs { - pub user_guid: String, -} - -#[async_trait] -impl BackgroundWorker for DownloadWorker { - fn build(ctx: &AppContext) -> Self { - Self { ctx: ctx.clone() } - } - async fn perform(&self, args: DownloadWorkerArgs) -> Result<()> { - // TODO: Some actual work goes here... - println!("================================================"); - println!("Sending payment report to user {}", args.user_guid); - - sleep(Duration::from_millis(2000)).await; - - let all = users::Entity::find() - .all(&self.ctx.db) - .await - .map_err(Box::from)?; - for user in &all { - println!("user: {}", user.id); - } - println!("================================================"); - Ok(()) - } -} diff --git a/examples/demo/src/workers/mod.rs b/examples/demo/src/workers/mod.rs deleted file mode 100644 index acb5733da..000000000 --- a/examples/demo/src/workers/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod downloader; diff --git a/examples/demo/storage-uploads/.gitignore b/examples/demo/storage-uploads/.gitignore deleted file mode 100644 index c96a04f00..000000000 --- a/examples/demo/storage-uploads/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/examples/demo/tests/cli_tests.rs b/examples/demo/tests/cli_tests.rs deleted file mode 100644 index b5269d0ed..000000000 --- a/examples/demo/tests/cli_tests.rs +++ /dev/null @@ -1,5 +0,0 @@ -#[test] -fn cli_tests() { - let t = trycmd::TestCases::new(); - t.case("tests/cmd/*.trycmd"); -} diff --git a/examples/demo/tests/cmd/cli.trycmd b/examples/demo/tests/cmd/cli.trycmd deleted file mode 100644 index 8c283a481..000000000 --- a/examples/demo/tests/cmd/cli.trycmd +++ /dev/null @@ -1,158 +0,0 @@ -```console -$ demo_app-cli -? 2 -The one-person framework for Rust - -Usage: demo_app-cli [OPTIONS] - -Commands: - start Start an app - db Perform DB operations - routes Describe all application endpoints - middleware Describe all application middlewares - task Run a custom task - jobs Managing jobs queue - scheduler Run the scheduler - generate code generation creates a set of files and code templates based on a predefined set of rules - doctor Validate and diagnose configurations - version Display the app version - watch Watch and restart the app - help Print this message or the help of the given subcommand(s) - -Options: - -e, --environment Specify the environment [default: development] - -h, --help Print help - -V, --version Print version - -``` - -```console -$ demo_app-cli db -? 2 -Perform DB operations - -Usage: demo_app-cli db [OPTIONS] - -Commands: - create Create schema - migrate Migrate schema (up) - down Run one down migration, or add a number to run multiple down migrations (i.e. `down 2`) - reset Drop all tables, then reapply all migrations - status Migration status - entities Generate entity .rs files from database schema - truncate Truncate data in tables (without dropping) - seed Seed your database with initial data or dump tables to files - schema Dump database schema - help Print this message or the help of the given subcommand(s) - -Options: - -e, --environment Specify the environment [default: development] - -h, --help Print help - -V, --version Print version - -``` - -```console -$ demo_app-cli generate -? 2 -code generation creates a set of files and code templates based on a predefined set of rules - -Usage: demo_app-cli generate [OPTIONS] - -Commands: - model Generates a new model file for defining the data structure of your application, and test file logic - migration Generates a new migration file - scaffold Generates a CRUD scaffold, model and controller - controller Generate a new controller with the given controller name, and test file - task Generate a Task based on the given name - scheduler Generate a scheduler jobs configuration template - worker Generate worker - mailer Generate mailer - deployment Generate a deployment infrastructure - override Override templates and allows you to take control of them. You can always go back when deleting the local template - help Print this message or the help of the given subcommand(s) - -Options: - -e, --environment Specify the environment [default: development] - -h, --help Print help - -V, --version Print version - -``` - -```console -$ LOCO_ENV=test demo_app-cli task -foo [run foo task] -seed_data [Task for seeding data] -user_report [output a user report] - -``` - -```console -$ demo_app-cli routes --environment test -/_health - └─ GET /_health -/_ping - └─ GET /_ping -/auth - ├─ POST /auth/forgot - ├─ POST /auth/login - ├─ POST /auth/register - ├─ POST /auth/reset - └─ POST /auth/verify -/cache - ├─ GET /cache - ├─ GET /cache/get_or_insert - └─ POST /cache/insert -/mylayer - ├─ GET /mylayer/admin - ├─ GET /mylayer/echo - └─ GET /mylayer/user -/mysession - └─ GET /mysession -/notes - ├─ GET /notes - │ POST /notes - │ - ├─ GET /notes/{id} - │ POST /notes/{id} - └─ DELETE /notes/{id} -/response - ├─ GET /response/album - ├─ GET /response/empty - ├─ GET /response/empty_json - ├─ GET /response/etag - ├─ GET /response/html - ├─ GET /response/json - ├─ GET /response/redirect - ├─ GET /response/render_with_status_code - ├─ GET /response/set_cookie - └─ GET /response/text -/upload - └─ POST /upload/file -/user - ├─ POST /user/convert/admin - ├─ POST /user/convert/user - ├─ GET /user/current - └─ GET /user/current_api_key -/view-engine - ├─ GET /view-engine/hello - ├─ GET /view-engine/home - └─ GET /view-engine/simple - -``` - -```console -$ demo_app-cli doctor -[..][0m DEBUG app: loco_rs::bgworker: job queue ping requested environment=development -✅ SeaORM CLI is installed -✅ DB connection: success -✅ redis queue: queue connection: success -✅ Dependencies -✅ Loco version: latest - -``` - -```console -$ LOCO_ENV=test demo_app-cli db reset - -``` diff --git a/examples/demo/tests/cmd/scheduler.trycmd b/examples/demo/tests/cmd/scheduler.trycmd deleted file mode 100644 index 35911ad47..000000000 --- a/examples/demo/tests/cmd/scheduler.trycmd +++ /dev/null @@ -1,19 +0,0 @@ -```console -$ LOCO_ENV=test blo-cli scheduler --list -# job_name schedule tags run -1 list_if_users * 2 * * * * base, users "user_report" -2 run_task at 10:00 am - "foo" -3 write_content run every 1 second base, infra "echo loco >> ./scheduler.txt" - - -``` - -```console -$ LOCO_ENV=test blo-cli scheduler --config ./config/scheduler.yaml --list -# job_name schedule tags run -1 list_if_users * 2 * * * * base, users "user_report" -2 run_task at 10:00 am - "foo" -3 write_content run every 1 second base, infra "echo loco >> ./scheduler.txt" - - -``` diff --git a/examples/demo/tests/mod.rs b/examples/demo/tests/mod.rs deleted file mode 100644 index b42f2343c..000000000 --- a/examples/demo/tests/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -mod models; -mod requests; -mod tasks; -mod workers; diff --git a/examples/demo/tests/models/mod.rs b/examples/demo/tests/models/mod.rs deleted file mode 100644 index 160ce6008..000000000 --- a/examples/demo/tests/models/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod roles; -mod users; -mod users_roles; diff --git a/examples/demo/tests/models/roles.rs b/examples/demo/tests/models/roles.rs deleted file mode 100644 index 05b033100..000000000 --- a/examples/demo/tests/models/roles.rs +++ /dev/null @@ -1,146 +0,0 @@ -use demo_app::{ - app::App, - models::{roles, sea_orm_active_enums, users, users::RegisterParams}, -}; -use loco_rs::testing::prelude::*; -use serial_test::serial; - -macro_rules! configure_insta { - ($($expr:expr),*) => { - let mut settings = insta::Settings::clone_current(); - settings.set_prepend_module_to_snapshot(false); - settings.set_snapshot_suffix("roles"); - let _guard = settings.bind_to_scope(); - }; -} - -#[tokio::test] -#[serial] -async fn can_add_user_to_admin() { - configure_insta!(); - - let boot = boot_test::().await.unwrap(); - let new_user = users::Model::create_with_password( - &boot.app_context.db, - &RegisterParams { - email: "user1@example.com".to_string(), - password: "1234".to_string(), - name: "framework".to_string(), - }, - ) - .await - .unwrap(); - let role = roles::Model::add_user_to_admin_role(&boot.app_context.db, &new_user) - .await - .unwrap(); - assert_eq!(role.name, sea_orm_active_enums::RolesName::Admin); -} - -#[tokio::test] -#[serial] -async fn can_add_user_to_user() { - configure_insta!(); - - let boot = boot_test::().await.unwrap(); - let new_user = users::Model::create_with_password( - &boot.app_context.db, - &RegisterParams { - email: "user1@example.com".to_string(), - password: "1234".to_string(), - name: "framework".to_string(), - }, - ) - .await - .unwrap(); - let role = roles::Model::add_user_to_user_role(&boot.app_context.db, &new_user) - .await - .unwrap(); - assert_eq!(role.name, sea_orm_active_enums::RolesName::User); -} - -#[tokio::test] -#[serial] -async fn can_convert_between_user_and_admin() { - configure_insta!(); - - let boot = boot_test::().await.unwrap(); - let new_user = users::Model::create_with_password( - &boot.app_context.db, - &RegisterParams { - email: "user1@example.com".to_string(), - password: "1234".to_string(), - name: "framework".to_string(), - }, - ) - .await - .unwrap(); - let role = roles::Model::add_user_to_user_role(&boot.app_context.db, &new_user) - .await - .unwrap(); - assert_eq!(role.name, sea_orm_active_enums::RolesName::User); - let role = roles::Model::add_user_to_admin_role(&boot.app_context.db, &new_user) - .await - .unwrap(); - assert_eq!(role.name, sea_orm_active_enums::RolesName::Admin); - let role = roles::Model::add_user_to_user_role(&boot.app_context.db, &new_user) - .await - .unwrap(); - assert_eq!(role.name, sea_orm_active_enums::RolesName::User); -} - -#[tokio::test] -#[serial] -async fn can_find_user_roles() { - configure_insta!(); - - let boot = boot_test::().await.unwrap(); - let new_user = users::Model::create_with_password( - &boot.app_context.db, - &RegisterParams { - email: "user1@example.com".to_string(), - password: "1234".to_string(), - name: "framework".to_string(), - }, - ) - .await - .unwrap(); - let role = roles::Model::add_user_to_user_role(&boot.app_context.db, &new_user) - .await - .unwrap(); - assert_eq!(role.name, sea_orm_active_enums::RolesName::User); - - let role = roles::Model::find_by_user(&boot.app_context.db, &new_user) - .await - .unwrap(); - assert_eq!(role.name, sea_orm_active_enums::RolesName::User); - - let role = roles::Model::add_user_to_admin_role(&boot.app_context.db, &new_user) - .await - .unwrap(); - assert_eq!(role.name, sea_orm_active_enums::RolesName::Admin); - - let role = roles::Model::find_by_user(&boot.app_context.db, &new_user) - .await - .unwrap(); - assert_eq!(role.name, sea_orm_active_enums::RolesName::Admin); -} - -#[tokio::test] -#[serial] -async fn cannot_find_user_before_conversation() { - configure_insta!(); - - let boot = boot_test::().await.unwrap(); - let new_user = users::Model::create_with_password( - &boot.app_context.db, - &RegisterParams { - email: "user1@example.com".to_string(), - password: "1234".to_string(), - name: "framework".to_string(), - }, - ) - .await - .unwrap(); - let role = roles::Model::find_by_user(&boot.app_context.db, &new_user).await; - assert!(role.is_err()); -} diff --git a/examples/demo/tests/models/snapshots/can_create_with_password@users.snap b/examples/demo/tests/models/snapshots/can_create_with_password@users.snap deleted file mode 100644 index 6e66fd35a..000000000 --- a/examples/demo/tests/models/snapshots/can_create_with_password@users.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: tests/models/users.rs -expression: res ---- -Ok( - Model { - created_at: DATE, - updated_at: DATE, - id: ID - pid: PID, - email: "test@framework.com", - password: "PASSWORD", - api_key: "lo-PID", - name: "framework", - reset_token: None, - reset_sent_at: None, - email_verification_token: None, - email_verification_sent_at: None, - email_verified_at: None, - }, -) diff --git a/examples/demo/tests/models/snapshots/can_find_by_email-2@users.snap b/examples/demo/tests/models/snapshots/can_find_by_email-2@users.snap deleted file mode 100644 index 83dc06e1d..000000000 --- a/examples/demo/tests/models/snapshots/can_find_by_email-2@users.snap +++ /dev/null @@ -1,7 +0,0 @@ ---- -source: tests/models/main.rs -expression: non_existing_user_results ---- -Err( - EntityNotFound, -) diff --git a/examples/demo/tests/models/snapshots/can_find_by_email@users-2.snap b/examples/demo/tests/models/snapshots/can_find_by_email@users-2.snap deleted file mode 100644 index 25c700a5a..000000000 --- a/examples/demo/tests/models/snapshots/can_find_by_email@users-2.snap +++ /dev/null @@ -1,7 +0,0 @@ ---- -source: tests/models/users.rs -expression: non_existing_user_results ---- -Err( - EntityNotFound, -) diff --git a/examples/demo/tests/models/snapshots/can_find_by_email@users.snap b/examples/demo/tests/models/snapshots/can_find_by_email@users.snap deleted file mode 100644 index 1c6295990..000000000 --- a/examples/demo/tests/models/snapshots/can_find_by_email@users.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: tests/models/users.rs -expression: existing_user ---- -Ok( - Model { - created_at: 2023-11-12T12:34:56.789, - updated_at: 2023-11-12T12:34:56.789, - id: 1, - pid: 11111111-1111-1111-1111-111111111111, - email: "user1@example.com", - password: "$argon2id$v=19$m=19456,t=2,p=1$JkBeJfBWoNlj4D684c568g$bKRQ+Ud8qwYGIaAu+x+4flGHPS4WJh3ylUUV4sEtDBY", - api_key: "lo-95ec80d7-cb60-4b70-9b4b-9ef74cb88758", - name: "user1", - reset_token: None, - reset_sent_at: None, - email_verification_token: None, - email_verification_sent_at: None, - email_verified_at: None, - }, -) diff --git a/examples/demo/tests/models/snapshots/can_find_by_pid-2@users.snap b/examples/demo/tests/models/snapshots/can_find_by_pid-2@users.snap deleted file mode 100644 index 83dc06e1d..000000000 --- a/examples/demo/tests/models/snapshots/can_find_by_pid-2@users.snap +++ /dev/null @@ -1,7 +0,0 @@ ---- -source: tests/models/main.rs -expression: non_existing_user_results ---- -Err( - EntityNotFound, -) diff --git a/examples/demo/tests/models/snapshots/can_find_by_pid@users-2.snap b/examples/demo/tests/models/snapshots/can_find_by_pid@users-2.snap deleted file mode 100644 index 25c700a5a..000000000 --- a/examples/demo/tests/models/snapshots/can_find_by_pid@users-2.snap +++ /dev/null @@ -1,7 +0,0 @@ ---- -source: tests/models/users.rs -expression: non_existing_user_results ---- -Err( - EntityNotFound, -) diff --git a/examples/demo/tests/models/snapshots/can_find_by_pid@users.snap b/examples/demo/tests/models/snapshots/can_find_by_pid@users.snap deleted file mode 100644 index 1c6295990..000000000 --- a/examples/demo/tests/models/snapshots/can_find_by_pid@users.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: tests/models/users.rs -expression: existing_user ---- -Ok( - Model { - created_at: 2023-11-12T12:34:56.789, - updated_at: 2023-11-12T12:34:56.789, - id: 1, - pid: 11111111-1111-1111-1111-111111111111, - email: "user1@example.com", - password: "$argon2id$v=19$m=19456,t=2,p=1$JkBeJfBWoNlj4D684c568g$bKRQ+Ud8qwYGIaAu+x+4flGHPS4WJh3ylUUV4sEtDBY", - api_key: "lo-95ec80d7-cb60-4b70-9b4b-9ef74cb88758", - name: "user1", - reset_token: None, - reset_sent_at: None, - email_verification_token: None, - email_verification_sent_at: None, - email_verified_at: None, - }, -) diff --git a/examples/demo/tests/models/snapshots/can_validate_model@users.snap b/examples/demo/tests/models/snapshots/can_validate_model@users.snap deleted file mode 100644 index 708479af8..000000000 --- a/examples/demo/tests/models/snapshots/can_validate_model@users.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: tests/models/users.rs -expression: res ---- -Err( - Custom( - "{\"email\":[{\"code\":\"invalid email\",\"message\":null}],\"name\":[{\"code\":\"length\",\"message\":\"Name must be at least 2 characters long.\"}]}", - ), -) diff --git a/examples/demo/tests/models/snapshots/handle_create_with_password_with_duplicate@users.snap b/examples/demo/tests/models/snapshots/handle_create_with_password_with_duplicate@users.snap deleted file mode 100644 index ff28ea196..000000000 --- a/examples/demo/tests/models/snapshots/handle_create_with_password_with_duplicate@users.snap +++ /dev/null @@ -1,7 +0,0 @@ ---- -source: tests/models/users.rs -expression: new_user ---- -Err( - EntityAlreadyExists, -) diff --git a/examples/demo/tests/models/users.rs b/examples/demo/tests/models/users.rs deleted file mode 100644 index 81d5fef71..000000000 --- a/examples/demo/tests/models/users.rs +++ /dev/null @@ -1,223 +0,0 @@ -use demo_app::{ - app::App, - models::users::{self, Model, RegisterParams}, -}; -use insta::assert_debug_snapshot; -use loco_rs::{model::ModelError, prelude::*}; -use sea_orm::{ActiveModelTrait, ActiveValue, IntoActiveModel}; -use serial_test::serial; - -macro_rules! configure_insta { - ($($expr:expr),*) => { - let mut settings = insta::Settings::clone_current(); - settings.set_prepend_module_to_snapshot(false); - settings.set_snapshot_suffix("users"); - let _guard = settings.bind_to_scope(); - }; -} - -#[tokio::test] -#[serial] -async fn test_can_validate_model() { - configure_insta!(); - - let boot = boot_test::().await.unwrap(); - - let res = users::ActiveModel { - name: ActiveValue::set("1".to_string()), - email: ActiveValue::set("invalid-email".to_string()), - ..Default::default() - } - .insert(&boot.app_context.db) - .await; - - assert_debug_snapshot!(res); -} - -#[tokio::test] -#[serial] -async fn can_create_with_password() { - configure_insta!(); - - let boot = boot_test::().await.unwrap(); - - let params = RegisterParams { - email: "test@framework.com".to_string(), - password: "1234".to_string(), - name: "framework".to_string(), - }; - let res = Model::create_with_password(&boot.app_context.db, ¶ms).await; - - insta::with_settings!({ - filters => cleanup_user_model() - }, { - assert_debug_snapshot!(res); - }); -} - -#[tokio::test] -#[serial] -async fn handle_create_with_password_with_duplicate() { - configure_insta!(); - - let boot = boot_test::().await.unwrap(); - seed::(&boot.app_context).await.unwrap(); - - let new_user: Result = Model::create_with_password( - &boot.app_context.db, - &RegisterParams { - email: "user1@example.com".to_string(), - password: "1234".to_string(), - name: "framework".to_string(), - }, - ) - .await; - assert_debug_snapshot!(new_user); -} - -#[tokio::test] -#[serial] -async fn can_find_by_email() { - configure_insta!(); - - let boot = boot_test::().await.unwrap(); - seed::(&boot.app_context).await.unwrap(); - - let existing_user = Model::find_by_email(&boot.app_context.db, "user1@example.com").await; - let non_existing_user_results = - Model::find_by_email(&boot.app_context.db, "un@existing-email.com").await; - - assert_debug_snapshot!(existing_user); - assert_debug_snapshot!(non_existing_user_results); -} - -#[tokio::test] -#[serial] -async fn can_find_by_pid() { - configure_insta!(); - - let boot = boot_test::().await.unwrap(); - seed::(&boot.app_context).await.unwrap(); - - let existing_user = - Model::find_by_pid(&boot.app_context.db, "11111111-1111-1111-1111-111111111111").await; - let non_existing_user_results = - Model::find_by_email(&boot.app_context.db, "23232323-2323-2323-2323-232323232323").await; - - assert_debug_snapshot!(existing_user); - assert_debug_snapshot!(non_existing_user_results); -} - -#[tokio::test] -#[serial] -async fn can_verification_token() { - configure_insta!(); - - let boot = boot_test::().await.unwrap(); - seed::(&boot.app_context).await.unwrap(); - - let user = Model::find_by_pid(&boot.app_context.db, "11111111-1111-1111-1111-111111111111") - .await - .unwrap(); - - assert!(user.email_verification_sent_at.is_none()); - assert!(user.email_verification_token.is_none()); - - assert!(user - .into_active_model() - .set_email_verification_sent(&boot.app_context.db) - .await - .is_ok()); - - let user = Model::find_by_pid(&boot.app_context.db, "11111111-1111-1111-1111-111111111111") - .await - .unwrap(); - - assert!(user.email_verification_sent_at.is_some()); - assert!(user.email_verification_token.is_some()); -} - -#[tokio::test] -#[serial] -async fn can_set_forgot_password_sent() { - configure_insta!(); - - let boot = boot_test::().await.unwrap(); - seed::(&boot.app_context).await.unwrap(); - - let user = Model::find_by_pid(&boot.app_context.db, "11111111-1111-1111-1111-111111111111") - .await - .unwrap(); - - assert!(user.reset_sent_at.is_none()); - assert!(user.reset_token.is_none()); - - assert!(user - .into_active_model() - .set_forgot_password_sent(&boot.app_context.db) - .await - .is_ok()); - - let user = Model::find_by_pid(&boot.app_context.db, "11111111-1111-1111-1111-111111111111") - .await - .unwrap(); - - assert!(user.reset_sent_at.is_some()); - assert!(user.reset_token.is_some()); -} - -#[tokio::test] -#[serial] -async fn can_verified() { - configure_insta!(); - - let boot = boot_test::().await.unwrap(); - seed::(&boot.app_context).await.unwrap(); - - let user = Model::find_by_pid(&boot.app_context.db, "11111111-1111-1111-1111-111111111111") - .await - .unwrap(); - - assert!(user.email_verified_at.is_none()); - - assert!(user - .into_active_model() - .verified(&boot.app_context.db) - .await - .is_ok()); - - let user = Model::find_by_pid(&boot.app_context.db, "11111111-1111-1111-1111-111111111111") - .await - .unwrap(); - - assert!(user.email_verified_at.is_some()); -} - -#[tokio::test] -#[serial] -async fn can_reset_password() { - configure_insta!(); - - let boot = boot_test::().await.unwrap(); - seed::(&boot.app_context).await.unwrap(); - - let user = Model::find_by_pid(&boot.app_context.db, "11111111-1111-1111-1111-111111111111") - .await - .unwrap(); - - assert!(user.verify_password("12341234")); - - assert!(user - .clone() - .into_active_model() - .reset_password(&boot.app_context.db, "new-password") - .await - .is_ok()); - - assert!( - Model::find_by_pid(&boot.app_context.db, "11111111-1111-1111-1111-111111111111") - .await - .unwrap() - .verify_password("new-password") - ); -} diff --git a/examples/demo/tests/models/users_roles.rs b/examples/demo/tests/models/users_roles.rs deleted file mode 100644 index 619464fdb..000000000 --- a/examples/demo/tests/models/users_roles.rs +++ /dev/null @@ -1,96 +0,0 @@ -use demo_app::{ - app::App, - models::{roles, sea_orm_active_enums, users, users::RegisterParams, users_roles}, -}; -use loco_rs::prelude::*; -use sea_orm::ColumnTrait; -use serial_test::serial; -macro_rules! configure_insta { - ($($expr:expr),*) => { - let mut settings = insta::Settings::clone_current(); - settings.set_prepend_module_to_snapshot(false); - settings.set_snapshot_suffix("users_roles"); - let _guard = settings.bind_to_scope(); - }; -} - -#[tokio::test] -#[serial] -async fn can_connect_user_to_user_role() { - configure_insta!(); - - let boot = boot_test::().await.unwrap(); - let new_user: Result = users::Model::create_with_password( - &boot.app_context.db, - &RegisterParams { - email: "user1@example.com".to_string(), - password: "1234".to_string(), - name: "framework".to_string(), - }, - ) - .await; - let new_user = new_user.unwrap(); - // create role - let role = - roles::Model::upsert_by_name(&boot.app_context.db, sea_orm_active_enums::RolesName::User) - .await - .unwrap(); - // connect user to role - let user_role = - users_roles::Model::connect_user_to_role(&boot.app_context.db, &new_user, &role) - .await - .unwrap(); - assert_eq!(user_role.users_id, new_user.id); - assert_eq!(user_role.roles_id, role.id); - - // Find the user role if it exists by user id - let user_role = users_roles::Entity::find() - .filter(users_roles::Column::UsersId.eq(new_user.id.clone())) - .filter(users_roles::Column::RolesId.eq(role.id.clone())) - .one(&boot.app_context.db) - .await - .unwrap(); - assert!(user_role.is_some()); - let user_role = user_role.unwrap(); - assert_eq!(user_role.users_id, new_user.id); - assert_eq!(user_role.roles_id, role.id); -} - -#[tokio::test] -#[serial] -async fn can_connect_user_to_admin_role() { - configure_insta!(); - - let boot = boot_test::().await.unwrap(); - let new_user: Result = users::Model::create_with_password( - &boot.app_context.db, - &RegisterParams { - email: "user1@example.com".to_string(), - password: "1234".to_string(), - name: "framework".to_string(), - }, - ) - .await; - let new_user = new_user.unwrap(); - // create role - let role = - roles::Model::upsert_by_name(&boot.app_context.db, sea_orm_active_enums::RolesName::Admin) - .await - .unwrap(); - // connect user to role - let user_role = - users_roles::Model::connect_user_to_role(&boot.app_context.db, &new_user, &role) - .await - .unwrap(); - assert_eq!(user_role.users_id, new_user.id); - assert_eq!(user_role.roles_id, role.id); - - // Find the user role if it exists by user id - let user_role = users_roles::Entity::find() - .filter(users_roles::Column::UsersId.eq(new_user.id.clone())) - .filter(users_roles::Column::RolesId.eq(role.id.clone())) - .one(&boot.app_context.db) - .await - .unwrap(); - assert!(user_role.is_some()); -} diff --git a/examples/demo/tests/requests/auth.rs b/examples/demo/tests/requests/auth.rs deleted file mode 100644 index 93bb6bde4..000000000 --- a/examples/demo/tests/requests/auth.rs +++ /dev/null @@ -1,189 +0,0 @@ -use demo_app::{app::App, models::users}; -use insta::{assert_debug_snapshot, with_settings}; -use loco_rs::prelude::*; -use rstest::rstest; -use serial_test::serial; - -use super::prepare_data; - -// TODO: see how to dedup / extract this to app-local test utils -// not to framework, because that would require a runtime dep on insta -macro_rules! configure_insta { - ($($expr:expr),*) => { - let mut settings = insta::Settings::clone_current(); - settings.set_prepend_module_to_snapshot(false); - settings.set_snapshot_suffix("auth_request"); - let _guard = settings.bind_to_scope(); - }; -} - -#[tokio::test] -#[serial] -async fn can_register() { - configure_insta!(); - - request::(|request, ctx| async move { - let email = "test@loco.com"; - let payload = serde_json::json!({ - "name": "loco", - "email": email, - "password": "12341234" - }); - - let _response = request.post("/auth/register").json(&payload).await; - let saved_user = users::Model::find_by_email(&ctx.db, email).await; - - with_settings!({ - filters => cleanup_user_model() - }, { - assert_debug_snapshot!(saved_user); - }); - - with_settings!({ - filters => cleanup_email() - }, { - assert_debug_snapshot!(ctx.mailer.unwrap().deliveries()); - }); - }) - .await; -} - -#[rstest] -#[case("login_with_valid_password", "12341234")] -#[case("login_with_invalid_password", "invalid-password")] -#[tokio::test] -#[serial] -async fn can_login_with_verify(#[case] test_name: &str, #[case] password: &str) { - configure_insta!(); - - request::(|request, ctx| async move { - let email = "test@loco.com"; - let register_payload = serde_json::json!({ - "name": "loco", - "email": email, - "password": "12341234" - }); - - //Creating a new user - _ = request.post("/auth/register").json(®ister_payload).await; - - let user = users::Model::find_by_email(&ctx.db, email).await.unwrap(); - let verify_payload = serde_json::json!({ - "token": user.email_verification_token, - }); - request.post("/auth/verify").json(&verify_payload).await; - - //verify user request - let response = request - .post("/auth/login") - .json(&serde_json::json!({ - "email": email, - "password": password - })) - .await; - - // Make sure email_verified_at is set - assert!(users::Model::find_by_email(&ctx.db, email) - .await - .unwrap() - .email_verified_at - .is_some()); - - with_settings!({ - filters => cleanup_user_model() - }, { - assert_debug_snapshot!(test_name, (response.status_code(), response.text())); - }); - }) - .await; -} - -#[tokio::test] -#[serial] -async fn can_login_without_verify() { - configure_insta!(); - - request::(|request, _ctx| async move { - let email = "test@loco.com"; - let password = "12341234"; - let register_payload = serde_json::json!({ - "name": "loco", - "email": email, - "password": password - }); - - //Creating a new user - _ = request.post("/auth/register").json(®ister_payload).await; - - //verify user request - let response = request - .post("/auth/login") - .json(&serde_json::json!({ - "email": email, - "password": password - })) - .await; - - with_settings!({ - filters => cleanup_user_model() - }, { - assert_debug_snapshot!((response.status_code(), response.text())); - }); - }) - .await; -} - -#[tokio::test] -#[serial] -async fn can_reset_password() { - configure_insta!(); - - request::(|request, ctx| async move { - let login_data = prepare_data::init_user_login(&request, &ctx).await; - - let forgot_payload = serde_json::json!({ - "email": login_data.user.email, - }); - _ = request.post("/auth/forgot").json(&forgot_payload).await; - - let user = users::Model::find_by_email(&ctx.db, &login_data.user.email) - .await - .unwrap(); - assert!(user.reset_token.is_some()); - assert!(user.reset_sent_at.is_some()); - - let new_password = "new-password"; - let reset_payload = serde_json::json!({ - "token": user.reset_token, - "password": new_password, - }); - - let reset_response = request.post("/auth/reset").json(&reset_payload).await; - - let user = users::Model::find_by_email(&ctx.db, &user.email) - .await - .unwrap(); - - assert!(user.reset_token.is_none()); - assert!(user.reset_sent_at.is_none()); - - assert_debug_snapshot!((reset_response.status_code(), reset_response.text())); - - let response = request - .post("/auth/login") - .json(&serde_json::json!({ - "email": user.email, - "password": new_password - })) - .await; - - assert_eq!(response.status_code(), 200); - - with_settings!({ - filters => cleanup_email() - }, { - assert_debug_snapshot!(ctx.mailer.unwrap().deliveries()); - }); - }) - .await; -} diff --git a/examples/demo/tests/requests/cache.rs b/examples/demo/tests/requests/cache.rs deleted file mode 100644 index 5b69f0fd2..000000000 --- a/examples/demo/tests/requests/cache.rs +++ /dev/null @@ -1,52 +0,0 @@ -use demo_app::{app::App, models::users}; -use insta::assert_debug_snapshot; -use loco_rs::testing::prelude::*; -use sea_orm::ModelTrait; -use serial_test::serial; - -// TODO: see how to dedup / extract this to app-local test utils -// not to framework, because that would require a runtime dep on insta -macro_rules! configure_insta { - ($($expr:expr),*) => { - let mut settings = insta::Settings::clone_current(); - settings.set_prepend_module_to_snapshot(false); - settings.set_snapshot_suffix("cache"); - let _guard = settings.bind_to_scope(); - }; -} - -#[tokio::test] -#[serial] -async fn ping() { - configure_insta!(); - - request::(|request, _ctx| async move { - let response = request.get("cache").await; - assert_debug_snapshot!("key_not_exists", (response.text(), response.status_code())); - let response = request.post("/cache/insert").await; - assert_debug_snapshot!("insert", (response.text(), response.status_code())); - let response = request.get("cache").await; - assert_debug_snapshot!("read_cache_key", (response.text(), response.status_code())); - }) - .await; -} - -#[tokio::test] -#[serial] -async fn can_get_or_insert() { - configure_insta!(); - - request::(|request, ctx| async move { - seed::(&ctx).await.unwrap(); - let response = request.get("/cache/get_or_insert").await; - assert_eq!(response.text(), "user1"); - - let user = users::Model::find_by_email(&ctx.db, "user1@example.com") - .await - .unwrap(); - user.delete(&ctx.db).await.unwrap(); - let response = request.get("/cache/get_or_insert").await; - assert_eq!(response.text(), "user1"); - }) - .await; -} diff --git a/examples/demo/tests/requests/mod.rs b/examples/demo/tests/requests/mod.rs deleted file mode 100644 index fbd7fb8b4..000000000 --- a/examples/demo/tests/requests/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -mod auth; -mod cache; -mod mylayer; -mod notes; -mod ping; -mod prepare_data; -mod responses; -mod upload; -mod user; -mod view_engine; diff --git a/examples/demo/tests/requests/mylayer.rs b/examples/demo/tests/requests/mylayer.rs deleted file mode 100644 index 27b8a5e72..000000000 --- a/examples/demo/tests/requests/mylayer.rs +++ /dev/null @@ -1,179 +0,0 @@ -use demo_app::{app::App, views::user::UserResponse}; -use loco_rs::testing::prelude::*; -use serial_test::serial; - -use crate::requests::prepare_data; -macro_rules! configure_insta { - ($($expr:expr),*) => { - let mut settings = insta::Settings::clone_current(); - settings.set_prepend_module_to_snapshot(false); - settings.set_snapshot_suffix("mylayer_request"); - let _guard = settings.bind_to_scope(); - }; -} -#[tokio::test] -#[serial] -async fn cannot_get_echo_when_no_role_assigned() { - configure_insta!(); - request::(|request, ctx| async move { - let user = prepare_data::init_user_login(&request, &ctx).await; - let (auth_key, auth_value) = prepare_data::auth_header(&user.token); - let response = request - .get("/mylayer/echo") - .add_header(auth_key, auth_value) - .await; - assert_eq!(response.status_code(), 401); - }) - .await; -} - -#[tokio::test] -#[serial] -async fn can_get_echo_when_admin_role_assigned() { - configure_insta!(); - request::(|request, ctx| async move { - let user = prepare_data::init_user_login(&request, &ctx).await; - let (auth_key, auth_value) = prepare_data::auth_header(&user.token); - let response = request - .post("/user/convert/admin") - .add_header(auth_key.clone(), auth_value.clone()) - .await; - assert_eq!(response.status_code(), 200); - let body = response.json::(); - assert_eq!(body.role, "Admin"); - - let response = request - .get("/mylayer/echo") - .add_header(auth_key.clone(), auth_value.clone()) - .await; - assert_eq!(response.status_code(), 200); - }) - .await; -} -#[tokio::test] -#[serial] -async fn can_get_echo_when_user_role_assigned() { - configure_insta!(); - request::(|request, ctx| async move { - let user = prepare_data::init_user_login(&request, &ctx).await; - let (auth_key, auth_value) = prepare_data::auth_header(&user.token); - let response = request - .post("/user/convert/user") - .add_header(auth_key.clone(), auth_value.clone()) - .await; - assert_eq!(response.status_code(), 200); - let body = response.json::(); - assert_eq!(body.role, "User"); - - let response = request - .get("/mylayer/echo") - .add_header(auth_key.clone(), auth_value.clone()) - .await; - assert_eq!(response.status_code(), 200); - }) - .await; -} - -#[tokio::test] -#[serial] -async fn cannot_get_admin_when_no_role() { - configure_insta!(); - request::(|request, ctx| async move { - let user = prepare_data::init_user_login(&request, &ctx).await; - let (auth_key, auth_value) = prepare_data::auth_header(&user.token); - let response = request - .get("/mylayer/admin") - .add_header(auth_key, auth_value) - .await; - assert_eq!(response.status_code(), 401); - }) - .await; -} - -#[tokio::test] -#[serial] -async fn cannot_get_admin_when_user_role_assigned() { - configure_insta!(); - request::(|request, ctx| async move { - let user = prepare_data::init_user_login(&request, &ctx).await; - let (auth_key, auth_value) = prepare_data::auth_header(&user.token); - let response = request - .post("/user/convert/user") - .add_header(auth_key.clone(), auth_value.clone()) - .await; - assert_eq!(response.status_code(), 200); - let body = response.json::(); - assert_eq!(body.role, "User"); - - let response = request - .get("/mylayer/admin") - .add_header(auth_key.clone(), auth_value.clone()) - .await; - assert_eq!(response.status_code(), 401); - }) - .await; -} - -#[tokio::test] -#[serial] -async fn can_get_admin_when_admin_role_assigned() { - configure_insta!(); - request::(|request, ctx| async move { - let user = prepare_data::init_user_login(&request, &ctx).await; - let (auth_key, auth_value) = prepare_data::auth_header(&user.token); - let response = request - .post("/user/convert/admin") - .add_header(auth_key.clone(), auth_value.clone()) - .await; - assert_eq!(response.status_code(), 200); - let body = response.json::(); - assert_eq!(body.role, "Admin"); - - let response = request - .get("/mylayer/admin") - .add_header(auth_key.clone(), auth_value.clone()) - .await; - assert_eq!(response.status_code(), 200); - }) - .await; -} - -#[tokio::test] -#[serial] -async fn cannot_get_user_when_no_role() { - configure_insta!(); - request::(|request, ctx| async move { - let user = prepare_data::init_user_login(&request, &ctx).await; - let (auth_key, auth_value) = prepare_data::auth_header(&user.token); - let response = request - .get("/mylayer/user") - .add_header(auth_key, auth_value) - .await; - assert_eq!(response.status_code(), 401); - }) - .await; -} - -#[tokio::test] -#[serial] -async fn can_get_user_when_user_role_assigned() { - configure_insta!(); - request::(|request, ctx| async move { - let user = prepare_data::init_user_login(&request, &ctx).await; - let (auth_key, auth_value) = prepare_data::auth_header(&user.token); - let response = request - .post("/user/convert/user") - .add_header(auth_key.clone(), auth_value.clone()) - .await; - assert_eq!(response.status_code(), 200); - let body = response.json::(); - assert_eq!(body.role, "User"); - - let response = request - .get("/mylayer/user") - .add_header(auth_key.clone(), auth_value.clone()) - .await; - assert_eq!(response.status_code(), 200); - }) - .await; -} diff --git a/examples/demo/tests/requests/notes.rs b/examples/demo/tests/requests/notes.rs deleted file mode 100644 index 99d762674..000000000 --- a/examples/demo/tests/requests/notes.rs +++ /dev/null @@ -1,129 +0,0 @@ -use demo_app::{app::App, models::_entities::notes::Entity}; -use insta::{assert_debug_snapshot, with_settings}; -use loco_rs::testing::prelude::*; -use rstest::rstest; -use sea_orm::entity::prelude::*; -use serial_test::serial; - -// TODO: see how to dedup / extract this to app-local test utils -// not to framework, because that would require a runtime dep on insta -macro_rules! configure_insta { - ($($expr:expr),*) => { - let mut settings = insta::Settings::clone_current(); - settings.set_prepend_module_to_snapshot(false); - settings.set_snapshot_suffix("notes_request"); - let _guard = settings.bind_to_scope(); - }; -} - -#[rstest] -#[case("get_notes", serde_json::json!({}))] -#[case("get_notes_with_page_size", serde_json::json!({"page_size":"1"}))] -#[case("get_notes_with_size_and_page", serde_json::json!({"page":"2", "page_size": "5"}))] -#[case("get_notes_with_filters", serde_json::json!({"page":"1", "page_size": "2", "title": "%note%"}))] -#[tokio::test] -#[serial] -async fn can_get_notes(#[case] test_name: &str, #[case] params: serde_json::Value) { - configure_insta!(); - - request::(|request, ctx| async move { - seed::(&ctx).await.unwrap(); - - let notes = request.get("notes").add_query_params(params).await; - - with_settings!({ - filters => { - let mut combined_filters = get_cleanup_date().clone(); - combined_filters.extend(vec![(r#"\"id\\":\d+"#, r#""id\":ID"#)]); - combined_filters - } - }, { - assert_debug_snapshot!( - test_name, (notes.status_code(), notes.text()) - ); - }); - }) - .await; -} - -#[tokio::test] -#[serial] -async fn can_add_note() { - configure_insta!(); - - request::(|request, _ctx| async move { - let payload = serde_json::json!({ - "title": "loco", - "content": "loco note test", - }); - - let add_note_request = request.post("notes").json(&payload).await; - - with_settings!({ - filters => { - let mut combined_filters = get_cleanup_date().clone(); - combined_filters.extend(vec![(r#"\"id\\":\d+"#, r#""id\":ID"#)]); - combined_filters - } - }, { - assert_debug_snapshot!( - (add_note_request.status_code(), add_note_request.text()) - ); - }); - }) - .await; -} - -#[tokio::test] -#[serial] -async fn can_get_note() { - configure_insta!(); - - request::(|request, ctx| async move { - seed::(&ctx).await.unwrap(); - - let add_note_request = request.get("/notes/1").await; - - with_settings!({ - filters => { - let mut combined_filters = get_cleanup_date().clone(); - combined_filters.extend(vec![(r#"\"id\\":\d+"#, r#""id\":ID"#)]); - combined_filters - } - }, { - assert_debug_snapshot!( - (add_note_request.status_code(), add_note_request.text()) - ); - }); - }) - .await; -} - -#[tokio::test] -#[serial] -async fn can_delete_note() { - configure_insta!(); - - request::(|request, ctx| async move { - seed::(&ctx).await.unwrap(); - - let count_before_delete = Entity::find().all(&ctx.db).await.unwrap().len(); - let delete_note_request = request.delete("/notes/1").await; - - with_settings!({ - filters => { - let mut combined_filters = get_cleanup_date().clone(); - combined_filters.extend(vec![(r#"\"id\\":\d+"#, r#""id\":ID"#)]); - combined_filters - } - }, { - assert_debug_snapshot!( - (delete_note_request.status_code(), delete_note_request.text()) - ); - }); - - let count_after_delete = Entity::find().all(&ctx.db).await.unwrap().len(); - assert_eq!(count_after_delete, count_before_delete - 1); - }) - .await; -} diff --git a/examples/demo/tests/requests/ping.rs b/examples/demo/tests/requests/ping.rs deleted file mode 100644 index 84bfae8f6..000000000 --- a/examples/demo/tests/requests/ping.rs +++ /dev/null @@ -1,31 +0,0 @@ -use demo_app::app::App; -use insta::assert_debug_snapshot; -use loco_rs::testing::prelude::*; -use rstest::rstest; - -// TODO: see how to dedup / extract this to app-local test utils -// not to framework, because that would require a runtime dep on insta -macro_rules! configure_insta { - ($($expr:expr),*) => { - let mut settings = insta::Settings::clone_current(); - settings.set_prepend_module_to_snapshot(false); - settings.set_snapshot_suffix("ping_request"); - let _guard = settings.bind_to_scope(); - }; -} - -// This tests the `_ping` endpoint, as well as the `NormalizePathLayer` that -// removes trailing slashes from the request path. -#[rstest] -#[case("ping", "/_ping")] -#[tokio::test] -async fn ping(#[case] test_name: &str, #[case] path: &str) { - configure_insta!(); - - request::(|request, _ctx| async move { - let response = request.get(path).await; - - assert_debug_snapshot!(test_name, (response.text(), response.status_code())); - }) - .await; -} diff --git a/examples/demo/tests/requests/prepare_data.rs b/examples/demo/tests/requests/prepare_data.rs deleted file mode 100644 index 8732efe6e..000000000 --- a/examples/demo/tests/requests/prepare_data.rs +++ /dev/null @@ -1,54 +0,0 @@ -use axum::http::{HeaderName, HeaderValue}; -use demo_app::{models::users, views::auth::UserSession}; -use loco_rs::{app::AppContext, TestServer}; - -const USER_EMAIL: &str = "test@loco.com"; -const USER_PASSWORD: &str = "1234"; - -pub struct LoggedInUser { - pub user: users::Model, - pub token: String, -} - -pub async fn init_user_login(request: &TestServer, ctx: &AppContext) -> LoggedInUser { - let register_payload = serde_json::json!({ - "name": "loco", - "email": USER_EMAIL, - "password": USER_PASSWORD - }); - - //Creating a new user - let _res = request.post("/auth/register").json(®ister_payload).await; - let user = users::Model::find_by_email(&ctx.db, USER_EMAIL) - .await - .unwrap(); - - let verify_payload = serde_json::json!({ - "token": user.email_verification_token, - }); - - request.post("/auth/verify").json(&verify_payload).await; - - let response = request - .post("/auth/login") - .json(&serde_json::json!({ - "email": USER_EMAIL, - "password": USER_PASSWORD - })) - .await; - - let session: UserSession = serde_json::from_str(&response.text()).unwrap(); - - LoggedInUser { - user: users::Model::find_by_email(&ctx.db, USER_EMAIL) - .await - .unwrap(), - token: session.token, - } -} - -pub fn auth_header(token: &str) -> (HeaderName, HeaderValue) { - let auth_header_value = HeaderValue::from_str(&format!("Bearer {}", &token)).unwrap(); - - (HeaderName::from_static("authorization"), auth_header_value) -} diff --git a/examples/demo/tests/requests/responses.rs b/examples/demo/tests/requests/responses.rs deleted file mode 100644 index 05ae12f61..000000000 --- a/examples/demo/tests/requests/responses.rs +++ /dev/null @@ -1,50 +0,0 @@ -use axum::http::HeaderMap; -use demo_app::app::App; -use insta::assert_debug_snapshot; -use loco_rs::testing::prelude::*; -use rstest::rstest; -use serial_test::serial; -// TODO: see how to dedup / extract this to app-local test utils -// not to framework, because that would require a runtime dep on insta -macro_rules! configure_insta { - ($($expr:expr),*) => { - let mut settings = insta::Settings::clone_current(); - settings.set_prepend_module_to_snapshot(false); - settings.set_snapshot_suffix("auth_request"); - let _guard = settings.bind_to_scope(); - }; -} - -#[rstest] -#[case("/response/empty")] -#[case("/response/text")] -#[case("/response/json")] -#[case("/response/empty_json")] -#[case("/response/html")] -#[case("/response/redirect")] -#[case("/response/render_with_status_code")] -#[case("/response/etag")] -#[case("/response/set_cookie")] -#[tokio::test] -#[serial] -async fn can_return_different_responses(#[case] uri: &str) { - configure_insta!(); - request::(|request, _ctx| async move { - let response = request.get(uri).await; - - let mut headers = HeaderMap::new(); - for (key, value) in response.headers() { - if ["content-type", "x-powered-by", "location", "etag"].contains(&key.as_str()) - || value.to_str().unwrap().contains("loco-cookie-name") - { - headers.insert(key, value.clone()); - } - } - - assert_debug_snapshot!( - uri.replace('/', "_"), - (response.status_code(), response.text(), headers,) - ); - }) - .await; -} diff --git a/examples/demo/tests/requests/snapshots/_response_empty@auth_request.snap b/examples/demo/tests/requests/snapshots/_response_empty@auth_request.snap deleted file mode 100644 index 2b04ccfd9..000000000 --- a/examples/demo/tests/requests/snapshots/_response_empty@auth_request.snap +++ /dev/null @@ -1,11 +0,0 @@ ---- -source: tests/requests/responses.rs -expression: "(response.status_code(), response.text(), headers)" ---- -( - 200, - "", - { - "x-powered-by": "loco.rs", - }, -) diff --git a/examples/demo/tests/requests/snapshots/_response_empty_json@auth_request.snap b/examples/demo/tests/requests/snapshots/_response_empty_json@auth_request.snap deleted file mode 100644 index 6876b7467..000000000 --- a/examples/demo/tests/requests/snapshots/_response_empty_json@auth_request.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: tests/requests/responses.rs -expression: "(response.status_code(), response.text(), headers)" ---- -( - 200, - "{}", - { - "content-type": "application/json", - "x-powered-by": "loco.rs", - }, -) diff --git a/examples/demo/tests/requests/snapshots/_response_etag@auth_request.snap b/examples/demo/tests/requests/snapshots/_response_etag@auth_request.snap deleted file mode 100644 index fa17279a4..000000000 --- a/examples/demo/tests/requests/snapshots/_response_etag@auth_request.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: tests/requests/responses.rs -expression: "(response.status_code(), response.text(), headers)" ---- -( - 200, - "", - { - "etag": "loco-etag", - "x-powered-by": "loco.rs", - }, -) diff --git a/examples/demo/tests/requests/snapshots/_response_html@auth_request.snap b/examples/demo/tests/requests/snapshots/_response_html@auth_request.snap deleted file mode 100644 index 8a6c0d7b5..000000000 --- a/examples/demo/tests/requests/snapshots/_response_html@auth_request.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: tests/requests/responses.rs -expression: "(response.status_code(), response.text(), headers)" ---- -( - 200, - "hello, world", - { - "content-type": "text/html; charset=utf-8", - "x-powered-by": "loco.rs", - }, -) diff --git a/examples/demo/tests/requests/snapshots/_response_json@auth_request.snap b/examples/demo/tests/requests/snapshots/_response_json@auth_request.snap deleted file mode 100644 index 7d47f003e..000000000 --- a/examples/demo/tests/requests/snapshots/_response_json@auth_request.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: tests/requests/responses.rs -expression: "(response.status_code(), response.text(), headers)" ---- -( - 200, - "{\"ok\":true}", - { - "content-type": "application/json", - "x-powered-by": "loco.rs", - }, -) diff --git a/examples/demo/tests/requests/snapshots/_response_redirect@auth_request.snap b/examples/demo/tests/requests/snapshots/_response_redirect@auth_request.snap deleted file mode 100644 index ae782b82d..000000000 --- a/examples/demo/tests/requests/snapshots/_response_redirect@auth_request.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: tests/requests/responses.rs -expression: "(response.status_code(), response.text(), headers)" ---- -( - 303, - "", - { - "location": "/dashboard", - "x-powered-by": "loco.rs", - }, -) diff --git a/examples/demo/tests/requests/snapshots/_response_render_with_status_code@auth_request.snap b/examples/demo/tests/requests/snapshots/_response_render_with_status_code@auth_request.snap deleted file mode 100644 index ac8d04a0f..000000000 --- a/examples/demo/tests/requests/snapshots/_response_render_with_status_code@auth_request.snap +++ /dev/null @@ -1,11 +0,0 @@ ---- -source: tests/requests/responses.rs -expression: "(response.status_code(), response.text(), headers)" ---- -( - 201, - "", - { - "x-powered-by": "loco.rs", - }, -) diff --git a/examples/demo/tests/requests/snapshots/_response_set_cookie@auth_request.snap b/examples/demo/tests/requests/snapshots/_response_set_cookie@auth_request.snap deleted file mode 100644 index a04dd78c3..000000000 --- a/examples/demo/tests/requests/snapshots/_response_set_cookie@auth_request.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: tests/requests/responses.rs -expression: "(response.status_code(), response.text(), headers)" ---- -( - 200, - "null", - { - "set-cookie": "loco-cookie-name=loco-cookie-value; HttpOnly; SameSite=Strict; Secure; Path=/", - "content-type": "application/json", - "x-powered-by": "loco.rs", - }, -) diff --git a/examples/demo/tests/requests/snapshots/_response_text@auth_request.snap b/examples/demo/tests/requests/snapshots/_response_text@auth_request.snap deleted file mode 100644 index d0935ab86..000000000 --- a/examples/demo/tests/requests/snapshots/_response_text@auth_request.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: tests/requests/responses.rs -expression: "(response.status_code(), response.text(), headers)" ---- -( - 200, - "Loco", - { - "content-type": "text/plain; charset=utf-8", - "x-powered-by": "loco.rs", - }, -) diff --git a/examples/demo/tests/requests/snapshots/can_add_note@notes_request.snap b/examples/demo/tests/requests/snapshots/can_add_note@notes_request.snap deleted file mode 100644 index 03fef48b7..000000000 --- a/examples/demo/tests/requests/snapshots/can_add_note@notes_request.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: tests/requests/notes.rs -expression: "(add_note_request.status_code(), add_note_request.text())" ---- -( - 200, - "{\"created_at\":\"DATE\",\"updated_at\":\"DATE\",\"id\":ID,\"title\":\"loco\",\"content\":\"loco note test\"}", -) diff --git a/examples/demo/tests/requests/snapshots/can_convert_user_to_admin_role@auth_request.snap b/examples/demo/tests/requests/snapshots/can_convert_user_to_admin_role@auth_request.snap deleted file mode 100644 index 01cf04062..000000000 --- a/examples/demo/tests/requests/snapshots/can_convert_user_to_admin_role@auth_request.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: tests/requests/user.rs -expression: "(response.status_code(), response.text())" ---- -( - 200, - "{\"pid\":\"PID\",\"name\":\"loco\",\"email\":\"test@loco.com\",\"role\":\"Admin\"}", -) diff --git a/examples/demo/tests/requests/snapshots/can_convert_user_to_user_role@auth_request.snap b/examples/demo/tests/requests/snapshots/can_convert_user_to_user_role@auth_request.snap deleted file mode 100644 index 19ec77244..000000000 --- a/examples/demo/tests/requests/snapshots/can_convert_user_to_user_role@auth_request.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: tests/requests/user.rs -expression: "(response.status_code(), response.text())" ---- -( - 200, - "{\"pid\":\"PID\",\"name\":\"loco\",\"email\":\"test@loco.com\",\"role\":\"User\"}", -) diff --git a/examples/demo/tests/requests/snapshots/can_delete_note@notes_request.snap b/examples/demo/tests/requests/snapshots/can_delete_note@notes_request.snap deleted file mode 100644 index 3481fc36d..000000000 --- a/examples/demo/tests/requests/snapshots/can_delete_note@notes_request.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: tests/requests/notes.rs -expression: "(delete_note_request.status_code(), delete_note_request.text())" ---- -( - 200, - "", -) diff --git a/examples/demo/tests/requests/snapshots/can_get_current_user@auth_request.snap b/examples/demo/tests/requests/snapshots/can_get_current_user@auth_request.snap deleted file mode 100644 index 85d53db17..000000000 --- a/examples/demo/tests/requests/snapshots/can_get_current_user@auth_request.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: tests/requests/user.rs -expression: "(response.status_code(), response.text())" ---- -( - 200, - "{\"pid\":\"PID\",\"name\":\"loco\",\"email\":\"test@loco.com\"}", -) diff --git a/examples/demo/tests/requests/snapshots/can_get_current_user_from_cookie_auth@auth_request.snap b/examples/demo/tests/requests/snapshots/can_get_current_user_from_cookie_auth@auth_request.snap deleted file mode 100644 index 85d53db17..000000000 --- a/examples/demo/tests/requests/snapshots/can_get_current_user_from_cookie_auth@auth_request.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: tests/requests/user.rs -expression: "(response.status_code(), response.text())" ---- -( - 200, - "{\"pid\":\"PID\",\"name\":\"loco\",\"email\":\"test@loco.com\"}", -) diff --git a/examples/demo/tests/requests/snapshots/can_get_current_user_with_api_key@auth_request.snap b/examples/demo/tests/requests/snapshots/can_get_current_user_with_api_key@auth_request.snap deleted file mode 100644 index 85d53db17..000000000 --- a/examples/demo/tests/requests/snapshots/can_get_current_user_with_api_key@auth_request.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: tests/requests/user.rs -expression: "(response.status_code(), response.text())" ---- -( - 200, - "{\"pid\":\"PID\",\"name\":\"loco\",\"email\":\"test@loco.com\"}", -) diff --git a/examples/demo/tests/requests/snapshots/can_get_note@notes_request.snap b/examples/demo/tests/requests/snapshots/can_get_note@notes_request.snap deleted file mode 100644 index a651c579a..000000000 --- a/examples/demo/tests/requests/snapshots/can_get_note@notes_request.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: tests/requests/notes.rs -expression: "(add_note_request.status_code(), add_note_request.text())" ---- -( - 200, - "{\"created_at\":\"DATE\",\"updated_at\":\"DATE\",\"id\":ID,\"title\":null,\"content\":\"content 1\"}", -) diff --git a/examples/demo/tests/requests/snapshots/can_get_note_gzip@notes_request.snap b/examples/demo/tests/requests/snapshots/can_get_note_gzip@notes_request.snap deleted file mode 100644 index 2ea4832dd..000000000 --- a/examples/demo/tests/requests/snapshots/can_get_note_gzip@notes_request.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: tests/requests/notes.rs -expression: "(add_note_request.status_code(), add_note_request.text())" ---- -( - 200, - "{\"created_at\":\"DATE\",\"updated_at\":\"DATE\",\"id\":ID,\"title\":\"Loco note 1\",\"content\":\"content 1\"}", -) diff --git a/examples/demo/tests/requests/snapshots/can_get_notes@notes_request.snap b/examples/demo/tests/requests/snapshots/can_get_notes@notes_request.snap deleted file mode 100644 index 6b25cc056..000000000 --- a/examples/demo/tests/requests/snapshots/can_get_notes@notes_request.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: tests/requests/notes.rs -expression: "(notes.status_code(), notes.text())" ---- -( - 200, - "[{\"created_at\":\"DATE\",\"updated_at\":\"DATE\",\"id\":ID,\"title\":\"Loco note 1\",\"content\":\"Loco note 1 content\"},{\"created_at\":\"DATE\",\"updated_at\":\"DATE\",\"id\":ID,\"title\":\"Loco note 2\",\"content\":\"Loco note 2 content\"}]", -) diff --git a/examples/demo/tests/requests/snapshots/can_login_without_verify@auth_request.snap b/examples/demo/tests/requests/snapshots/can_login_without_verify@auth_request.snap deleted file mode 100644 index 10a558676..000000000 --- a/examples/demo/tests/requests/snapshots/can_login_without_verify@auth_request.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: tests/requests/auth.rs -expression: "(response.status_code(), response.text())" ---- -( - 200, - "{\"token\":\"TOKEN\",\"user\":{\"pid\":\"PID\",\"email\":\"test@loco.com\",\"name\":\"loco\",\"last_login\":\"n/a\"}}", -) diff --git a/examples/demo/tests/requests/snapshots/can_register@auth_request-2.snap b/examples/demo/tests/requests/snapshots/can_register@auth_request-2.snap deleted file mode 100644 index 429e365cd..000000000 --- a/examples/demo/tests/requests/snapshots/can_register@auth_request-2.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: tests/requests/auth.rs -expression: ctx.mailer.unwrap().deliveries() ---- -Deliveries { - count: 1, - messages: [ - "From: System \r\nTo: test@loco.com\r\nSubject: Welcome =?utf-8?b?bG9jbwo=?=\r\nMIME-Version: 1.0\r\nDate: DATE\r\nContent-Type: multipart/alternative;\r\n boundary=\"IDENTIFIER\"\r\n\r\n--IDENTIFIER\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Transfer-Encoding: 7bit\r\n\r\nWelcome loco, you can now log in.\r\n Verify your account with the link below:\r\n\r\nhttp://localhost/verify/RANDOM_ID\r\n\r\n--IDENTIFIER\r\nContent-Type: text/html; charset=utf-8\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\n;\r\n\r\n\r\n Dear loco,\r\n Welcome to Loco! You can now log in to your account.\r\n Before you get started, please verify your account by clicking the link b=\r\nelow:\r\n \r\nTo: test@loco.com\r\nSubject: Welcome =?utf-8?b?bG9jbwo=?=\r\nMIME-Version: 1.0\r\nDate: DATE\r\nContent-Type: multipart/alternative;\r\n boundary=\"IDENTIFIER\"\r\n\r\n--IDENTIFIER\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Transfer-Encoding: 7bit\r\n\r\nWelcome loco, you can now log in.\r\n Verify your account with the link below:\r\n\r\nhttp://localhost/verify/RANDOM_ID\r\n\r\n--IDENTIFIER\r\nContent-Type: text/html; charset=utf-8\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\n;\r\n\r\n\r\n Dear loco,\r\n Welcome to Loco! You can now log in to your account.\r\n Before you get started, please verify your account by clicking the link b=\r\nelow:\r\n \r\nTo: test@loco.com\r\nSubject: Your reset password =?utf-8?b?bGluawo=?=\r\nMIME-Version: 1.0\r\nDate: DATE\r\nContent-Type: multipart/alternative;\r\n boundary=\"IDENTIFIER\"\r\n\r\n--IDENTIFIER\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Transfer-Encoding: 7bit\r\n\r\nReset your password with this link:\r\n\r\nhttp://localhost/reset/RANDOM_ID\r\n\r\n--IDENTIFIER\r\nContent-Type: text/html; charset=utf-8\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\n\r\n\r\n\r\n Hey loco,\r\n Forgot your password? No worries! You can reset it by clicking the link b=\r\nelow:\r\n R=\r\neset Your Password\r\n If you didn't request a password reset, please ignore this email.\r\n Best regards,
The Loco Team
\r\n\r\n\r\n\r\n\r\n--IDENTIFIER--\r\n", - ], -} diff --git a/examples/demo/tests/requests/snapshots/can_reset_password@auth_request.snap b/examples/demo/tests/requests/snapshots/can_reset_password@auth_request.snap deleted file mode 100644 index 83304ccfe..000000000 --- a/examples/demo/tests/requests/snapshots/can_reset_password@auth_request.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: tests/requests/auth.rs -expression: "(reset_response.status_code(), reset_response.text())" ---- -( - 200, - "{}", -) diff --git a/examples/demo/tests/requests/snapshots/get_notes@notes_request.snap b/examples/demo/tests/requests/snapshots/get_notes@notes_request.snap deleted file mode 100644 index 4a103a03e..000000000 --- a/examples/demo/tests/requests/snapshots/get_notes@notes_request.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: tests/requests/notes.rs -assertion_line: 41 -expression: "(notes.status_code(), notes.text())" ---- -( - 200, - "{\"results\":[{\"id\":ID,\"title\":null,\"content\":\"content 1\"},{\"id\":ID,\"title\":\"Loco note 2\",\"content\":null},{\"id\":ID,\"title\":\"Loco note 3\",\"content\":\"content 3\"},{\"id\":ID,\"title\":\"Loco note 4\",\"content\":\"content 4\"},{\"id\":ID,\"title\":\"Loco note 5\",\"content\":\"content 5\"},{\"id\":ID,\"title\":\"Loco 6\",\"content\":\"content 6\"},{\"id\":ID,\"title\":\"Loco 7\",\"content\":\"content 7\"},{\"id\":ID,\"title\":\"Loco 8\",\"content\":\"content 8\"},{\"id\":ID,\"title\":\"Loco 9\",\"content\":\"content 9\"},{\"id\":ID,\"title\":\"Loco 10\",\"content\":\"content 10\"},{\"id\":ID,\"title\":\"Loco 11\",\"content\":\"content 11\"}],\"pagination\":{\"page\":1,\"page_size\":25,\"total_pages\":1,\"total_items\":11}}", -) diff --git a/examples/demo/tests/requests/snapshots/get_notes_with_filters@notes_request.snap b/examples/demo/tests/requests/snapshots/get_notes_with_filters@notes_request.snap deleted file mode 100644 index f9cb22e48..000000000 --- a/examples/demo/tests/requests/snapshots/get_notes_with_filters@notes_request.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: tests/requests/notes.rs -assertion_line: 41 -expression: "(notes.status_code(), notes.text())" ---- -( - 200, - "{\"results\":[{\"id\":ID,\"title\":\"Loco note 2\",\"content\":null},{\"id\":ID,\"title\":\"Loco note 3\",\"content\":\"content 3\"}],\"pagination\":{\"page\":1,\"page_size\":2,\"total_pages\":2,\"total_items\":4}}", -) diff --git a/examples/demo/tests/requests/snapshots/get_notes_with_page_size@notes_request.snap b/examples/demo/tests/requests/snapshots/get_notes_with_page_size@notes_request.snap deleted file mode 100644 index 42447a072..000000000 --- a/examples/demo/tests/requests/snapshots/get_notes_with_page_size@notes_request.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: tests/requests/notes.rs -assertion_line: 41 -expression: "(notes.status_code(), notes.text())" ---- -( - 200, - "{\"results\":[{\"id\":ID,\"title\":null,\"content\":\"content 1\"}],\"pagination\":{\"page\":1,\"page_size\":1,\"total_pages\":11,\"total_items\":11}}", -) diff --git a/examples/demo/tests/requests/snapshots/get_notes_with_size_and_page@notes_request.snap b/examples/demo/tests/requests/snapshots/get_notes_with_size_and_page@notes_request.snap deleted file mode 100644 index 94b3c8993..000000000 --- a/examples/demo/tests/requests/snapshots/get_notes_with_size_and_page@notes_request.snap +++ /dev/null @@ -1,9 +0,0 @@ ---- -source: tests/requests/notes.rs -assertion_line: 41 -expression: "(notes.status_code(), notes.text())" ---- -( - 200, - "{\"results\":[{\"id\":ID,\"title\":\"Loco 6\",\"content\":\"content 6\"},{\"id\":ID,\"title\":\"Loco 7\",\"content\":\"content 7\"},{\"id\":ID,\"title\":\"Loco 8\",\"content\":\"content 8\"},{\"id\":ID,\"title\":\"Loco 9\",\"content\":\"content 9\"},{\"id\":ID,\"title\":\"Loco 10\",\"content\":\"content 10\"}],\"pagination\":{\"page\":2,\"page_size\":5,\"total_pages\":3,\"total_items\":11}}", -) diff --git a/examples/demo/tests/requests/snapshots/hello@view_engine.snap b/examples/demo/tests/requests/snapshots/hello@view_engine.snap deleted file mode 100644 index 5375baad7..000000000 --- a/examples/demo/tests/requests/snapshots/hello@view_engine.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: tests/requests/view_engine.rs -expression: "(response.status_code(), response.text())" ---- -( - 200, - "hello", -) diff --git a/examples/demo/tests/requests/snapshots/home@view_engine.snap b/examples/demo/tests/requests/snapshots/home@view_engine.snap deleted file mode 100644 index 144d89820..000000000 --- a/examples/demo/tests/requests/snapshots/home@view_engine.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: tests/requests/view_engine.rs -expression: "(response.status_code(), response.text())" ---- -( - 200, - "\n \n
\n find this tera template at assets/views/home/hello.html: \n
\n
\n Hello World!, \n
\n Hallo Welt!\n \n\n ", -) diff --git a/examples/demo/tests/requests/snapshots/insert@cache.snap b/examples/demo/tests/requests/snapshots/insert@cache.snap deleted file mode 100644 index e4108c4da..000000000 --- a/examples/demo/tests/requests/snapshots/insert@cache.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: tests/requests/cache.rs -expression: "(response.text(), response.status_code())" ---- -( - "", - 200, -) diff --git a/examples/demo/tests/requests/snapshots/key_not_exists@cache.snap b/examples/demo/tests/requests/snapshots/key_not_exists@cache.snap deleted file mode 100644 index 8fd34bc61..000000000 --- a/examples/demo/tests/requests/snapshots/key_not_exists@cache.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: tests/requests/cache.rs -expression: "(response.text(), response.status_code())" ---- -( - "{\"value\":null}", - 200, -) diff --git a/examples/demo/tests/requests/snapshots/login_with_invalid_password@auth_request.snap b/examples/demo/tests/requests/snapshots/login_with_invalid_password@auth_request.snap deleted file mode 100644 index eb6e89f44..000000000 --- a/examples/demo/tests/requests/snapshots/login_with_invalid_password@auth_request.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: tests/requests/auth.rs -expression: "(response.status_code(), response.text())" ---- -( - 401, - "{\"error\":\"unauthorized\",\"description\":\"You do not have permission to access this resource\"}", -) diff --git a/examples/demo/tests/requests/snapshots/login_with_valid_password@auth_request.snap b/examples/demo/tests/requests/snapshots/login_with_valid_password@auth_request.snap deleted file mode 100644 index 10a558676..000000000 --- a/examples/demo/tests/requests/snapshots/login_with_valid_password@auth_request.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: tests/requests/auth.rs -expression: "(response.status_code(), response.text())" ---- -( - 200, - "{\"token\":\"TOKEN\",\"user\":{\"pid\":\"PID\",\"email\":\"test@loco.com\",\"name\":\"loco\",\"last_login\":\"n/a\"}}", -) diff --git a/examples/demo/tests/requests/snapshots/ping@ping_request.snap b/examples/demo/tests/requests/snapshots/ping@ping_request.snap deleted file mode 100644 index d47e899fe..000000000 --- a/examples/demo/tests/requests/snapshots/ping@ping_request.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: tests/requests/ping.rs -expression: "(response.text(), response.status_code())" ---- -( - "{\"ok\":true}", - 200, -) diff --git a/examples/demo/tests/requests/snapshots/ping_with_multiple_trailing_slashes@ping_request.snap b/examples/demo/tests/requests/snapshots/ping_with_multiple_trailing_slashes@ping_request.snap deleted file mode 100644 index d47e899fe..000000000 --- a/examples/demo/tests/requests/snapshots/ping_with_multiple_trailing_slashes@ping_request.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: tests/requests/ping.rs -expression: "(response.text(), response.status_code())" ---- -( - "{\"ok\":true}", - 200, -) diff --git a/examples/demo/tests/requests/snapshots/ping_with_trailing_slash@ping_request.snap b/examples/demo/tests/requests/snapshots/ping_with_trailing_slash@ping_request.snap deleted file mode 100644 index d47e899fe..000000000 --- a/examples/demo/tests/requests/snapshots/ping_with_trailing_slash@ping_request.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: tests/requests/ping.rs -expression: "(response.text(), response.status_code())" ---- -( - "{\"ok\":true}", - 200, -) diff --git a/examples/demo/tests/requests/snapshots/read_cache_key@cache.snap b/examples/demo/tests/requests/snapshots/read_cache_key@cache.snap deleted file mode 100644 index a06ae0dc3..000000000 --- a/examples/demo/tests/requests/snapshots/read_cache_key@cache.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: tests/requests/cache.rs -expression: "(response.text(), response.status_code())" ---- -( - "{\"value\":\"loco cache value\"}", - 200, -) diff --git a/examples/demo/tests/requests/snapshots/simple@view_engine.snap b/examples/demo/tests/requests/snapshots/simple@view_engine.snap deleted file mode 100644 index 953f50e8e..000000000 --- a/examples/demo/tests/requests/snapshots/simple@view_engine.snap +++ /dev/null @@ -1,8 +0,0 @@ ---- -source: tests/requests/view_engine.rs -expression: "(response.status_code(), response.text())" ---- -( - 200, - "Loco website", -) diff --git a/examples/demo/tests/requests/upload.rs b/examples/demo/tests/requests/upload.rs deleted file mode 100644 index a5c1fa2e8..000000000 --- a/examples/demo/tests/requests/upload.rs +++ /dev/null @@ -1,26 +0,0 @@ -use axum_test::multipart::{MultipartForm, Part}; -use demo_app::{app::App, views}; -use loco_rs::testing::prelude::*; -use serial_test::serial; - -#[tokio::test] -#[serial] -async fn can_upload_file() { - request::(|request, ctx| async move { - let file_content = "loco file upload"; - let file_part = Part::bytes(file_content.as_bytes()).file_name("loco.txt"); - - let multipart_form = MultipartForm::new().add_part("file", file_part); - - let response = request.post("/upload/file").multipart(multipart_form).await; - - response.assert_status_ok(); - - let res: views::upload::Response = serde_json::from_str(&response.text()).unwrap(); - - let stored_file: String = ctx.storage.download(&res.path).await.unwrap(); - - assert_eq!(stored_file, file_content); - }) - .await; -} diff --git a/examples/demo/tests/requests/user.rs b/examples/demo/tests/requests/user.rs deleted file mode 100644 index 4ca15477c..000000000 --- a/examples/demo/tests/requests/user.rs +++ /dev/null @@ -1,109 +0,0 @@ -use demo_app::app::App; -use insta::{assert_debug_snapshot, with_settings}; -use loco_rs::testing::prelude::*; -use serial_test::serial; - -use super::prepare_data; - -// TODO: see how to dedup / extract this to app-local test utils -// not to framework, because that would require a runtime dep on insta -macro_rules! configure_insta { - ($($expr:expr),*) => { - let mut settings = insta::Settings::clone_current(); - settings.set_prepend_module_to_snapshot(false); - settings.set_snapshot_suffix("auth_request"); - let _guard = settings.bind_to_scope(); - }; -} - -#[tokio::test] -#[serial] -async fn can_get_current_user() { - configure_insta!(); - - request::(|request, ctx| async move { - let user = prepare_data::init_user_login(&request, &ctx).await; - - let (auth_key, auth_value) = prepare_data::auth_header(&user.token); - let response = request - .get("/user/current") - .add_header(auth_key, auth_value) - .await; - - with_settings!({ - filters => cleanup_user_model() - }, { - assert_debug_snapshot!((response.status_code(), response.text())); - }); - }) - .await; -} - -#[tokio::test] -#[serial] -async fn can_get_current_user_with_api_key() { - configure_insta!(); - - request::(|request, ctx| async move { - let user_data = prepare_data::init_user_login(&request, &ctx).await; - - let (auth_key, auth_value) = prepare_data::auth_header(&user_data.user.api_key); - let response = request - .get("/user/current_api_key") - .add_header(auth_key, auth_value) - .await; - - with_settings!({ - filters => cleanup_user_model() - }, { - assert_debug_snapshot!((response.status_code(), response.text())); - }); - }) - .await; -} - -#[tokio::test] -#[serial] -async fn can_convert_user_to_user_role() { - configure_insta!(); - - request::(|request, ctx| async move { - let user = prepare_data::init_user_login(&request, &ctx).await; - - let (auth_key, auth_value) = prepare_data::auth_header(&user.token); - let response = request - .post("/user/convert/user") - .add_header(auth_key, auth_value) - .await; - - with_settings!({ - filters => cleanup_user_model() - }, { - assert_debug_snapshot!((response.status_code(), response.text())); - }); - }) - .await; -} - -#[tokio::test] -#[serial] -async fn can_convert_user_to_admin_role() { - configure_insta!(); - - request::(|request, ctx| async move { - let user = prepare_data::init_user_login(&request, &ctx).await; - - let (auth_key, auth_value) = prepare_data::auth_header(&user.token); - let response = request - .post("/user/convert/admin") - .add_header(auth_key, auth_value) - .await; - - with_settings!({ - filters => cleanup_user_model() - }, { - assert_debug_snapshot!((response.status_code(), response.text())); - }); - }) - .await; -} diff --git a/examples/demo/tests/requests/view_engine.rs b/examples/demo/tests/requests/view_engine.rs deleted file mode 100644 index b8980e0e0..000000000 --- a/examples/demo/tests/requests/view_engine.rs +++ /dev/null @@ -1,34 +0,0 @@ -use demo_app::app::App; -use insta::assert_debug_snapshot; -use loco_rs::testing::prelude::*; -use rstest::rstest; -use serial_test::serial; -// TODO: see how to dedup / extract this to app-local test utils -// not to framework, because that would require a runtime dep on insta -macro_rules! configure_insta { - ($($expr:expr),*) => { - let mut settings = insta::Settings::clone_current(); - settings.set_prepend_module_to_snapshot(false); - settings.set_snapshot_suffix("view_engine"); - let _guard = settings.bind_to_scope(); - }; -} - -#[rstest] -#[case("home")] -#[case("hello")] -#[case("simple")] -#[tokio::test] -#[serial] -async fn can_get_view_engine(#[case] uri: &str) { - configure_insta!(); - request::(|request, _ctx| async move { - let response = request.get(&format!("/view-engine/{uri}")).await; - - assert_debug_snapshot!( - uri.replace('/', "_"), - (response.status_code(), response.text()) - ); - }) - .await; -} diff --git a/examples/demo/tests/tasks/foo.rs b/examples/demo/tests/tasks/foo.rs deleted file mode 100644 index 4d19e4397..000000000 --- a/examples/demo/tests/tasks/foo.rs +++ /dev/null @@ -1,17 +0,0 @@ -use demo_app::app::App; -use loco_rs::{boot::run_task, task, testing::prelude::*}; -use serial_test::serial; - -#[tokio::test] -#[serial] -async fn test_can_run_foo_task() { - let boot = boot_test::().await.unwrap(); - - assert!(run_task::( - &boot.app_context, - Some(&"foo".to_string()), - &task::Vars::default() - ) - .await - .is_ok()); -} diff --git a/examples/demo/tests/tasks/mod.rs b/examples/demo/tests/tasks/mod.rs deleted file mode 100644 index 716e26d52..000000000 --- a/examples/demo/tests/tasks/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod foo; -mod seed; diff --git a/examples/demo/tests/tasks/seed.rs b/examples/demo/tests/tasks/seed.rs deleted file mode 100644 index f1666d08a..000000000 --- a/examples/demo/tests/tasks/seed.rs +++ /dev/null @@ -1,17 +0,0 @@ -use demo_app::app::App; -use loco_rs::{boot::run_task, task, testing::prelude::*}; -use serial_test::serial; - -#[tokio::test] -#[serial] -async fn test_can_seed_data() { - let boot = boot_test::().await.unwrap(); - - assert!(run_task::( - &boot.app_context, - Some(&"seed_data".to_string()), - &task::Vars::default() - ) - .await - .is_ok()); -} diff --git a/examples/demo/tests/workers/mod.rs b/examples/demo/tests/workers/mod.rs deleted file mode 100644 index 8b1378917..000000000 --- a/examples/demo/tests/workers/mod.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/examples/llm-candle-inference/.cargo/config.toml b/examples/llm-candle-inference/.cargo/config.toml deleted file mode 100644 index 5ebf03388..000000000 --- a/examples/llm-candle-inference/.cargo/config.toml +++ /dev/null @@ -1,2 +0,0 @@ -[alias] -loco = "run --" diff --git a/examples/llm-candle-inference/.gitignore b/examples/llm-candle-inference/.gitignore deleted file mode 100644 index b7cdb187c..000000000 --- a/examples/llm-candle-inference/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -**/config/local.yaml - -# Generated by Cargo -# will have compiled files and executables -debug/ -target/ - - -# These are backup files generated by rustfmt -**/*.rs.bk - -# MSVC Windows builds of rustc generate these, which store debugging information -*.pdb diff --git a/examples/llm-candle-inference/Cargo.toml b/examples/llm-candle-inference/Cargo.toml deleted file mode 100644 index f7487f8f7..000000000 --- a/examples/llm-candle-inference/Cargo.toml +++ /dev/null @@ -1,47 +0,0 @@ -[workspace] - -[package] -name = "inference" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] - -loco-rs = { path = "../../", version = "*", default-features = false, features = [ - "cli", -] } -serde = "1" -serde_json = "1" -tokio = { version = "1.33.0", default-features = false } -async-trait = "0.1.74" -tracing = "0.1.40" -validator = { version = "0.20.0" } - -axum = "0.8.1" -include_dir = "0.7.3" -uuid = { version = "1.8.0", features = ["v4"] } -tracing-subscriber = { version = "0.3.17", features = ["env-filter", "json"] } - -lazy_static = "1" - -kalosm = { version = "0.3.2", features = ["language", "metal"] } -futures-util = "0.3.30" -axum-streams = { version = "0.14.2", features = ["text"] } -zstd-sys = { version = "=2.0.9" } - -[[bin]] -name = "inference" -path = "src/bin/main.rs" -required-features = [] - -[dev-dependencies] -serial_test = "3.1.1" -rstest = "0.21.0" -loco-rs = { path = "../../", version = "*", default-features = false, features = [ - "cli", - "testing", -] } -trycmd = "0.14.19" -insta = { version = "1.38.0", features = ["redactions", "yaml", "filters"] } diff --git a/examples/llm-candle-inference/README.md b/examples/llm-candle-inference/README.md deleted file mode 100644 index cbe8f1ac2..000000000 --- a/examples/llm-candle-inference/README.md +++ /dev/null @@ -1,94 +0,0 @@ -# `huggingface/candle` LLM Inference example - -This example showcases using `candle`, through a higher level library called [kalosm](https://github.com/floneum/floneum/tree/main/interfaces/kalosm). - -Looking at inference in Rust, `candle` is probably where we all want to be. Note that `kalosm` GREATLY simplifies text generation with candle, so give it a deep look. - -## Points of interest - -### This example implements streaming with Axum - -We're going to do LLM text generation, the example is configured to work with macOS, using `accelerate`, and exhibits around 2-3 tokens/s on my M1 Mac. Start your app in `release` because we want every inch of performance: - -```sh -cargo run --release -- start -``` - -It may download a large model file, and will take some more time to prepare and load it to memory. - -Next, try your first inference request and wait for the tokens to start streaming: - -```sh -$ curl -vvv --no-buffer localhost:5150/candle-llm -``` - -### Adding a global state for your controllers - -This is done by using Axum `Extension` state, in the `after_routes` lifecycle hook: - -```rust - async fn after_routes(router: axum::Router, _ctx: &AppContext) -> Result { - // cache should reside at: ~/.cache/huggingface/hub - println!("loading model"); - let model = Llama::builder() - .with_source(LlamaSource::llama_7b_code()) - .build() - .await - .unwrap(); - println!("model ready"); - - Ok(router.layer(Extension(model))) - } -``` - -You can add any state with `router.layer(Extension(<..>))`, then consume it in your controller: - -```rust -async fn candle_llm(Extension(m): Extension) -> impl IntoResponse { - // use `m` from your state extension - let prompt = "write binary search"; - ... -``` - ---- - -Loco is a web and API framework running on Rust. - -This is the **Stateless starter** which comes with no database or state dependencies. - -## Quick Start - -Start your app: - -``` -$ cargo loco start -Finished dev [unoptimized + debuginfo] target(s) in 21.63s - Running `target/debug/myapp start` - - : - : - : - -controller/app_routes.rs:203: [Middleware] Adding log trace id - - ▄ ▀ - ▀ ▄ - ▄ ▀ ▄ ▄ ▄▀ - ▄ ▀▄▄ - ▄ ▀ ▀ ▀▄▀█▄ - ▀█▄ -▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄ ▀▀█ - ██████ █████ ███ █████ ███ █████ ███ ▀█ - ██████ █████ ███ █████ ▀▀▀ █████ ███ ▄█▄ - ██████ █████ ███ █████ █████ ███ ████▄ - ██████ █████ ███ █████ ▄▄▄ █████ ███ █████ - ██████ █████ ███ ████ ███ █████ ███ ████▀ - ▀▀▀██▄ ▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀ ██▀ - ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ - -started on port 5150 -``` - -## Getting help - -Check out [a quick tour](https://loco.rs/docs/getting-started/tour/) or [the complete guide](https://loco.rs/docs/getting-started/guide/). diff --git a/examples/llm-candle-inference/config/development.yaml b/examples/llm-candle-inference/config/development.yaml deleted file mode 100644 index 7617f26f9..000000000 --- a/examples/llm-candle-inference/config/development.yaml +++ /dev/null @@ -1,42 +0,0 @@ -# Loco configuration file documentation - -# Application logging configuration -logger: - # Enable or disable logging. - enable: false - # Log level, options: trace, debug, info, warn or error. - level: debug - # Define the logging format. options: compact, pretty or json - format: compact - # By default the logger has filtering only logs that came from your code or logs that came from `loco` framework. to see all third party libraries - # Uncomment the line below to override to see all third party libraries you can enable this config and override the logger filters. - # override_filter: trace - -# Web server configuration -server: - # Port on which the server will listen. the server binding is 0.0.0.0:{PORT} - port: 5150 - # The UI hostname or IP address that mailers will point to. - host: http://localhost - # Out of the box middleware configuration. to disable middleware you can changed the `enable` field to `false` of comment the middleware block - middlewares: - # Allows to limit the payload size request. payload that bigger than this file will blocked the request. - limit_payload: - # Enable/Disable the middleware. - enable: true - # the limit size. can be b,kb,kib,mb,mib,gb,gib - body_limit: 5mb - # Generating a unique request ID and enhancing logging with additional information such as the start and completion of request processing, latency, status code, and other request details. - logger: - # Enable/Disable the middleware. - enable: true - # when your code is panicked, the request still returns 500 status code. - catch_panic: - # Enable/Disable the middleware. - enable: true - # Timeout for incoming requests middleware. requests that take more time from the configuration will cute and 408 status code will returned. - timeout_request: - # Enable/Disable the middleware. - enable: true - # Duration time in milliseconds. - timeout: 5000 diff --git a/examples/llm-candle-inference/config/production.yaml b/examples/llm-candle-inference/config/production.yaml deleted file mode 100644 index e69de29bb..000000000 diff --git a/examples/llm-candle-inference/config/test.yaml b/examples/llm-candle-inference/config/test.yaml deleted file mode 100644 index 7617f26f9..000000000 --- a/examples/llm-candle-inference/config/test.yaml +++ /dev/null @@ -1,42 +0,0 @@ -# Loco configuration file documentation - -# Application logging configuration -logger: - # Enable or disable logging. - enable: false - # Log level, options: trace, debug, info, warn or error. - level: debug - # Define the logging format. options: compact, pretty or json - format: compact - # By default the logger has filtering only logs that came from your code or logs that came from `loco` framework. to see all third party libraries - # Uncomment the line below to override to see all third party libraries you can enable this config and override the logger filters. - # override_filter: trace - -# Web server configuration -server: - # Port on which the server will listen. the server binding is 0.0.0.0:{PORT} - port: 5150 - # The UI hostname or IP address that mailers will point to. - host: http://localhost - # Out of the box middleware configuration. to disable middleware you can changed the `enable` field to `false` of comment the middleware block - middlewares: - # Allows to limit the payload size request. payload that bigger than this file will blocked the request. - limit_payload: - # Enable/Disable the middleware. - enable: true - # the limit size. can be b,kb,kib,mb,mib,gb,gib - body_limit: 5mb - # Generating a unique request ID and enhancing logging with additional information such as the start and completion of request processing, latency, status code, and other request details. - logger: - # Enable/Disable the middleware. - enable: true - # when your code is panicked, the request still returns 500 status code. - catch_panic: - # Enable/Disable the middleware. - enable: true - # Timeout for incoming requests middleware. requests that take more time from the configuration will cute and 408 status code will returned. - timeout_request: - # Enable/Disable the middleware. - enable: true - # Duration time in milliseconds. - timeout: 5000 diff --git a/examples/llm-candle-inference/src/app.rs b/examples/llm-candle-inference/src/app.rs deleted file mode 100644 index e1ca418fc..000000000 --- a/examples/llm-candle-inference/src/app.rs +++ /dev/null @@ -1,57 +0,0 @@ -use async_trait::async_trait; -use axum::Extension; -use kalosm::language::{Llama, LlamaSource}; -use loco_rs::{ - app::{AppContext, Hooks}, - boot::{create_app, BootResult, StartMode}, - config::Config, - controller::AppRoutes, - environment::Environment, - prelude::*, - task::Tasks, - Result, -}; - -use crate::controllers; - -pub struct App; -#[async_trait] -impl Hooks for App { - fn app_name() -> &'static str { - env!("CARGO_CRATE_NAME") - } - - async fn boot( - mode: StartMode, - environment: &Environment, - config: Config, - ) -> Result { - create_app::(mode, environment, config).await - } - - async fn before_run(_ctx: &AppContext) -> Result<()> { - // force static load now - Ok(()) - } - - async fn after_routes(router: axum::Router, _ctx: &AppContext) -> Result { - // cache should reside at: ~/.cache/huggingface/hub - println!("loading model"); - let model = Llama::builder() - .with_source(LlamaSource::llama_7b_code()) - .build() - .await - .unwrap(); - println!("model ready"); - Ok(router.layer(Extension(model))) - } - fn routes(_ctx: &AppContext) -> AppRoutes { - AppRoutes::with_default_routes().add_route(controllers::home::routes()) - } - - async fn connect_workers(_ctx: &AppContext, _queue: &Queue) -> Result<()> { - Ok(()) - } - - fn register_tasks(_tasks: &mut Tasks) {} -} diff --git a/examples/llm-candle-inference/src/bin/main.rs b/examples/llm-candle-inference/src/bin/main.rs deleted file mode 100644 index 378e9ceb3..000000000 --- a/examples/llm-candle-inference/src/bin/main.rs +++ /dev/null @@ -1,7 +0,0 @@ -use inference::app::App; -use loco_rs::cli; - -#[tokio::main] -async fn main() -> loco_rs::Result<()> { - cli::main::().await -} diff --git a/examples/llm-candle-inference/src/controllers/home.rs b/examples/llm-candle-inference/src/controllers/home.rs deleted file mode 100644 index f01bb534c..000000000 --- a/examples/llm-candle-inference/src/controllers/home.rs +++ /dev/null @@ -1,27 +0,0 @@ -use axum::{body::Body, response::IntoResponse, routing::get, Extension}; -use futures_util::StreamExt; -use kalosm::language::{Llama, ModelExt}; -use loco_rs::controller::Routes; - -#[allow(clippy::missing_const_for_fn)] -#[allow(clippy::unnecessary_wraps)] -fn infallible(t: String) -> Result { - Ok(t) -} - -async fn candle_llm(Extension(m): Extension) -> impl IntoResponse { - let prompt = "write binary search"; - println!("{prompt}"); - let result = m.stream_text(prompt).await.unwrap(); - println!("stream ready"); - - Body::from_stream(result.map(infallible)) // Adding infallible - // makes - // the stream - // return - // Result -} - -pub fn routes() -> Routes { - Routes::new().add("/candle-llm", get(candle_llm)) -} diff --git a/examples/llm-candle-inference/src/controllers/mod.rs b/examples/llm-candle-inference/src/controllers/mod.rs deleted file mode 100644 index 9b86bcf61..000000000 --- a/examples/llm-candle-inference/src/controllers/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod home; diff --git a/examples/llm-candle-inference/src/lib.rs b/examples/llm-candle-inference/src/lib.rs deleted file mode 100644 index cee1ed48d..000000000 --- a/examples/llm-candle-inference/src/lib.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod app; -pub mod controllers; diff --git a/examples/llm-candle-inference/tests/cli_tests.rs b/examples/llm-candle-inference/tests/cli_tests.rs deleted file mode 100644 index b5269d0ed..000000000 --- a/examples/llm-candle-inference/tests/cli_tests.rs +++ /dev/null @@ -1,5 +0,0 @@ -#[test] -fn cli_tests() { - let t = trycmd::TestCases::new(); - t.case("tests/cmd/*.trycmd"); -} diff --git a/examples/llm-candle-inference/tests/cmd/cli.trycmd b/examples/llm-candle-inference/tests/cmd/cli.trycmd deleted file mode 100644 index 06f7866d1..000000000 --- a/examples/llm-candle-inference/tests/cmd/cli.trycmd +++ /dev/null @@ -1,56 +0,0 @@ -```console -$ inference -? 2 -The one-person framework for Rust - -Usage: inference [OPTIONS] - -Commands: - start Start an app - routes Describe all application endpoints - task Run a custom task - generate code generation creates a set of files and code templates based on a predefined set of rules - version Display the app version - help Print this message or the help of the given subcommand(s) - -Options: - -e, --environment Specify the environment [default: development] - -h, --help Print help - -V, --version Print version - -``` - -```console -$ inference generate -? 2 -code generation creates a set of files and code templates based on a predefined set of rules - -Usage: inference generate [OPTIONS] - -Commands: - controller Generate a new controller with the given controller name, and test file - task Generate a Task based on the given name - worker Generate worker - mailer Generate mailer - deployment Generate a deployment infrastructure - help Print this message or the help of the given subcommand(s) - -Options: - -e, --environment Specify the environment [default: development] - -h, --help Print help - -V, --version Print version - -``` - -```console -$ inference task - -``` - - -```console -$ inference routes -[GET] /_ping -[GET] /candle-llm - -``` \ No newline at end of file diff --git a/examples/llm-candle-inference/tests/cmd/mod.rs b/examples/llm-candle-inference/tests/cmd/mod.rs deleted file mode 100644 index c2e46cdd7..000000000 --- a/examples/llm-candle-inference/tests/cmd/mod.rs +++ /dev/null @@ -1 +0,0 @@ -mod requests; diff --git a/examples/llm-candle-inference/tests/mod.rs b/examples/llm-candle-inference/tests/mod.rs deleted file mode 100644 index c2e46cdd7..000000000 --- a/examples/llm-candle-inference/tests/mod.rs +++ /dev/null @@ -1 +0,0 @@ -mod requests; diff --git a/examples/llm-candle-inference/tests/requests/mod.rs b/examples/llm-candle-inference/tests/requests/mod.rs deleted file mode 100644 index 8b1378917..000000000 --- a/examples/llm-candle-inference/tests/requests/mod.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/environment.rs b/src/environment.rs index 52ea42b0b..563e438d5 100644 --- a/src/environment.rs +++ b/src/environment.rs @@ -130,10 +130,4 @@ mod tests { let e: Environment = "custom".to_string().into(); assert_eq!(e, Environment::Any("custom".to_string())); } - - #[test] - fn test_from_folder() { - let config = Environment::Development.load_from_folder(Path::new("examples/demo/config")); - assert!(config.is_ok()); - } }