From 0c1cc2900aa5e01f003b1e651b7780d4acbdf5f5 Mon Sep 17 00:00:00 2001 From: FireMario211 <17692105+FireMario211@users.noreply.github.com> Date: Sun, 5 Jul 2026 18:21:24 -0400 Subject: [PATCH 01/11] config for now --- .env.example | 9 ++++++++- src/config.rs | 28 ++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/.env.example b/.env.example index 0310196..d3fd487 100644 --- a/.env.example +++ b/.env.example @@ -31,4 +31,11 @@ DISABLE_DOWNLOAD_COUNTS=0 # Path where uploaded files are stored on disk (default: ./storage) # The reverse proxy must serve {STORAGE_PATH}/submission_attachments/ at /storage/submission-attachments/ -STORAGE_PATH=./storage \ No newline at end of file +STORAGE_PATH=./storage + +# Used for S3-compatible APIs (R2). Automatically disabled if S3_ENDPOINT_URL is not set. +S3_ENDPOINT_URL= +S3_BUCKET_NAME= +S3_REGION= +AWS_ACCESS_KEY_ID= +AWS_SECRET_ACCESS_KEY= diff --git a/src/config.rs b/src/config.rs index 18a451d..7617618 100644 --- a/src/config.rs +++ b/src/config.rs @@ -17,6 +17,7 @@ pub struct AppData { app_url: String, front_url: String, github: GitHubClientData, + s3: Option, webhook_url: String, index_admin_webhook_url: String, static_storage: PublicDisk, @@ -36,6 +37,12 @@ pub struct GitHubClientData { client_secret: String, } +#[derive(Clone)] +pub struct S3ClientData { + client: aws_sdk_s3::Client, + bucket_name: String, +} + pub async fn build_config() -> anyhow::Result { let env_url = dotenvy::var("DATABASE_URL")?; @@ -68,6 +75,11 @@ pub async fn build_config() -> anyhow::Result { .time_to_live(Duration::from_mins(10)) .build(); + // https://developers.cloudflare.com/r2/reference/data-location + let s3_endpoint = dotenvy::var("S3_ENDPOINT_URL").unwrap_or("".to_string()); + let s3_region = dotenvy::var("S3_REGION").unwrap_or("auto".to_string()); + let s3_bucket = dotenvy::var("S3_BUCKET_NAME").unwrap_or("".to_string()); + Ok(AppData { db: pool, app_url: app_url.clone(), @@ -76,6 +88,18 @@ pub async fn build_config() -> anyhow::Result { client_id: github_client, client_secret: github_secret, }, + s3: if s3_endpoint.is_empty() { None } else { + let config = aws_config::defaults(aws_config::BehaviorVersion::latest()) + .region(aws_config::Region::new(s3_region)) + //.credentials_provider(credentials) + .endpoint_url(&s3_endpoint) + .load() + .await; + Some(S3ClientData { + client: aws_sdk_s3::Client::new(&config), + bucket_name: s3_bucket + }) + }, webhook_url, index_admin_webhook_url, static_storage: PublicDisk::new( @@ -122,6 +146,10 @@ impl AppData { &self.github } + pub fn s3(&self) -> &Option { + &self.s3 + } + pub fn webhook_url(&self) -> &str { &self.webhook_url } From 151930315094d051ba60ee27e70ce890751bc652 Mon Sep 17 00:00:00 2001 From: dankmeme01 <42031238+dankmeme01@users.noreply.github.com> Date: Sat, 18 Jul 2026 14:02:11 +0200 Subject: [PATCH 02/11] implement the s3 backend fully --- .env.example | 17 +- Cargo.lock | 594 +++++++++++++++++- Cargo.toml | 2 + ...8120021_add_managed_download_link.down.sql | 1 + ...718120021_add_managed_download_link.up.sql | 1 + src/config.rs | 38 +- src/storage/local.rs | 63 ++ src/{storage.rs => storage/mod.rs} | 72 +-- src/storage/s3.rs | 139 ++++ 9 files changed, 821 insertions(+), 106 deletions(-) create mode 100644 migrations/20260718120021_add_managed_download_link.down.sql create mode 100644 migrations/20260718120021_add_managed_download_link.up.sql create mode 100644 src/storage/local.rs rename src/{storage.rs => storage/mod.rs} (68%) create mode 100644 src/storage/s3.rs diff --git a/.env.example b/.env.example index d3fd487..4b2539a 100644 --- a/.env.example +++ b/.env.example @@ -33,9 +33,14 @@ DISABLE_DOWNLOAD_COUNTS=0 # The reverse proxy must serve {STORAGE_PATH}/submission_attachments/ at /storage/submission-attachments/ STORAGE_PATH=./storage -# Used for S3-compatible APIs (R2). Automatically disabled if S3_ENDPOINT_URL is not set. -S3_ENDPOINT_URL= -S3_BUCKET_NAME= -S3_REGION= -AWS_ACCESS_KEY_ID= -AWS_SECRET_ACCESS_KEY= +# Used for S3-compatible APIs (R2). Automatically disabled if STORAGE_PROVIDER is not set. +# Currently only supports AWS S3 ('aws') and Cloudflare R2 ('cloudflare'), but providers with an identical API may work too. +STORAGE_PROVIDER= +STORAGE_BUCKET= +STORAGE_PUBLIC_URL= +STORAGE_ACCESS_KEY= +STORAGE_SECRET_KEY= +# only applies to AWS S3 +STORAGE_REGION= +# only applies to Cloudflare R2 +STORAGE_ACCOUNT_ID= diff --git a/Cargo.lock b/Cargo.lock index 9005f8f..dde3876 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -487,6 +487,23 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "attohttpc" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e2cdb6d5ed835199484bb92bb8b3edd526effe995c61732580439c1a67e2e9" +dependencies = [ + "base64", + "http 1.4.2", + "log", + "native-tls", + "rustls", + "serde", + "serde_json", + "url", + "webpki-roots", +] + [[package]] name = "autocfg" version = "1.5.1" @@ -536,6 +553,23 @@ dependencies = [ "arrayvec", ] +[[package]] +name = "aws-creds" +version = "0.39.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3b85155d265df828f84e53886ed9e427aed979dd8a39f5b8b2162c77e142d7" +dependencies = [ + "attohttpc", + "home", + "log", + "quick-xml", + "rust-ini", + "serde", + "thiserror", + "time", + "url", +] + [[package]] name = "aws-lc-rs" version = "1.17.1" @@ -559,6 +593,15 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "aws-region" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "838b36c8dc927b6db1b6c6b8f5d05865f2213550b9e83bf92fa99ed6525472c0" +dependencies = [ + "thiserror", +] + [[package]] name = "base64" version = "0.22.1" @@ -689,6 +732,15 @@ dependencies = [ "libbz2-rs-sys", ] +[[package]] +name = "castaway" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" +dependencies = [ + "rustversion", +] + [[package]] name = "cc" version = "1.2.66" @@ -735,7 +787,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -825,6 +877,19 @@ dependencies = [ "memchr", ] +[[package]] +name = "compact_str" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f" +dependencies = [ + "castaway", + "cfg-if", + "itoa", + "ryu", + "static_assertions", +] + [[package]] name = "compression-codecs" version = "0.4.38" @@ -857,6 +922,26 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom 0.2.17", + "once_cell", + "tiny-keccak", +] + [[package]] name = "constant_time_eq" version = "0.4.2" @@ -1080,6 +1165,9 @@ name = "deranged" version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "serde_core", +] [[package]] name = "derive_arbitrary" @@ -1123,6 +1211,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", "crypto-common 0.1.7", + "subtle", ] [[package]] @@ -1149,6 +1238,15 @@ dependencies = [ "syn", ] +[[package]] +name = "dlv-list" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f" +dependencies = [ + "const-random", +] + [[package]] name = "dotenvy" version = "0.15.7" @@ -1339,6 +1437,21 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.2.2" @@ -1483,7 +1596,8 @@ dependencies = [ "mimalloc", "moka", "regex", - "reqwest", + "reqwest 0.13.4", + "rust-s3", "semver", "serde", "serde_json", @@ -1581,6 +1695,12 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + [[package]] name = "hashbrown" version = "0.16.1" @@ -1625,7 +1745,16 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4aaa26c720c68b866f2c96ef5c1264b3e6f473fe5d4ce61cd44bbe913e553018" dependencies = [ - "hmac", + "hmac 0.13.0", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", ] [[package]] @@ -1637,6 +1766,15 @@ dependencies = [ "digest 0.11.3", ] +[[package]] +name = "home" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "html5ever" version = "0.39.0" @@ -1751,6 +1889,23 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", + "webpki-roots", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", ] [[package]] @@ -1788,7 +1943,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core", + "windows-core 0.62.2", ] [[package]] @@ -2034,7 +2189,7 @@ dependencies = [ "simd_cesu8", "thiserror", "walkdir", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -2249,6 +2404,17 @@ dependencies = [ "regex-automata", ] +[[package]] +name = "maybe-async" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "746873a384ad60adc5db74471dfaba74bd278afbdcfd81db93fafcdfc8b5ca0c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "maybe-rayon" version = "0.1.1" @@ -2269,6 +2435,12 @@ dependencies = [ "digest 0.11.3", ] +[[package]] +name = "md5" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebb8d8732c6a6df3d8f032a82911cfc747e00efb95cc46e8d0acd5b5b88570c" + [[package]] name = "memchr" version = "2.8.3" @@ -2300,6 +2472,15 @@ dependencies = [ "unicase", ] +[[package]] +name = "minidom" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e394a0e3c7ccc2daea3dffabe82f09857b6b510cb25af87d54bf3e910ac1642d" +dependencies = [ + "rxml", +] + [[package]] name = "miniz_oxide" version = "0.8.9" @@ -2358,6 +2539,23 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e94e1e6445d314f972ff7395df2de295fe51b71821694f0b0e1e79c4f12c8577" +[[package]] +name = "native-tls" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "new_debug_unreachable" version = "1.0.6" @@ -2388,6 +2586,15 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" +[[package]] +name = "ntapi" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3b335231dfd352ffb0f8017f3b6027a4917f7df785ea2143d8af2adc66980ae" +dependencies = [ + "winapi", +] + [[package]] name = "nu-ansi-term" version = "0.50.3" @@ -2463,6 +2670,25 @@ dependencies = [ "autocfg", ] +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags", +] + +[[package]] +name = "objc2-io-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15" +dependencies = [ + "libc", + "objc2-core-foundation", +] + [[package]] name = "once_cell" version = "1.21.4" @@ -2475,12 +2701,59 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +[[package]] +name = "openssl" +version = "0.10.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77823a27f0babb03091cb9ed9ef80af3b39dbc82f97e8fa530374b7dafd87a45" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "openssl-probe" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" +[[package]] +name = "openssl-sys" +version = "0.9.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b47e7e6bb2c38cd930d25a23b40fa52e068c10e85f3e03a7f5ba5aaca5713695" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "ordered-multimap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79" +dependencies = [ + "dlv-list", + "hashbrown 0.14.5", +] + [[package]] name = "parking" version = "2.2.1" @@ -2507,7 +2780,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -2529,7 +2802,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112d82ceb8c5bf524d9af484d4e4970c9fd5a0cc15ba14ad93dccd28873b0629" dependencies = [ "digest 0.11.3", - "hmac", + "hmac 0.13.0", ] [[package]] @@ -2758,6 +3031,16 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" +[[package]] +name = "quick-xml" +version = "0.38.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "quinn" version = "0.11.11" @@ -3020,6 +3303,50 @@ version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" +[[package]] +name = "reqwest" +version = "0.12.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64", + "bytes", + "futures-core", + "futures-util", + "http 1.4.2", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-tls", + "hyper-util", + "js-sys", + "log", + "native-tls", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-native-tls", + "tokio-rustls", + "tokio-util", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "webpki-roots", +] + [[package]] name = "reqwest" version = "0.13.4" @@ -3113,6 +3440,50 @@ dependencies = [ "walkdir", ] +[[package]] +name = "rust-ini" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "796e8d2b6696392a43bea58116b667fb4c29727dc5abd27d6acf338bb4f688c7" +dependencies = [ + "cfg-if", + "ordered-multimap", +] + +[[package]] +name = "rust-s3" +version = "0.37.2" +source = "git+https://github.com/w4nderlust/rust-s3?rev=2936eb7#2936eb7e856655a4a49a65377e3cdb59e29fea71" +dependencies = [ + "async-trait", + "aws-creds", + "aws-region", + "base64", + "bytes", + "cfg-if", + "futures-util", + "hex", + "hmac 0.12.1", + "http 1.4.2", + "log", + "maybe-async", + "md5", + "minidom", + "percent-encoding", + "quick-xml", + "reqwest 0.12.28", + "serde", + "serde_derive", + "serde_json", + "sha2 0.10.9", + "sysinfo", + "thiserror", + "time", + "tokio", + "tokio-stream", + "url", +] + [[package]] name = "rustc-hash" version = "2.1.3" @@ -3148,7 +3519,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b92b125634d9b795e7beca796cc790df15a7fb38323bf3196fda83292d06b1f" dependencies = [ "aws-lc-rs", + "log", "once_cell", + "ring", "rustls-pki-types", "rustls-webpki", "subtle", @@ -3222,6 +3595,25 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" +[[package]] +name = "rxml" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc94b580d0f5a6b7a2d604e597513d3c673154b52ddeccd1d5c32360d945ee" +dependencies = [ + "bytes", + "rxml_validation", +] + +[[package]] +name = "rxml_validation" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826e80413b9a35e9d33217b3dcac04cf95f6559d15944b93887a08be5496c4a4" +dependencies = [ + "compact_str", +] + [[package]] name = "ryu" version = "1.0.23" @@ -3633,7 +4025,7 @@ dependencies = [ "futures-util", "hex", "hkdf", - "hmac", + "hmac 0.13.0", "ipnetwork", "itoa", "log", @@ -3684,6 +4076,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[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.9.0" @@ -3762,6 +4160,20 @@ dependencies = [ "syn", ] +[[package]] +name = "sysinfo" +version = "0.37.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16607d5caffd1c07ce073528f9ed972d88db15dd44023fa57142963be3feb11f" +dependencies = [ + "libc", + "memchr", + "ntapi", + "objc2-core-foundation", + "objc2-io-kit", + "windows", +] + [[package]] name = "tagptr" version = "0.2.0" @@ -3864,6 +4276,15 @@ dependencies = [ "time-core", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinystr" version = "0.8.3" @@ -3917,6 +4338,16 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.26.4" @@ -4397,6 +4828,19 @@ dependencies = [ "unicode-ident", ] +[[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.103" @@ -4438,6 +4882,15 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "webpki-roots" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "weezl" version = "0.1.12" @@ -4450,6 +4903,22 @@ version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "998767ef88740d1f5b0682a9c53c24431453923962269c2db68ee43788c5a40d" +[[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.11" @@ -4459,6 +4928,47 @@ dependencies = [ "windows-sys 0.61.2", ] +[[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.61.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +dependencies = [ + "windows-collections", + "windows-core 0.61.2", + "windows-future", + "windows-link 0.1.3", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core 0.61.2", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.1.3", + "windows-result 0.3.4", + "windows-strings 0.4.2", +] + [[package]] name = "windows-core" version = "0.62.2" @@ -4467,9 +4977,20 @@ checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", - "windows-link", - "windows-result", - "windows-strings", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", + "windows-threading", ] [[package]] @@ -4494,19 +5015,53 @@ dependencies = [ "syn", ] +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link 0.1.3", +] + [[package]] name = "windows-result" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-link", + "windows-link 0.2.1", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link 0.1.3", ] [[package]] @@ -4515,7 +5070,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -4533,7 +5088,7 @@ version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -4552,6 +5107,15 @@ dependencies = [ "windows_x86_64_msvc", ] +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link 0.1.3", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -4748,7 +5312,7 @@ dependencies = [ "deflate64", "flate2", "getrandom 0.4.3", - "hmac", + "hmac 0.13.0", "indexmap", "lzma-rust2", "memchr", diff --git a/Cargo.toml b/Cargo.toml index 9f153d6..66adb1f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,6 +55,8 @@ utoipa-swagger-ui = { version = "9.0.2", features = ["actix-web"] } uuid = { version = "1.8", features = ["v4", "fast-rng", "macro-diagnostics"] } validator = { version = "0.20.0", features = ["derive"] } zip = "8.6.0" +# have to do this until https://github.com/durch/rust-s3/pull/452 is merged :( +rust-s3 = { git = "https://github.com/w4nderlust/rust-s3", rev = "2936eb7", features = ["tokio-rustls-tls"] } [target.'cfg(target_env = "musl")'.dependencies] mimalloc = "0.1.52" diff --git a/migrations/20260718120021_add_managed_download_link.down.sql b/migrations/20260718120021_add_managed_download_link.down.sql new file mode 100644 index 0000000..c2e9517 --- /dev/null +++ b/migrations/20260718120021_add_managed_download_link.down.sql @@ -0,0 +1 @@ +ALTER TABLE mod_versions DROP COLUMN managed_download_link; diff --git a/migrations/20260718120021_add_managed_download_link.up.sql b/migrations/20260718120021_add_managed_download_link.up.sql new file mode 100644 index 0000000..da9db1e --- /dev/null +++ b/migrations/20260718120021_add_managed_download_link.up.sql @@ -0,0 +1 @@ +ALTER TABLE mod_versions ADD COLUMN managed_download_link TEXT; diff --git a/src/config.rs b/src/config.rs index 7617618..ca10e5e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -4,7 +4,7 @@ use moka::future::Cache; use crate::{ endpoints::mods::IndexQueryParams, - storage::{LocalBackend, PrivateDisk, PublicDisk}, + storage::{LocalBackend, PrivateDisk, PublicDisk, S3Backend, S3Configuration}, types::{ api::{ApiResponse, PaginatedData}, models::mod_entity::Mod, @@ -17,12 +17,12 @@ pub struct AppData { app_url: String, front_url: String, github: GitHubClientData, - s3: Option, webhook_url: String, index_admin_webhook_url: String, static_storage: PublicDisk, public_storage: PublicDisk, private_storage: PrivateDisk, + mod_storage: Option, disable_downloads: bool, max_download_mb: u32, port: u16, @@ -39,8 +39,7 @@ pub struct GitHubClientData { #[derive(Clone)] pub struct S3ClientData { - client: aws_sdk_s3::Client, - bucket_name: String, + bucket: Box, } pub async fn build_config() -> anyhow::Result { @@ -75,10 +74,12 @@ pub async fn build_config() -> anyhow::Result { .time_to_live(Duration::from_mins(10)) .build(); - // https://developers.cloudflare.com/r2/reference/data-location - let s3_endpoint = dotenvy::var("S3_ENDPOINT_URL").unwrap_or("".to_string()); - let s3_region = dotenvy::var("S3_REGION").unwrap_or("auto".to_string()); - let s3_bucket = dotenvy::var("S3_BUCKET_NAME").unwrap_or("".to_string()); + let mod_storage = if let Some(s3_config) = S3Configuration::from_env()? { + let backend = Arc::new(S3Backend::new(&s3_config)?); + Some(PublicDisk::new(backend, s3_config.public_url)) + } else { + None + }; Ok(AppData { db: pool, @@ -88,18 +89,6 @@ pub async fn build_config() -> anyhow::Result { client_id: github_client, client_secret: github_secret, }, - s3: if s3_endpoint.is_empty() { None } else { - let config = aws_config::defaults(aws_config::BehaviorVersion::latest()) - .region(aws_config::Region::new(s3_region)) - //.credentials_provider(credentials) - .endpoint_url(&s3_endpoint) - .load() - .await; - Some(S3ClientData { - client: aws_sdk_s3::Client::new(&config), - bucket_name: s3_bucket - }) - }, webhook_url, index_admin_webhook_url, static_storage: PublicDisk::new( @@ -111,6 +100,7 @@ pub async fn build_config() -> anyhow::Result { format!("{app_url}/storage"), ), private_storage: PrivateDisk::new(Arc::new(LocalBackend::new("storage/private"))), + mod_storage, disable_downloads, max_download_mb, port, @@ -146,10 +136,6 @@ impl AppData { &self.github } - pub fn s3(&self) -> &Option { - &self.s3 - } - pub fn webhook_url(&self) -> &str { &self.webhook_url } @@ -186,6 +172,10 @@ impl AppData { &self.private_storage } + pub fn mod_storage(&self) -> Option<&PublicDisk> { + self.mod_storage.as_ref() + } + pub fn mods_cache(&self) -> &Cache>> { &self.mods_cache } diff --git a/src/storage/local.rs b/src/storage/local.rs new file mode 100644 index 0000000..b451d7a --- /dev/null +++ b/src/storage/local.rs @@ -0,0 +1,63 @@ +use std::path::PathBuf; +use super::*; + + +pub struct LocalBackend { + base_path: PathBuf, +} + +impl LocalBackend { + pub fn new(base_path: impl Into) -> LocalBackend { + LocalBackend { + base_path: base_path.into(), + } + } +} + +impl StorageBackend for LocalBackend { + fn store<'a>( + &'a self, + relative_path: &'a str, + data: &'a [u8], + ) -> BoxFuture<'a, StorageResult<()>> { + Box::pin(async move { + let path = self.base_path.join(relative_path); + if let Some(parent) = path.parent() { + tokio::fs::create_dir_all(parent).await?; + } + + tokio::fs::write(path, data).await.map_err(|e| e.into()) + }) + } + + fn read<'a>(&'a self, path: &'a str) -> BoxFuture<'a, StorageResult>> { + Box::pin(async move { + let path = self.base_path.join(path); + match tokio::fs::read(path).await { + Ok(data) => Ok(data), + Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(vec![]), + Err(e) => Err(e), + } + .map_err(|e| e.into()) + }) + } + + fn exists<'a>(&'a self, path: &'a str) -> BoxFuture<'a, StorageResult> { + Box::pin(async move { + let path = self.base_path.join(path); + Ok(tokio::fs::metadata(path).await.is_ok()) + }) + } + + fn delete<'a>(&'a self, path: &'a str) -> BoxFuture<'a, StorageResult<()>> { + Box::pin(async move { + let path = self.base_path.join(path); + match tokio::fs::remove_file(path).await { + Ok(()) => Ok(()), + Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(()), + Err(e) => Err(e), + } + .map_err(|e| e.into()) + }) + } +} diff --git a/src/storage.rs b/src/storage/mod.rs similarity index 68% rename from src/storage.rs rename to src/storage/mod.rs index 44a0d3a..dff9642 100644 --- a/src/storage.rs +++ b/src/storage/mod.rs @@ -1,13 +1,23 @@ use std::{path::PathBuf, pin::Pin, sync::Arc}; +pub use local::LocalBackend; +pub use s3::*; + +mod local; +mod s3; + #[derive(thiserror::Error, Debug)] pub enum StorageError { #[error("I/O error: {0}")] Io(#[from] std::io::Error), + #[error("S3 error: {0}")] + S3(#[from] ::s3::error::S3Error), + #[error("{0}")] + Other(String), } pub type StorageResult = Result; -type BoxFuture<'a, T> = Pin + Send + 'a>>; +pub type BoxFuture<'a, T> = Pin + Send + 'a>>; pub trait StorageBackend: Send + Sync { fn init(&self) -> BoxFuture<'_, StorageResult<()>> { @@ -19,66 +29,6 @@ pub trait StorageBackend: Send + Sync { fn delete<'a>(&'a self, path: &'a str) -> BoxFuture<'a, StorageResult<()>>; } -pub struct LocalBackend { - base_path: PathBuf, -} - -impl LocalBackend { - pub fn new(base_path: impl Into) -> LocalBackend { - LocalBackend { - base_path: base_path.into(), - } - } -} - -impl StorageBackend for LocalBackend { - fn store<'a>( - &'a self, - relative_path: &'a str, - data: &'a [u8], - ) -> BoxFuture<'a, StorageResult<()>> { - Box::pin(async move { - let path = self.base_path.join(relative_path); - if let Some(parent) = path.parent() { - tokio::fs::create_dir_all(parent).await?; - } - - tokio::fs::write(path, data).await.map_err(|e| e.into()) - }) - } - - fn read<'a>(&'a self, path: &'a str) -> BoxFuture<'a, StorageResult>> { - Box::pin(async move { - let path = self.base_path.join(path); - match tokio::fs::read(path).await { - Ok(data) => Ok(data), - Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(vec![]), - Err(e) => Err(e), - } - .map_err(|e| e.into()) - }) - } - - fn exists<'a>(&'a self, path: &'a str) -> BoxFuture<'a, StorageResult> { - Box::pin(async move { - let path = self.base_path.join(path); - Ok(tokio::fs::metadata(path).await.is_ok()) - }) - } - - fn delete<'a>(&'a self, path: &'a str) -> BoxFuture<'a, StorageResult<()>> { - Box::pin(async move { - let path = self.base_path.join(path); - match tokio::fs::remove_file(path).await { - Ok(()) => Ok(()), - Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(()), - Err(e) => Err(e), - } - .map_err(|e| e.into()) - }) - } -} - #[derive(Clone)] struct DiskCore { backend: Arc, diff --git a/src/storage/s3.rs b/src/storage/s3.rs new file mode 100644 index 0000000..48e055b --- /dev/null +++ b/src/storage/s3.rs @@ -0,0 +1,139 @@ +use super::*; +use ::s3::{Bucket, Region, creds::Credentials}; + +pub enum S3Provider { + AWS, + Cloudflare, +} + +impl S3Provider { + pub fn from_str(s: &str) -> Option { + match s.to_lowercase().as_str() { + "aws" => Some(S3Provider::AWS), + "cloudflare" => Some(S3Provider::Cloudflare), + _ => None, + } + } +} + +pub struct S3Configuration { + pub provider: S3Provider, + pub bucket: String, + pub region: Option, + pub access_key: String, + pub secret_key: String, + pub account_id: Option, + pub public_url: String, +} + +impl S3Configuration { + pub fn from_env() -> anyhow::Result> { + let provider = dotenvy::var("STORAGE_PROVIDER").unwrap_or_default(); + if provider.is_empty() { + return Ok(None); + } + + let provider = S3Provider::from_str(&provider).ok_or_else(|| { + anyhow::anyhow!("Invalid STORAGE_PROVIDER value, must be 'aws' or 'cloudflare'") + })?; + + let config = S3Configuration { + provider, + bucket: dotenvy::var("STORAGE_BUCKET")?, + region: dotenvy::var("STORAGE_REGION").ok(), + access_key: dotenvy::var("STORAGE_ACCESS_KEY")?, + secret_key: dotenvy::var("STORAGE_SECRET_KEY")?, + account_id: dotenvy::var("STORAGE_ACCOUNT_ID").ok(), + public_url: dotenvy::var("STORAGE_PUBLIC_URL")?, + }; + + Ok(Some(config)) + } +} + +pub struct S3Backend { + bucket: Box, +} + +impl S3Backend { + pub fn new(config: &S3Configuration) -> anyhow::Result { + match config.provider { + S3Provider::AWS => S3Backend::new_aws(config), + S3Provider::Cloudflare => S3Backend::new_cloudflare(config), + } + } + + fn new_aws(config: &S3Configuration) -> anyhow::Result { + let Some(region) = &config.region else { + return Err(anyhow::anyhow!("STORAGE_REGION is required for AWS S3")); + }; + + let credentials = Credentials::new( + Some(&config.access_key), + Some(&config.secret_key), + None, + None, + None, + )?; + + let bucket = Bucket::new(&config.bucket, region.parse()?, credentials)?; + + Ok(S3Backend { bucket }) + } + + fn new_cloudflare(config: &S3Configuration) -> anyhow::Result { + let Some(account_id) = config.account_id.clone() else { + return Err(anyhow::anyhow!("STORAGE_ACCOUNT_ID is required for Cloudflare R2")); + }; + + let credentials = Credentials::new( + Some(&config.access_key), + Some(&config.secret_key), + None, + None, + None, + )?; + + let bucket = Bucket::new(&config.bucket, Region::R2 { account_id }, credentials)?; + + Ok(S3Backend { bucket }) + } +} + +impl StorageBackend for S3Backend { + fn store<'a>( + &'a self, + relative_path: &'a str, + data: &'a [u8], + ) -> BoxFuture<'a, StorageResult<()>> { + Box::pin(async move { + let _ = self.bucket.put_object(relative_path, data).await?; + Ok(()) + }) + } + + fn read<'a>(&'a self, path: &'a str) -> BoxFuture<'a, StorageResult>> { + Box::pin(async move { + let data = self.bucket.get_object(path).await?; + + if data.status_code() != 200 { + return Err(StorageError::Other(format!("S3 API returned HTTP error {}", data.status_code()))); + } + + Ok(data.to_vec()) + }) + } + + fn exists<'a>(&'a self, path: &'a str) -> BoxFuture<'a, StorageResult> { + Box::pin(async move { + Ok(self.bucket.object_exists(path).await?) + }) + } + + fn delete<'a>(&'a self, path: &'a str) -> BoxFuture<'a, StorageResult<()>> { + Box::pin(async move { + let _ = self.bucket.delete_object(path).await?; + Ok(()) + }) + } +} From 85fc899e5f6bd3896d2c185c444a7612fd1c5363 Mon Sep 17 00:00:00 2001 From: dankmeme01 <42031238+dankmeme01@users.noreply.github.com> Date: Sat, 18 Jul 2026 15:54:12 +0200 Subject: [PATCH 03/11] implement most of S3 support, some minor refactors for http --- src/config.rs | 30 ++++- src/database/repository/mod_versions.rs | 29 +++- src/endpoints/mod_version_submissions.rs | 2 +- src/endpoints/mod_versions.rs | 40 ++++-- src/endpoints/mods.rs | 13 +- src/main.rs | 9 +- src/mod_zip.rs | 27 ++-- src/s3_worker.rs | 165 +++++++++++++++++++++++ src/storage/local.rs | 3 +- src/storage/s3.rs | 13 +- src/types/mod_json.rs | 13 +- src/types/models/mod_entity.rs | 9 +- src/types/models/mod_gd_version.rs | 7 + src/types/models/mod_version.rs | 12 +- src/webhook/discord.rs | 5 +- 15 files changed, 326 insertions(+), 51 deletions(-) create mode 100644 src/s3_worker.rs diff --git a/src/config.rs b/src/config.rs index ca10e5e..9e3d495 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,9 +1,14 @@ -use std::{sync::Arc, time::Duration}; +use std::{ + sync::{Arc, OnceLock}, + time::Duration, +}; use moka::future::Cache; +use tokio::sync::mpsc::Sender; use crate::{ endpoints::mods::IndexQueryParams, + s3_worker::S3WorkerTask, storage::{LocalBackend, PrivateDisk, PublicDisk, S3Backend, S3Configuration}, types::{ api::{ApiResponse, PaginatedData}, @@ -29,6 +34,9 @@ pub struct AppData { debug: bool, mods_cache: Cache>>, + http_client: reqwest::Client, + + s3_sender: OnceLock>, } #[derive(Clone)] @@ -106,6 +114,8 @@ pub async fn build_config() -> anyhow::Result { port, debug, mods_cache, + http_client: reqwest::Client::builder().build()?, + s3_sender: OnceLock::new(), }) } @@ -179,4 +189,22 @@ impl AppData { pub fn mods_cache(&self) -> &Cache>> { &self.mods_cache } + + pub fn http_client(&self) -> &reqwest::Client { + &self.http_client + } + + pub fn init_s3_sender(&self, sender: Sender) { + self.s3_sender + .set(sender) + .expect("init_s3_sender must be called only once"); + } + + pub fn send_s3_task(&self, task: S3WorkerTask) -> bool { + if let Some(sender) = self.s3_sender.get() { + sender.try_send(task).is_ok() + } else { + false + } + } } diff --git a/src/database/repository/mod_versions.rs b/src/database/repository/mod_versions.rs index a9a64dc..ec5f694 100644 --- a/src/database/repository/mod_versions.rs +++ b/src/database/repository/mod_versions.rs @@ -18,6 +18,7 @@ struct ModVersionRow { description: Option, version: String, download_link: String, + managed_download_link: Option, download_count: i32, hash: String, geode: String, @@ -40,6 +41,7 @@ impl ModVersionRow { description: self.description, version: self.version, download_link: self.download_link, + managed_download_link: self.managed_download_link, hash: self.hash, geode: self.geode, early_load: self.early_load, @@ -71,7 +73,7 @@ pub async fn get_by_version_str( ModVersionRow, r#"SELECT mv.id, mv.name, mv.description, mv.version, - mv.download_link, mv.download_count, mv.hash, + mv.download_link, mv.managed_download_link, mv.download_count, mv.hash, format_semver(mv.geode_major, mv.geode_minor, mv.geode_patch, mv.geode_meta) as "geode!: _", mv.early_load, mv.requires_patching, mv.api, mv.mod_id, mv.created_at, mv.updated_at, @@ -100,7 +102,7 @@ pub async fn get_for_mod( ModVersionRow, r#"SELECT mv.id, mv.name, mv.description, mv.version, - mv.download_link, mv.download_count, mv.hash, + mv.download_link, mv.managed_download_link, mv.download_count, mv.hash, format_semver(mv.geode_major, mv.geode_minor, mv.geode_patch, mv.geode_meta) as "geode!: _", mv.early_load, mv.requires_patching, mv.api, mv.mod_id, mv.created_at, mv.updated_at, @@ -227,6 +229,7 @@ pub async fn create_from_json( description: row.description, version: row.version, download_link: row.download_link, + managed_download_link: None, hash: row.hash, geode: geode.to_string(), download_count: 0.into(), @@ -331,6 +334,7 @@ pub async fn update_pending_version( description: row.description, version: row.version, download_link: row.download_link, + managed_download_link: None, hash: row.hash, geode: geode.to_string(), download_count: row.download_count.into(), @@ -386,3 +390,24 @@ pub async fn update_version_status( Ok(version) } + +#[tracing::instrument(skip_all, fields(id = %id, link = ?link))] +pub async fn update_managed_download_link( + id: i32, + link: Option<&str>, + conn: &mut PgConnection, +) -> Result<(), DatabaseError> { + sqlx::query!( + "UPDATE mod_versions + SET managed_download_link = $1, + updated_at = NOW() + WHERE id = $2", + link, + id + ) + .execute(&mut *conn) + .await + .inspect_err(|e| tracing::error!("{:?}", e))?; + + Ok(()) +} diff --git a/src/endpoints/mod_version_submissions.rs b/src/endpoints/mod_version_submissions.rs index 2e49ddc..9b1954e 100644 --- a/src/endpoints/mod_version_submissions.rs +++ b/src/endpoints/mod_version_submissions.rs @@ -466,7 +466,7 @@ pub async fn create_comment( username: dev.username.clone(), } .to_discord_webhook() - .send(data.index_admin_webhook_url()); + .send(data.http_client(), data.index_admin_webhook_url()); } Ok(HttpResponse::Created().json(ApiResponse { diff --git a/src/endpoints/mod_versions.rs b/src/endpoints/mod_versions.rs index 93dd2ab..742a396 100644 --- a/src/endpoints/mod_versions.rs +++ b/src/endpoints/mod_versions.rs @@ -16,6 +16,7 @@ use crate::events::mod_created::{ NewUnverifiedModVersionCreated, }; use crate::mod_zip::{self, download_mod}; +use crate::s3_worker::S3WorkerTask; use crate::types::models; use crate::types::models::mod_version_submission::ModVersionSubmissionLock; use crate::webhook::discord::DiscordWebhook; @@ -235,7 +236,10 @@ pub async fn download_version( .ok_or(ApiError::NotFound( "Couldn't find valid mod version for given filters".into(), ))?; - let url = mod_version.download_link; + + let url = mod_version + .managed_download_link + .unwrap_or(mod_version.download_link); if data.disable_downloads() || mod_version.status != ModVersionStatusEnum::Accepted { // whatever @@ -346,8 +350,8 @@ pub async fn create_version( .filter(|c| c.is_ascii() && *c != '\0') .collect(); - let bytes = download_mod(&download_link, data.max_download_mb()).await?; - let json = ModJson::from_zip(bytes, &download_link, make_accepted) + let bytes = download_mod(data.http_client(), &download_link, data.max_download_mb()).await?; + let json = ModJson::from_zip(&bytes, &download_link, make_accepted) .inspect_err(|e| tracing::error!("Failed to parse mod.json: {e}"))?; if json.id != the_mod.id { return Err(ApiError::BadRequest(format!( @@ -463,7 +467,14 @@ pub async fn create_version( base_url: data.app_url().to_string(), } .to_discord_webhook() - .send(data.webhook_url()); + .send(data.http_client(), data.webhook_url()); + + data.send_s3_task(S3WorkerTask::UploadMod { + data: bytes, + mod_id: the_mod.id, + version: version.version.clone(), + version_id: version.id, + }); } else { NewUnverifiedModVersionCreated { id: the_mod.id.clone(), @@ -472,7 +483,7 @@ pub async fn create_version( owner: dev.clone(), } .to_discord_webhook() - .send(data.index_admin_webhook_url()); + .send(data.http_client(), data.index_admin_webhook_url()); } version.modify_metadata(data.app_url(), false); @@ -516,6 +527,7 @@ pub async fn update_version( let the_mod = mods::get_one(&path.id, false, &mut pool) .await? .ok_or(ApiError::NotFound(format!("Mod {} not found", path.id)))?; + let mod_id = the_mod.id.clone(); if !dev.admin { return Err(ApiError::Authorization); @@ -560,18 +572,19 @@ pub async fn update_version( } let bytes = mod_zip::download_mod_hash_comp( + data.http_client(), &version.download_link, &version.hash, data.max_download_mb(), ) .await?; - let json = ModJson::from_zip(bytes, &version.download_link, true)?; + let json = ModJson::from_zip(&bytes, &version.download_link, true)?; // Update links with data from mod.json if let Some(links) = json.links.clone() { mod_links::upsert( - the_mod.id.as_str(), + &mod_id, links.community, links.homepage, links.source, @@ -579,7 +592,7 @@ pub async fn update_version( ) .await?; } else { - mod_links::upsert(the_mod.id.as_str(), None, None, None, &mut tx).await?; + mod_links::upsert(&mod_id, None, None, None, &mut tx).await?; } // Update tags with data from mod.json @@ -593,6 +606,13 @@ pub async fn update_version( mods::update_with_json_moved(the_mod, json, &mut tx).await?; + data.send_s3_task(S3WorkerTask::UploadMod { + data: bytes, + mod_id, + version: version.version.clone(), + version_id: version.id, + }); + // Let's also maybe lock the thread if it exists! let thread = mod_version_submissions::get_for_mod_version(version.id, &mut tx).await?; if let Some(thread) = thread @@ -629,7 +649,7 @@ pub async fn update_version( base_url: data.app_url().to_string(), } .to_discord_webhook() - .send(data.webhook_url()); + .send(data.http_client(), data.webhook_url()); } else { NewModVersionAcceptedEvent { id: version.mod_id, @@ -640,7 +660,7 @@ pub async fn update_version( base_url: data.app_url().to_string(), } .to_discord_webhook() - .send(data.webhook_url()); + .send(data.http_client(), data.webhook_url()); } } diff --git a/src/endpoints/mods.rs b/src/endpoints/mods.rs index 195cbd8..2b53f41 100644 --- a/src/endpoints/mods.rs +++ b/src/endpoints/mods.rs @@ -217,8 +217,13 @@ pub async fn create( ) -> Result { let dev = auth.developer()?; let mut pool = data.db().acquire().await?; - let bytes = mod_zip::download_mod(&payload.download_link, data.max_download_mb()).await?; - let json = ModJson::from_zip(bytes, &payload.download_link, false)?; + let bytes = mod_zip::download_mod( + data.http_client(), + &payload.download_link, + data.max_download_mb(), + ) + .await?; + let json = ModJson::from_zip(&bytes, &payload.download_link, false)?; json.validate()?; let existing: Option = mods::get_one(&json.id, false, &mut pool).await?; @@ -302,7 +307,7 @@ pub async fn create( owner: dev.clone(), } .to_discord_webhook() - .send(data.index_admin_webhook_url()); + .send(data.http_client(), data.index_admin_webhook_url()); for i in &mut the_mod.versions { i.modify_metadata(data.app_url(), false); @@ -485,7 +490,7 @@ pub async fn update_mod( featured: payload.featured, } .to_discord_webhook() - .send(data.webhook_url()); + .send(data.http_client(), data.webhook_url()); } } diff --git a/src/main.rs b/src/main.rs index 1b17007..f6746f9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,6 +20,7 @@ mod jobs; mod logging; mod mod_zip; mod openapi; +mod s3_worker; mod storage; mod types; mod webhook; @@ -37,6 +38,9 @@ async fn main() -> anyhow::Result<()> { let app_data = config::build_config().await?; app_data.static_storage().init().await?; app_data.private_storage().init().await?; + if let Some(mod_storage) = app_data.mod_storage() { + mod_storage.init().await?; + } if cli::maybe_cli(&app_data).await? { return Ok(()); @@ -48,12 +52,15 @@ async fn main() -> anyhow::Result<()> { let port = app_data.port(); let debug = app_data.debug(); + let data = web::Data::new(app_data.clone()); + tokio::spawn(s3_worker::run_s3_worker(data.clone())); + tracing::info!("Starting server on 0.0.0.0:{}", port); let server = HttpServer::new(move || { let openapi = ApiDoc::openapi(); let app = App::new() - .app_data(web::Data::new(app_data.clone())) + .app_data(data.clone()) .app_data(QueryConfig::default().error_handler(api::query_error_handler)) .service( SwaggerUi::new("/swagger/{_:.*}").url("/swagger/openapi.json", openapi.clone()), diff --git a/src/mod_zip.rs b/src/mod_zip.rs index 8b08958..6a5b039 100644 --- a/src/mod_zip.rs +++ b/src/mod_zip.rs @@ -36,7 +36,7 @@ pub enum ModZipError { InvalidBinaries(String), } -pub fn extract_mod_logo(file: &mut ZipFile>) -> Result, ModZipError> { +pub fn extract_mod_logo(file: &mut ZipFile) -> Result, ModZipError> { const FIVE_MEGABYTES: u64 = 5 * 1000 * 1000; if file.size() > FIVE_MEGABYTES { return Err(ModZipError::InvalidLogo( @@ -89,7 +89,7 @@ pub fn extract_mod_logo(file: &mut ZipFile>) -> Result, Mo Ok(bytes) } -pub fn validate_mod_logo(file: &mut ZipFile>) -> Result<(), ModZipError> { +pub fn validate_mod_logo(file: &mut ZipFile) -> Result<(), ModZipError> { const FIVE_MEGABYTES: u64 = 5 * 1000 * 1000; if file.size() > FIVE_MEGABYTES { return Err(ModZipError::InvalidLogo( @@ -119,16 +119,21 @@ pub fn validate_mod_logo(file: &mut ZipFile>) -> Result<(), ModZip } } -pub async fn download_mod(url: &str, limit_mb: u32) -> Result { - download(url, limit_mb).await +pub async fn download_mod( + http_client: &reqwest::Client, + url: &str, + limit_mb: u32, +) -> Result { + download(http_client, url, limit_mb).await } pub async fn download_mod_hash_comp( + http_client: &reqwest::Client, url: &str, hash: &str, limit_mb: u32, ) -> Result { - let bytes = download(url, limit_mb).await?; + let bytes = download(http_client, url, limit_mb).await?; let slice: &[u8] = &bytes; @@ -140,15 +145,21 @@ pub async fn download_mod_hash_comp( Ok(bytes) } -pub fn bytes_to_ziparchive(bytes: Bytes) -> Result>, ModZipError> { +pub fn bytes_to_ziparchive(bytes: &[u8]) -> Result>, ModZipError> { ZipArchive::new(Cursor::new(bytes)) .inspect_err(|e| tracing::error!("Failed to create ZipArchive: {}", e)) .map_err(|e| e.into()) } -async fn download(url: &str, limit_mb: u32) -> Result { +async fn download( + http_client: &reqwest::Client, + url: &str, + limit_mb: u32, +) -> Result { let limit_bytes: u64 = limit_mb as u64 * 1_000_000; - let mut response = reqwest::get(url) + let mut response = http_client + .get(url) + .send() .await .inspect_err(|e| tracing::error!("Failed to fetch .geode file: {e}"))? .error_for_status() diff --git a/src/s3_worker.rs b/src/s3_worker.rs new file mode 100644 index 0000000..34a26cb --- /dev/null +++ b/src/s3_worker.rs @@ -0,0 +1,165 @@ +use std::time::Duration; + +use actix_web::web; +use bytes::Bytes; + +use crate::{ + config::AppData, database::repository::mod_versions::update_managed_download_link, + types::models::mod_gd_version::GDVersionEnum, +}; + +pub enum S3WorkerTask { + UploadMod { + data: Bytes, + mod_id: String, + version: String, + version_id: i32, + }, +} + +fn path_for_mod(mod_id: &str, version: &str) -> String { + format!("mods/{mod_id}/{version}/{mod_id}.geode") +} + +async fn process_task(data: &AppData, task: S3WorkerTask) -> anyhow::Result<()> { + let storage = data.mod_storage().expect("mod storage must be set by now"); + + match task { + S3WorkerTask::UploadMod { + data: bytes, + mod_id, + version, + version_id, + } => { + let path = path_for_mod(&mod_id, &version); + let public_url = storage.asset_url(&path); + + storage.store(&path, &bytes).await?; + + let mut tx = data.db().begin().await?; + update_managed_download_link(version_id, Some(&public_url), &mut tx).await?; + tx.commit().await?; + + tracing::info!( + "Uploaded mod {} {} to S3 at {}", + mod_id, + version, + public_url + ); + } + } + + Ok(()) +} + +async fn cleanup_old_s3_files(data: &AppData) -> anyhow::Result<()> { + // TODO + Ok(()) +} + +async fn migrate_one( + data: &AppData, + original_url: &str, + mod_id: &str, + version: &str, + version_id: i32, +) -> anyhow::Result<()> { + let resp = data + .http_client() + .get(original_url) + .send() + .await? + .error_for_status()?; + let bytes = resp.bytes().await?; + + process_task( + data, + S3WorkerTask::UploadMod { + data: bytes, + mod_id: mod_id.to_owned(), + version: version.to_owned(), + version_id, + }, + ) + .await +} + +async fn migrate_existing_mods_to_s3(data: &AppData) -> anyhow::Result<()> { + let supported_gd = GDVersionEnum::latest_supported(); + + let mut db = data.db().acquire().await?; + + // gets the latest approved version of each mod for each supported GD version + let versions = sqlx::query!( + "SELECT final_q.id, final_q.version, final_q.download_link, final_q.mv_id FROM ( + SELECT DISTINCT ON (q.mv_id) q.id, q.version, q.download_link, q.mv_id, q.gd FROM ( + SELECT DISTINCT ON (m.id, mgv.gd) m.id, mv.name, mv.version, mv.download_link, mv.id as mv_id, mgv.gd + FROM MODS m + INNER JOIN mod_versions mv ON m.id = mv.mod_id + INNER JOIN mod_version_statuses mvs ON mvs.mod_version_id = mv.id + INNER JOIN mod_gd_versions mgv ON mgv.mod_id = mv.id + WHERE mvs.status = 'accepted' + AND mgv.gd = ANY($1::gd_version[]) + AND mv.managed_download_link IS NULL + ORDER BY m.id, mgv.gd, mv.id DESC + ) q + ORDER BY q.mv_id, q.gd DESC + ) final_q", + supported_gd as &[GDVersionEnum] + ) + .fetch_all(&mut *db) + .await?; + + for record in versions { + if let Err(e) = migrate_one( + data, + &record.download_link, + &record.id, + &record.version, + record.mv_id, + ) + .await + { + tracing::error!( + "error migrating mod {} {} to S3: {e:?}", + record.id, + record.version + ); + } + } + + Ok(()) +} + +pub async fn run_s3_worker(data: web::Data) { + if data.mod_storage().is_none() { + return; + } + + let (tx, mut rx) = tokio::sync::mpsc::channel(64); + data.init_s3_sender(tx); + + let s_data = data.clone(); + tokio::spawn(async move { + if let Err(e) = migrate_existing_mods_to_s3(&s_data).await { + tracing::error!("Error migrating existing mods to S3: {:?}", e); + } + }); + + let mut interval = tokio::time::interval(Duration::from_mins(30)); + + loop { + let result = tokio::select! { + task = rx.recv() => match task { + Some(task) => process_task(&data, task).await, + None => break, + }, + + _ = interval.tick() => cleanup_old_s3_files(&data).await, + }; + + if let Err(e) = result { + tracing::error!("Error processing S3 worker task: {:?}", e); + } + } +} diff --git a/src/storage/local.rs b/src/storage/local.rs index b451d7a..ffc2eaa 100644 --- a/src/storage/local.rs +++ b/src/storage/local.rs @@ -1,6 +1,5 @@ -use std::path::PathBuf; use super::*; - +use std::path::PathBuf; pub struct LocalBackend { base_path: PathBuf, diff --git a/src/storage/s3.rs b/src/storage/s3.rs index 48e055b..aa11aa1 100644 --- a/src/storage/s3.rs +++ b/src/storage/s3.rs @@ -83,7 +83,9 @@ impl S3Backend { fn new_cloudflare(config: &S3Configuration) -> anyhow::Result { let Some(account_id) = config.account_id.clone() else { - return Err(anyhow::anyhow!("STORAGE_ACCOUNT_ID is required for Cloudflare R2")); + return Err(anyhow::anyhow!( + "STORAGE_ACCOUNT_ID is required for Cloudflare R2" + )); }; let credentials = Credentials::new( @@ -117,7 +119,10 @@ impl StorageBackend for S3Backend { let data = self.bucket.get_object(path).await?; if data.status_code() != 200 { - return Err(StorageError::Other(format!("S3 API returned HTTP error {}", data.status_code()))); + return Err(StorageError::Other(format!( + "S3 API returned HTTP error {}", + data.status_code() + ))); } Ok(data.to_vec()) @@ -125,9 +130,7 @@ impl StorageBackend for S3Backend { } fn exists<'a>(&'a self, path: &'a str) -> BoxFuture<'a, StorageResult> { - Box::pin(async move { - Ok(self.bucket.object_exists(path).await?) - }) + Box::pin(async move { Ok(self.bucket.object_exists(path).await?) }) } fn delete<'a>(&'a self, path: &'a str) -> BoxFuture<'a, StorageResult<()>> { diff --git a/src/types/mod_json.rs b/src/types/mod_json.rs index fc99457..c890ab9 100644 --- a/src/types/mod_json.rs +++ b/src/types/mod_json.rs @@ -180,12 +180,11 @@ pub struct OldModJsonIncompatibility { impl ModJson { pub fn from_zip( - file: Bytes, + file: &[u8], download_url: &str, store_image: bool, ) -> Result { - let slice: &[u8] = &file; - let hash = sha256::digest(slice); + let hash = sha256::digest(file); let mut archive = mod_zip::bytes_to_ziparchive(file)?; // check total size of the zip file @@ -216,7 +215,7 @@ impl ModJson { ))); } - let mut json = serde_json::from_reader::>, ModJson>(json_file) + let mut json = serde_json::from_reader::>, ModJson>(json_file) .inspect_err(|e| tracing::error!("Failed to parse mod.json: {e}"))?; json.version = json.version.trim_start_matches('v').to_string(); @@ -618,7 +617,7 @@ impl ModJson { } } -fn parse_zip_entry_to_str(file: &mut ZipFile>) -> Result { +fn parse_zip_entry_to_str(file: &mut ZipFile) -> Result { let mut string: String = String::from(""); match file.read_to_string(&mut string) { Ok(_) => Ok(string), @@ -660,9 +659,9 @@ fn parse_download_url(url: &str) -> String { String::from(url.trim_end_matches("\\/")) } -fn check_mac_binary(file: &mut ZipFile>) -> Result<(bool, bool), ModZipError> { +fn check_mac_binary(file: &mut ZipFile) -> Result<(bool, bool), ModZipError> { // 12 bytes is all we need - let mut bytes: Vec = vec![0; 12]; + let mut bytes = [0u8; 12]; file.read_exact(&mut bytes).map_err(|e| { tracing::error!("Failed to read MacOS binary: {}", e); ModZipError::InvalidBinaries(format!("Failed to read macOS binary: {e}")) diff --git a/src/types/models/mod_entity.rs b/src/types/models/mod_entity.rs index ee05d08..6f8bb98 100644 --- a/src/types/models/mod_entity.rs +++ b/src/types/models/mod_entity.rs @@ -86,6 +86,7 @@ struct ModRecordGetOne { description: Option, version: String, download_link: String, + managed_download_link: Option, mod_version_download_count: i32, hash: String, geode: String, @@ -359,7 +360,7 @@ impl Mod { records_builder.push(" LIMIT ").push_bind(limit); records_builder.push(" OFFSET ").push_bind(offset); - // tracing::debug!("sql: {}", records_builder.sql()); + // tracing::info!("sql: {:?}", records_builder.sql()); let records: Vec = records_builder .build_query_as() @@ -586,9 +587,8 @@ impl Mod { ModRecordGetOne, r#"SELECT m.id, m.repository, m.about, m.changelog, m.featured, m.download_count as mod_download_count, m.created_at, m.updated_at, - mv.id as version_id, mv.name, mv.description, mv.version, mv.download_link, mv.download_count as mod_version_download_count, - mv.created_at as mod_version_created_at, mv.updated_at as mod_version_updated_at, - mv.hash, + mv.id as version_id, mv.name, mv.description, mv.version, mv.download_link, mv.managed_download_link, + mv.download_count as mod_version_download_count, mv.created_at as mod_version_created_at, mv.updated_at as mod_version_updated_at, mv.hash, format_semver(mv.geode_major, mv.geode_minor, mv.geode_patch, mv.geode_meta) as "geode!: _", mv.early_load, mv.requires_patching, mv.api, mv.mod_id, mvs.status as "status: _", mvs.info FROM mods m @@ -616,6 +616,7 @@ impl Mod { description: x.description.clone(), version: x.version.clone(), download_link: x.download_link.clone(), + managed_download_link: x.managed_download_link.clone(), download_count: x.mod_version_download_count.into(), hash: x.hash.clone(), geode: x.geode.clone(), diff --git a/src/types/models/mod_gd_version.rs b/src/types/models/mod_gd_version.rs index 67d36e5..734bdbc 100644 --- a/src/types/models/mod_gd_version.rs +++ b/src/types/models/mod_gd_version.rs @@ -53,6 +53,13 @@ pub enum GDVersionEnum { GD22082, } +impl GDVersionEnum { + pub fn latest_supported() -> &'static [GDVersionEnum] { + // please do not forget to update this with the versions we currently support! + &[GDVersionEnum::GD22081, GDVersionEnum::GD22082] + } +} + impl FromStr for GDVersionEnum { type Err = (); fn from_str(s: &str) -> Result { diff --git a/src/types/models/mod_version.rs b/src/types/models/mod_version.rs index 4bc4660..0abfede 100644 --- a/src/types/models/mod_version.rs +++ b/src/types/models/mod_version.rs @@ -30,6 +30,8 @@ pub struct ModVersion { pub description: Option, pub version: String, pub download_link: String, + #[serde(skip_serializing)] + pub managed_download_link: Option, pub hash: String, pub geode: String, #[schema(value_type = i32)] @@ -67,6 +69,7 @@ struct ModVersionGetOne { description: Option, version: String, download_link: String, + managed_download_link: Option, download_count: i32, hash: String, geode: String, @@ -99,6 +102,7 @@ impl ModVersionGetOne { description: self.description.clone(), version: self.version.clone(), download_link: self.download_link.clone(), + managed_download_link: self.managed_download_link.clone(), hash: self.hash.clone(), geode: self.geode.clone(), early_load: self.early_load, @@ -318,13 +322,13 @@ impl ModVersion { sqlx::query_as( "SELECT q.name, q.id, q.description, q.version, - q.download_link, q.hash, q.geode, + q.download_link, q.managed_download_link, q.hash, q.geode, q.download_count, q.early_load, q.requires_patching, q.api, q.mod_id, 'accepted'::mod_version_status as status, q.created_at, q.updated_at FROM ( SELECT - mv.name, mv.id, mv.description, mv.version, mv.download_link, mv.hash, + mv.name, mv.id, mv.description, mv.version, mv.download_link, mv.managed_download_link, mv.hash, format_semver(mv.geode_major, mv.geode_minor, mv.geode_patch, mv.geode_meta) as geode, mv.download_count, mv.early_load, mv.requires_patching, mv.api, mv.mod_id, mv.created_at, mv.updated_at, @@ -396,7 +400,7 @@ impl ModVersion { let records = sqlx::query_as!( ModVersionGetOne, r#"SELECT DISTINCT - mv.name, mv.id, mv.description, mv.version, mv.download_link, mv.hash, + mv.name, mv.id, mv.description, mv.version, mv.download_link, mv.managed_download_link, mv.hash, format_semver(mv.geode_major, mv.geode_minor, mv.geode_patch, mv.geode_meta) as "geode!: _", mv.download_count, mv.early_load, mv.requires_patching, mv.api, mv.mod_id, mv.created_at, mv.updated_at, 'pending'::mod_version_status as "status!: _", NULL as info @@ -523,7 +527,7 @@ impl ModVersion { let result = sqlx::query_as!( ModVersionGetOne, r#"SELECT mv.id, mv.name, mv.description, mv.version, - mv.download_link, mv.download_count, + mv.download_link, mv.managed_download_link, mv.download_count, mv.hash, format_semver(mv.geode_major, mv.geode_minor, mv.geode_patch, mv.geode_meta) as "geode!: _", mv.early_load, mv.requires_patching, mv.api, diff --git a/src/webhook/discord.rs b/src/webhook/discord.rs index de3bd16..ba80256 100644 --- a/src/webhook/discord.rs +++ b/src/webhook/discord.rs @@ -65,7 +65,7 @@ impl DiscordMessage { } } - pub fn send(&self, url: &str) { + pub fn send(&self, http_client: &reqwest::Client, url: &str) { if url.is_empty() { tracing::error!("Not sending webhook since URL is empty"); return; @@ -75,8 +75,9 @@ impl DiscordMessage { let url = String::from(url); let copy = self.clone(); + let client = http_client.clone(); tokio::spawn(async move { - if let Err(e) = reqwest::Client::new().post(&url).json(©).send().await { + if let Err(e) = client.post(&url).json(©).send().await { tracing::error!("Failed to broadcast Discord webhook {}: {}", url, e); } }); From 05fa7a7c6fe4fca858ff559087a07655b8458f6d Mon Sep 17 00:00:00 2001 From: dankmeme01 <42031238+dankmeme01@users.noreply.github.com> Date: Sat, 18 Jul 2026 16:12:32 +0200 Subject: [PATCH 04/11] update supported gd versions --- src/s3_worker.rs | 2 +- src/types/models/mod_gd_version.rs | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/s3_worker.rs b/src/s3_worker.rs index 34a26cb..ee15eb0 100644 --- a/src/s3_worker.rs +++ b/src/s3_worker.rs @@ -85,7 +85,7 @@ async fn migrate_one( } async fn migrate_existing_mods_to_s3(data: &AppData) -> anyhow::Result<()> { - let supported_gd = GDVersionEnum::latest_supported(); + let supported_gd = GDVersionEnum::supported_for_storage(); let mut db = data.db().acquire().await?; diff --git a/src/types/models/mod_gd_version.rs b/src/types/models/mod_gd_version.rs index 734bdbc..e034473 100644 --- a/src/types/models/mod_gd_version.rs +++ b/src/types/models/mod_gd_version.rs @@ -54,10 +54,20 @@ pub enum GDVersionEnum { } impl GDVersionEnum { + /// GD versions that are currently actively supported pub fn latest_supported() -> &'static [GDVersionEnum] { - // please do not forget to update this with the versions we currently support! &[GDVersionEnum::GD22081, GDVersionEnum::GD22082] } + + /// GD versions for which we apply auto-migration to S3 storage + /// Generally should include versions that some users might still be using + pub fn supported_for_storage() -> &'static [GDVersionEnum] { + &[ + GDVersionEnum::GD2206, + GDVersionEnum::GD22074, + GDVersionEnum::GD22081, + ] + } } impl FromStr for GDVersionEnum { From 5ce5bf9be73d52db98a11048707758fd536414ab Mon Sep 17 00:00:00 2001 From: dankmeme01 <42031238+dankmeme01@users.noreply.github.com> Date: Sat, 18 Jul 2026 16:22:24 +0200 Subject: [PATCH 05/11] small warning cleanups --- src/config.rs | 5 ----- src/storage/s3.rs | 6 +++--- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/config.rs b/src/config.rs index 9e3d495..69b384f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -45,11 +45,6 @@ pub struct GitHubClientData { client_secret: String, } -#[derive(Clone)] -pub struct S3ClientData { - bucket: Box, -} - pub async fn build_config() -> anyhow::Result { let env_url = dotenvy::var("DATABASE_URL")?; diff --git a/src/storage/s3.rs b/src/storage/s3.rs index aa11aa1..a8124cc 100644 --- a/src/storage/s3.rs +++ b/src/storage/s3.rs @@ -2,14 +2,14 @@ use super::*; use ::s3::{Bucket, Region, creds::Credentials}; pub enum S3Provider { - AWS, + Aws, Cloudflare, } impl S3Provider { pub fn from_str(s: &str) -> Option { match s.to_lowercase().as_str() { - "aws" => Some(S3Provider::AWS), + "aws" => Some(S3Provider::Aws), "cloudflare" => Some(S3Provider::Cloudflare), _ => None, } @@ -58,7 +58,7 @@ pub struct S3Backend { impl S3Backend { pub fn new(config: &S3Configuration) -> anyhow::Result { match config.provider { - S3Provider::AWS => S3Backend::new_aws(config), + S3Provider::Aws => S3Backend::new_aws(config), S3Provider::Cloudflare => S3Backend::new_cloudflare(config), } } From 7e272498b6f50b030d84998c839c8763e3e676b9 Mon Sep 17 00:00:00 2001 From: dankmeme01 <42031238+dankmeme01@users.noreply.github.com> Date: Sat, 18 Jul 2026 16:57:42 +0200 Subject: [PATCH 06/11] support for gd * and fix the silly query going further down the version list --- src/s3_worker.rs | 9 ++++----- src/types/models/mod_gd_version.rs | 4 +++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/s3_worker.rs b/src/s3_worker.rs index ee15eb0..b524185 100644 --- a/src/s3_worker.rs +++ b/src/s3_worker.rs @@ -93,16 +93,15 @@ async fn migrate_existing_mods_to_s3(data: &AppData) -> anyhow::Result<()> { let versions = sqlx::query!( "SELECT final_q.id, final_q.version, final_q.download_link, final_q.mv_id FROM ( SELECT DISTINCT ON (q.mv_id) q.id, q.version, q.download_link, q.mv_id, q.gd FROM ( - SELECT DISTINCT ON (m.id, mgv.gd) m.id, mv.name, mv.version, mv.download_link, mv.id as mv_id, mgv.gd + SELECT DISTINCT ON (m.id, mgv.gd) m.id, mv.name, mv.version, mv.download_link, mv.managed_download_link, mv.id as mv_id, mgv.gd FROM MODS m INNER JOIN mod_versions mv ON m.id = mv.mod_id INNER JOIN mod_version_statuses mvs ON mvs.mod_version_id = mv.id INNER JOIN mod_gd_versions mgv ON mgv.mod_id = mv.id - WHERE mvs.status = 'accepted' - AND mgv.gd = ANY($1::gd_version[]) - AND mv.managed_download_link IS NULL - ORDER BY m.id, mgv.gd, mv.id DESC + WHERE mvs.status = 'accepted' AND mgv.gd = ANY($1::gd_version[]) + ORDER BY m.id, mgv.gd DESC, mv.id DESC ) q + WHERE q.managed_download_link IS NULL ORDER BY q.mv_id, q.gd DESC ) final_q", supported_gd as &[GDVersionEnum] diff --git a/src/types/models/mod_gd_version.rs b/src/types/models/mod_gd_version.rs index e034473..6aaadab 100644 --- a/src/types/models/mod_gd_version.rs +++ b/src/types/models/mod_gd_version.rs @@ -55,14 +55,16 @@ pub enum GDVersionEnum { impl GDVersionEnum { /// GD versions that are currently actively supported + #[allow(unused)] pub fn latest_supported() -> &'static [GDVersionEnum] { - &[GDVersionEnum::GD22081, GDVersionEnum::GD22082] + &[GDVersionEnum::All, GDVersionEnum::GD22081, GDVersionEnum::GD22082] } /// GD versions for which we apply auto-migration to S3 storage /// Generally should include versions that some users might still be using pub fn supported_for_storage() -> &'static [GDVersionEnum] { &[ + GDVersionEnum::All, GDVersionEnum::GD2206, GDVersionEnum::GD22074, GDVersionEnum::GD22081, From ed09f0aa2a3903e914ac2a4bc7584ed7ffda360f Mon Sep 17 00:00:00 2001 From: dankmeme01 <42031238+dankmeme01@users.noreply.github.com> Date: Sat, 18 Jul 2026 18:35:59 +0200 Subject: [PATCH 07/11] do migration for gd * more correctly, improve reqwest client defaults --- Cargo.lock | 23 ++++++++++++++++++++++- Cargo.toml | 1 + src/config.rs | 6 +++++- src/s3_worker.rs | 6 ++++-- src/types/models/mod_gd_version.rs | 6 +++++- 5 files changed, 37 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dde3876..6681761 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -77,7 +77,7 @@ dependencies = [ "flate2", "foldhash", "futures-core", - "h2", + "h2 0.3.27", "http 0.2.12", "httparse", "httpdate", @@ -1684,6 +1684,25 @@ dependencies = [ "tracing", ] +[[package]] +name = "h2" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cb093c84e8bd9b188d4c4a8cb6579fc016968d14c99882163cd3ff402a4f155" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.4.2", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "half" version = "2.7.1" @@ -1866,6 +1885,7 @@ dependencies = [ "bytes", "futures-channel", "futures-core", + "h2 0.4.15", "http 1.4.2", "http-body", "httparse", @@ -3356,6 +3376,7 @@ dependencies = [ "base64", "bytes", "futures-core", + "h2 0.4.15", "http 1.4.2", "http-body", "http-body-util", diff --git a/Cargo.toml b/Cargo.toml index 66adb1f..801137b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ reqwest = { version = "0.13", default-features = false, features = [ "gzip", "rustls", "query", + "http2" ] } semver = "1.0" serde = { version = "1.0", features = ["derive"] } diff --git a/src/config.rs b/src/config.rs index 69b384f..76cf5df 100644 --- a/src/config.rs +++ b/src/config.rs @@ -109,7 +109,11 @@ pub async fn build_config() -> anyhow::Result { port, debug, mods_cache, - http_client: reqwest::Client::builder().build()?, + http_client: reqwest::Client::builder() + .pool_max_idle_per_host(4) + .connect_timeout(Duration::from_secs(10)) + .read_timeout(Duration::from_secs(30)) + .build()?, s3_sender: OnceLock::new(), }) } diff --git a/src/s3_worker.rs b/src/s3_worker.rs index b524185..99d8db2 100644 --- a/src/s3_worker.rs +++ b/src/s3_worker.rs @@ -93,13 +93,13 @@ async fn migrate_existing_mods_to_s3(data: &AppData) -> anyhow::Result<()> { let versions = sqlx::query!( "SELECT final_q.id, final_q.version, final_q.download_link, final_q.mv_id FROM ( SELECT DISTINCT ON (q.mv_id) q.id, q.version, q.download_link, q.mv_id, q.gd FROM ( - SELECT DISTINCT ON (m.id, mgv.gd) m.id, mv.name, mv.version, mv.download_link, mv.managed_download_link, mv.id as mv_id, mgv.gd + SELECT DISTINCT ON (m.id, mgv.gd, mv.geode_major) m.id, mv.name, mv.version, mv.download_link, mv.managed_download_link, mv.id as mv_id, mgv.gd FROM MODS m INNER JOIN mod_versions mv ON m.id = mv.mod_id INNER JOIN mod_version_statuses mvs ON mvs.mod_version_id = mv.id INNER JOIN mod_gd_versions mgv ON mgv.mod_id = mv.id WHERE mvs.status = 'accepted' AND mgv.gd = ANY($1::gd_version[]) - ORDER BY m.id, mgv.gd DESC, mv.id DESC + ORDER BY m.id, mgv.gd DESC, mv.geode_major DESC, mv.id DESC ) q WHERE q.managed_download_link IS NULL ORDER BY q.mv_id, q.gd DESC @@ -109,6 +109,8 @@ async fn migrate_existing_mods_to_s3(data: &AppData) -> anyhow::Result<()> { .fetch_all(&mut *db) .await?; + tracing::info!("Migrating {} existing mods to S3", versions.len()); + for record in versions { if let Err(e) = migrate_one( data, diff --git a/src/types/models/mod_gd_version.rs b/src/types/models/mod_gd_version.rs index 6aaadab..6cd3449 100644 --- a/src/types/models/mod_gd_version.rs +++ b/src/types/models/mod_gd_version.rs @@ -57,7 +57,11 @@ impl GDVersionEnum { /// GD versions that are currently actively supported #[allow(unused)] pub fn latest_supported() -> &'static [GDVersionEnum] { - &[GDVersionEnum::All, GDVersionEnum::GD22081, GDVersionEnum::GD22082] + &[ + GDVersionEnum::All, + GDVersionEnum::GD22081, + GDVersionEnum::GD22082, + ] } /// GD versions for which we apply auto-migration to S3 storage From 7356a18ff32db14b9859e2da8f108641d8932b58 Mon Sep 17 00:00:00 2001 From: dankmeme01 <42031238+dankmeme01@users.noreply.github.com> Date: Sat, 18 Jul 2026 19:01:50 +0200 Subject: [PATCH 08/11] implement cleanup for old s3 files --- src/database/repository/mod_versions.rs | 8 ++--- src/s3_worker.rs | 43 ++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/src/database/repository/mod_versions.rs b/src/database/repository/mod_versions.rs index ec5f694..abd6a56 100644 --- a/src/database/repository/mod_versions.rs +++ b/src/database/repository/mod_versions.rs @@ -398,12 +398,8 @@ pub async fn update_managed_download_link( conn: &mut PgConnection, ) -> Result<(), DatabaseError> { sqlx::query!( - "UPDATE mod_versions - SET managed_download_link = $1, - updated_at = NOW() - WHERE id = $2", - link, - id + "UPDATE mod_versions SET managed_download_link = $1 WHERE id = $2", + link, id ) .execute(&mut *conn) .await diff --git a/src/s3_worker.rs b/src/s3_worker.rs index 99d8db2..f7a5ed8 100644 --- a/src/s3_worker.rs +++ b/src/s3_worker.rs @@ -53,7 +53,48 @@ async fn process_task(data: &AppData, task: S3WorkerTask) -> anyhow::Result<()> } async fn cleanup_old_s3_files(data: &AppData) -> anyhow::Result<()> { - // TODO + let supported_gd = GDVersionEnum::supported_for_storage(); + let storage = data.mod_storage().expect("mod storage must be set by now"); + + let mut db = data.db().acquire().await?; + + let versions = sqlx::query!( + "SELECT mv.id, mv.version, mv.managed_download_link, mv.mod_id FROM mod_versions mv + WHERE managed_download_link IS NOT NULL + AND mv.id NOT IN ( + SELECT DISTINCT ON (q.mv_id) q.mv_id FROM ( + SELECT DISTINCT ON (m.id, mgv.gd, mv.geode_major) m.id, mv.name, mv.version, mv.download_link, mv.managed_download_link, mv.id as mv_id, mgv.gd + FROM MODS m + INNER JOIN mod_versions mv ON m.id = mv.mod_id + INNER JOIN mod_version_statuses mvs ON mvs.mod_version_id = mv.id + INNER JOIN mod_gd_versions mgv ON mgv.mod_id = mv.id + WHERE mvs.status = 'accepted' AND mgv.gd = ANY($1::gd_version[]) + ORDER BY m.id, mgv.gd DESC, mv.geode_major DESC, mv.id DESC + ) q + ORDER BY q.mv_id + ) + ", + supported_gd as &[GDVersionEnum] + ) + .fetch_all(&mut *db) + .await?; + + tracing::info!("Cleaning up {} old S3 files", versions.len()); + + for record in versions { + let path = path_for_mod(&record.mod_id, &record.version); + if let Err(e) = storage.delete(&path).await { + tracing::error!("error deleting old S3 file for mod {} {} at {:?}: {e:?}", record.mod_id, record.version, record.managed_download_link); + continue; + } + + tracing::debug!("Deleted S3 file at path {}", path); + + let mut tx = data.db().begin().await?; + update_managed_download_link(record.id, None, &mut tx).await?; + tx.commit().await?; + } + Ok(()) } From 5d44dfd287c24db11b56be075800d972ae47a002 Mon Sep 17 00:00:00 2001 From: dankmeme01 <42031238+dankmeme01@users.noreply.github.com> Date: Sat, 18 Jul 2026 19:15:00 +0200 Subject: [PATCH 09/11] disable default features for rust s3 --- Cargo.lock | 156 ----------------------------------------------------- Cargo.toml | 2 +- 2 files changed, 1 insertion(+), 157 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6681761..e3f6a8a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -496,7 +496,6 @@ dependencies = [ "base64", "http 1.4.2", "log", - "native-tls", "rustls", "serde", "serde_json", @@ -732,15 +731,6 @@ dependencies = [ "libbz2-rs-sys", ] -[[package]] -name = "castaway" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" -dependencies = [ - "rustversion", -] - [[package]] name = "cc" version = "1.2.66" @@ -877,19 +867,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "compact_str" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f" -dependencies = [ - "castaway", - "cfg-if", - "itoa", - "ryu", - "static_assertions", -] - [[package]] name = "compression-codecs" version = "0.4.38" @@ -1437,21 +1414,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "form_urlencoded" version = "1.2.2" @@ -1912,22 +1874,6 @@ dependencies = [ "webpki-roots", ] -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - [[package]] name = "hyper-util" version = "0.1.20" @@ -2492,15 +2438,6 @@ dependencies = [ "unicase", ] -[[package]] -name = "minidom" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e394a0e3c7ccc2daea3dffabe82f09857b6b510cb25af87d54bf3e910ac1642d" -dependencies = [ - "rxml", -] - [[package]] name = "miniz_oxide" version = "0.8.9" @@ -2559,23 +2496,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e94e1e6445d314f972ff7395df2de295fe51b71821694f0b0e1e79c4f12c8577" -[[package]] -name = "native-tls" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - [[package]] name = "new_debug_unreachable" version = "1.0.6" @@ -2721,49 +2641,12 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" -[[package]] -name = "openssl" -version = "0.10.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77823a27f0babb03091cb9ed9ef80af3b39dbc82f97e8fa530374b7dafd87a45" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "openssl-probe" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" -[[package]] -name = "openssl-sys" -version = "0.9.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b47e7e6bb2c38cd930d25a23b40fa52e068c10e85f3e03a7f5ba5aaca5713695" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "ordered-multimap" version = "0.7.3" @@ -3338,11 +3221,9 @@ dependencies = [ "http-body-util", "hyper", "hyper-rustls", - "hyper-tls", "hyper-util", "js-sys", "log", - "native-tls", "percent-encoding", "pin-project-lite", "quinn", @@ -3353,7 +3234,6 @@ dependencies = [ "serde_urlencoded", "sync_wrapper", "tokio", - "tokio-native-tls", "tokio-rustls", "tokio-util", "tower", @@ -3489,7 +3369,6 @@ dependencies = [ "log", "maybe-async", "md5", - "minidom", "percent-encoding", "quick-xml", "reqwest 0.12.28", @@ -3616,25 +3495,6 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" -[[package]] -name = "rxml" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc94b580d0f5a6b7a2d604e597513d3c673154b52ddeccd1d5c32360d945ee" -dependencies = [ - "bytes", - "rxml_validation", -] - -[[package]] -name = "rxml_validation" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826e80413b9a35e9d33217b3dcac04cf95f6559d15944b93887a08be5496c4a4" -dependencies = [ - "compact_str", -] - [[package]] name = "ryu" version = "1.0.23" @@ -4097,12 +3957,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" -[[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.9.0" @@ -4359,16 +4213,6 @@ dependencies = [ "syn", ] -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - [[package]] name = "tokio-rustls" version = "0.26.4" diff --git a/Cargo.toml b/Cargo.toml index 801137b..84d3c06 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,7 +57,7 @@ uuid = { version = "1.8", features = ["v4", "fast-rng", "macro-diagnostics"] } validator = { version = "0.20.0", features = ["derive"] } zip = "8.6.0" # have to do this until https://github.com/durch/rust-s3/pull/452 is merged :( -rust-s3 = { git = "https://github.com/w4nderlust/rust-s3", rev = "2936eb7", features = ["tokio-rustls-tls"] } +rust-s3 = { git = "https://github.com/w4nderlust/rust-s3", rev = "2936eb7", default-features = false, features = ["tokio-rustls-tls", "fail-on-err"] } [target.'cfg(target_env = "musl")'.dependencies] mimalloc = "0.1.52" From 172814647d25a433bfa2b0f87d8c303b24a20f63 Mon Sep 17 00:00:00 2001 From: dankmeme01 <42031238+dankmeme01@users.noreply.github.com> Date: Sat, 18 Jul 2026 19:30:38 +0200 Subject: [PATCH 10/11] update queries --- ...79a58e0bae2d79af6c2b9e53ead7d9b6e214d.json | 32 +- ...853cb699faca7c34507e314ae5225b592ed87.json | 48 ++- ...ac1a75139bf9937a76d542e0fc3361fe156d1.json | 3 +- ...85b2bc796c64f42f15f078a5639f717aa21b9.json | 32 +- ...2d609e107196eca233278f827f11c242b6e38.json | 6 +- ...9bc6167fe80a2e7eae6c06390b92538347e33.json | 15 + ...73587610f5e01e75b3d205401623af7a94d65.json | 8 +- ...2525567231dc56cb1663c4e41aec26ffa6799.json | 144 -------- ...b076dc43adb58d626d76818d73fc3a762ba91.json | 24 +- ...1eb3d413d28283d97c0b9bfca6f4ca3c80256.json | 48 ++- ...084ef1440d4a166a1296bedf9529395272486.json | 48 ++- ...a757ad86edfe06094087b2654c9428a2469d6.json | 65 +++- ...700f96676190fca5b0a7e11eb036e523e33d5.json | 36 +- ...813b6e0ebb2708fe344fd8c3914bb5971d914.json | 93 +++++ ...66304005a571cd8871cc84b2010315c7d9692.json | 8 +- ...e630726cf78d354b586094b1ee8c16a6fe9ee.json | 324 ++++++++++++++++++ ...f2d290c453d70fb12bf4eb4f099f099f29aa4.json | 8 +- ...ba34475ebf9db478c8c1debeed64552bb6fd7.json | 228 ++++++++++++ ...dcef430294ba0e874ab1706115541f68828d1.json | 32 +- ...a387a44c47030bcac9aba859ed5080dcc165e.json | 38 +- ...dc7dd76adc19d954d73ca8c2d031813307aa2.json | 16 +- ...f54d36ff0819639c15a2e70d32dce65a39803.json | 32 +- ...780ef48dc808cdb2fe71ab1e9ed2c2ffcb3a6.json | 48 ++- ...83bb2398a64b23eed89a0746badb07eb73b1a.json | 32 +- ...8a49bc08edb530ebcb8a967747c881af4b5f5.json | 48 ++- ...fd7ab3f67d6d97529d862ba75dd01e6544f81.json | 72 +++- ...ed41b993407ae32bf0e90fbdd2c8ca3ea9d22.json | 32 +- ...2bd71dcb15053d899b6a8cd6cc75327d52bff.json | 38 +- ...d7633e0e322cb3895d7bcf347f35bf30169c7.json | 48 ++- ...ca08ae8f9144fed83971c3b1190ace209a9f5.json | 48 ++- ...741860b8b7658980ce348fadb9bf03e3cce03.json | 36 +- ...3cb5d8e3e4d1fcff129d2fbc897d3cd64c971.json | 8 +- ...6ff825e406eb44887480cb36801b054ed9051.json | 24 +- ...47ba12f948e60e815ad917846d7ff6733245a.json | 30 +- ...1add4ca9ea87043d8444d6db938a83f400f54.json | 16 +- ...52082349b104f6f50382325d4291ab10f3b82.json | 16 +- ...6299e3e19eee7b530be498c609e6cd6fc2b33.json | 32 +- ...e092e6de4a4e3189c0d86735f030bbb0a60b3.json | 8 +- ...cc3566512dc2273dc3b72ba1ba5c2d281aeb9.json | 3 +- ...d6b412b621e2cc3a5b63481643d7e90d05566.json | 28 +- ...aab11bb4b6634b7e6d9420097ec25faea4d8c.json | 217 ++++++++++++ ...56e16fa96998dc0cc1869ed06c84e567c6ff8.json | 124 ------- ...1a8b86519a68c061300278aaa58dcbe82b551.json | 88 +++++ ...daf4b82d907eba99837083e21909ea9c195a7.json | 48 ++- ...bc4cda1f108a749cc953adb9d25a2fffa4072.json | 48 ++- ...8fa38da224bae0ad16be16445bf210230e33e.json | 8 +- ...d1c5c88c27e43b9e0f19b8ed13d150bcd67d8.json | 173 ---------- ...27118f0a35841049fc0914add705241d471f6.json | 3 +- ...8247ea42f0f7c5f68391642480758ddf9b4bc.json | 8 +- ...70bcdc7112d9ad0d153aaad6bf7b00e27d74a.json | 56 ++- ...3bdd1268c75d03563eaf78eec41752cc1a491.json | 64 +++- ...a4a94573787ab881df61c69818b6c0435951c.json | 247 +++++++++++++ ...f635e70dd70cdafc327486aaa6a6f49e3c5db.json | 229 +++++++++++++ ...76dac05938b5b33b61f2667955ea1b5832d87.json | 32 +- ...e4e806b378409a148cb0728c03c70470954f5.json | 38 +- ...732ccafe10fe556de4659124e59abe8cd7552.json | 72 +++- ...05fef1f99e69979838e30f908f20244caba1d.json | 126 ------- ...f9ab2485fc07b1b3d47f5327b91c6fcb9a653.json | 28 +- ...db540c91edbc36c595ce8c6644bdb36a771c3.json | 8 +- ...c1d9343a95ff30a648d9c9b21120651a1caaa.json | 54 ++- ...4bcd78f595e7059cec91429fc0e734456bde1.json | 3 +- ...53947f6252f641ed3af00a17cb069440e9570.json | 8 +- ...fa22a00f19dca10f573b3f9331a830b0884d7.json | 11 +- ...42f6ee3f09ca365893cd95ff3821e1bb3a43b.json | 125 ------- ...b2593d77d4d24d6e2d9ba052ba4bf1cc6489d.json | 48 ++- ...c5bddac1f2347d7b1f4308478acf731e0145e.json | 8 +- ...00ce8d2cf76047bb0d1bb97b6e20c8d527224.json | 3 +- ...0ecfb1fb6315509f5002a3bfc6fd66c2f83f7.json | 112 +++++- ...b7a945863ec09c57e4165f9cd66888ab5405f.json | 32 +- ...fb3855ab4c697528a1b4ff8d074595ee82413.json | 96 +++++- ...dfa901fbbc2cc4c12fb3268d22aa0f6b76a64.json | 8 +- ...8a56617000567bfd04ed8f9be0e501f438937.json | 48 ++- ...9b90a0b101b5f2abf3e2c3acb2df18cf2d001.json | 36 +- ...256798593badec03e4a7507b4537ee50f1e6e.json | 24 +- ...11a909895fdc0e98541bed9816362862968f7.json | 30 +- ...5ba26571d4abff8f13b07b65707985e78ef82.json | 40 ++- ...e813fbc3f8d8f22fcaaeefa24cc1f97146bbe.json | 72 +++- ...6d9a3f8d0504dfdf1c18e9fc653468faa505a.json | 32 +- ...1b081128d2a2cf67057da0e4b726463ceb40a.json | 52 --- ...3fc091bfaab8ab9286c04c1bd4f83c91a68cb.json | 48 ++- ...0f4350aa059506c65c84df6445310feae9669.json | 48 ++- ...282dfd1dc2cb69bb9803e0a7a4d648239389f.json | 16 +- ...1fcc9f5ebe72d4948e0403ef5d488a9c8a370.json | 8 +- ...7588c3b0cd770f82b53fa2248cdbcbe2c8f49.json | 32 +- ...2cd380be6976024923abe0442430d20c8b0bd.json | 93 +++++ ...56a741fbad1d2e4682e1e748037bb08962912.json | 64 +++- ...7451a8fc46a5fd1114888b8a5d2ab42db1135.json | 8 +- ...c157560ec9d314947ea11c35f10a736a31684.json | 48 ++- ...98622b4e452c66855a4be5a749c1576b83c25.json | 8 +- 89 files changed, 3650 insertions(+), 1037 deletions(-) create mode 100644 .sqlx/query-0a9a3184f02328c15c2928ab6a39bc6167fe80a2e7eae6c06390b92538347e33.json delete mode 100644 .sqlx/query-1303aee56285c1870f8808999c22525567231dc56cb1663c4e41aec26ffa6799.json create mode 100644 .sqlx/query-270c2e5479f104bdb52357cedb9813b6e0ebb2708fe344fd8c3914bb5971d914.json create mode 100644 .sqlx/query-2894a3bf8b4f43496a3a1532ba1e630726cf78d354b586094b1ee8c16a6fe9ee.json create mode 100644 .sqlx/query-343cc93a2b99bed5e20d46ce54eba34475ebf9db478c8c1debeed64552bb6fd7.json create mode 100644 .sqlx/query-87c39e971df622c0ae622e37563aab11bb4b6634b7e6d9420097ec25faea4d8c.json delete mode 100644 .sqlx/query-880569e638c035da1f99ed07e9d56e16fa96998dc0cc1869ed06c84e567c6ff8.json create mode 100644 .sqlx/query-896ab2c695cc66255b9d168f59e1a8b86519a68c061300278aaa58dcbe82b551.json delete mode 100644 .sqlx/query-905ee0c060aad711f949eef40c3d1c5c88c27e43b9e0f19b8ed13d150bcd67d8.json create mode 100644 .sqlx/query-964d894336ec2b5381c454d50a8a4a94573787ab881df61c69818b6c0435951c.json create mode 100644 .sqlx/query-96f3e4f9ceffa7f3d9a609252d9f635e70dd70cdafc327486aaa6a6f49e3c5db.json delete mode 100644 .sqlx/query-a29dd2a2f869ef9fda4b366ee9005fef1f99e69979838e30f908f20244caba1d.json delete mode 100644 .sqlx/query-b520ba987e3979c769e9dab052e42f6ee3f09ca365893cd95ff3821e1bb3a43b.json delete mode 100644 .sqlx/query-e76119227a3fcb00348279467161b081128d2a2cf67057da0e4b726463ceb40a.json create mode 100644 .sqlx/query-f879d614ff765e840a2cc426e262cd380be6976024923abe0442430d20c8b0bd.json diff --git a/.sqlx/query-01959e9a4fdc1c6b0d9dbeff80c79a58e0bae2d79af6c2b9e53ead7d9b6e214d.json b/.sqlx/query-01959e9a4fdc1c6b0d9dbeff80c79a58e0bae2d79af6c2b9e53ead7d9b6e214d.json index 5ff525a..6c8bf7b 100644 --- a/.sqlx/query-01959e9a4fdc1c6b0d9dbeff80c79a58e0bae2d79af6c2b9e53ead7d9b6e214d.json +++ b/.sqlx/query-01959e9a4fdc1c6b0d9dbeff80c79a58e0bae2d79af6c2b9e53ead7d9b6e214d.json @@ -6,22 +6,46 @@ { "ordinal": 0, "name": "id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_tags", + "name": "id" + } + } }, { "ordinal": 1, "name": "name", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_tags", + "name": "name" + } + } }, { "ordinal": 2, "name": "display_name", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_tags", + "name": "display_name" + } + } }, { "ordinal": 3, "name": "is_readonly", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "mod_tags", + "name": "is_readonly" + } + } } ], "parameters": { diff --git a/.sqlx/query-0333e917f75fd481ec494abb6e2853cb699faca7c34507e314ae5225b592ed87.json b/.sqlx/query-0333e917f75fd481ec494abb6e2853cb699faca7c34507e314ae5225b592ed87.json index fe65757..3d12ae8 100644 --- a/.sqlx/query-0333e917f75fd481ec494abb6e2853cb699faca7c34507e314ae5225b592ed87.json +++ b/.sqlx/query-0333e917f75fd481ec494abb6e2853cb699faca7c34507e314ae5225b592ed87.json @@ -6,32 +6,68 @@ { "ordinal": 0, "name": "id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "developers", + "name": "id" + } + } }, { "ordinal": 1, "name": "username", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "developers", + "name": "username" + } + } }, { "ordinal": 2, "name": "display_name", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "developers", + "name": "display_name" + } + } }, { "ordinal": 3, "name": "verified", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "developers", + "name": "verified" + } + } }, { "ordinal": 4, "name": "admin", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "developers", + "name": "admin" + } + } }, { "ordinal": 5, "name": "github_id", - "type_info": "Int8" + "type_info": "Int8", + "origin": { + "Table": { + "table": "developers", + "name": "github_user_id" + } + } } ], "parameters": { diff --git a/.sqlx/query-0411ef36ab03892ea4fcf4bb8e7ac1a75139bf9937a76d542e0fc3361fe156d1.json b/.sqlx/query-0411ef36ab03892ea4fcf4bb8e7ac1a75139bf9937a76d542e0fc3361fe156d1.json index 0bb81ef..9e278c4 100644 --- a/.sqlx/query-0411ef36ab03892ea4fcf4bb8e7ac1a75139bf9937a76d542e0fc3361fe156d1.json +++ b/.sqlx/query-0411ef36ab03892ea4fcf4bb8e7ac1a75139bf9937a76d542e0fc3361fe156d1.json @@ -6,7 +6,8 @@ { "ordinal": 0, "name": "count", - "type_info": "Int8" + "type_info": "Int8", + "origin": "Expression" } ], "parameters": { diff --git a/.sqlx/query-0519d0d7c6d97ffbff763ba2d1c85b2bc796c64f42f15f078a5639f717aa21b9.json b/.sqlx/query-0519d0d7c6d97ffbff763ba2d1c85b2bc796c64f42f15f078a5639f717aa21b9.json index 0ceae2a..fb10ac6 100644 --- a/.sqlx/query-0519d0d7c6d97ffbff763ba2d1c85b2bc796c64f42f15f078a5639f717aa21b9.json +++ b/.sqlx/query-0519d0d7c6d97ffbff763ba2d1c85b2bc796c64f42f15f078a5639f717aa21b9.json @@ -6,22 +6,46 @@ { "ordinal": 0, "name": "id", - "type_info": "Int8" + "type_info": "Int8", + "origin": { + "Table": { + "table": "mod_version_submission_comment_attachments", + "name": "id" + } + } }, { "ordinal": 1, "name": "comment_id", - "type_info": "Int8" + "type_info": "Int8", + "origin": { + "Table": { + "table": "mod_version_submission_comment_attachments", + "name": "comment_id" + } + } }, { "ordinal": 2, "name": "filename", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_version_submission_comment_attachments", + "name": "filename" + } + } }, { "ordinal": 3, "name": "created_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_version_submission_comment_attachments", + "name": "created_at" + } + } } ], "parameters": { diff --git a/.sqlx/query-0a18d6fc5b51dc801d8e674590b2d609e107196eca233278f827f11c242b6e38.json b/.sqlx/query-0a18d6fc5b51dc801d8e674590b2d609e107196eca233278f827f11c242b6e38.json index c4f6546..09de68c 100644 --- a/.sqlx/query-0a18d6fc5b51dc801d8e674590b2d609e107196eca233278f827f11c242b6e38.json +++ b/.sqlx/query-0a18d6fc5b51dc801d8e674590b2d609e107196eca233278f827f11c242b6e38.json @@ -6,12 +6,14 @@ { "ordinal": 0, "name": "id_count", - "type_info": "Int8" + "type_info": "Int8", + "origin": "Expression" }, { "ordinal": 1, "name": "download_sum", - "type_info": "Int8" + "type_info": "Int8", + "origin": "Expression" } ], "parameters": { diff --git a/.sqlx/query-0a9a3184f02328c15c2928ab6a39bc6167fe80a2e7eae6c06390b92538347e33.json b/.sqlx/query-0a9a3184f02328c15c2928ab6a39bc6167fe80a2e7eae6c06390b92538347e33.json new file mode 100644 index 0000000..ff38696 --- /dev/null +++ b/.sqlx/query-0a9a3184f02328c15c2928ab6a39bc6167fe80a2e7eae6c06390b92538347e33.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE mod_versions SET managed_download_link = $1 WHERE id = $2", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Int4" + ] + }, + "nullable": [] + }, + "hash": "0a9a3184f02328c15c2928ab6a39bc6167fe80a2e7eae6c06390b92538347e33" +} diff --git a/.sqlx/query-0eed3c807b61381f067354bf1f573587610f5e01e75b3d205401623af7a94d65.json b/.sqlx/query-0eed3c807b61381f067354bf1f573587610f5e01e75b3d205401623af7a94d65.json index 2cf06ce..77e7fec 100644 --- a/.sqlx/query-0eed3c807b61381f067354bf1f573587610f5e01e75b3d205401623af7a94d65.json +++ b/.sqlx/query-0eed3c807b61381f067354bf1f573587610f5e01e75b3d205401623af7a94d65.json @@ -6,7 +6,13 @@ { "ordinal": 0, "name": "ip", - "type_info": "Inet" + "type_info": "Inet", + "origin": { + "Table": { + "table": "mod_downloads", + "name": "ip" + } + } } ], "parameters": { diff --git a/.sqlx/query-1303aee56285c1870f8808999c22525567231dc56cb1663c4e41aec26ffa6799.json b/.sqlx/query-1303aee56285c1870f8808999c22525567231dc56cb1663c4e41aec26ffa6799.json deleted file mode 100644 index 31521bf..0000000 --- a/.sqlx/query-1303aee56285c1870f8808999c22525567231dc56cb1663c4e41aec26ffa6799.json +++ /dev/null @@ -1,144 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "SELECT\n mv.id, mv.name, mv.description, mv.version,\n mv.download_link, mv.download_count, mv.hash,\n format_semver(mv.geode_major, mv.geode_minor, mv.geode_patch, mv.geode_meta) as \"geode!: _\",\n mv.early_load, mv.requires_patching, mv.api, mv.mod_id,\n mv.created_at, mv.updated_at,\n mvs.status as \"status: _\", mvs.info\n FROM mod_versions mv\n INNER JOIN mod_version_statuses mvs ON mvs.mod_version_id = mv.id\n WHERE mv.mod_id = $1\n AND ($2::mod_version_status[] IS NULL OR mvs.status = ANY($2))\n ORDER BY mv.id DESC", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "id", - "type_info": "Int4" - }, - { - "ordinal": 1, - "name": "name", - "type_info": "Text" - }, - { - "ordinal": 2, - "name": "description", - "type_info": "Text" - }, - { - "ordinal": 3, - "name": "version", - "type_info": "Text" - }, - { - "ordinal": 4, - "name": "download_link", - "type_info": "Text" - }, - { - "ordinal": 5, - "name": "download_count", - "type_info": "Int4" - }, - { - "ordinal": 6, - "name": "hash", - "type_info": "Text" - }, - { - "ordinal": 7, - "name": "geode!: _", - "type_info": "Text" - }, - { - "ordinal": 8, - "name": "early_load", - "type_info": "Bool" - }, - { - "ordinal": 9, - "name": "requires_patching", - "type_info": "Bool" - }, - { - "ordinal": 10, - "name": "api", - "type_info": "Bool" - }, - { - "ordinal": 11, - "name": "mod_id", - "type_info": "Text" - }, - { - "ordinal": 12, - "name": "created_at", - "type_info": "Timestamptz" - }, - { - "ordinal": 13, - "name": "updated_at", - "type_info": "Timestamptz" - }, - { - "ordinal": 14, - "name": "status: _", - "type_info": { - "Custom": { - "name": "mod_version_status", - "kind": { - "Enum": [ - "pending", - "rejected", - "accepted", - "unlisted" - ] - } - } - } - }, - { - "ordinal": 15, - "name": "info", - "type_info": "Text" - } - ], - "parameters": { - "Left": [ - "Text", - { - "Custom": { - "name": "mod_version_status[]", - "kind": { - "Array": { - "Custom": { - "name": "mod_version_status", - "kind": { - "Enum": [ - "pending", - "rejected", - "accepted", - "unlisted" - ] - } - } - } - } - } - } - ] - }, - "nullable": [ - false, - false, - true, - false, - false, - false, - false, - null, - false, - false, - false, - false, - true, - true, - false, - true - ] - }, - "hash": "1303aee56285c1870f8808999c22525567231dc56cb1663c4e41aec26ffa6799" -} diff --git a/.sqlx/query-181036cd0f64802504fe5025f18b076dc43adb58d626d76818d73fc3a762ba91.json b/.sqlx/query-181036cd0f64802504fe5025f18b076dc43adb58d626d76818d73fc3a762ba91.json index cbde480..67e736d 100644 --- a/.sqlx/query-181036cd0f64802504fe5025f18b076dc43adb58d626d76818d73fc3a762ba91.json +++ b/.sqlx/query-181036cd0f64802504fe5025f18b076dc43adb58d626d76818d73fc3a762ba91.json @@ -6,17 +6,35 @@ { "ordinal": 0, "name": "id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "deprecations", + "name": "id" + } + } }, { "ordinal": 1, "name": "mod_id", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "deprecations", + "name": "mod_id" + } + } }, { "ordinal": 2, "name": "reason", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "deprecations", + "name": "reason" + } + } } ], "parameters": { diff --git a/.sqlx/query-1ed87bd1d14f9c1febbb2a2a2d11eb3d413d28283d97c0b9bfca6f4ca3c80256.json b/.sqlx/query-1ed87bd1d14f9c1febbb2a2a2d11eb3d413d28283d97c0b9bfca6f4ca3c80256.json index 5651f29..c418db5 100644 --- a/.sqlx/query-1ed87bd1d14f9c1febbb2a2a2d11eb3d413d28283d97c0b9bfca6f4ca3c80256.json +++ b/.sqlx/query-1ed87bd1d14f9c1febbb2a2a2d11eb3d413d28283d97c0b9bfca6f4ca3c80256.json @@ -6,32 +6,68 @@ { "ordinal": 0, "name": "id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "developers", + "name": "id" + } + } }, { "ordinal": 1, "name": "username", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "developers", + "name": "username" + } + } }, { "ordinal": 2, "name": "display_name", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "developers", + "name": "display_name" + } + } }, { "ordinal": 3, "name": "verified", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "developers", + "name": "verified" + } + } }, { "ordinal": 4, "name": "admin", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "developers", + "name": "admin" + } + } }, { "ordinal": 5, "name": "github_id", - "type_info": "Int8" + "type_info": "Int8", + "origin": { + "Table": { + "table": "developers", + "name": "github_user_id" + } + } } ], "parameters": { diff --git a/.sqlx/query-1ee95124185a80b20fffcc2ca64084ef1440d4a166a1296bedf9529395272486.json b/.sqlx/query-1ee95124185a80b20fffcc2ca64084ef1440d4a166a1296bedf9529395272486.json index 5b67d13..edb322c 100644 --- a/.sqlx/query-1ee95124185a80b20fffcc2ca64084ef1440d4a166a1296bedf9529395272486.json +++ b/.sqlx/query-1ee95124185a80b20fffcc2ca64084ef1440d4a166a1296bedf9529395272486.json @@ -6,32 +6,68 @@ { "ordinal": 0, "name": "id", - "type_info": "Int8" + "type_info": "Int8", + "origin": { + "Table": { + "table": "mod_version_submission_comments", + "name": "id" + } + } }, { "ordinal": 1, "name": "submission_id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_version_submission_comments", + "name": "submission_id" + } + } }, { "ordinal": 2, "name": "comment", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_version_submission_comments", + "name": "comment" + } + } }, { "ordinal": 3, "name": "author_id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_version_submission_comments", + "name": "author_id" + } + } }, { "ordinal": 4, "name": "created_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_version_submission_comments", + "name": "created_at" + } + } }, { "ordinal": 5, "name": "updated_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_version_submission_comments", + "name": "updated_at" + } + } } ], "parameters": { diff --git a/.sqlx/query-20cc5dba1dbe11790912ff32e24a757ad86edfe06094087b2654c9428a2469d6.json b/.sqlx/query-20cc5dba1dbe11790912ff32e24a757ad86edfe06094087b2654c9428a2469d6.json index d157eb8..af0ceae 100644 --- a/.sqlx/query-20cc5dba1dbe11790912ff32e24a757ad86edfe06094087b2654c9428a2469d6.json +++ b/.sqlx/query-20cc5dba1dbe11790912ff32e24a757ad86edfe06094087b2654c9428a2469d6.json @@ -6,37 +6,79 @@ { "ordinal": 0, "name": "id", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mods", + "name": "id" + } + } }, { "ordinal": 1, "name": "featured", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "mods", + "name": "featured" + } + } }, { "ordinal": 2, "name": "mod_download_count", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mods", + "name": "download_count" + } + } }, { "ordinal": 3, "name": "name", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "name" + } + } }, { "ordinal": 4, "name": "version", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "version" + } + } }, { "ordinal": 5, "name": "mod_version_download_count", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_versions", + "name": "download_count" + } + } }, { "ordinal": 6, "name": "info", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_version_statuses", + "name": "info" + } + } }, { "ordinal": 7, @@ -53,12 +95,19 @@ ] } } + }, + "origin": { + "Table": { + "table": "mod_version_statuses", + "name": "status" + } } }, { "ordinal": 8, "name": "validated!: _", - "type_info": "Bool" + "type_info": "Bool", + "origin": "Expression" } ], "parameters": { diff --git a/.sqlx/query-25e42d6a179e920a58a6034b724700f96676190fca5b0a7e11eb036e523e33d5.json b/.sqlx/query-25e42d6a179e920a58a6034b724700f96676190fca5b0a7e11eb036e523e33d5.json index 52af53e..b474a14 100644 --- a/.sqlx/query-25e42d6a179e920a58a6034b724700f96676190fca5b0a7e11eb036e523e33d5.json +++ b/.sqlx/query-25e42d6a179e920a58a6034b724700f96676190fca5b0a7e11eb036e523e33d5.json @@ -6,17 +6,35 @@ { "ordinal": 0, "name": "mod_version_id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "dependencies", + "name": "dependent_id" + } + } }, { "ordinal": 1, "name": "dependency_id", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "dependencies", + "name": "dependency_id" + } + } }, { "ordinal": 2, "name": "version", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "dependencies", + "name": "version" + } + } }, { "ordinal": 3, @@ -34,6 +52,12 @@ ] } } + }, + "origin": { + "Table": { + "table": "dependencies", + "name": "compare" + } } }, { @@ -50,6 +74,12 @@ ] } } + }, + "origin": { + "Table": { + "table": "dependencies", + "name": "importance" + } } } ], diff --git a/.sqlx/query-270c2e5479f104bdb52357cedb9813b6e0ebb2708fe344fd8c3914bb5971d914.json b/.sqlx/query-270c2e5479f104bdb52357cedb9813b6e0ebb2708fe344fd8c3914bb5971d914.json new file mode 100644 index 0000000..9b7aaad --- /dev/null +++ b/.sqlx/query-270c2e5479f104bdb52357cedb9813b6e0ebb2708fe344fd8c3914bb5971d914.json @@ -0,0 +1,93 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT mv.id, mv.version, mv.managed_download_link, mv.mod_id FROM mod_versions mv\n WHERE managed_download_link IS NOT NULL\n AND mv.id NOT IN (\n SELECT DISTINCT ON (q.mv_id) q.mv_id FROM (\n SELECT DISTINCT ON (m.id, mgv.gd, mv.geode_major) m.id, mv.name, mv.version, mv.download_link, mv.managed_download_link, mv.id as mv_id, mgv.gd\n FROM MODS m\n INNER JOIN mod_versions mv ON m.id = mv.mod_id\n INNER JOIN mod_version_statuses mvs ON mvs.mod_version_id = mv.id\n INNER JOIN mod_gd_versions mgv ON mgv.mod_id = mv.id\n WHERE mvs.status = 'accepted' AND mgv.gd = ANY($1::gd_version[])\n ORDER BY m.id, mgv.gd DESC, mv.geode_major DESC, mv.id DESC\n ) q\n ORDER BY q.mv_id\n )\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_versions", + "name": "id" + } + } + }, + { + "ordinal": 1, + "name": "version", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "version" + } + } + }, + { + "ordinal": 2, + "name": "managed_download_link", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "managed_download_link" + } + } + }, + { + "ordinal": 3, + "name": "mod_id", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "mod_id" + } + } + } + ], + "parameters": { + "Left": [ + { + "Custom": { + "name": "gd_version[]", + "kind": { + "Array": { + "Custom": { + "name": "gd_version", + "kind": { + "Enum": [ + "*", + "2.113", + "2.200", + "2.204", + "2.205", + "2.206", + "2.207", + "2.2071", + "2.2072", + "2.2073", + "2.2074", + "2.208", + "2.2081", + "2.2082" + ] + } + } + } + } + } + } + ] + }, + "nullable": [ + false, + false, + true, + false + ] + }, + "hash": "270c2e5479f104bdb52357cedb9813b6e0ebb2708fe344fd8c3914bb5971d914" +} diff --git a/.sqlx/query-27c67f136d2f37a916b0bfb8d4966304005a571cd8871cc84b2010315c7d9692.json b/.sqlx/query-27c67f136d2f37a916b0bfb8d4966304005a571cd8871cc84b2010315c7d9692.json index a117b30..337a109 100644 --- a/.sqlx/query-27c67f136d2f37a916b0bfb8d4966304005a571cd8871cc84b2010315c7d9692.json +++ b/.sqlx/query-27c67f136d2f37a916b0bfb8d4966304005a571cd8871cc84b2010315c7d9692.json @@ -6,7 +6,13 @@ { "ordinal": 0, "name": "id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_versions", + "name": "id" + } + } } ], "parameters": { diff --git a/.sqlx/query-2894a3bf8b4f43496a3a1532ba1e630726cf78d354b586094b1ee8c16a6fe9ee.json b/.sqlx/query-2894a3bf8b4f43496a3a1532ba1e630726cf78d354b586094b1ee8c16a6fe9ee.json new file mode 100644 index 0000000..91dd8c2 --- /dev/null +++ b/.sqlx/query-2894a3bf8b4f43496a3a1532ba1e630726cf78d354b586094b1ee8c16a6fe9ee.json @@ -0,0 +1,324 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT\n m.id, m.repository, m.about, m.changelog, m.featured, m.download_count as mod_download_count, m.created_at, m.updated_at,\n mv.id as version_id, mv.name, mv.description, mv.version, mv.download_link, mv.managed_download_link,\n mv.download_count as mod_version_download_count, mv.created_at as mod_version_created_at, mv.updated_at as mod_version_updated_at, mv.hash,\n format_semver(mv.geode_major, mv.geode_minor, mv.geode_patch, mv.geode_meta) as \"geode!: _\",\n mv.early_load, mv.requires_patching, mv.api, mv.mod_id, mvs.status as \"status: _\", mvs.info\n FROM mods m\n INNER JOIN mod_versions mv ON m.id = mv.mod_id\n INNER JOIN mod_version_statuses mvs ON mvs.mod_version_id = mv.id\n WHERE m.id = $1\n AND ($2 = false OR mvs.status = 'accepted')\n ORDER BY mv.id DESC", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Text", + "origin": { + "Table": { + "table": "mods", + "name": "id" + } + } + }, + { + "ordinal": 1, + "name": "repository", + "type_info": "Text", + "origin": { + "Table": { + "table": "mods", + "name": "repository" + } + } + }, + { + "ordinal": 2, + "name": "about", + "type_info": "Text", + "origin": { + "Table": { + "table": "mods", + "name": "about" + } + } + }, + { + "ordinal": 3, + "name": "changelog", + "type_info": "Text", + "origin": { + "Table": { + "table": "mods", + "name": "changelog" + } + } + }, + { + "ordinal": 4, + "name": "featured", + "type_info": "Bool", + "origin": { + "Table": { + "table": "mods", + "name": "featured" + } + } + }, + { + "ordinal": 5, + "name": "mod_download_count", + "type_info": "Int4", + "origin": { + "Table": { + "table": "mods", + "name": "download_count" + } + } + }, + { + "ordinal": 6, + "name": "created_at", + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mods", + "name": "created_at" + } + } + }, + { + "ordinal": 7, + "name": "updated_at", + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mods", + "name": "updated_at" + } + } + }, + { + "ordinal": 8, + "name": "version_id", + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_versions", + "name": "id" + } + } + }, + { + "ordinal": 9, + "name": "name", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "name" + } + } + }, + { + "ordinal": 10, + "name": "description", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "description" + } + } + }, + { + "ordinal": 11, + "name": "version", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "version" + } + } + }, + { + "ordinal": 12, + "name": "download_link", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "download_link" + } + } + }, + { + "ordinal": 13, + "name": "managed_download_link", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "managed_download_link" + } + } + }, + { + "ordinal": 14, + "name": "mod_version_download_count", + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_versions", + "name": "download_count" + } + } + }, + { + "ordinal": 15, + "name": "mod_version_created_at", + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_versions", + "name": "created_at" + } + } + }, + { + "ordinal": 16, + "name": "mod_version_updated_at", + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_versions", + "name": "updated_at" + } + } + }, + { + "ordinal": 17, + "name": "hash", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "hash" + } + } + }, + { + "ordinal": 18, + "name": "geode!: _", + "type_info": "Text", + "origin": "Expression" + }, + { + "ordinal": 19, + "name": "early_load", + "type_info": "Bool", + "origin": { + "Table": { + "table": "mod_versions", + "name": "early_load" + } + } + }, + { + "ordinal": 20, + "name": "requires_patching", + "type_info": "Bool", + "origin": { + "Table": { + "table": "mod_versions", + "name": "requires_patching" + } + } + }, + { + "ordinal": 21, + "name": "api", + "type_info": "Bool", + "origin": { + "Table": { + "table": "mod_versions", + "name": "api" + } + } + }, + { + "ordinal": 22, + "name": "mod_id", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "mod_id" + } + } + }, + { + "ordinal": 23, + "name": "status: _", + "type_info": { + "Custom": { + "name": "mod_version_status", + "kind": { + "Enum": [ + "pending", + "rejected", + "accepted", + "unlisted" + ] + } + } + }, + "origin": { + "Table": { + "table": "mod_version_statuses", + "name": "status" + } + } + }, + { + "ordinal": 24, + "name": "info", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_version_statuses", + "name": "info" + } + } + } + ], + "parameters": { + "Left": [ + "Text", + "Bool" + ] + }, + "nullable": [ + false, + true, + true, + true, + false, + false, + false, + false, + false, + false, + true, + false, + false, + true, + false, + true, + true, + false, + null, + false, + false, + false, + false, + false, + true + ] + }, + "hash": "2894a3bf8b4f43496a3a1532ba1e630726cf78d354b586094b1ee8c16a6fe9ee" +} diff --git a/.sqlx/query-2b55fed2c473a9b2b249d9afcaff2d290c453d70fb12bf4eb4f099f099f29aa4.json b/.sqlx/query-2b55fed2c473a9b2b249d9afcaff2d290c453d70fb12bf4eb4f099f099f29aa4.json index bb020af..94d69b8 100644 --- a/.sqlx/query-2b55fed2c473a9b2b249d9afcaff2d290c453d70fb12bf4eb4f099f099f29aa4.json +++ b/.sqlx/query-2b55fed2c473a9b2b249d9afcaff2d290c453d70fb12bf4eb4f099f099f29aa4.json @@ -6,7 +6,13 @@ { "ordinal": 0, "name": "image", - "type_info": "Bytea" + "type_info": "Bytea", + "origin": { + "Table": { + "table": "mods", + "name": "image" + } + } } ], "parameters": { diff --git a/.sqlx/query-343cc93a2b99bed5e20d46ce54eba34475ebf9db478c8c1debeed64552bb6fd7.json b/.sqlx/query-343cc93a2b99bed5e20d46ce54eba34475ebf9db478c8c1debeed64552bb6fd7.json new file mode 100644 index 0000000..f41f7a7 --- /dev/null +++ b/.sqlx/query-343cc93a2b99bed5e20d46ce54eba34475ebf9db478c8c1debeed64552bb6fd7.json @@ -0,0 +1,228 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT\n mv.id, mv.name, mv.description, mv.version,\n mv.download_link, mv.managed_download_link, mv.download_count, mv.hash,\n format_semver(mv.geode_major, mv.geode_minor, mv.geode_patch, mv.geode_meta) as \"geode!: _\",\n mv.early_load, mv.requires_patching, mv.api, mv.mod_id,\n mv.created_at, mv.updated_at,\n mvs.status as \"status: _\", mvs.info\n FROM mod_versions mv\n INNER JOIN mod_version_statuses mvs ON mvs.mod_version_id = mv.id\n WHERE mv.mod_id = $1\n AND mv.version = $2", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_versions", + "name": "id" + } + } + }, + { + "ordinal": 1, + "name": "name", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "name" + } + } + }, + { + "ordinal": 2, + "name": "description", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "description" + } + } + }, + { + "ordinal": 3, + "name": "version", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "version" + } + } + }, + { + "ordinal": 4, + "name": "download_link", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "download_link" + } + } + }, + { + "ordinal": 5, + "name": "managed_download_link", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "managed_download_link" + } + } + }, + { + "ordinal": 6, + "name": "download_count", + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_versions", + "name": "download_count" + } + } + }, + { + "ordinal": 7, + "name": "hash", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "hash" + } + } + }, + { + "ordinal": 8, + "name": "geode!: _", + "type_info": "Text", + "origin": "Expression" + }, + { + "ordinal": 9, + "name": "early_load", + "type_info": "Bool", + "origin": { + "Table": { + "table": "mod_versions", + "name": "early_load" + } + } + }, + { + "ordinal": 10, + "name": "requires_patching", + "type_info": "Bool", + "origin": { + "Table": { + "table": "mod_versions", + "name": "requires_patching" + } + } + }, + { + "ordinal": 11, + "name": "api", + "type_info": "Bool", + "origin": { + "Table": { + "table": "mod_versions", + "name": "api" + } + } + }, + { + "ordinal": 12, + "name": "mod_id", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "mod_id" + } + } + }, + { + "ordinal": 13, + "name": "created_at", + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_versions", + "name": "created_at" + } + } + }, + { + "ordinal": 14, + "name": "updated_at", + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_versions", + "name": "updated_at" + } + } + }, + { + "ordinal": 15, + "name": "status: _", + "type_info": { + "Custom": { + "name": "mod_version_status", + "kind": { + "Enum": [ + "pending", + "rejected", + "accepted", + "unlisted" + ] + } + } + }, + "origin": { + "Table": { + "table": "mod_version_statuses", + "name": "status" + } + } + }, + { + "ordinal": 16, + "name": "info", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_version_statuses", + "name": "info" + } + } + } + ], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [ + false, + false, + true, + false, + false, + true, + false, + false, + null, + false, + false, + false, + false, + true, + true, + false, + true + ] + }, + "hash": "343cc93a2b99bed5e20d46ce54eba34475ebf9db478c8c1debeed64552bb6fd7" +} diff --git a/.sqlx/query-358511533c7ab481f97ffdf9bdbdcef430294ba0e874ab1706115541f68828d1.json b/.sqlx/query-358511533c7ab481f97ffdf9bdbdcef430294ba0e874ab1706115541f68828d1.json index b09cd5d..2b2120e 100644 --- a/.sqlx/query-358511533c7ab481f97ffdf9bdbdcef430294ba0e874ab1706115541f68828d1.json +++ b/.sqlx/query-358511533c7ab481f97ffdf9bdbdcef430294ba0e874ab1706115541f68828d1.json @@ -6,22 +6,46 @@ { "ordinal": 0, "name": "id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_tags", + "name": "id" + } + } }, { "ordinal": 1, "name": "name", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_tags", + "name": "name" + } + } }, { "ordinal": 2, "name": "display_name", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_tags", + "name": "display_name" + } + } }, { "ordinal": 3, "name": "is_readonly", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "mod_tags", + "name": "is_readonly" + } + } } ], "parameters": { diff --git a/.sqlx/query-3a9e0f2e4c810e63811251c2da5a387a44c47030bcac9aba859ed5080dcc165e.json b/.sqlx/query-3a9e0f2e4c810e63811251c2da5a387a44c47030bcac9aba859ed5080dcc165e.json index 04a238d..c2c4b57 100644 --- a/.sqlx/query-3a9e0f2e4c810e63811251c2da5a387a44c47030bcac9aba859ed5080dcc165e.json +++ b/.sqlx/query-3a9e0f2e4c810e63811251c2da5a387a44c47030bcac9aba859ed5080dcc165e.json @@ -6,7 +6,13 @@ { "ordinal": 0, "name": "mod_version_id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_version_submissions", + "name": "mod_version_id" + } + } }, { "ordinal": 1, @@ -22,22 +28,46 @@ ] } } + }, + "origin": { + "Table": { + "table": "mod_version_submissions", + "name": "lock" + } } }, { "ordinal": 2, "name": "locked_by", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_version_submissions", + "name": "locked_by" + } + } }, { "ordinal": 3, "name": "created_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_version_submissions", + "name": "created_at" + } + } }, { "ordinal": 4, "name": "updated_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_version_submissions", + "name": "updated_at" + } + } } ], "parameters": { diff --git a/.sqlx/query-3c81951bc3ef36210fce1b2bc89dc7dd76adc19d954d73ca8c2d031813307aa2.json b/.sqlx/query-3c81951bc3ef36210fce1b2bc89dc7dd76adc19d954d73ca8c2d031813307aa2.json index f383bb4..f195f4f 100644 --- a/.sqlx/query-3c81951bc3ef36210fce1b2bc89dc7dd76adc19d954d73ca8c2d031813307aa2.json +++ b/.sqlx/query-3c81951bc3ef36210fce1b2bc89dc7dd76adc19d954d73ca8c2d031813307aa2.json @@ -6,12 +6,24 @@ { "ordinal": 0, "name": "deprecation_id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "deprecated_by", + "name": "deprecation_id" + } + } }, { "ordinal": 1, "name": "by_mod_id", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "deprecated_by", + "name": "by_mod_id" + } + } } ], "parameters": { diff --git a/.sqlx/query-3e911a3e12f4d239c0d1a3185c7f54d36ff0819639c15a2e70d32dce65a39803.json b/.sqlx/query-3e911a3e12f4d239c0d1a3185c7f54d36ff0819639c15a2e70d32dce65a39803.json index 6ea2de4..94beeb7 100644 --- a/.sqlx/query-3e911a3e12f4d239c0d1a3185c7f54d36ff0819639c15a2e70d32dce65a39803.json +++ b/.sqlx/query-3e911a3e12f4d239c0d1a3185c7f54d36ff0819639c15a2e70d32dce65a39803.json @@ -6,22 +6,46 @@ { "ordinal": 0, "name": "id", - "type_info": "Int8" + "type_info": "Int8", + "origin": { + "Table": { + "table": "mod_version_submission_comment_attachments", + "name": "id" + } + } }, { "ordinal": 1, "name": "comment_id", - "type_info": "Int8" + "type_info": "Int8", + "origin": { + "Table": { + "table": "mod_version_submission_comment_attachments", + "name": "comment_id" + } + } }, { "ordinal": 2, "name": "filename", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_version_submission_comment_attachments", + "name": "filename" + } + } }, { "ordinal": 3, "name": "created_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_version_submission_comment_attachments", + "name": "created_at" + } + } } ], "parameters": { diff --git a/.sqlx/query-413daf884b398b94a5c9731618c780ef48dc808cdb2fe71ab1e9ed2c2ffcb3a6.json b/.sqlx/query-413daf884b398b94a5c9731618c780ef48dc808cdb2fe71ab1e9ed2c2ffcb3a6.json index 8afe8fe..cf9662f 100644 --- a/.sqlx/query-413daf884b398b94a5c9731618c780ef48dc808cdb2fe71ab1e9ed2c2ffcb3a6.json +++ b/.sqlx/query-413daf884b398b94a5c9731618c780ef48dc808cdb2fe71ab1e9ed2c2ffcb3a6.json @@ -6,32 +6,68 @@ { "ordinal": 0, "name": "id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "developers", + "name": "id" + } + } }, { "ordinal": 1, "name": "username", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "developers", + "name": "username" + } + } }, { "ordinal": 2, "name": "display_name", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "developers", + "name": "display_name" + } + } }, { "ordinal": 3, "name": "verified", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "developers", + "name": "verified" + } + } }, { "ordinal": 4, "name": "admin", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "developers", + "name": "admin" + } + } }, { "ordinal": 5, "name": "github_id", - "type_info": "Int8" + "type_info": "Int8", + "origin": { + "Table": { + "table": "developers", + "name": "github_user_id" + } + } } ], "parameters": { diff --git a/.sqlx/query-4250be7721057fee9a8fdbb9ab083bb2398a64b23eed89a0746badb07eb73b1a.json b/.sqlx/query-4250be7721057fee9a8fdbb9ab083bb2398a64b23eed89a0746badb07eb73b1a.json index f0fb381..1ff60f7 100644 --- a/.sqlx/query-4250be7721057fee9a8fdbb9ab083bb2398a64b23eed89a0746badb07eb73b1a.json +++ b/.sqlx/query-4250be7721057fee9a8fdbb9ab083bb2398a64b23eed89a0746badb07eb73b1a.json @@ -6,22 +6,46 @@ { "ordinal": 0, "name": "mod_id", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_links", + "name": "mod_id" + } + } }, { "ordinal": 1, "name": "community", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_links", + "name": "community" + } + } }, { "ordinal": 2, "name": "homepage", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_links", + "name": "homepage" + } + } }, { "ordinal": 3, "name": "source", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_links", + "name": "source" + } + } } ], "parameters": { diff --git a/.sqlx/query-4289772ae34ff1b1fe1c212bd8a8a49bc08edb530ebcb8a967747c881af4b5f5.json b/.sqlx/query-4289772ae34ff1b1fe1c212bd8a8a49bc08edb530ebcb8a967747c881af4b5f5.json index cdc7cb5..2e018ca 100644 --- a/.sqlx/query-4289772ae34ff1b1fe1c212bd8a8a49bc08edb530ebcb8a967747c881af4b5f5.json +++ b/.sqlx/query-4289772ae34ff1b1fe1c212bd8a8a49bc08edb530ebcb8a967747c881af4b5f5.json @@ -6,32 +6,68 @@ { "ordinal": 0, "name": "id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "developers", + "name": "id" + } + } }, { "ordinal": 1, "name": "username", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "developers", + "name": "username" + } + } }, { "ordinal": 2, "name": "display_name", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "developers", + "name": "display_name" + } + } }, { "ordinal": 3, "name": "verified", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "developers", + "name": "verified" + } + } }, { "ordinal": 4, "name": "admin", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "developers", + "name": "admin" + } + } }, { "ordinal": 5, "name": "github_id", - "type_info": "Int8" + "type_info": "Int8", + "origin": { + "Table": { + "table": "developers", + "name": "github_user_id" + } + } } ], "parameters": { diff --git a/.sqlx/query-4a624bdb7a8320e4cb18a9e955bfd7ab3f67d6d97529d862ba75dd01e6544f81.json b/.sqlx/query-4a624bdb7a8320e4cb18a9e955bfd7ab3f67d6d97529d862ba75dd01e6544f81.json index bb4e48d..eb8caad 100644 --- a/.sqlx/query-4a624bdb7a8320e4cb18a9e955bfd7ab3f67d6d97529d862ba75dd01e6544f81.json +++ b/.sqlx/query-4a624bdb7a8320e4cb18a9e955bfd7ab3f67d6d97529d862ba75dd01e6544f81.json @@ -6,47 +6,101 @@ { "ordinal": 0, "name": "uuid", - "type_info": "Uuid" + "type_info": "Uuid", + "origin": { + "Table": { + "table": "github_login_attempts", + "name": "uid" + } + } }, { "ordinal": 1, "name": "ip", - "type_info": "Inet" + "type_info": "Inet", + "origin": { + "Table": { + "table": "github_login_attempts", + "name": "ip" + } + } }, { "ordinal": 2, "name": "interval", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "github_login_attempts", + "name": "interval" + } + } }, { "ordinal": 3, "name": "expires_in", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "github_login_attempts", + "name": "expires_in" + } + } }, { "ordinal": 4, "name": "created_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "github_login_attempts", + "name": "created_at" + } + } }, { "ordinal": 5, "name": "last_poll", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "github_login_attempts", + "name": "last_poll" + } + } }, { "ordinal": 6, "name": "uri", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "github_login_attempts", + "name": "challenge_uri" + } + } }, { "ordinal": 7, "name": "device_code", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "github_login_attempts", + "name": "device_code" + } + } }, { "ordinal": 8, "name": "user_code", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "github_login_attempts", + "name": "user_code" + } + } } ], "parameters": { diff --git a/.sqlx/query-4ad2b61d2fa7a7edc9ec5ec68eaed41b993407ae32bf0e90fbdd2c8ca3ea9d22.json b/.sqlx/query-4ad2b61d2fa7a7edc9ec5ec68eaed41b993407ae32bf0e90fbdd2c8ca3ea9d22.json index 4d84f0d..46e9373 100644 --- a/.sqlx/query-4ad2b61d2fa7a7edc9ec5ec68eaed41b993407ae32bf0e90fbdd2c8ca3ea9d22.json +++ b/.sqlx/query-4ad2b61d2fa7a7edc9ec5ec68eaed41b993407ae32bf0e90fbdd2c8ca3ea9d22.json @@ -6,22 +6,46 @@ { "ordinal": 0, "name": "id", - "type_info": "Int8" + "type_info": "Int8", + "origin": { + "Table": { + "table": "mod_version_submission_comment_attachments", + "name": "id" + } + } }, { "ordinal": 1, "name": "comment_id", - "type_info": "Int8" + "type_info": "Int8", + "origin": { + "Table": { + "table": "mod_version_submission_comment_attachments", + "name": "comment_id" + } + } }, { "ordinal": 2, "name": "filename", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_version_submission_comment_attachments", + "name": "filename" + } + } }, { "ordinal": 3, "name": "created_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_version_submission_comment_attachments", + "name": "created_at" + } + } } ], "parameters": { diff --git a/.sqlx/query-5687bf51d606c491a75a05ffed72bd71dcb15053d899b6a8cd6cc75327d52bff.json b/.sqlx/query-5687bf51d606c491a75a05ffed72bd71dcb15053d899b6a8cd6cc75327d52bff.json index 606c83e..13c40aa 100644 --- a/.sqlx/query-5687bf51d606c491a75a05ffed72bd71dcb15053d899b6a8cd6cc75327d52bff.json +++ b/.sqlx/query-5687bf51d606c491a75a05ffed72bd71dcb15053d899b6a8cd6cc75327d52bff.json @@ -6,7 +6,13 @@ { "ordinal": 0, "name": "mod_version_id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_version_submissions", + "name": "mod_version_id" + } + } }, { "ordinal": 1, @@ -22,22 +28,46 @@ ] } } + }, + "origin": { + "Table": { + "table": "mod_version_submissions", + "name": "lock" + } } }, { "ordinal": 2, "name": "locked_by", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_version_submissions", + "name": "locked_by" + } + } }, { "ordinal": 3, "name": "created_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_version_submissions", + "name": "created_at" + } + } }, { "ordinal": 4, "name": "updated_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_version_submissions", + "name": "updated_at" + } + } } ], "parameters": { diff --git a/.sqlx/query-58d1a6eafbfe3aaf8836459f8a9d7633e0e322cb3895d7bcf347f35bf30169c7.json b/.sqlx/query-58d1a6eafbfe3aaf8836459f8a9d7633e0e322cb3895d7bcf347f35bf30169c7.json index a7d7c08..64c91c1 100644 --- a/.sqlx/query-58d1a6eafbfe3aaf8836459f8a9d7633e0e322cb3895d7bcf347f35bf30169c7.json +++ b/.sqlx/query-58d1a6eafbfe3aaf8836459f8a9d7633e0e322cb3895d7bcf347f35bf30169c7.json @@ -6,32 +6,68 @@ { "ordinal": 0, "name": "id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "developers", + "name": "id" + } + } }, { "ordinal": 1, "name": "username", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "developers", + "name": "username" + } + } }, { "ordinal": 2, "name": "display_name", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "developers", + "name": "display_name" + } + } }, { "ordinal": 3, "name": "verified", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "developers", + "name": "verified" + } + } }, { "ordinal": 4, "name": "admin", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "developers", + "name": "admin" + } + } }, { "ordinal": 5, "name": "github_id", - "type_info": "Int8" + "type_info": "Int8", + "origin": { + "Table": { + "table": "developers", + "name": "github_user_id" + } + } } ], "parameters": { diff --git a/.sqlx/query-5e73a555131f87c514751236ad5ca08ae8f9144fed83971c3b1190ace209a9f5.json b/.sqlx/query-5e73a555131f87c514751236ad5ca08ae8f9144fed83971c3b1190ace209a9f5.json index e86f244..bbfcfe7 100644 --- a/.sqlx/query-5e73a555131f87c514751236ad5ca08ae8f9144fed83971c3b1190ace209a9f5.json +++ b/.sqlx/query-5e73a555131f87c514751236ad5ca08ae8f9144fed83971c3b1190ace209a9f5.json @@ -6,32 +6,68 @@ { "ordinal": 0, "name": "id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "developers", + "name": "id" + } + } }, { "ordinal": 1, "name": "username", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "developers", + "name": "username" + } + } }, { "ordinal": 2, "name": "display_name", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "developers", + "name": "display_name" + } + } }, { "ordinal": 3, "name": "verified", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "developers", + "name": "verified" + } + } }, { "ordinal": 4, "name": "admin", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "developers", + "name": "admin" + } + } }, { "ordinal": 5, "name": "github_id", - "type_info": "Int8" + "type_info": "Int8", + "origin": { + "Table": { + "table": "developers", + "name": "github_user_id" + } + } } ], "parameters": { diff --git a/.sqlx/query-6589899a5fb9ef87d704598a7ab741860b8b7658980ce348fadb9bf03e3cce03.json b/.sqlx/query-6589899a5fb9ef87d704598a7ab741860b8b7658980ce348fadb9bf03e3cce03.json index 24bcc1a..af1dece 100644 --- a/.sqlx/query-6589899a5fb9ef87d704598a7ab741860b8b7658980ce348fadb9bf03e3cce03.json +++ b/.sqlx/query-6589899a5fb9ef87d704598a7ab741860b8b7658980ce348fadb9bf03e3cce03.json @@ -6,17 +6,35 @@ { "ordinal": 0, "name": "mod_id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "incompatibilities", + "name": "mod_id" + } + } }, { "ordinal": 1, "name": "incompatibility_id", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "incompatibilities", + "name": "incompatibility_id" + } + } }, { "ordinal": 2, "name": "version", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "incompatibilities", + "name": "version" + } + } }, { "ordinal": 3, @@ -34,6 +52,12 @@ ] } } + }, + "origin": { + "Table": { + "table": "incompatibilities", + "name": "compare" + } } }, { @@ -51,6 +75,12 @@ ] } } + }, + "origin": { + "Table": { + "table": "incompatibilities", + "name": "importance" + } } } ], diff --git a/.sqlx/query-6b9a4fc83126ec8a512b825b3183cb5d8e3e4d1fcff129d2fbc897d3cd64c971.json b/.sqlx/query-6b9a4fc83126ec8a512b825b3183cb5d8e3e4d1fcff129d2fbc897d3cd64c971.json index 7023eea..5178bc8 100644 --- a/.sqlx/query-6b9a4fc83126ec8a512b825b3183cb5d8e3e4d1fcff129d2fbc897d3cd64c971.json +++ b/.sqlx/query-6b9a4fc83126ec8a512b825b3183cb5d8e3e4d1fcff129d2fbc897d3cd64c971.json @@ -6,7 +6,13 @@ { "ordinal": 0, "name": "developer_id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mods_developers", + "name": "developer_id" + } + } } ], "parameters": { diff --git a/.sqlx/query-6bc0d557eeaf39e217f8cb77b446ff825e406eb44887480cb36801b054ed9051.json b/.sqlx/query-6bc0d557eeaf39e217f8cb77b446ff825e406eb44887480cb36801b054ed9051.json index e52f4d4..51bc5c7 100644 --- a/.sqlx/query-6bc0d557eeaf39e217f8cb77b446ff825e406eb44887480cb36801b054ed9051.json +++ b/.sqlx/query-6bc0d557eeaf39e217f8cb77b446ff825e406eb44887480cb36801b054ed9051.json @@ -6,17 +6,35 @@ { "ordinal": 0, "name": "id", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mods", + "name": "id" + } + } }, { "ordinal": 1, "name": "version", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "version" + } + } }, { "ordinal": 2, "name": "mod_version_id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_versions", + "name": "id" + } + } } ], "parameters": { diff --git a/.sqlx/query-6be04be9bbf53814144d17355ba47ba12f948e60e815ad917846d7ff6733245a.json b/.sqlx/query-6be04be9bbf53814144d17355ba47ba12f948e60e815ad917846d7ff6733245a.json index 3df40f2..0a4751c 100644 --- a/.sqlx/query-6be04be9bbf53814144d17355ba47ba12f948e60e815ad917846d7ff6733245a.json +++ b/.sqlx/query-6be04be9bbf53814144d17355ba47ba12f948e60e815ad917846d7ff6733245a.json @@ -18,22 +18,46 @@ ] } } + }, + "origin": { + "Table": { + "table": "mod_version_submissions_audit", + "name": "action" + } } }, { "ordinal": 1, "name": "details", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_version_submissions_audit", + "name": "details" + } + } }, { "ordinal": 2, "name": "performed_by", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_version_submissions_audit", + "name": "performed_by" + } + } }, { "ordinal": 3, "name": "performed_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_version_submissions_audit", + "name": "performed_at" + } + } } ], "parameters": { diff --git a/.sqlx/query-6c237ee29dee664dabe8175e9d81add4ca9ea87043d8444d6db938a83f400f54.json b/.sqlx/query-6c237ee29dee664dabe8175e9d81add4ca9ea87043d8444d6db938a83f400f54.json index 73e1b99..c474d10 100644 --- a/.sqlx/query-6c237ee29dee664dabe8175e9d81add4ca9ea87043d8444d6db938a83f400f54.json +++ b/.sqlx/query-6c237ee29dee664dabe8175e9d81add4ca9ea87043d8444d6db938a83f400f54.json @@ -6,12 +6,24 @@ { "ordinal": 0, "name": "id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_tags", + "name": "id" + } + } }, { "ordinal": 1, "name": "name", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_tags", + "name": "name" + } + } } ], "parameters": { diff --git a/.sqlx/query-74a8ad8da9121d864db3b38a0df52082349b104f6f50382325d4291ab10f3b82.json b/.sqlx/query-74a8ad8da9121d864db3b38a0df52082349b104f6f50382325d4291ab10f3b82.json index e2de993..edf78f7 100644 --- a/.sqlx/query-74a8ad8da9121d864db3b38a0df52082349b104f6f50382325d4291ab10f3b82.json +++ b/.sqlx/query-74a8ad8da9121d864db3b38a0df52082349b104f6f50382325d4291ab10f3b82.json @@ -6,12 +6,24 @@ { "ordinal": 0, "name": "name", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_tags", + "name": "name" + } + } }, { "ordinal": 1, "name": "mod_id", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mods_mod_tags", + "name": "mod_id" + } + } } ], "parameters": { diff --git a/.sqlx/query-75645a63e093cdaadb0ba84844e6299e3e19eee7b530be498c609e6cd6fc2b33.json b/.sqlx/query-75645a63e093cdaadb0ba84844e6299e3e19eee7b530be498c609e6cd6fc2b33.json index 0b4f393..9c37b09 100644 --- a/.sqlx/query-75645a63e093cdaadb0ba84844e6299e3e19eee7b530be498c609e6cd6fc2b33.json +++ b/.sqlx/query-75645a63e093cdaadb0ba84844e6299e3e19eee7b530be498c609e6cd6fc2b33.json @@ -6,22 +6,46 @@ { "ordinal": 0, "name": "id", - "type_info": "Int8" + "type_info": "Int8", + "origin": { + "Table": { + "table": "mod_version_submission_comment_attachments", + "name": "id" + } + } }, { "ordinal": 1, "name": "comment_id", - "type_info": "Int8" + "type_info": "Int8", + "origin": { + "Table": { + "table": "mod_version_submission_comment_attachments", + "name": "comment_id" + } + } }, { "ordinal": 2, "name": "filename", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_version_submission_comment_attachments", + "name": "filename" + } + } }, { "ordinal": 3, "name": "created_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_version_submission_comment_attachments", + "name": "created_at" + } + } } ], "parameters": { diff --git a/.sqlx/query-79c07336d3e245d46e7e07e0e32e092e6de4a4e3189c0d86735f030bbb0a60b3.json b/.sqlx/query-79c07336d3e245d46e7e07e0e32e092e6de4a4e3189c0d86735f030bbb0a60b3.json index ce3fdde..f0b6f34 100644 --- a/.sqlx/query-79c07336d3e245d46e7e07e0e32e092e6de4a4e3189c0d86735f030bbb0a60b3.json +++ b/.sqlx/query-79c07336d3e245d46e7e07e0e32e092e6de4a4e3189c0d86735f030bbb0a60b3.json @@ -6,7 +6,13 @@ { "ordinal": 0, "name": "id", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mods", + "name": "id" + } + } } ], "parameters": { diff --git a/.sqlx/query-7a9ffa7b59f3550e2bd38c756b9cc3566512dc2273dc3b72ba1ba5c2d281aeb9.json b/.sqlx/query-7a9ffa7b59f3550e2bd38c756b9cc3566512dc2273dc3b72ba1ba5c2d281aeb9.json index 568b54b..d4e9d44 100644 --- a/.sqlx/query-7a9ffa7b59f3550e2bd38c756b9cc3566512dc2273dc3b72ba1ba5c2d281aeb9.json +++ b/.sqlx/query-7a9ffa7b59f3550e2bd38c756b9cc3566512dc2273dc3b72ba1ba5c2d281aeb9.json @@ -6,7 +6,8 @@ { "ordinal": 0, "name": "count", - "type_info": "Int8" + "type_info": "Int8", + "origin": "Expression" } ], "parameters": { diff --git a/.sqlx/query-7d171a79184b68e491ed200d347d6b412b621e2cc3a5b63481643d7e90d05566.json b/.sqlx/query-7d171a79184b68e491ed200d347d6b412b621e2cc3a5b63481643d7e90d05566.json index 4fb2fb6..60dc112 100644 --- a/.sqlx/query-7d171a79184b68e491ed200d347d6b412b621e2cc3a5b63481643d7e90d05566.json +++ b/.sqlx/query-7d171a79184b68e491ed200d347d6b412b621e2cc3a5b63481643d7e90d05566.json @@ -6,12 +6,24 @@ { "ordinal": 0, "name": "id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_gd_versions", + "name": "id" + } + } }, { "ordinal": 1, "name": "mod_id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_gd_versions", + "name": "mod_id" + } + } }, { "ordinal": 2, @@ -38,6 +50,12 @@ ] } } + }, + "origin": { + "Table": { + "table": "mod_gd_versions", + "name": "gd" + } } }, { @@ -57,6 +75,12 @@ ] } } + }, + "origin": { + "Table": { + "table": "mod_gd_versions", + "name": "platform" + } } } ], diff --git a/.sqlx/query-87c39e971df622c0ae622e37563aab11bb4b6634b7e6d9420097ec25faea4d8c.json b/.sqlx/query-87c39e971df622c0ae622e37563aab11bb4b6634b7e6d9420097ec25faea4d8c.json new file mode 100644 index 0000000..7b5bf4c --- /dev/null +++ b/.sqlx/query-87c39e971df622c0ae622e37563aab11bb4b6634b7e6d9420097ec25faea4d8c.json @@ -0,0 +1,217 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT DISTINCT\n mv.name, mv.id, mv.description, mv.version, mv.download_link, mv.managed_download_link, mv.hash,\n format_semver(mv.geode_major, mv.geode_minor, mv.geode_patch, mv.geode_meta) as \"geode!: _\",\n mv.download_count, mv.early_load, mv.requires_patching, mv.api, mv.mod_id, mv.created_at, mv.updated_at,\n 'pending'::mod_version_status as \"status!: _\", NULL as info\n FROM mod_versions mv\n INNER JOIN mod_version_statuses mvs ON mvs.mod_version_id = mv.id\n WHERE mvs.status = 'pending'\n AND mv.mod_id = ANY($1)\n ORDER BY mv.id DESC", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "name", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "name" + } + } + }, + { + "ordinal": 1, + "name": "id", + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_versions", + "name": "id" + } + } + }, + { + "ordinal": 2, + "name": "description", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "description" + } + } + }, + { + "ordinal": 3, + "name": "version", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "version" + } + } + }, + { + "ordinal": 4, + "name": "download_link", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "download_link" + } + } + }, + { + "ordinal": 5, + "name": "managed_download_link", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "managed_download_link" + } + } + }, + { + "ordinal": 6, + "name": "hash", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "hash" + } + } + }, + { + "ordinal": 7, + "name": "geode!: _", + "type_info": "Text", + "origin": "Expression" + }, + { + "ordinal": 8, + "name": "download_count", + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_versions", + "name": "download_count" + } + } + }, + { + "ordinal": 9, + "name": "early_load", + "type_info": "Bool", + "origin": { + "Table": { + "table": "mod_versions", + "name": "early_load" + } + } + }, + { + "ordinal": 10, + "name": "requires_patching", + "type_info": "Bool", + "origin": { + "Table": { + "table": "mod_versions", + "name": "requires_patching" + } + } + }, + { + "ordinal": 11, + "name": "api", + "type_info": "Bool", + "origin": { + "Table": { + "table": "mod_versions", + "name": "api" + } + } + }, + { + "ordinal": 12, + "name": "mod_id", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "mod_id" + } + } + }, + { + "ordinal": 13, + "name": "created_at", + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_versions", + "name": "created_at" + } + } + }, + { + "ordinal": 14, + "name": "updated_at", + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_versions", + "name": "updated_at" + } + } + }, + { + "ordinal": 15, + "name": "status!: _", + "type_info": { + "Custom": { + "name": "mod_version_status", + "kind": { + "Enum": [ + "pending", + "rejected", + "accepted", + "unlisted" + ] + } + } + }, + "origin": "Expression" + }, + { + "ordinal": 16, + "name": "info", + "type_info": "Text", + "origin": "Expression" + } + ], + "parameters": { + "Left": [ + "TextArray" + ] + }, + "nullable": [ + false, + false, + true, + false, + false, + true, + false, + null, + false, + false, + false, + false, + false, + true, + true, + null, + null + ] + }, + "hash": "87c39e971df622c0ae622e37563aab11bb4b6634b7e6d9420097ec25faea4d8c" +} diff --git a/.sqlx/query-880569e638c035da1f99ed07e9d56e16fa96998dc0cc1869ed06c84e567c6ff8.json b/.sqlx/query-880569e638c035da1f99ed07e9d56e16fa96998dc0cc1869ed06c84e567c6ff8.json deleted file mode 100644 index ed52e71..0000000 --- a/.sqlx/query-880569e638c035da1f99ed07e9d56e16fa96998dc0cc1869ed06c84e567c6ff8.json +++ /dev/null @@ -1,124 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "SELECT DISTINCT\n mv.name, mv.id, mv.description, mv.version, mv.download_link, mv.hash,\n format_semver(mv.geode_major, mv.geode_minor, mv.geode_patch, mv.geode_meta) as \"geode!: _\",\n mv.download_count, mv.early_load, mv.requires_patching, mv.api, mv.mod_id, mv.created_at, mv.updated_at,\n 'pending'::mod_version_status as \"status!: _\", NULL as info\n FROM mod_versions mv\n INNER JOIN mod_version_statuses mvs ON mvs.mod_version_id = mv.id\n WHERE mvs.status = 'pending'\n AND mv.mod_id = ANY($1)\n ORDER BY mv.id DESC", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "name", - "type_info": "Text" - }, - { - "ordinal": 1, - "name": "id", - "type_info": "Int4" - }, - { - "ordinal": 2, - "name": "description", - "type_info": "Text" - }, - { - "ordinal": 3, - "name": "version", - "type_info": "Text" - }, - { - "ordinal": 4, - "name": "download_link", - "type_info": "Text" - }, - { - "ordinal": 5, - "name": "hash", - "type_info": "Text" - }, - { - "ordinal": 6, - "name": "geode!: _", - "type_info": "Text" - }, - { - "ordinal": 7, - "name": "download_count", - "type_info": "Int4" - }, - { - "ordinal": 8, - "name": "early_load", - "type_info": "Bool" - }, - { - "ordinal": 9, - "name": "requires_patching", - "type_info": "Bool" - }, - { - "ordinal": 10, - "name": "api", - "type_info": "Bool" - }, - { - "ordinal": 11, - "name": "mod_id", - "type_info": "Text" - }, - { - "ordinal": 12, - "name": "created_at", - "type_info": "Timestamptz" - }, - { - "ordinal": 13, - "name": "updated_at", - "type_info": "Timestamptz" - }, - { - "ordinal": 14, - "name": "status!: _", - "type_info": { - "Custom": { - "name": "mod_version_status", - "kind": { - "Enum": [ - "pending", - "rejected", - "accepted", - "unlisted" - ] - } - } - } - }, - { - "ordinal": 15, - "name": "info", - "type_info": "Text" - } - ], - "parameters": { - "Left": [ - "TextArray" - ] - }, - "nullable": [ - false, - false, - true, - false, - false, - false, - null, - false, - false, - false, - false, - false, - true, - true, - null, - null - ] - }, - "hash": "880569e638c035da1f99ed07e9d56e16fa96998dc0cc1869ed06c84e567c6ff8" -} diff --git a/.sqlx/query-896ab2c695cc66255b9d168f59e1a8b86519a68c061300278aaa58dcbe82b551.json b/.sqlx/query-896ab2c695cc66255b9d168f59e1a8b86519a68c061300278aaa58dcbe82b551.json new file mode 100644 index 0000000..454420a --- /dev/null +++ b/.sqlx/query-896ab2c695cc66255b9d168f59e1a8b86519a68c061300278aaa58dcbe82b551.json @@ -0,0 +1,88 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT\n d.id,\n d.username,\n d.display_name,\n d.verified,\n d.admin,\n d.github_user_id as github_id\n FROM developers d\n INNER JOIN auth_tokens a ON d.id = a.developer_id\n WHERE d.id = 5 AND $1 = $1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int4", + "origin": { + "Table": { + "table": "developers", + "name": "id" + } + } + }, + { + "ordinal": 1, + "name": "username", + "type_info": "Text", + "origin": { + "Table": { + "table": "developers", + "name": "username" + } + } + }, + { + "ordinal": 2, + "name": "display_name", + "type_info": "Text", + "origin": { + "Table": { + "table": "developers", + "name": "display_name" + } + } + }, + { + "ordinal": 3, + "name": "verified", + "type_info": "Bool", + "origin": { + "Table": { + "table": "developers", + "name": "verified" + } + } + }, + { + "ordinal": 4, + "name": "admin", + "type_info": "Bool", + "origin": { + "Table": { + "table": "developers", + "name": "admin" + } + } + }, + { + "ordinal": 5, + "name": "github_id", + "type_info": "Int8", + "origin": { + "Table": { + "table": "developers", + "name": "github_user_id" + } + } + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false, + false, + false, + false, + false, + false + ] + }, + "hash": "896ab2c695cc66255b9d168f59e1a8b86519a68c061300278aaa58dcbe82b551" +} diff --git a/.sqlx/query-8affc6971c1e33b14f3696d0bd9daf4b82d907eba99837083e21909ea9c195a7.json b/.sqlx/query-8affc6971c1e33b14f3696d0bd9daf4b82d907eba99837083e21909ea9c195a7.json index 2ca4f75..8ee28a5 100644 --- a/.sqlx/query-8affc6971c1e33b14f3696d0bd9daf4b82d907eba99837083e21909ea9c195a7.json +++ b/.sqlx/query-8affc6971c1e33b14f3696d0bd9daf4b82d907eba99837083e21909ea9c195a7.json @@ -6,32 +6,68 @@ { "ordinal": 0, "name": "id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "developers", + "name": "id" + } + } }, { "ordinal": 1, "name": "username", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "developers", + "name": "username" + } + } }, { "ordinal": 2, "name": "display_name", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "developers", + "name": "display_name" + } + } }, { "ordinal": 3, "name": "verified", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "developers", + "name": "verified" + } + } }, { "ordinal": 4, "name": "admin", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "developers", + "name": "admin" + } + } }, { "ordinal": 5, "name": "github_id", - "type_info": "Int8" + "type_info": "Int8", + "origin": { + "Table": { + "table": "developers", + "name": "github_user_id" + } + } } ], "parameters": { diff --git a/.sqlx/query-8c1f2dd19652bb6c393d83c6443bc4cda1f108a749cc953adb9d25a2fffa4072.json b/.sqlx/query-8c1f2dd19652bb6c393d83c6443bc4cda1f108a749cc953adb9d25a2fffa4072.json index 4f049ef..b531e2d 100644 --- a/.sqlx/query-8c1f2dd19652bb6c393d83c6443bc4cda1f108a749cc953adb9d25a2fffa4072.json +++ b/.sqlx/query-8c1f2dd19652bb6c393d83c6443bc4cda1f108a749cc953adb9d25a2fffa4072.json @@ -6,32 +6,68 @@ { "ordinal": 0, "name": "id", - "type_info": "Int8" + "type_info": "Int8", + "origin": { + "Table": { + "table": "mod_version_submission_comments", + "name": "id" + } + } }, { "ordinal": 1, "name": "submission_id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_version_submission_comments", + "name": "submission_id" + } + } }, { "ordinal": 2, "name": "comment", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_version_submission_comments", + "name": "comment" + } + } }, { "ordinal": 3, "name": "author_id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_version_submission_comments", + "name": "author_id" + } + } }, { "ordinal": 4, "name": "created_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_version_submission_comments", + "name": "created_at" + } + } }, { "ordinal": 5, "name": "updated_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_version_submission_comments", + "name": "updated_at" + } + } } ], "parameters": { diff --git a/.sqlx/query-8e2101aa5b21d78fe39d03122248fa38da224bae0ad16be16445bf210230e33e.json b/.sqlx/query-8e2101aa5b21d78fe39d03122248fa38da224bae0ad16be16445bf210230e33e.json index e65c4f2..538ebb0 100644 --- a/.sqlx/query-8e2101aa5b21d78fe39d03122248fa38da224bae0ad16be16445bf210230e33e.json +++ b/.sqlx/query-8e2101aa5b21d78fe39d03122248fa38da224bae0ad16be16445bf210230e33e.json @@ -6,7 +6,13 @@ { "ordinal": 0, "name": "id", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mods", + "name": "id" + } + } } ], "parameters": { diff --git a/.sqlx/query-905ee0c060aad711f949eef40c3d1c5c88c27e43b9e0f19b8ed13d150bcd67d8.json b/.sqlx/query-905ee0c060aad711f949eef40c3d1c5c88c27e43b9e0f19b8ed13d150bcd67d8.json deleted file mode 100644 index 9ebff9f..0000000 --- a/.sqlx/query-905ee0c060aad711f949eef40c3d1c5c88c27e43b9e0f19b8ed13d150bcd67d8.json +++ /dev/null @@ -1,173 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "SELECT\n m.id, m.repository, m.about, m.changelog, m.featured, m.download_count as mod_download_count, m.created_at, m.updated_at,\n mv.id as version_id, mv.name, mv.description, mv.version, mv.download_link, mv.download_count as mod_version_download_count,\n mv.created_at as mod_version_created_at, mv.updated_at as mod_version_updated_at,\n mv.hash,\n format_semver(mv.geode_major, mv.geode_minor, mv.geode_patch, mv.geode_meta) as \"geode!: _\",\n mv.early_load, mv.requires_patching, mv.api, mv.mod_id, mvs.status as \"status: _\", mvs.info\n FROM mods m\n INNER JOIN mod_versions mv ON m.id = mv.mod_id\n INNER JOIN mod_version_statuses mvs ON mvs.mod_version_id = mv.id\n WHERE m.id = $1\n AND ($2 = false OR mvs.status = 'accepted')\n ORDER BY mv.id DESC", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "id", - "type_info": "Text" - }, - { - "ordinal": 1, - "name": "repository", - "type_info": "Text" - }, - { - "ordinal": 2, - "name": "about", - "type_info": "Text" - }, - { - "ordinal": 3, - "name": "changelog", - "type_info": "Text" - }, - { - "ordinal": 4, - "name": "featured", - "type_info": "Bool" - }, - { - "ordinal": 5, - "name": "mod_download_count", - "type_info": "Int4" - }, - { - "ordinal": 6, - "name": "created_at", - "type_info": "Timestamptz" - }, - { - "ordinal": 7, - "name": "updated_at", - "type_info": "Timestamptz" - }, - { - "ordinal": 8, - "name": "version_id", - "type_info": "Int4" - }, - { - "ordinal": 9, - "name": "name", - "type_info": "Text" - }, - { - "ordinal": 10, - "name": "description", - "type_info": "Text" - }, - { - "ordinal": 11, - "name": "version", - "type_info": "Text" - }, - { - "ordinal": 12, - "name": "download_link", - "type_info": "Text" - }, - { - "ordinal": 13, - "name": "mod_version_download_count", - "type_info": "Int4" - }, - { - "ordinal": 14, - "name": "mod_version_created_at", - "type_info": "Timestamptz" - }, - { - "ordinal": 15, - "name": "mod_version_updated_at", - "type_info": "Timestamptz" - }, - { - "ordinal": 16, - "name": "hash", - "type_info": "Text" - }, - { - "ordinal": 17, - "name": "geode!: _", - "type_info": "Text" - }, - { - "ordinal": 18, - "name": "early_load", - "type_info": "Bool" - }, - { - "ordinal": 19, - "name": "requires_patching", - "type_info": "Bool" - }, - { - "ordinal": 20, - "name": "api", - "type_info": "Bool" - }, - { - "ordinal": 21, - "name": "mod_id", - "type_info": "Text" - }, - { - "ordinal": 22, - "name": "status: _", - "type_info": { - "Custom": { - "name": "mod_version_status", - "kind": { - "Enum": [ - "pending", - "rejected", - "accepted", - "unlisted" - ] - } - } - } - }, - { - "ordinal": 23, - "name": "info", - "type_info": "Text" - } - ], - "parameters": { - "Left": [ - "Text", - "Bool" - ] - }, - "nullable": [ - false, - true, - true, - true, - false, - false, - false, - false, - false, - false, - true, - false, - false, - false, - true, - true, - false, - null, - false, - false, - false, - false, - false, - true - ] - }, - "hash": "905ee0c060aad711f949eef40c3d1c5c88c27e43b9e0f19b8ed13d150bcd67d8" -} diff --git a/.sqlx/query-91bc425cc6b35915fc00d39b1f127118f0a35841049fc0914add705241d471f6.json b/.sqlx/query-91bc425cc6b35915fc00d39b1f127118f0a35841049fc0914add705241d471f6.json index 4f45f9b..3b86213 100644 --- a/.sqlx/query-91bc425cc6b35915fc00d39b1f127118f0a35841049fc0914add705241d471f6.json +++ b/.sqlx/query-91bc425cc6b35915fc00d39b1f127118f0a35841049fc0914add705241d471f6.json @@ -6,7 +6,8 @@ { "ordinal": 0, "name": "count", - "type_info": "Int8" + "type_info": "Int8", + "origin": "Expression" } ], "parameters": { diff --git a/.sqlx/query-91ce04c955fe760ea792a973e258247ea42f0f7c5f68391642480758ddf9b4bc.json b/.sqlx/query-91ce04c955fe760ea792a973e258247ea42f0f7c5f68391642480758ddf9b4bc.json index ba74b44..1a047e1 100644 --- a/.sqlx/query-91ce04c955fe760ea792a973e258247ea42f0f7c5f68391642480758ddf9b4bc.json +++ b/.sqlx/query-91ce04c955fe760ea792a973e258247ea42f0f7c5f68391642480758ddf9b4bc.json @@ -6,7 +6,13 @@ { "ordinal": 0, "name": "developer_id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mods_developers", + "name": "developer_id" + } + } } ], "parameters": { diff --git a/.sqlx/query-94a9f2bc14d5a6c21eb7f638e5d70bcdc7112d9ad0d153aaad6bf7b00e27d74a.json b/.sqlx/query-94a9f2bc14d5a6c21eb7f638e5d70bcdc7112d9ad0d153aaad6bf7b00e27d74a.json index e2cb267..3933afc 100644 --- a/.sqlx/query-94a9f2bc14d5a6c21eb7f638e5d70bcdc7112d9ad0d153aaad6bf7b00e27d74a.json +++ b/.sqlx/query-94a9f2bc14d5a6c21eb7f638e5d70bcdc7112d9ad0d153aaad6bf7b00e27d74a.json @@ -28,6 +28,12 @@ ] } } + }, + "origin": { + "Table": { + "table": "geode_versions", + "name": "mac" + } } }, { @@ -55,6 +61,12 @@ ] } } + }, + "origin": { + "Table": { + "table": "geode_versions", + "name": "win" + } } }, { @@ -82,6 +94,12 @@ ] } } + }, + "origin": { + "Table": { + "table": "geode_versions", + "name": "android" + } } }, { @@ -109,27 +127,57 @@ ] } } + }, + "origin": { + "Table": { + "table": "geode_versions", + "name": "ios" + } } }, { "ordinal": 4, "name": "tag", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "geode_versions", + "name": "tag" + } + } }, { "ordinal": 5, "name": "created_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "geode_versions", + "name": "created_at" + } + } }, { "ordinal": 6, "name": "commit_hash", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "geode_versions", + "name": "commit_hash" + } + } }, { "ordinal": 7, "name": "prerelease", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "geode_versions", + "name": "prerelease" + } + } } ], "parameters": { diff --git a/.sqlx/query-959d6a60bbb47b24bc86963c0063bdd1268c75d03563eaf78eec41752cc1a491.json b/.sqlx/query-959d6a60bbb47b24bc86963c0063bdd1268c75d03563eaf78eec41752cc1a491.json index 5df17d6..6cf71c0 100644 --- a/.sqlx/query-959d6a60bbb47b24bc86963c0063bdd1268c75d03563eaf78eec41752cc1a491.json +++ b/.sqlx/query-959d6a60bbb47b24bc86963c0063bdd1268c75d03563eaf78eec41752cc1a491.json @@ -6,42 +6,90 @@ { "ordinal": 0, "name": "id", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mods", + "name": "id" + } + } }, { "ordinal": 1, "name": "repository", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mods", + "name": "repository" + } + } }, { "ordinal": 2, "name": "about", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mods", + "name": "about" + } + } }, { "ordinal": 3, "name": "changelog", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mods", + "name": "changelog" + } + } }, { "ordinal": 4, "name": "featured", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "mods", + "name": "featured" + } + } }, { "ordinal": 5, "name": "download_count", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mods", + "name": "download_count" + } + } }, { "ordinal": 6, "name": "created_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mods", + "name": "created_at" + } + } }, { "ordinal": 7, "name": "updated_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mods", + "name": "updated_at" + } + } } ], "parameters": { diff --git a/.sqlx/query-964d894336ec2b5381c454d50a8a4a94573787ab881df61c69818b6c0435951c.json b/.sqlx/query-964d894336ec2b5381c454d50a8a4a94573787ab881df61c69818b6c0435951c.json new file mode 100644 index 0000000..e470cd0 --- /dev/null +++ b/.sqlx/query-964d894336ec2b5381c454d50a8a4a94573787ab881df61c69818b6c0435951c.json @@ -0,0 +1,247 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT\n mv.id, mv.name, mv.description, mv.version,\n mv.download_link, mv.managed_download_link, mv.download_count, mv.hash,\n format_semver(mv.geode_major, mv.geode_minor, mv.geode_patch, mv.geode_meta) as \"geode!: _\",\n mv.early_load, mv.requires_patching, mv.api, mv.mod_id,\n mv.created_at, mv.updated_at,\n mvs.status as \"status: _\", mvs.info\n FROM mod_versions mv\n INNER JOIN mod_version_statuses mvs ON mvs.mod_version_id = mv.id\n WHERE mv.mod_id = $1\n AND ($2::mod_version_status[] IS NULL OR mvs.status = ANY($2))\n ORDER BY mv.id DESC", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_versions", + "name": "id" + } + } + }, + { + "ordinal": 1, + "name": "name", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "name" + } + } + }, + { + "ordinal": 2, + "name": "description", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "description" + } + } + }, + { + "ordinal": 3, + "name": "version", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "version" + } + } + }, + { + "ordinal": 4, + "name": "download_link", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "download_link" + } + } + }, + { + "ordinal": 5, + "name": "managed_download_link", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "managed_download_link" + } + } + }, + { + "ordinal": 6, + "name": "download_count", + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_versions", + "name": "download_count" + } + } + }, + { + "ordinal": 7, + "name": "hash", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "hash" + } + } + }, + { + "ordinal": 8, + "name": "geode!: _", + "type_info": "Text", + "origin": "Expression" + }, + { + "ordinal": 9, + "name": "early_load", + "type_info": "Bool", + "origin": { + "Table": { + "table": "mod_versions", + "name": "early_load" + } + } + }, + { + "ordinal": 10, + "name": "requires_patching", + "type_info": "Bool", + "origin": { + "Table": { + "table": "mod_versions", + "name": "requires_patching" + } + } + }, + { + "ordinal": 11, + "name": "api", + "type_info": "Bool", + "origin": { + "Table": { + "table": "mod_versions", + "name": "api" + } + } + }, + { + "ordinal": 12, + "name": "mod_id", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "mod_id" + } + } + }, + { + "ordinal": 13, + "name": "created_at", + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_versions", + "name": "created_at" + } + } + }, + { + "ordinal": 14, + "name": "updated_at", + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_versions", + "name": "updated_at" + } + } + }, + { + "ordinal": 15, + "name": "status: _", + "type_info": { + "Custom": { + "name": "mod_version_status", + "kind": { + "Enum": [ + "pending", + "rejected", + "accepted", + "unlisted" + ] + } + } + }, + "origin": { + "Table": { + "table": "mod_version_statuses", + "name": "status" + } + } + }, + { + "ordinal": 16, + "name": "info", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_version_statuses", + "name": "info" + } + } + } + ], + "parameters": { + "Left": [ + "Text", + { + "Custom": { + "name": "mod_version_status[]", + "kind": { + "Array": { + "Custom": { + "name": "mod_version_status", + "kind": { + "Enum": [ + "pending", + "rejected", + "accepted", + "unlisted" + ] + } + } + } + } + } + } + ] + }, + "nullable": [ + false, + false, + true, + false, + false, + true, + false, + false, + null, + false, + false, + false, + false, + true, + true, + false, + true + ] + }, + "hash": "964d894336ec2b5381c454d50a8a4a94573787ab881df61c69818b6c0435951c" +} diff --git a/.sqlx/query-96f3e4f9ceffa7f3d9a609252d9f635e70dd70cdafc327486aaa6a6f49e3c5db.json b/.sqlx/query-96f3e4f9ceffa7f3d9a609252d9f635e70dd70cdafc327486aaa6a6f49e3c5db.json new file mode 100644 index 0000000..9a8c102 --- /dev/null +++ b/.sqlx/query-96f3e4f9ceffa7f3d9a609252d9f635e70dd70cdafc327486aaa6a6f49e3c5db.json @@ -0,0 +1,229 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT mv.id, mv.name, mv.description, mv.version,\n mv.download_link, mv.managed_download_link, mv.download_count,\n mv.hash,\n format_semver(mv.geode_major, mv.geode_minor, mv.geode_patch, mv.geode_meta) as \"geode!: _\",\n mv.early_load, mv.requires_patching, mv.api,\n mv.created_at, mv.updated_at,\n mv.mod_id, mvs.status as \"status: _\", mvs.info\n FROM mod_versions mv\n INNER JOIN mods m ON m.id = mv.mod_id\n INNER JOIN mod_version_statuses mvs ON mvs.mod_version_id = mv.id\n WHERE mv.mod_id = $1 AND mv.version = $2\n AND (mvs.status = 'accepted' OR $3 = false)", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_versions", + "name": "id" + } + } + }, + { + "ordinal": 1, + "name": "name", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "name" + } + } + }, + { + "ordinal": 2, + "name": "description", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "description" + } + } + }, + { + "ordinal": 3, + "name": "version", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "version" + } + } + }, + { + "ordinal": 4, + "name": "download_link", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "download_link" + } + } + }, + { + "ordinal": 5, + "name": "managed_download_link", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "managed_download_link" + } + } + }, + { + "ordinal": 6, + "name": "download_count", + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_versions", + "name": "download_count" + } + } + }, + { + "ordinal": 7, + "name": "hash", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "hash" + } + } + }, + { + "ordinal": 8, + "name": "geode!: _", + "type_info": "Text", + "origin": "Expression" + }, + { + "ordinal": 9, + "name": "early_load", + "type_info": "Bool", + "origin": { + "Table": { + "table": "mod_versions", + "name": "early_load" + } + } + }, + { + "ordinal": 10, + "name": "requires_patching", + "type_info": "Bool", + "origin": { + "Table": { + "table": "mod_versions", + "name": "requires_patching" + } + } + }, + { + "ordinal": 11, + "name": "api", + "type_info": "Bool", + "origin": { + "Table": { + "table": "mod_versions", + "name": "api" + } + } + }, + { + "ordinal": 12, + "name": "created_at", + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_versions", + "name": "created_at" + } + } + }, + { + "ordinal": 13, + "name": "updated_at", + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_versions", + "name": "updated_at" + } + } + }, + { + "ordinal": 14, + "name": "mod_id", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "mod_id" + } + } + }, + { + "ordinal": 15, + "name": "status: _", + "type_info": { + "Custom": { + "name": "mod_version_status", + "kind": { + "Enum": [ + "pending", + "rejected", + "accepted", + "unlisted" + ] + } + } + }, + "origin": { + "Table": { + "table": "mod_version_statuses", + "name": "status" + } + } + }, + { + "ordinal": 16, + "name": "info", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_version_statuses", + "name": "info" + } + } + } + ], + "parameters": { + "Left": [ + "Text", + "Text", + "Bool" + ] + }, + "nullable": [ + false, + false, + true, + false, + false, + true, + false, + false, + null, + false, + false, + false, + true, + true, + false, + false, + true + ] + }, + "hash": "96f3e4f9ceffa7f3d9a609252d9f635e70dd70cdafc327486aaa6a6f49e3c5db" +} diff --git a/.sqlx/query-9931bc9f6820c39fdb3c287b4cc76dac05938b5b33b61f2667955ea1b5832d87.json b/.sqlx/query-9931bc9f6820c39fdb3c287b4cc76dac05938b5b33b61f2667955ea1b5832d87.json index 8cfea75..981a89e 100644 --- a/.sqlx/query-9931bc9f6820c39fdb3c287b4cc76dac05938b5b33b61f2667955ea1b5832d87.json +++ b/.sqlx/query-9931bc9f6820c39fdb3c287b4cc76dac05938b5b33b61f2667955ea1b5832d87.json @@ -6,22 +6,46 @@ { "ordinal": 0, "name": "mod_id", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_links", + "name": "mod_id" + } + } }, { "ordinal": 1, "name": "community", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_links", + "name": "community" + } + } }, { "ordinal": 2, "name": "homepage", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_links", + "name": "homepage" + } + } }, { "ordinal": 3, "name": "source", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_links", + "name": "source" + } + } } ], "parameters": { diff --git a/.sqlx/query-9a23bc60988017bdb2d3770f0cbe4e806b378409a148cb0728c03c70470954f5.json b/.sqlx/query-9a23bc60988017bdb2d3770f0cbe4e806b378409a148cb0728c03c70470954f5.json index 05d0e99..c4ad304 100644 --- a/.sqlx/query-9a23bc60988017bdb2d3770f0cbe4e806b378409a148cb0728c03c70470954f5.json +++ b/.sqlx/query-9a23bc60988017bdb2d3770f0cbe4e806b378409a148cb0728c03c70470954f5.json @@ -6,7 +6,13 @@ { "ordinal": 0, "name": "mod_version_id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_version_submissions", + "name": "mod_version_id" + } + } }, { "ordinal": 1, @@ -22,22 +28,46 @@ ] } } + }, + "origin": { + "Table": { + "table": "mod_version_submissions", + "name": "lock" + } } }, { "ordinal": 2, "name": "locked_by", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_version_submissions", + "name": "locked_by" + } + } }, { "ordinal": 3, "name": "created_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_version_submissions", + "name": "created_at" + } + } }, { "ordinal": 4, "name": "updated_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_version_submissions", + "name": "updated_at" + } + } } ], "parameters": { diff --git a/.sqlx/query-9d56e772c5f6697ab40d0b43581732ccafe10fe556de4659124e59abe8cd7552.json b/.sqlx/query-9d56e772c5f6697ab40d0b43581732ccafe10fe556de4659124e59abe8cd7552.json index db73844..bc01530 100644 --- a/.sqlx/query-9d56e772c5f6697ab40d0b43581732ccafe10fe556de4659124e59abe8cd7552.json +++ b/.sqlx/query-9d56e772c5f6697ab40d0b43581732ccafe10fe556de4659124e59abe8cd7552.json @@ -6,47 +6,101 @@ { "ordinal": 0, "name": "uuid", - "type_info": "Uuid" + "type_info": "Uuid", + "origin": { + "Table": { + "table": "github_login_attempts", + "name": "uid" + } + } }, { "ordinal": 1, "name": "ip", - "type_info": "Inet" + "type_info": "Inet", + "origin": { + "Table": { + "table": "github_login_attempts", + "name": "ip" + } + } }, { "ordinal": 2, "name": "device_code", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "github_login_attempts", + "name": "device_code" + } + } }, { "ordinal": 3, "name": "uri", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "github_login_attempts", + "name": "challenge_uri" + } + } }, { "ordinal": 4, "name": "user_code", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "github_login_attempts", + "name": "user_code" + } + } }, { "ordinal": 5, "name": "interval", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "github_login_attempts", + "name": "interval" + } + } }, { "ordinal": 6, "name": "expires_in", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "github_login_attempts", + "name": "expires_in" + } + } }, { "ordinal": 7, "name": "created_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "github_login_attempts", + "name": "created_at" + } + } }, { "ordinal": 8, "name": "last_poll", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "github_login_attempts", + "name": "last_poll" + } + } } ], "parameters": { diff --git a/.sqlx/query-a29dd2a2f869ef9fda4b366ee9005fef1f99e69979838e30f908f20244caba1d.json b/.sqlx/query-a29dd2a2f869ef9fda4b366ee9005fef1f99e69979838e30f908f20244caba1d.json deleted file mode 100644 index f7c7128..0000000 --- a/.sqlx/query-a29dd2a2f869ef9fda4b366ee9005fef1f99e69979838e30f908f20244caba1d.json +++ /dev/null @@ -1,126 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "SELECT mv.id, mv.name, mv.description, mv.version,\n mv.download_link, mv.download_count,\n mv.hash,\n format_semver(mv.geode_major, mv.geode_minor, mv.geode_patch, mv.geode_meta) as \"geode!: _\",\n mv.early_load, mv.requires_patching, mv.api,\n mv.created_at, mv.updated_at,\n mv.mod_id, mvs.status as \"status: _\", mvs.info\n FROM mod_versions mv\n INNER JOIN mods m ON m.id = mv.mod_id\n INNER JOIN mod_version_statuses mvs ON mvs.mod_version_id = mv.id\n WHERE mv.mod_id = $1 AND mv.version = $2\n AND (mvs.status = 'accepted' OR $3 = false)", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "id", - "type_info": "Int4" - }, - { - "ordinal": 1, - "name": "name", - "type_info": "Text" - }, - { - "ordinal": 2, - "name": "description", - "type_info": "Text" - }, - { - "ordinal": 3, - "name": "version", - "type_info": "Text" - }, - { - "ordinal": 4, - "name": "download_link", - "type_info": "Text" - }, - { - "ordinal": 5, - "name": "download_count", - "type_info": "Int4" - }, - { - "ordinal": 6, - "name": "hash", - "type_info": "Text" - }, - { - "ordinal": 7, - "name": "geode!: _", - "type_info": "Text" - }, - { - "ordinal": 8, - "name": "early_load", - "type_info": "Bool" - }, - { - "ordinal": 9, - "name": "requires_patching", - "type_info": "Bool" - }, - { - "ordinal": 10, - "name": "api", - "type_info": "Bool" - }, - { - "ordinal": 11, - "name": "created_at", - "type_info": "Timestamptz" - }, - { - "ordinal": 12, - "name": "updated_at", - "type_info": "Timestamptz" - }, - { - "ordinal": 13, - "name": "mod_id", - "type_info": "Text" - }, - { - "ordinal": 14, - "name": "status: _", - "type_info": { - "Custom": { - "name": "mod_version_status", - "kind": { - "Enum": [ - "pending", - "rejected", - "accepted", - "unlisted" - ] - } - } - } - }, - { - "ordinal": 15, - "name": "info", - "type_info": "Text" - } - ], - "parameters": { - "Left": [ - "Text", - "Text", - "Bool" - ] - }, - "nullable": [ - false, - false, - true, - false, - false, - false, - false, - null, - false, - false, - false, - true, - true, - false, - false, - true - ] - }, - "hash": "a29dd2a2f869ef9fda4b366ee9005fef1f99e69979838e30f908f20244caba1d" -} diff --git a/.sqlx/query-a6c2a86e7f95612a9a2fdcc5168f9ab2485fc07b1b3d47f5327b91c6fcb9a653.json b/.sqlx/query-a6c2a86e7f95612a9a2fdcc5168f9ab2485fc07b1b3d47f5327b91c6fcb9a653.json index 1531665..bdd7380 100644 --- a/.sqlx/query-a6c2a86e7f95612a9a2fdcc5168f9ab2485fc07b1b3d47f5327b91c6fcb9a653.json +++ b/.sqlx/query-a6c2a86e7f95612a9a2fdcc5168f9ab2485fc07b1b3d47f5327b91c6fcb9a653.json @@ -6,12 +6,24 @@ { "ordinal": 0, "name": "id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_gd_versions", + "name": "id" + } + } }, { "ordinal": 1, "name": "mod_id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_gd_versions", + "name": "mod_id" + } + } }, { "ordinal": 2, @@ -38,6 +50,12 @@ ] } } + }, + "origin": { + "Table": { + "table": "mod_gd_versions", + "name": "gd" + } } }, { @@ -57,6 +75,12 @@ ] } } + }, + "origin": { + "Table": { + "table": "mod_gd_versions", + "name": "platform" + } } } ], diff --git a/.sqlx/query-a83c43f2bdb4c61f72ae41987a3db540c91edbc36c595ce8c6644bdb36a771c3.json b/.sqlx/query-a83c43f2bdb4c61f72ae41987a3db540c91edbc36c595ce8c6644bdb36a771c3.json index dffd2dc..5857037 100644 --- a/.sqlx/query-a83c43f2bdb4c61f72ae41987a3db540c91edbc36c595ce8c6644bdb36a771c3.json +++ b/.sqlx/query-a83c43f2bdb4c61f72ae41987a3db540c91edbc36c595ce8c6644bdb36a771c3.json @@ -6,7 +6,13 @@ { "ordinal": 0, "name": "by_mod_id", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "deprecated_by", + "name": "by_mod_id" + } + } } ], "parameters": { diff --git a/.sqlx/query-a9131f0ab03fa27cc7e6531397dc1d9343a95ff30a648d9c9b21120651a1caaa.json b/.sqlx/query-a9131f0ab03fa27cc7e6531397dc1d9343a95ff30a648d9c9b21120651a1caaa.json index 88a3327..e7c2506 100644 --- a/.sqlx/query-a9131f0ab03fa27cc7e6531397dc1d9343a95ff30a648d9c9b21120651a1caaa.json +++ b/.sqlx/query-a9131f0ab03fa27cc7e6531397dc1d9343a95ff30a648d9c9b21120651a1caaa.json @@ -6,42 +6,80 @@ { "ordinal": 0, "name": "id", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mods", + "name": "id" + } + } }, { "ordinal": 1, "name": "repository", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mods", + "name": "repository" + } + } }, { "ordinal": 2, "name": "about", - "type_info": "Text" + "type_info": "Text", + "origin": "Expression" }, { "ordinal": 3, "name": "changelog", - "type_info": "Text" + "type_info": "Text", + "origin": "Expression" }, { "ordinal": 4, "name": "featured", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "mods", + "name": "featured" + } + } }, { "ordinal": 5, "name": "download_count", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mods", + "name": "download_count" + } + } }, { "ordinal": 6, "name": "created_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mods", + "name": "created_at" + } + } }, { "ordinal": 7, "name": "updated_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mods", + "name": "updated_at" + } + } } ], "parameters": { diff --git a/.sqlx/query-ae5d56bcbbcbbd970d63fe9a3324bcd78f595e7059cec91429fc0e734456bde1.json b/.sqlx/query-ae5d56bcbbcbbd970d63fe9a3324bcd78f595e7059cec91429fc0e734456bde1.json index c882a62..f3d4ce7 100644 --- a/.sqlx/query-ae5d56bcbbcbbd970d63fe9a3324bcd78f595e7059cec91429fc0e734456bde1.json +++ b/.sqlx/query-ae5d56bcbbcbbd970d63fe9a3324bcd78f595e7059cec91429fc0e734456bde1.json @@ -6,7 +6,8 @@ { "ordinal": 0, "name": "count", - "type_info": "Int8" + "type_info": "Int8", + "origin": "Expression" } ], "parameters": { diff --git a/.sqlx/query-b13ceba1c001ab7955a7ff8e50853947f6252f641ed3af00a17cb069440e9570.json b/.sqlx/query-b13ceba1c001ab7955a7ff8e50853947f6252f641ed3af00a17cb069440e9570.json index 5944ca3..d6aed55 100644 --- a/.sqlx/query-b13ceba1c001ab7955a7ff8e50853947f6252f641ed3af00a17cb069440e9570.json +++ b/.sqlx/query-b13ceba1c001ab7955a7ff8e50853947f6252f641ed3af00a17cb069440e9570.json @@ -6,7 +6,13 @@ { "ordinal": 0, "name": "state", - "type_info": "Uuid" + "type_info": "Uuid", + "origin": { + "Table": { + "table": "github_web_logins", + "name": "state" + } + } } ], "parameters": { diff --git a/.sqlx/query-b248e326b0e2d3c803bedffef28fa22a00f19dca10f573b3f9331a830b0884d7.json b/.sqlx/query-b248e326b0e2d3c803bedffef28fa22a00f19dca10f573b3f9331a830b0884d7.json index ff275ba..559217f 100644 --- a/.sqlx/query-b248e326b0e2d3c803bedffef28fa22a00f19dca10f573b3f9331a830b0884d7.json +++ b/.sqlx/query-b248e326b0e2d3c803bedffef28fa22a00f19dca10f573b3f9331a830b0884d7.json @@ -6,12 +6,19 @@ { "ordinal": 0, "name": "filename", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_version_submission_comment_attachments", + "name": "filename" + } + } }, { "ordinal": 1, "name": "count", - "type_info": "Int8" + "type_info": "Int8", + "origin": "Expression" } ], "parameters": { diff --git a/.sqlx/query-b520ba987e3979c769e9dab052e42f6ee3f09ca365893cd95ff3821e1bb3a43b.json b/.sqlx/query-b520ba987e3979c769e9dab052e42f6ee3f09ca365893cd95ff3821e1bb3a43b.json deleted file mode 100644 index 93c3f84..0000000 --- a/.sqlx/query-b520ba987e3979c769e9dab052e42f6ee3f09ca365893cd95ff3821e1bb3a43b.json +++ /dev/null @@ -1,125 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "SELECT\n mv.id, mv.name, mv.description, mv.version,\n mv.download_link, mv.download_count, mv.hash,\n format_semver(mv.geode_major, mv.geode_minor, mv.geode_patch, mv.geode_meta) as \"geode!: _\",\n mv.early_load, mv.requires_patching, mv.api, mv.mod_id,\n mv.created_at, mv.updated_at,\n mvs.status as \"status: _\", mvs.info\n FROM mod_versions mv\n INNER JOIN mod_version_statuses mvs ON mvs.mod_version_id = mv.id\n WHERE mv.mod_id = $1\n AND mv.version = $2", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "id", - "type_info": "Int4" - }, - { - "ordinal": 1, - "name": "name", - "type_info": "Text" - }, - { - "ordinal": 2, - "name": "description", - "type_info": "Text" - }, - { - "ordinal": 3, - "name": "version", - "type_info": "Text" - }, - { - "ordinal": 4, - "name": "download_link", - "type_info": "Text" - }, - { - "ordinal": 5, - "name": "download_count", - "type_info": "Int4" - }, - { - "ordinal": 6, - "name": "hash", - "type_info": "Text" - }, - { - "ordinal": 7, - "name": "geode!: _", - "type_info": "Text" - }, - { - "ordinal": 8, - "name": "early_load", - "type_info": "Bool" - }, - { - "ordinal": 9, - "name": "requires_patching", - "type_info": "Bool" - }, - { - "ordinal": 10, - "name": "api", - "type_info": "Bool" - }, - { - "ordinal": 11, - "name": "mod_id", - "type_info": "Text" - }, - { - "ordinal": 12, - "name": "created_at", - "type_info": "Timestamptz" - }, - { - "ordinal": 13, - "name": "updated_at", - "type_info": "Timestamptz" - }, - { - "ordinal": 14, - "name": "status: _", - "type_info": { - "Custom": { - "name": "mod_version_status", - "kind": { - "Enum": [ - "pending", - "rejected", - "accepted", - "unlisted" - ] - } - } - } - }, - { - "ordinal": 15, - "name": "info", - "type_info": "Text" - } - ], - "parameters": { - "Left": [ - "Text", - "Text" - ] - }, - "nullable": [ - false, - false, - true, - false, - false, - false, - false, - null, - false, - false, - false, - false, - true, - true, - false, - true - ] - }, - "hash": "b520ba987e3979c769e9dab052e42f6ee3f09ca365893cd95ff3821e1bb3a43b" -} diff --git a/.sqlx/query-bad99b175dfe2ffccfc71b69175b2593d77d4d24d6e2d9ba052ba4bf1cc6489d.json b/.sqlx/query-bad99b175dfe2ffccfc71b69175b2593d77d4d24d6e2d9ba052ba4bf1cc6489d.json index f983d45..970dd59 100644 --- a/.sqlx/query-bad99b175dfe2ffccfc71b69175b2593d77d4d24d6e2d9ba052ba4bf1cc6489d.json +++ b/.sqlx/query-bad99b175dfe2ffccfc71b69175b2593d77d4d24d6e2d9ba052ba4bf1cc6489d.json @@ -6,32 +6,68 @@ { "ordinal": 0, "name": "id", - "type_info": "Int8" + "type_info": "Int8", + "origin": { + "Table": { + "table": "mod_version_submission_comments", + "name": "id" + } + } }, { "ordinal": 1, "name": "submission_id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_version_submission_comments", + "name": "submission_id" + } + } }, { "ordinal": 2, "name": "comment", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_version_submission_comments", + "name": "comment" + } + } }, { "ordinal": 3, "name": "author_id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_version_submission_comments", + "name": "author_id" + } + } }, { "ordinal": 4, "name": "created_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_version_submission_comments", + "name": "created_at" + } + } }, { "ordinal": 5, "name": "updated_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_version_submission_comments", + "name": "updated_at" + } + } } ], "parameters": { diff --git a/.sqlx/query-bcf3969b4f9bc4ca27bdca6bff0c5bddac1f2347d7b1f4308478acf731e0145e.json b/.sqlx/query-bcf3969b4f9bc4ca27bdca6bff0c5bddac1f2347d7b1f4308478acf731e0145e.json index 4301f0b..503bafb 100644 --- a/.sqlx/query-bcf3969b4f9bc4ca27bdca6bff0c5bddac1f2347d7b1f4308478acf731e0145e.json +++ b/.sqlx/query-bcf3969b4f9bc4ca27bdca6bff0c5bddac1f2347d7b1f4308478acf731e0145e.json @@ -6,7 +6,13 @@ { "ordinal": 0, "name": "featured", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "mods", + "name": "featured" + } + } } ], "parameters": { diff --git a/.sqlx/query-c376c807583ad0bec9f6abe17ba00ce8d2cf76047bb0d1bb97b6e20c8d527224.json b/.sqlx/query-c376c807583ad0bec9f6abe17ba00ce8d2cf76047bb0d1bb97b6e20c8d527224.json index fce49e2..2788d35 100644 --- a/.sqlx/query-c376c807583ad0bec9f6abe17ba00ce8d2cf76047bb0d1bb97b6e20c8d527224.json +++ b/.sqlx/query-c376c807583ad0bec9f6abe17ba00ce8d2cf76047bb0d1bb97b6e20c8d527224.json @@ -6,7 +6,8 @@ { "ordinal": 0, "name": "count", - "type_info": "Int8" + "type_info": "Int8", + "origin": "Expression" } ], "parameters": { diff --git a/.sqlx/query-c4a5479111161c08985997365f50ecfb1fb6315509f5002a3bfc6fd66c2f83f7.json b/.sqlx/query-c4a5479111161c08985997365f50ecfb1fb6315509f5002a3bfc6fd66c2f83f7.json index d60636b..50eca5a 100644 --- a/.sqlx/query-c4a5479111161c08985997365f50ecfb1fb6315509f5002a3bfc6fd66c2f83f7.json +++ b/.sqlx/query-c4a5479111161c08985997365f50ecfb1fb6315509f5002a3bfc6fd66c2f83f7.json @@ -6,72 +6,156 @@ { "ordinal": 0, "name": "id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_versions", + "name": "id" + } + } }, { "ordinal": 1, "name": "name", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "name" + } + } }, { "ordinal": 2, "name": "version", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "version" + } + } }, { "ordinal": 3, "name": "download_link", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "download_link" + } + } }, { "ordinal": 4, "name": "download_count", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_versions", + "name": "download_count" + } + } }, { "ordinal": 5, "name": "hash", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "hash" + } + } }, { "ordinal": 6, "name": "early_load", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "mod_versions", + "name": "early_load" + } + } }, { "ordinal": 7, "name": "requires_patching", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "mod_versions", + "name": "requires_patching" + } + } }, { "ordinal": 8, "name": "api", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "mod_versions", + "name": "api" + } + } }, { "ordinal": 9, "name": "status_id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_versions", + "name": "status_id" + } + } }, { "ordinal": 10, "name": "description", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "description" + } + } }, { "ordinal": 11, "name": "mod_id", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "mod_id" + } + } }, { "ordinal": 12, "name": "created_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_versions", + "name": "created_at" + } + } }, { "ordinal": 13, "name": "updated_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_versions", + "name": "updated_at" + } + } } ], "parameters": { diff --git a/.sqlx/query-c8e6b3a10dc50c1b7b24eb55c86b7a945863ec09c57e4165f9cd66888ab5405f.json b/.sqlx/query-c8e6b3a10dc50c1b7b24eb55c86b7a945863ec09c57e4165f9cd66888ab5405f.json index 911b9ed..95ffcba 100644 --- a/.sqlx/query-c8e6b3a10dc50c1b7b24eb55c86b7a945863ec09c57e4165f9cd66888ab5405f.json +++ b/.sqlx/query-c8e6b3a10dc50c1b7b24eb55c86b7a945863ec09c57e4165f9cd66888ab5405f.json @@ -6,22 +6,46 @@ { "ordinal": 0, "name": "id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "developers", + "name": "id" + } + } }, { "ordinal": 1, "name": "username", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "developers", + "name": "username" + } + } }, { "ordinal": 2, "name": "display_name", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "developers", + "name": "display_name" + } + } }, { "ordinal": 3, "name": "is_owner", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "mods_developers", + "name": "is_owner" + } + } } ], "parameters": { diff --git a/.sqlx/query-cc4706434166bf9d5d6c3fde308fb3855ab4c697528a1b4ff8d074595ee82413.json b/.sqlx/query-cc4706434166bf9d5d6c3fde308fb3855ab4c697528a1b4ff8d074595ee82413.json index 1759cc2..12320e3 100644 --- a/.sqlx/query-cc4706434166bf9d5d6c3fde308fb3855ab4c697528a1b4ff8d074595ee82413.json +++ b/.sqlx/query-cc4706434166bf9d5d6c3fde308fb3855ab4c697528a1b4ff8d074595ee82413.json @@ -6,62 +6,134 @@ { "ordinal": 0, "name": "id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_versions", + "name": "id" + } + } }, { "ordinal": 1, "name": "name", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "name" + } + } }, { "ordinal": 2, "name": "version", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "version" + } + } }, { "ordinal": 3, "name": "description", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "description" + } + } }, { "ordinal": 4, "name": "download_link", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "download_link" + } + } }, { "ordinal": 5, "name": "hash", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "hash" + } + } }, { "ordinal": 6, "name": "early_load", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "mod_versions", + "name": "early_load" + } + } }, { "ordinal": 7, "name": "requires_patching", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "mod_versions", + "name": "requires_patching" + } + } }, { "ordinal": 8, "name": "api", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "mod_versions", + "name": "api" + } + } }, { "ordinal": 9, "name": "mod_id", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "mod_id" + } + } }, { "ordinal": 10, "name": "created_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_versions", + "name": "created_at" + } + } }, { "ordinal": 11, "name": "updated_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_versions", + "name": "updated_at" + } + } } ], "parameters": { diff --git a/.sqlx/query-d3f5cc5729d842ba8c9a259592cdfa901fbbc2cc4c12fb3268d22aa0f6b76a64.json b/.sqlx/query-d3f5cc5729d842ba8c9a259592cdfa901fbbc2cc4c12fb3268d22aa0f6b76a64.json index ec9b25c..59935d1 100644 --- a/.sqlx/query-d3f5cc5729d842ba8c9a259592cdfa901fbbc2cc4c12fb3268d22aa0f6b76a64.json +++ b/.sqlx/query-d3f5cc5729d842ba8c9a259592cdfa901fbbc2cc4c12fb3268d22aa0f6b76a64.json @@ -6,7 +6,13 @@ { "ordinal": 0, "name": "name", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_tags", + "name": "name" + } + } } ], "parameters": { diff --git a/.sqlx/query-ddcfdb20c8c93a41da225a937478a56617000567bfd04ed8f9be0e501f438937.json b/.sqlx/query-ddcfdb20c8c93a41da225a937478a56617000567bfd04ed8f9be0e501f438937.json index 644bfe3..2d18028 100644 --- a/.sqlx/query-ddcfdb20c8c93a41da225a937478a56617000567bfd04ed8f9be0e501f438937.json +++ b/.sqlx/query-ddcfdb20c8c93a41da225a937478a56617000567bfd04ed8f9be0e501f438937.json @@ -6,32 +6,68 @@ { "ordinal": 0, "name": "id", - "type_info": "Int8" + "type_info": "Int8", + "origin": { + "Table": { + "table": "mod_version_submission_comments", + "name": "id" + } + } }, { "ordinal": 1, "name": "submission_id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_version_submission_comments", + "name": "submission_id" + } + } }, { "ordinal": 2, "name": "comment", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_version_submission_comments", + "name": "comment" + } + } }, { "ordinal": 3, "name": "author_id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_version_submission_comments", + "name": "author_id" + } + } }, { "ordinal": 4, "name": "created_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_version_submission_comments", + "name": "created_at" + } + } }, { "ordinal": 5, "name": "updated_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_version_submission_comments", + "name": "updated_at" + } + } } ], "parameters": { diff --git a/.sqlx/query-ddef8117c5f97a1dbef19f8248b9b90a0b101b5f2abf3e2c3acb2df18cf2d001.json b/.sqlx/query-ddef8117c5f97a1dbef19f8248b9b90a0b101b5f2abf3e2c3acb2df18cf2d001.json index e75188d..86c9973 100644 --- a/.sqlx/query-ddef8117c5f97a1dbef19f8248b9b90a0b101b5f2abf3e2c3acb2df18cf2d001.json +++ b/.sqlx/query-ddef8117c5f97a1dbef19f8248b9b90a0b101b5f2abf3e2c3acb2df18cf2d001.json @@ -19,6 +19,12 @@ ] } } + }, + "origin": { + "Table": { + "table": "incompatibilities", + "name": "compare" + } } }, { @@ -36,22 +42,46 @@ ] } } + }, + "origin": { + "Table": { + "table": "incompatibilities", + "name": "importance" + } } }, { "ordinal": 2, "name": "incompatibility_id", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "incompatibilities", + "name": "incompatibility_id" + } + } }, { "ordinal": 3, "name": "mod_id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "incompatibilities", + "name": "mod_id" + } + } }, { "ordinal": 4, "name": "version", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "incompatibilities", + "name": "version" + } + } } ], "parameters": { diff --git a/.sqlx/query-de581a1dcbd3b435b67aa1e39bd256798593badec03e4a7507b4537ee50f1e6e.json b/.sqlx/query-de581a1dcbd3b435b67aa1e39bd256798593badec03e4a7507b4537ee50f1e6e.json index b09cde7..980ef35 100644 --- a/.sqlx/query-de581a1dcbd3b435b67aa1e39bd256798593badec03e4a7507b4537ee50f1e6e.json +++ b/.sqlx/query-de581a1dcbd3b435b67aa1e39bd256798593badec03e4a7507b4537ee50f1e6e.json @@ -6,17 +6,35 @@ { "ordinal": 0, "name": "id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "deprecations", + "name": "id" + } + } }, { "ordinal": 1, "name": "mod_id", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "deprecations", + "name": "mod_id" + } + } }, { "ordinal": 2, "name": "reason", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "deprecations", + "name": "reason" + } + } } ], "parameters": { diff --git a/.sqlx/query-dfe205a13013db7ee5dbeb0ea3011a909895fdc0e98541bed9816362862968f7.json b/.sqlx/query-dfe205a13013db7ee5dbeb0ea3011a909895fdc0e98541bed9816362862968f7.json index a2e157f..9d8f1f0 100644 --- a/.sqlx/query-dfe205a13013db7ee5dbeb0ea3011a909895fdc0e98541bed9816362862968f7.json +++ b/.sqlx/query-dfe205a13013db7ee5dbeb0ea3011a909895fdc0e98541bed9816362862968f7.json @@ -18,22 +18,46 @@ ] } } + }, + "origin": { + "Table": { + "table": "mod_version_submission_comment_audit", + "name": "action" + } } }, { "ordinal": 1, "name": "details", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_version_submission_comment_audit", + "name": "details" + } + } }, { "ordinal": 2, "name": "performed_by", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_version_submission_comment_audit", + "name": "performed_by" + } + } }, { "ordinal": 3, "name": "performed_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mod_version_submission_comment_audit", + "name": "performed_at" + } + } } ], "parameters": { diff --git a/.sqlx/query-e135a61fc8cd6fb39851cf232ed5ba26571d4abff8f13b07b65707985e78ef82.json b/.sqlx/query-e135a61fc8cd6fb39851cf232ed5ba26571d4abff8f13b07b65707985e78ef82.json index 38eff6d..af1d417 100644 --- a/.sqlx/query-e135a61fc8cd6fb39851cf232ed5ba26571d4abff8f13b07b65707985e78ef82.json +++ b/.sqlx/query-e135a61fc8cd6fb39851cf232ed5ba26571d4abff8f13b07b65707985e78ef82.json @@ -6,27 +6,57 @@ { "ordinal": 0, "name": "id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "developers", + "name": "id" + } + } }, { "ordinal": 1, "name": "username", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "developers", + "name": "username" + } + } }, { "ordinal": 2, "name": "display_name", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "developers", + "name": "display_name" + } + } }, { "ordinal": 3, "name": "is_owner", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "mods_developers", + "name": "is_owner" + } + } }, { "ordinal": 4, "name": "mod_id", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mods_developers", + "name": "mod_id" + } + } } ], "parameters": { diff --git a/.sqlx/query-e3b9e16724458e4ac536d3df57ae813fbc3f8d8f22fcaaeefa24cc1f97146bbe.json b/.sqlx/query-e3b9e16724458e4ac536d3df57ae813fbc3f8d8f22fcaaeefa24cc1f97146bbe.json index 0f4d005..d61b885 100644 --- a/.sqlx/query-e3b9e16724458e4ac536d3df57ae813fbc3f8d8f22fcaaeefa24cc1f97146bbe.json +++ b/.sqlx/query-e3b9e16724458e4ac536d3df57ae813fbc3f8d8f22fcaaeefa24cc1f97146bbe.json @@ -6,47 +6,101 @@ { "ordinal": 0, "name": "uuid", - "type_info": "Uuid" + "type_info": "Uuid", + "origin": { + "Table": { + "table": "github_login_attempts", + "name": "uid" + } + } }, { "ordinal": 1, "name": "ip", - "type_info": "Inet" + "type_info": "Inet", + "origin": { + "Table": { + "table": "github_login_attempts", + "name": "ip" + } + } }, { "ordinal": 2, "name": "interval", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "github_login_attempts", + "name": "interval" + } + } }, { "ordinal": 3, "name": "expires_in", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "github_login_attempts", + "name": "expires_in" + } + } }, { "ordinal": 4, "name": "created_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "github_login_attempts", + "name": "created_at" + } + } }, { "ordinal": 5, "name": "last_poll", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "github_login_attempts", + "name": "last_poll" + } + } }, { "ordinal": 6, "name": "uri", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "github_login_attempts", + "name": "challenge_uri" + } + } }, { "ordinal": 7, "name": "device_code", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "github_login_attempts", + "name": "device_code" + } + } }, { "ordinal": 8, "name": "user_code", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "github_login_attempts", + "name": "user_code" + } + } } ], "parameters": { diff --git a/.sqlx/query-e6428914db0f351cc0e276729ac6d9a3f8d0504dfdf1c18e9fc653468faa505a.json b/.sqlx/query-e6428914db0f351cc0e276729ac6d9a3f8d0504dfdf1c18e9fc653468faa505a.json index 2f45786..f2000a6 100644 --- a/.sqlx/query-e6428914db0f351cc0e276729ac6d9a3f8d0504dfdf1c18e9fc653468faa505a.json +++ b/.sqlx/query-e6428914db0f351cc0e276729ac6d9a3f8d0504dfdf1c18e9fc653468faa505a.json @@ -6,22 +6,46 @@ { "ordinal": 0, "name": "id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_tags", + "name": "id" + } + } }, { "ordinal": 1, "name": "name", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_tags", + "name": "name" + } + } }, { "ordinal": 2, "name": "display_name", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_tags", + "name": "display_name" + } + } }, { "ordinal": 3, "name": "is_readonly", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "mod_tags", + "name": "is_readonly" + } + } } ], "parameters": { diff --git a/.sqlx/query-e76119227a3fcb00348279467161b081128d2a2cf67057da0e4b726463ceb40a.json b/.sqlx/query-e76119227a3fcb00348279467161b081128d2a2cf67057da0e4b726463ceb40a.json deleted file mode 100644 index 2e186ba..0000000 --- a/.sqlx/query-e76119227a3fcb00348279467161b081128d2a2cf67057da0e4b726463ceb40a.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "SELECT\n d.id,\n d.username,\n d.display_name,\n d.verified,\n d.admin,\n d.github_user_id as github_id\n FROM developers d\n INNER JOIN auth_tokens a ON d.id = a.developer_id\n WHERE a.token = $1\n AND (\n expires_at IS NULL\n OR expires_at > NOW()\n )", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "id", - "type_info": "Int4" - }, - { - "ordinal": 1, - "name": "username", - "type_info": "Text" - }, - { - "ordinal": 2, - "name": "display_name", - "type_info": "Text" - }, - { - "ordinal": 3, - "name": "verified", - "type_info": "Bool" - }, - { - "ordinal": 4, - "name": "admin", - "type_info": "Bool" - }, - { - "ordinal": 5, - "name": "github_id", - "type_info": "Int8" - } - ], - "parameters": { - "Left": [ - "Text" - ] - }, - "nullable": [ - false, - false, - false, - false, - false, - false - ] - }, - "hash": "e76119227a3fcb00348279467161b081128d2a2cf67057da0e4b726463ceb40a" -} diff --git a/.sqlx/query-ebf42091af98e77f7e036aa82cf3fc091bfaab8ab9286c04c1bd4f83c91a68cb.json b/.sqlx/query-ebf42091af98e77f7e036aa82cf3fc091bfaab8ab9286c04c1bd4f83c91a68cb.json index d8d8f51..e85b16c 100644 --- a/.sqlx/query-ebf42091af98e77f7e036aa82cf3fc091bfaab8ab9286c04c1bd4f83c91a68cb.json +++ b/.sqlx/query-ebf42091af98e77f7e036aa82cf3fc091bfaab8ab9286c04c1bd4f83c91a68cb.json @@ -6,32 +6,68 @@ { "ordinal": 0, "name": "id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "developers", + "name": "id" + } + } }, { "ordinal": 1, "name": "username", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "developers", + "name": "username" + } + } }, { "ordinal": 2, "name": "display_name", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "developers", + "name": "display_name" + } + } }, { "ordinal": 3, "name": "verified", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "developers", + "name": "verified" + } + } }, { "ordinal": 4, "name": "admin", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "developers", + "name": "admin" + } + } }, { "ordinal": 5, "name": "github_id", - "type_info": "Int8" + "type_info": "Int8", + "origin": { + "Table": { + "table": "developers", + "name": "github_user_id" + } + } } ], "parameters": { diff --git a/.sqlx/query-ef99dae03ba65d4f0cb2c81e1460f4350aa059506c65c84df6445310feae9669.json b/.sqlx/query-ef99dae03ba65d4f0cb2c81e1460f4350aa059506c65c84df6445310feae9669.json index 7f0a43a..52cc1d0 100644 --- a/.sqlx/query-ef99dae03ba65d4f0cb2c81e1460f4350aa059506c65c84df6445310feae9669.json +++ b/.sqlx/query-ef99dae03ba65d4f0cb2c81e1460f4350aa059506c65c84df6445310feae9669.json @@ -6,32 +6,68 @@ { "ordinal": 0, "name": "id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "developers", + "name": "id" + } + } }, { "ordinal": 1, "name": "username", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "developers", + "name": "username" + } + } }, { "ordinal": 2, "name": "display_name", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "developers", + "name": "display_name" + } + } }, { "ordinal": 3, "name": "verified", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "developers", + "name": "verified" + } + } }, { "ordinal": 4, "name": "admin", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "developers", + "name": "admin" + } + } }, { "ordinal": 5, "name": "github_id", - "type_info": "Int8" + "type_info": "Int8", + "origin": { + "Table": { + "table": "developers", + "name": "github_user_id" + } + } } ], "parameters": { diff --git a/.sqlx/query-f1945f11dce4a240cccbf4e8c2f282dfd1dc2cb69bb9803e0a7a4d648239389f.json b/.sqlx/query-f1945f11dce4a240cccbf4e8c2f282dfd1dc2cb69bb9803e0a7a4d648239389f.json index 30b2af7..8793eeb 100644 --- a/.sqlx/query-f1945f11dce4a240cccbf4e8c2f282dfd1dc2cb69bb9803e0a7a4d648239389f.json +++ b/.sqlx/query-f1945f11dce4a240cccbf4e8c2f282dfd1dc2cb69bb9803e0a7a4d648239389f.json @@ -6,12 +6,24 @@ { "ordinal": 0, "name": "checked_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "github_loader_release_stats", + "name": "checked_at" + } + } }, { "ordinal": 1, "name": "total_download_count", - "type_info": "Int8" + "type_info": "Int8", + "origin": { + "Table": { + "table": "github_loader_release_stats", + "name": "total_download_count" + } + } } ], "parameters": { diff --git a/.sqlx/query-f2c57d8bc7752c080fc45a6dd5b1fcc9f5ebe72d4948e0403ef5d488a9c8a370.json b/.sqlx/query-f2c57d8bc7752c080fc45a6dd5b1fcc9f5ebe72d4948e0403ef5d488a9c8a370.json index b232b57..8abdd0f 100644 --- a/.sqlx/query-f2c57d8bc7752c080fc45a6dd5b1fcc9f5ebe72d4948e0403ef5d488a9c8a370.json +++ b/.sqlx/query-f2c57d8bc7752c080fc45a6dd5b1fcc9f5ebe72d4948e0403ef5d488a9c8a370.json @@ -6,7 +6,13 @@ { "ordinal": 0, "name": "id", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mods", + "name": "id" + } + } } ], "parameters": { diff --git a/.sqlx/query-f683c5573877e25f4608a9d8cb97588c3b0cd770f82b53fa2248cdbcbe2c8f49.json b/.sqlx/query-f683c5573877e25f4608a9d8cb97588c3b0cd770f82b53fa2248cdbcbe2c8f49.json index fc35a3c..0858f05 100644 --- a/.sqlx/query-f683c5573877e25f4608a9d8cb97588c3b0cd770f82b53fa2248cdbcbe2c8f49.json +++ b/.sqlx/query-f683c5573877e25f4608a9d8cb97588c3b0cd770f82b53fa2248cdbcbe2c8f49.json @@ -6,22 +6,46 @@ { "ordinal": 0, "name": "id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_tags", + "name": "id" + } + } }, { "ordinal": 1, "name": "name", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_tags", + "name": "name" + } + } }, { "ordinal": 2, "name": "display_name", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_tags", + "name": "display_name" + } + } }, { "ordinal": 3, "name": "is_readonly", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "mod_tags", + "name": "is_readonly" + } + } } ], "parameters": { diff --git a/.sqlx/query-f879d614ff765e840a2cc426e262cd380be6976024923abe0442430d20c8b0bd.json b/.sqlx/query-f879d614ff765e840a2cc426e262cd380be6976024923abe0442430d20c8b0bd.json new file mode 100644 index 0000000..9e9f8b1 --- /dev/null +++ b/.sqlx/query-f879d614ff765e840a2cc426e262cd380be6976024923abe0442430d20c8b0bd.json @@ -0,0 +1,93 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT final_q.id, final_q.version, final_q.download_link, final_q.mv_id FROM (\n SELECT DISTINCT ON (q.mv_id) q.id, q.version, q.download_link, q.mv_id, q.gd FROM (\n SELECT DISTINCT ON (m.id, mgv.gd, mv.geode_major) m.id, mv.name, mv.version, mv.download_link, mv.managed_download_link, mv.id as mv_id, mgv.gd\n FROM MODS m\n INNER JOIN mod_versions mv ON m.id = mv.mod_id\n INNER JOIN mod_version_statuses mvs ON mvs.mod_version_id = mv.id\n INNER JOIN mod_gd_versions mgv ON mgv.mod_id = mv.id\n WHERE mvs.status = 'accepted' AND mgv.gd = ANY($1::gd_version[])\n ORDER BY m.id, mgv.gd DESC, mv.geode_major DESC, mv.id DESC\n ) q\n WHERE q.managed_download_link IS NULL\n ORDER BY q.mv_id, q.gd DESC\n ) final_q", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Text", + "origin": { + "Table": { + "table": "mods", + "name": "id" + } + } + }, + { + "ordinal": 1, + "name": "version", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "version" + } + } + }, + { + "ordinal": 2, + "name": "download_link", + "type_info": "Text", + "origin": { + "Table": { + "table": "mod_versions", + "name": "download_link" + } + } + }, + { + "ordinal": 3, + "name": "mv_id", + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_versions", + "name": "id" + } + } + } + ], + "parameters": { + "Left": [ + { + "Custom": { + "name": "gd_version[]", + "kind": { + "Array": { + "Custom": { + "name": "gd_version", + "kind": { + "Enum": [ + "*", + "2.113", + "2.200", + "2.204", + "2.205", + "2.206", + "2.207", + "2.2071", + "2.2072", + "2.2073", + "2.2074", + "2.208", + "2.2081", + "2.2082" + ] + } + } + } + } + } + } + ] + }, + "nullable": [ + false, + false, + false, + false + ] + }, + "hash": "f879d614ff765e840a2cc426e262cd380be6976024923abe0442430d20c8b0bd" +} diff --git a/.sqlx/query-f98fe5c88a7a234cc0b68fb39c156a741fbad1d2e4682e1e748037bb08962912.json b/.sqlx/query-f98fe5c88a7a234cc0b68fb39c156a741fbad1d2e4682e1e748037bb08962912.json index a012c0c..df6a0a8 100644 --- a/.sqlx/query-f98fe5c88a7a234cc0b68fb39c156a741fbad1d2e4682e1e748037bb08962912.json +++ b/.sqlx/query-f98fe5c88a7a234cc0b68fb39c156a741fbad1d2e4682e1e748037bb08962912.json @@ -6,42 +6,90 @@ { "ordinal": 0, "name": "id", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mods", + "name": "id" + } + } }, { "ordinal": 1, "name": "repository", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mods", + "name": "repository" + } + } }, { "ordinal": 2, "name": "about", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mods", + "name": "about" + } + } }, { "ordinal": 3, "name": "changelog", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "mods", + "name": "changelog" + } + } }, { "ordinal": 4, "name": "featured", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "mods", + "name": "featured" + } + } }, { "ordinal": 5, "name": "download_count", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mods", + "name": "download_count" + } + } }, { "ordinal": 6, "name": "created_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mods", + "name": "created_at" + } + } }, { "ordinal": 7, "name": "updated_at", - "type_info": "Timestamptz" + "type_info": "Timestamptz", + "origin": { + "Table": { + "table": "mods", + "name": "updated_at" + } + } } ], "parameters": { diff --git a/.sqlx/query-fca16bbe2790df77b2a7782389c7451a8fc46a5fd1114888b8a5d2ab42db1135.json b/.sqlx/query-fca16bbe2790df77b2a7782389c7451a8fc46a5fd1114888b8a5d2ab42db1135.json index 0e87f90..54a27ef 100644 --- a/.sqlx/query-fca16bbe2790df77b2a7782389c7451a8fc46a5fd1114888b8a5d2ab42db1135.json +++ b/.sqlx/query-fca16bbe2790df77b2a7782389c7451a8fc46a5fd1114888b8a5d2ab42db1135.json @@ -6,7 +6,13 @@ { "ordinal": 0, "name": "id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "mod_version_statuses", + "name": "id" + } + } } ], "parameters": { diff --git a/.sqlx/query-fced42c56c5c1a4ec5b47254c6ec157560ec9d314947ea11c35f10a736a31684.json b/.sqlx/query-fced42c56c5c1a4ec5b47254c6ec157560ec9d314947ea11c35f10a736a31684.json index 25b4bd5..57b01a5 100644 --- a/.sqlx/query-fced42c56c5c1a4ec5b47254c6ec157560ec9d314947ea11c35f10a736a31684.json +++ b/.sqlx/query-fced42c56c5c1a4ec5b47254c6ec157560ec9d314947ea11c35f10a736a31684.json @@ -6,32 +6,68 @@ { "ordinal": 0, "name": "id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "developers", + "name": "id" + } + } }, { "ordinal": 1, "name": "username", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "developers", + "name": "username" + } + } }, { "ordinal": 2, "name": "display_name", - "type_info": "Text" + "type_info": "Text", + "origin": { + "Table": { + "table": "developers", + "name": "display_name" + } + } }, { "ordinal": 3, "name": "admin", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "developers", + "name": "admin" + } + } }, { "ordinal": 4, "name": "verified", - "type_info": "Bool" + "type_info": "Bool", + "origin": { + "Table": { + "table": "developers", + "name": "verified" + } + } }, { "ordinal": 5, "name": "github_id", - "type_info": "Int8" + "type_info": "Int8", + "origin": { + "Table": { + "table": "developers", + "name": "github_user_id" + } + } } ], "parameters": { diff --git a/.sqlx/query-fdcb055531d7d980dd5447b521a98622b4e452c66855a4be5a749c1576b83c25.json b/.sqlx/query-fdcb055531d7d980dd5447b521a98622b4e452c66855a4be5a749c1576b83c25.json index 67426d7..4fd792d 100644 --- a/.sqlx/query-fdcb055531d7d980dd5447b521a98622b4e452c66855a4be5a749c1576b83c25.json +++ b/.sqlx/query-fdcb055531d7d980dd5447b521a98622b4e452c66855a4be5a749c1576b83c25.json @@ -6,7 +6,13 @@ { "ordinal": 0, "name": "id", - "type_info": "Int4" + "type_info": "Int4", + "origin": { + "Table": { + "table": "deprecations", + "name": "id" + } + } } ], "parameters": { From f00caf164a715e3bdd610a645c1782f6c3d2ad14 Mon Sep 17 00:00:00 2001 From: dankmeme01 <42031238+dankmeme01@users.noreply.github.com> Date: Sat, 18 Jul 2026 19:44:14 +0200 Subject: [PATCH 11/11] my bad --- ...cb00348279467161b081128d2a2cf67057da0e4b726463ceb40a.json} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename .sqlx/{query-896ab2c695cc66255b9d168f59e1a8b86519a68c061300278aaa58dcbe82b551.json => query-e76119227a3fcb00348279467161b081128d2a2cf67057da0e4b726463ceb40a.json} (89%) diff --git a/.sqlx/query-896ab2c695cc66255b9d168f59e1a8b86519a68c061300278aaa58dcbe82b551.json b/.sqlx/query-e76119227a3fcb00348279467161b081128d2a2cf67057da0e4b726463ceb40a.json similarity index 89% rename from .sqlx/query-896ab2c695cc66255b9d168f59e1a8b86519a68c061300278aaa58dcbe82b551.json rename to .sqlx/query-e76119227a3fcb00348279467161b081128d2a2cf67057da0e4b726463ceb40a.json index 454420a..094f155 100644 --- a/.sqlx/query-896ab2c695cc66255b9d168f59e1a8b86519a68c061300278aaa58dcbe82b551.json +++ b/.sqlx/query-e76119227a3fcb00348279467161b081128d2a2cf67057da0e4b726463ceb40a.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT\n d.id,\n d.username,\n d.display_name,\n d.verified,\n d.admin,\n d.github_user_id as github_id\n FROM developers d\n INNER JOIN auth_tokens a ON d.id = a.developer_id\n WHERE d.id = 5 AND $1 = $1", + "query": "SELECT\n d.id,\n d.username,\n d.display_name,\n d.verified,\n d.admin,\n d.github_user_id as github_id\n FROM developers d\n INNER JOIN auth_tokens a ON d.id = a.developer_id\n WHERE a.token = $1\n AND (\n expires_at IS NULL\n OR expires_at > NOW()\n )", "describe": { "columns": [ { @@ -84,5 +84,5 @@ false ] }, - "hash": "896ab2c695cc66255b9d168f59e1a8b86519a68c061300278aaa58dcbe82b551" + "hash": "e76119227a3fcb00348279467161b081128d2a2cf67057da0e4b726463ceb40a" }