diff --git a/.env b/.env index 14b7aa236..47c072aab 100644 --- a/.env +++ b/.env @@ -42,7 +42,10 @@ RATE_LIMIT_IGNORE_IPS='["127.0.0.1"]' WHITELISTED_MODPACK_DOMAINS='["cdn.modrinth.com", "edge.forgecdn.net", "github.com", "raw.githubusercontent.com"]' -ALLOWED_CALLBACK_URLS='["localhost", ".modrinth.com", "-modrinth.vercel.app"]' +ALLOWED_CALLBACK_URLS='["localhost", ".modrinth.com"]' ARIADNE_ADMIN_KEY=feedbeef -ARIADNE_URL=https://staging-ariadne.modrinth.com/v1/ \ No newline at end of file +ARIADNE_URL=https://staging-ariadne.modrinth.com/v1/ + +STRIPE_TOKEN=none +STRIPE_WEBHOOK_SECRET=none \ No newline at end of file diff --git a/.github/workflows/docker-compile.yml b/.github/workflows/docker-compile.yml index b1face878..035d723ba 100644 --- a/.github/workflows/docker-compile.yml +++ b/.github/workflows/docker-compile.yml @@ -12,32 +12,15 @@ jobs: docker: runs-on: ubuntu-latest steps: - - - name: Checkout + - name: Checkout uses: actions/checkout@v2 - - - name: Docker meta + - name: Fetch docker metadata id: docker_meta - uses: crazy-max/ghaction-docker-meta@v1 + uses: docker/metadata-action@v3 with: images: ghcr.io/modrinth/labrinth - - name: Set up QEMU - uses: docker/setup-qemu-action@v1 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - - name: Cache Docker layers - uses: actions/cache@v2 - with: - path: /tmp/.buildx-cache - key: ${{ runner.os }}-buildx-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-buildx- - - - name: Login to GHCR - if: github.event_name != 'pull_request' + name: Login to GitHub Images uses: docker/login-action@v1 with: registry: ghcr.io @@ -45,20 +28,11 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push + id: docker_build uses: docker/build-push-action@v2 with: context: . file: ./Dockerfile push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.docker_meta.outputs.tags }} - labels: ${{ steps.docker_meta.outputs.labels }} - cache-from: type=local,src=/tmp/.buildx-cache - cache-to: type=local,dest=/tmp/.buildx-cache-new - - - # Temp fix - # https://github.com/docker/build-push-action/issues/252 - # https://github.com/moby/buildkit/issues/1896 - name: Move cache - run: | - rm -rf /tmp/.buildx-cache - mv /tmp/.buildx-cache-new /tmp/.buildx-cache \ No newline at end of file + labels: ${{ steps.docker_meta.outputs.labels }} \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 53e648ac2..c6f7e4aef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,11 +19,11 @@ dependencies = [ "futures-util", "log", "once_cell", - "parking_lot 0.12.0", + "parking_lot", "pin-project-lite", "smallvec", "tokio", - "tokio-util 0.7.2", + "tokio-util", ] [[package]] @@ -40,14 +40,14 @@ dependencies = [ "memchr", "pin-project-lite", "tokio", - "tokio-util 0.7.2", + "tokio-util", ] [[package]] name = "actix-cors" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "684a6ce1562a5fcca49bc9302896c63547eea78a1e405e837e7416affd8b6eb9" +checksum = "b340e9cfa5b08690aae90fb61beb44e9b06f44fe3d0f93781aaa58cfba86245e" dependencies = [ "actix-utils", "actix-web", @@ -89,7 +89,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rand", - "sha1 0.10.1", + "sha1 0.10.5", "smallvec", "tracing", "zstd", @@ -125,16 +125,15 @@ dependencies = [ [[package]] name = "actix-router" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb60846b52c118f2f04a56cc90880a274271c489b2498623d58176f8ca21fa80" +checksum = "d66ff4d247d2b160861fa2866457e85706833527840e4133f8f49aa423a38799" dependencies = [ "bytestring", - "firestorm", "http", - "log", "regex", "serde", + "tracing", ] [[package]] @@ -179,9 +178,9 @@ dependencies = [ [[package]] name = "actix-utils" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e491cbaac2e7fc788dfff99ff48ef317e23b3cf63dbaf7aaab6418f40f92aa94" +checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8" dependencies = [ "local-waker", "pin-project-lite", @@ -224,7 +223,7 @@ dependencies = [ "serde_urlencoded", "smallvec", "socket2", - "time", + "time 0.3.16", "url", ] @@ -282,24 +281,24 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.18" +version = "0.7.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" dependencies = [ "memchr", ] [[package]] name = "alloc-no-stdlib" -version = "2.0.3" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35ef4730490ad1c4eae5c4325b2a95f521d023e5c885853ff7aca0a6a1631db3" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" [[package]] name = "alloc-stdlib" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "697ed7edc0f1711de49ce108c541623a0af97c6c60b2f6e2b65229847ac843c2" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" dependencies = [ "alloc-no-stdlib", ] @@ -320,10 +319,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] -name = "async-channel" -version = "1.6.1" +name = "arrayvec" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + +[[package]] +name = "async-channel" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14485364214912d3b19cc3435dde4df66065127f05fa0d75c712f36f12c2f28" dependencies = [ "concurrent-queue", "event-listener", @@ -332,9 +337,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.53" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed6aa3524a2dfcf9fe180c51eae2b58738348d819517ceadf95789c51fff7600" +checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c" dependencies = [ "proc-macro2", "quote", @@ -395,7 +400,7 @@ dependencies = [ "serde", "serde-xml-rs", "thiserror", - "time", + "time 0.3.16", "url", ] @@ -410,15 +415,15 @@ dependencies = [ [[package]] name = "base64" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64ct" -version = "1.0.1" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a32fd6af2b5827bce66c29053ba0e7c42b9dcab01835835058558c10851a46b" +checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" [[package]] name = "bitflags" @@ -437,9 +442,9 @@ dependencies = [ [[package]] name = "block-buffer" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" dependencies = [ "generic-array", ] @@ -467,9 +472,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.9.1" +version = "3.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" +checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" [[package]] name = "byteorder" @@ -479,15 +484,15 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" +checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" [[package]] name = "bytestring" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90706ba19e97b90786e19dc0d5e2abd80008d99d4c0c5d1ad0b5e72cec7c494d" +checksum = "86b6a75fd3048808ef06af5cd79712be8111960adaf89d90250974b38fc3928a" dependencies = [ "bytes", ] @@ -527,9 +532,9 @@ checksum = "a2698f953def977c68f935bb0dfa959375ad4638570e969e2f1e9f433cbf1af6" [[package]] name = "cc" -version = "1.0.73" +version = "1.0.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +checksum = "581f5dba903aac52ea3feb5ec4810848460ee833876f1f9b0fdeab1f19091574" dependencies = [ "jobserver", ] @@ -556,9 +561,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" dependencies = [ "iana-time-zone", + "js-sys", "num-integer", "num-traits", "serde", + "time 0.1.44", + "wasm-bindgen", "winapi", ] @@ -583,9 +591,9 @@ dependencies = [ [[package]] name = "concurrent-queue" -version = "1.2.2" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" +checksum = "af4780a44ab5696ea9e28294517f1fffb421a83a25af521333c838635509db9c" dependencies = [ "cache-padded", ] @@ -604,12 +612,12 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] name = "cookie" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94d4706de1b0fa5b132270cddffa8585166037822e260a944fe161acd137ca05" +checksum = "344adc371239ef32293cb1c4fe519592fcf21206c79c02854320afcdf3ab4917" dependencies = [ "percent-encoding", - "time", + "time 0.3.16", "version_check", ] @@ -631,9 +639,9 @@ checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" [[package]] name = "cpufeatures" -version = "0.2.2" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" dependencies = [ "libc", ] @@ -664,9 +672,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.4" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" dependencies = [ "cfg-if", "crossbeam-utils", @@ -674,9 +682,9 @@ dependencies = [ [[package]] name = "crossbeam-queue" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2" +checksum = "1cd42583b04998a5363558e5f9291ee5a5ff6b49944332103f251e7479a82aa7" dependencies = [ "cfg-if", "crossbeam-utils", @@ -684,29 +692,38 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.8" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +checksum = "edbafec5fa1f196ca66527c1b12c2ec4745ca14b50f1ad8f9f6f720b55d11fac" dependencies = [ "cfg-if", - "lazy_static", ] [[package]] name = "crypto-common" -version = "0.1.3" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", "typenum", ] [[package]] -name = "curl" -version = "0.4.43" +name = "crypto-mac" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d855aeef205b43f65a5001e0997d81f8efca7badad4fad7d897aa7f0d0651f" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "curl" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "509bd11746c7ac09ebd19f0b17782eae80aadee26237658a6b4808afb5c11a22" dependencies = [ "curl-sys", "libc", @@ -719,9 +736,9 @@ dependencies = [ [[package]] name = "curl-sys" -version = "0.4.55+curl-7.83.1" +version = "0.4.58+curl-7.86.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23734ec77368ec583c2e61dd3f0b0e5c98b93abe6d2a004ca06b91dd7e3e2762" +checksum = "430e2ecf0c5f4445334472cf8f9611a6eea404b4135ca5500f38a97a128c913e" dependencies = [ "cc", "libc", @@ -779,9 +796,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.13.4" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +checksum = "b0dd3cd20dc6b5a876612a6e5accfe7f3dd883db6d07acfbf14c128f61550dfa" dependencies = [ "darling_core", "darling_macro", @@ -789,9 +806,9 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.13.4" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +checksum = "a784d2ccaf7c98501746bf0be29b2022ba41fd62a2e622af997a03e9f972859f" dependencies = [ "fnv", "ident_case", @@ -803,9 +820,9 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.13.4" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +checksum = "7618812407e9402654622dd402b0a89dff9ba93badd6540781526117b92aab7e" dependencies = [ "darling_core", "quote", @@ -814,13 +831,15 @@ dependencies = [ [[package]] name = "dashmap" -version = "5.3.3" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391b56fbd302e585b7a9494fb70e40949567b1cf9003a8e4a6041a1687c26573" +checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" dependencies = [ "cfg-if", - "hashbrown 0.12.1", + "hashbrown", "lock_api", + "once_cell", + "parking_lot_core", ] [[package]] @@ -847,11 +866,11 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.3" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c" dependencies = [ - "block-buffer 0.10.2", + "block-buffer 0.10.3", "crypto-common", "subtle", ] @@ -882,12 +901,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257" -[[package]] -name = "dotenv" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" - [[package]] name = "dotenvy" version = "0.15.6" @@ -896,9 +909,9 @@ checksum = "03d8c417d7a8cb362e0c37e5d815f5eb7c37f79ff93707329d5a194e42e54ca0" [[package]] name = "either" -version = "1.6.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" dependencies = [ "serde", ] @@ -914,9 +927,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" +checksum = "c90bf5f19754d10198ccb95b70664fc925bd1fc090a0fd9a6ebc54acc8cd6272" dependencies = [ "atty", "humantime", @@ -927,34 +940,26 @@ dependencies = [ [[package]] name = "event-listener" -version = "2.5.2" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "fastrand" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" dependencies = [ "instant", ] -[[package]] -name = "firestorm" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c5f6c2c942da57e2aaaa84b8a521489486f14e75e7fa91dab70aba913975f98" - [[package]] name = "flate2" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39522e96686d38f4bc984b9198e3a0613264abaebaff2c5c918bfa6b6da09af" +checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" dependencies = [ - "cfg-if", "crc32fast", - "libc", "miniz_oxide", ] @@ -981,19 +986,18 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" dependencies = [ - "matches", "percent-encoding", ] [[package]] name = "futures" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" +checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" dependencies = [ "futures-channel", "futures-core", @@ -1006,9 +1010,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" dependencies = [ "futures-core", "futures-sink", @@ -1016,15 +1020,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" +checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" [[package]] name = "futures-executor" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" +checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" dependencies = [ "futures-core", "futures-task", @@ -1033,20 +1037,20 @@ dependencies = [ [[package]] name = "futures-intrusive" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62007592ac46aa7c2b6416f7deb9a8a8f63a01e0f1d6e1787d5630170db2b63e" +checksum = "1b6bdbb8c5a42b2bb5ee8dd9dc2c7d73ce3e15d26dfe100fb347ffa3f58c672b" dependencies = [ "futures-core", "lock_api", - "parking_lot 0.11.2", + "parking_lot", ] [[package]] name = "futures-io" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" +checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" [[package]] name = "futures-lite" @@ -1065,9 +1069,9 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" dependencies = [ "proc-macro2", "quote", @@ -1076,15 +1080,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" +checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" [[package]] name = "futures-task" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" +checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" [[package]] name = "futures-timer" @@ -1094,9 +1098,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" dependencies = [ "futures-channel", "futures-core", @@ -1112,9 +1116,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.5" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" dependencies = [ "typenum", "version_check", @@ -1122,40 +1126,20 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" dependencies = [ "cfg-if", "libc", - "wasi 0.10.0+wasi-snapshot-preview1", -] - -[[package]] -name = "gumdrop" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bc700f989d2f6f0248546222d9b4258f5b02a171a431f8285a81c08142629e3" -dependencies = [ - "gumdrop_derive", -] - -[[package]] -name = "gumdrop_derive" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "729f9bd3449d77e7831a18abfb7ba2f99ee813dfd15b8c2167c9a54ba20aa99d" -dependencies = [ - "proc-macro2", - "quote", - "syn", + "wasi 0.11.0+wasi-snapshot-preview1", ] [[package]] name = "h2" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57" +checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" dependencies = [ "bytes", "fnv", @@ -1166,32 +1150,26 @@ dependencies = [ "indexmap", "slab", "tokio", - "tokio-util 0.7.2", + "tokio-util", "tracing", ] [[package]] name = "hashbrown" -version = "0.11.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" - -[[package]] -name = "hashbrown" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ "ahash", ] [[package]] name = "hashlink" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d452c155cb93fecdfb02a73dd57b5d8e442c2063bd7aac72f1bc5e4263a43086" +checksum = "69fe1fcf8b4278d860ad0548329f892a3631fb63f82574df68275f34cdbe0ffa" dependencies = [ - "hashbrown 0.12.1", + "hashbrown", ] [[package]] @@ -1224,7 +1202,17 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" dependencies = [ - "hmac", + "hmac 0.12.1", +] + +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac", + "digest 0.9.0", ] [[package]] @@ -1233,7 +1221,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.3", + "digest 0.10.5", ] [[package]] @@ -1260,9 +1248,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" @@ -1278,9 +1266,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.18" +version = "0.14.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b26ae0a80afebe130861d90abf98e3814a4f28a4c6ffeb5ab8ebb2be311e0ef2" +checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac" dependencies = [ "bytes", "futures-channel", @@ -1315,9 +1303,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.51" +version = "0.1.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5a6ef98976b22b3b7f2f3a806f858cb862044cfa66805aa3ad84cb3d3b785ed" +checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1354,6 +1342,16 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "if_chain" version = "1.0.2" @@ -1362,12 +1360,13 @@ checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" [[package]] name = "indexmap" -version = "1.8.1" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ "autocfg", - "hashbrown 0.11.2", + "hashbrown", + "serde", ] [[package]] @@ -1423,33 +1422,33 @@ dependencies = [ [[package]] name = "itertools" -version = "0.10.3" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" +checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" [[package]] name = "jobserver" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" +checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.57" +version = "0.3.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" dependencies = [ "wasm-bindgen", ] @@ -1474,7 +1473,8 @@ dependencies = [ "env_logger", "futures", "futures-timer", - "gumdrop", + "hex", + "hmac 0.11.0", "itertools", "lazy_static", "log", @@ -1483,6 +1483,7 @@ dependencies = [ "regex", "reqwest", "rust-s3", + "rust_decimal", "serde", "serde_json", "serde_with", @@ -1519,7 +1520,7 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" dependencies = [ - "arrayvec", + "arrayvec 0.5.2", "bitflags", "cfg-if", "ryu", @@ -1528,9 +1529,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.126" +version = "0.2.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" [[package]] name = "libnghttp2-sys" @@ -1544,9 +1545,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.6" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e7e15d7610cce1d9752e137625f14e61a28cd45929b6e12e47b50fe154ee2e" +checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf" dependencies = [ "cc", "libc", @@ -1583,9 +1584,9 @@ checksum = "e34f76eb3611940e0e7d53a9aaa4e6a3151f69541a282fd0dad5571420c53ff1" [[package]] name = "lock_api" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" dependencies = [ "autocfg", "scopeguard", @@ -1619,11 +1620,11 @@ dependencies = [ [[package]] name = "md-5" -version = "0.10.1" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658646b21e0b72f7866c7038ab086d3d5e1cd6271f060fd37defb241949d0582" +checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" dependencies = [ - "digest 0.10.3", + "digest 0.10.5", ] [[package]] @@ -1646,7 +1647,7 @@ dependencies = [ "log", "serde", "serde_json", - "time", + "time 0.3.16", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -1681,23 +1682,23 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.5.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082" +checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713d550d9b44d89174e066b7a6217ae06234c10cb47819a88290d2b353c31799" +checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -1739,6 +1740,17 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-integer" version = "0.1.45" @@ -1779,9 +1791,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.12.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" [[package]] name = "opaque-debug" @@ -1791,9 +1803,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.40" +version = "0.10.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb81a6430ac911acb25fe5ac8f1d2af1b4ea8a4fdfda0f1ee4292af2e2d8eb0e" +checksum = "12fc0523e3bd51a692c8850d075d74dc062ccf251c0110668cbd921917118a13" dependencies = [ "bitflags", "cfg-if", @@ -1823,9 +1835,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.73" +version = "0.9.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5fd19fb3e0a8191c1e34935718976a3e70c112ab9a24af6d7cadccd9d90bc0" +checksum = "b03b84c3b2d099b81f0953422b4d4ad58761589d0229b5506356afca05a3670a" dependencies = [ "autocfg", "cc", @@ -1841,7 +1853,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a" dependencies = [ "dlv-list", - "hashbrown 0.12.1", + "hashbrown", ] [[package]] @@ -1852,50 +1864,25 @@ checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" [[package]] name = "parking_lot" -version = "0.11.2" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.5", -] - -[[package]] -name = "parking_lot" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.3", + "parking_lot_core", ] [[package]] name = "parking_lot_core" -version = "0.8.5" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall", - "smallvec", - "winapi", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -1911,9 +1898,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc" +checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" [[package]] name = "pbkdf2" @@ -1921,32 +1908,32 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" dependencies = [ - "digest 0.10.3", - "hmac", + "digest 0.10.5", + "hmac 0.12.1", "password-hash", - "sha2 0.10.2", + "sha2 0.10.6", ] [[package]] name = "percent-encoding" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "pin-project" -version = "1.0.10" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e" +checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.10" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb" +checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" dependencies = [ "proc-macro2", "quote", @@ -1967,16 +1954,17 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" [[package]] name = "polling" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685404d509889fade3e86fe3a5803bca2ec09b0c0778d5ada6ec8bf7a8de5259" +checksum = "ab4609a838d88b73d8238967b60dd115cc08d38e2bbaf51ee1e4b695f89122e2" dependencies = [ + "autocfg", "cfg-if", "libc", "log", @@ -2016,18 +2004,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.39" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.18" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" dependencies = [ "proc-macro2", ] @@ -2055,18 +2043,18 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", ] [[package]] name = "redox_syscall" -version = "0.2.13" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ "bitflags", ] @@ -2084,9 +2072,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.5.6" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" dependencies = [ "aho-corasick", "memchr", @@ -2095,9 +2083,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.26" +version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" [[package]] name = "remove_dir_all" @@ -2110,9 +2098,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.10" +version = "0.11.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46a1f7aa4f35e5e8b4160449f51afc758f0ce6454315a9fa7d0d113e958c41eb" +checksum = "431949c384f4e2ae07605ccaa56d1d9d2ecdb5cadd4f9577ccfab29f2e5149fc" dependencies = [ "base64", "bytes", @@ -2126,10 +2114,10 @@ dependencies = [ "hyper-tls", "ipnet", "js-sys", - "lazy_static", "log", "mime", "native-tls", + "once_cell", "percent-encoding", "pin-project-lite", "serde", @@ -2137,7 +2125,8 @@ dependencies = [ "serde_urlencoded", "tokio", "tokio-native-tls", - "tokio-util 0.6.10", + "tokio-util", + "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", @@ -2182,7 +2171,7 @@ dependencies = [ "base64", "cfg-if", "hex", - "hmac", + "hmac 0.12.1", "http", "log", "maybe-async", @@ -2193,14 +2182,25 @@ dependencies = [ "serde", "serde-xml-rs", "serde_derive", - "sha2 0.10.2", + "sha2 0.10.6", "thiserror", - "time", + "time 0.3.16", "tokio", "tokio-stream", "url", ] +[[package]] +name = "rust_decimal" +version = "1.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee9164faf726e4f3ece4978b25ca877ddc6802fa77f38cdccb32c7f805ecd70c" +dependencies = [ + "arrayvec 0.7.2", + "num-traits", + "serde", +] + [[package]] name = "rustc_version" version = "0.4.0" @@ -2212,9 +2212,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.20.6" +version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aab8ee6c7097ed6057f43c187a62418d0c05a4bd5f18b3571db50ee0f9ce033" +checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c" dependencies = [ "log", "ring", @@ -2224,19 +2224,13 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7522c9de787ff061458fe9a829dc790a3f5b22dc571694fc5883f448b94d9a9" +checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55" dependencies = [ "base64", ] -[[package]] -name = "rustversion" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" - [[package]] name = "rxml" version = "0.8.1" @@ -2258,9 +2252,9 @@ checksum = "a8633dff4bb93061867c8411c6e99068c5f59d9f890c87384169004b0fbb929a" [[package]] name = "ryu" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" [[package]] name = "schannel" @@ -2269,7 +2263,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" dependencies = [ "lazy_static", - "windows-sys", + "windows-sys 0.36.1", ] [[package]] @@ -2296,9 +2290,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.6.1" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" +checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" dependencies = [ "bitflags", "core-foundation", @@ -2319,15 +2313,15 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.9" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd" +checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" [[package]] name = "serde" -version = "1.0.137" +version = "1.0.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" dependencies = [ "serde_derive", ] @@ -2346,9 +2340,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.137" +version = "1.0.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" dependencies = [ "proc-macro2", "quote", @@ -2357,9 +2351,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.81" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45" dependencies = [ "itoa", "ryu", @@ -2380,20 +2374,25 @@ dependencies = [ [[package]] name = "serde_with" -version = "1.13.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b827f2113224f3f19a665136f006709194bdfdcb1fdc1e4b2b5cbac8e0cced54" +checksum = "368f2d60d049ea019a84dcd6687b0d1e0030fe663ae105039bdf967ed5e6a9a7" dependencies = [ - "rustversion", + "base64", + "chrono", + "hex", + "indexmap", "serde", + "serde_json", "serde_with_macros", + "time 0.3.16", ] [[package]] name = "serde_with_macros" -version = "1.5.2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" +checksum = "1ccadfacf6cf10faad22bbadf55986bdd0856edfb5d9210aa1dcf1f516e84e93" dependencies = [ "darling", "proc-macro2", @@ -2401,17 +2400,6 @@ dependencies = [ "syn", ] -[[package]] -name = "sha-1" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.3", -] - [[package]] name = "sha1" version = "0.6.1" @@ -2423,13 +2411,13 @@ dependencies = [ [[package]] name = "sha1" -version = "0.10.1" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c77f4e7f65455545c2153c1253d25056825e77ee2533f0e41deb65a93a34852f" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.3", + "digest 0.10.5", ] [[package]] @@ -2453,13 +2441,13 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.2" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.3", + "digest 0.10.5", ] [[package]] @@ -2473,9 +2461,12 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] [[package]] name = "sluice" @@ -2490,9 +2481,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "smartstring" @@ -2505,9 +2496,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.4.4" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" dependencies = [ "libc", "winapi", @@ -2521,9 +2512,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "sqlformat" -version = "0.1.8" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4b7922be017ee70900be125523f38bdd644f4f06a1b16e8fa5a8ee8c34bffd4" +checksum = "f87e292b4291f154971a43c3774364e2cbcaec599d3f5bf6fa9d122885dbc38a" dependencies = [ "itertools", "nom 7.1.1", @@ -2532,9 +2523,9 @@ dependencies = [ [[package]] name = "sqlx" -version = "0.6.0" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f82cbe94f41641d6c410ded25bbf5097c240cefdf8e3b06d04198d0a96af6a4" +checksum = "9249290c05928352f71c077cc44a464d880c63f26f7534728cca008e135c0428" dependencies = [ "sqlx-core", "sqlx-macros", @@ -2542,9 +2533,9 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.6.0" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b69bf218860335ddda60d6ce85ee39f6cf6e5630e300e19757d1de15886a093" +checksum = "dcbc16ddba161afc99e14d1713a453747a2b07fc097d2009f4c300ec99286105" dependencies = [ "ahash", "atoi", @@ -2556,6 +2547,7 @@ dependencies = [ "crc", "crossbeam-queue", "dirs", + "dotenvy", "either", "event-listener", "futures-channel", @@ -2565,23 +2557,25 @@ dependencies = [ "hashlink", "hex", "hkdf", - "hmac", + "hmac 0.12.1", "indexmap", "itoa", "libc", "log", "md-5", "memchr", + "num-bigint", "once_cell", "paste", "percent-encoding", "rand", + "rust_decimal", "rustls", "rustls-pemfile", "serde", "serde_json", - "sha-1", - "sha2 0.10.2", + "sha1 0.10.5", + "sha2 0.10.6", "smallvec", "sqlformat", "sqlx-rt", @@ -2595,11 +2589,11 @@ dependencies = [ [[package]] name = "sqlx-macros" -version = "0.6.0" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40c63177cf23d356b159b60acd27c54af7423f1736988502e36bae9a712118f" +checksum = "b850fa514dc11f2ee85be9d055c512aa866746adfacd1cb42d867d68e6a5b0d9" dependencies = [ - "dotenv", + "dotenvy", "either", "heck", "hex", @@ -2608,7 +2602,7 @@ dependencies = [ "quote", "serde", "serde_json", - "sha2 0.10.2", + "sha2 0.10.6", "sqlx-core", "sqlx-rt", "syn", @@ -2617,11 +2611,10 @@ dependencies = [ [[package]] name = "sqlx-rt" -version = "0.6.0" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874e93a365a598dc3dadb197565952cb143ae4aa716f7bcc933a8d836f6bf89f" +checksum = "24c5b2d25fa654cc5f841750b8e1cdedbe21189bf9a9382ee90bfa9dd3562396" dependencies = [ - "actix-rt", "once_cell", "tokio", "tokio-rustls", @@ -2657,9 +2650,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.95" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" +checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" dependencies = [ "proc-macro2", "quote", @@ -2691,18 +2684,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.31" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.31" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" dependencies = [ "proc-macro2", "quote", @@ -2711,22 +2704,43 @@ dependencies = [ [[package]] name = "time" -version = "0.3.9" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi", +] + +[[package]] +name = "time" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fab5c8b9980850e06d92ddbe3ab839c062c801f3927c0fb8abd6fc8e918fbca" dependencies = [ "itoa", "libc", "num_threads", "serde", + "time-core", "time-macros", ] [[package]] -name = "time-macros" -version = "0.2.4" +name = "time-core" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" +checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" + +[[package]] +name = "time-macros" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bb801831d812c562ae7d2bfb531f26e66e4e1f6b17307ba4149c5064710e5b" +dependencies = [ + "time-core", +] [[package]] name = "tinyvec" @@ -2745,17 +2759,17 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.19.1" +version = "1.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95eec79ea28c00a365f539f1961e9278fbcaf81c0ff6aaf0e93c181352446948" +checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099" dependencies = [ + "autocfg", "bytes", "libc", "memchr", "mio", "num_cpus", - "once_cell", - "parking_lot 0.12.0", + "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", @@ -2785,9 +2799,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.8" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3" +checksum = "d660770404473ccd7bc9f8b28494a811bc18542b915c0855c51e8f419d5223ce" dependencies = [ "futures-core", "pin-project-lite", @@ -2796,23 +2810,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.6.10" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "log", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f988a1a1adc2fb21f9c12aa96441da33a1728193ae0b95d2be22dbd17fcb4e5c" +checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" dependencies = [ "bytes", "futures-core", @@ -2824,15 +2824,15 @@ dependencies = [ [[package]] name = "tower-service" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.34" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if", "log", @@ -2843,9 +2843,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.21" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6b8ad3567499f98a1db7a752b07a7c8c7c7c34c332ec00effb2b0027974b7c" +checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" dependencies = [ "proc-macro2", "quote", @@ -2854,11 +2854,11 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.26" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" dependencies = [ - "lazy_static", + "once_cell", ] [[package]] @@ -2907,24 +2907,24 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" [[package]] name = "unicode-ident" -version = "1.0.0" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" [[package]] name = "unicode-normalization" -version = "0.1.19" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" +checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" [[package]] name = "unicode-width" @@ -2946,29 +2946,28 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.2.2" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" dependencies = [ "form_urlencoded", - "idna", - "matches", + "idna 0.3.0", "percent-encoding", ] [[package]] name = "urlencoding" -version = "2.1.0" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b90931029ab9b034b300b797048cf23723400aa757e8a2bfb9d748102f9821" +checksum = "e8db7427f936968176eaa7cdf81b7f98b980b18495ec28f1b5791ac3bfe3eea9" [[package]] name = "validator" -version = "0.14.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d0f08911ab0fee2c5009580f04615fa868898ee57de10692a45da0c3bcc3e5e" +checksum = "32ad5bf234c7d3ad1042e5252b7eddb2c4669ee23f32c7dd0e9b7705f07ef591" dependencies = [ - "idna", + "idna 0.2.3", "lazy_static", "regex", "serde", @@ -2976,14 +2975,13 @@ dependencies = [ "serde_json", "url", "validator_derive", - "validator_types", ] [[package]] name = "validator_derive" -version = "0.14.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d85135714dba11a1bd0b3eb1744169266f1a38977bf4e3ff5e2e1acb8c2b7eee" +checksum = "bc44ca3088bb3ba384d9aecf40c6a23a676ce23e09bdaca2073d99c207f864af" dependencies = [ "if_chain", "lazy_static", @@ -2997,9 +2995,9 @@ dependencies = [ [[package]] name = "validator_types" -version = "0.14.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded9d97e1d42327632f5f3bae6403c04886e2de3036261ef42deebd931a6a291" +checksum = "111abfe30072511849c5910134e8baf8dc05de4c0e5903d681cbd5c9c4d611e3" dependencies = [ "proc-macro2", "syn", @@ -3047,9 +3045,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.80" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -3057,13 +3055,13 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.80" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" dependencies = [ "bumpalo", - "lazy_static", "log", + "once_cell", "proc-macro2", "quote", "syn", @@ -3072,9 +3070,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.30" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f741de44b75e14c35df886aff5f1eb73aa114fa5d4d00dcd37b5e01259bf3b2" +checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" dependencies = [ "cfg-if", "js-sys", @@ -3084,9 +3082,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.80" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3094,9 +3092,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.80" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" dependencies = [ "proc-macro2", "quote", @@ -3107,15 +3105,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.80" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" [[package]] name = "web-sys" -version = "0.3.57" +version = "0.3.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283" +checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" dependencies = [ "js-sys", "wasm-bindgen", @@ -3133,9 +3131,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.22.4" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1c760f0d366a6c24a02ed7816e23e691f5d92291f94d15e836006fd11b04daf" +checksum = "368bfe657969fb01238bb756d351dcade285e0f6fcbd36dcb23359a5169975be" dependencies = [ "webpki", ] @@ -3151,19 +3149,20 @@ dependencies = [ [[package]] name = "whoami" -version = "1.2.1" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524b58fa5a20a2fb3014dd6358b70e6579692a56ef6fce928834e488f42f65e8" +checksum = "d6631b6a2fd59b1841b622e8f1a7ad241ef0a46f2d580464ce8140ac94cbd571" dependencies = [ + "bumpalo", "wasm-bindgen", "web-sys", ] [[package]] name = "wildmatch" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6c48bd20df7e4ced539c12f570f937c6b4884928a87fee70a479d72f031d4e0" +checksum = "ee583bdc5ff1cf9db20e9db5bb3ff4c3089a8f6b8b31aff265c9aba85812db86" [[package]] name = "winapi" @@ -3202,43 +3201,100 @@ version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" dependencies = [ - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_msvc", + "windows_aarch64_msvc 0.36.1", + "windows_i686_gnu 0.36.1", + "windows_i686_msvc 0.36.1", + "windows_x86_64_gnu 0.36.1", + "windows_x86_64_msvc 0.36.1", ] +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc 0.42.0", + "windows_i686_gnu 0.42.0", + "windows_i686_msvc 0.42.0", + "windows_x86_64_gnu 0.42.0", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc 0.42.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" + [[package]] name = "windows_aarch64_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" + [[package]] name = "windows_i686_gnu" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" +[[package]] +name = "windows_i686_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" + [[package]] name = "windows_i686_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" +[[package]] +name = "windows_i686_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" + [[package]] name = "windows_x86_64_gnu" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" + [[package]] name = "windows_x86_64_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" + [[package]] name = "winreg" version = "0.10.1" @@ -3280,9 +3336,8 @@ dependencies = [ [[package]] name = "zip" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "537ce7411d25e54e8ae21a7ce0b15840e7bfcff15b51d697ec3266cc76bdf080" +version = "0.6.2" +source = "git+https://github.com/zip-rs/zip?rev=bb230ef56adc13436d1fcdfaa489249d119c498f#bb230ef56adc13436d1fcdfaa489249d119c498f" dependencies = [ "aes", "byteorder", @@ -3291,10 +3346,10 @@ dependencies = [ "crc32fast", "crossbeam-utils", "flate2", - "hmac", + "hmac 0.12.1", "pbkdf2", - "sha1 0.10.1", - "time", + "sha1 0.10.5", + "time 0.3.16", "zstd", ] diff --git a/Cargo.toml b/Cargo.toml index 55ca3ee89..292cfa6cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,51 +15,55 @@ path = "src/main.rs" actix = "0.13.0" actix-web = "4.2.1" actix-rt = "2.7.0" -tokio = { version = "1.19.0", features = ["sync"] } -tokio-stream = "0.1.8" actix-multipart = "0.4.0" -actix-cors = "0.6.3" +actix-cors = "0.6.4" + +tokio = { version = "1.21.2", features = ["sync"] } +tokio-stream = "0.1.10" + +futures = "0.3.24" +futures-timer = "3.0.2" +async-trait = "0.1.57" +dashmap = "5.4.0" +lazy_static = "1.4.0" meilisearch-sdk = "0.15.0" -reqwest = { version = "0.11.10", features = ["json"] } +rust-s3 = "0.32.3" +reqwest = { version = "0.11.12", features = ["json"] } +serde_json = "1.0" +serde = { version = "1.0", features = ["derive"] } +serde_with = "2.0.1" +chrono = { version = "0.4.22", features = ["serde"]} yaserde = "0.8.0" yaserde_derive = "0.8.0" xml-rs = "0.8.4" -serde_json = "1.0" -serde = { version = "1.0", features = ["derive"] } -serde_with = "1.12.0" -chrono = { version = "0.4.22", default-features = false, features = ["clock", "serde", "std"] } rand = "0.8.5" +bytes = "1.2.1" base64 = "0.13.0" sha1 = { version = "0.6.1", features = ["std"] } sha2 = "0.9.9" +hmac = "0.11.0" bitflags = "1.3.2" -zip = "0.6.0" -itertools = "0.10.3" +hex = "0.4.3" -validator = { version = "0.14.0", features = ["derive"] } -regex = "1.5.5" -url = "2.2.2" -urlencoding = "2.1.0" +url = "2.3.1" +urlencoding = "2.1.2" + +# Temporary - to fix zstd conflict +zip = { git = "https://github.com/zip-rs/zip", rev = "bb230ef56adc13436d1fcdfaa489249d119c498f" } + +itertools = "0.10.5" + +validator = { version = "0.16.0", features = ["derive"] } +regex = "1.6.0" +censor = "0.2.0" -gumdrop = "0.8.1" dotenvy = "0.15.6" -log = "0.4.16" -env_logger = "0.9.0" -thiserror = "1.0.30" -lazy_static = "1.4.0" +log = "0.4.17" +env_logger = "0.9.1" +thiserror = "1.0.37" -futures = "0.3.21" -futures-timer = "3.0.2" -rust-s3 = "0.32.3" -async-trait = "0.1.53" - -sqlx = { version = "0.6.0", features = ["runtime-actix-rustls", "postgres", "chrono", "offline", "macros", "migrate"] } - -bytes = "1.1.0" - -dashmap = "5.2.0" - -censor = "0.2.0" \ No newline at end of file +sqlx = { version = "0.6.2", features = ["runtime-actix-rustls", "postgres", "chrono", "offline", "macros", "migrate", "decimal"] } +rust_decimal = { version = "1.26", features = ["serde-with-float"] } \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 987010761..132d1173f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.59.0 as build +FROM rust:1.64.0 as build ENV PKG_CONFIG_ALLOW_CROSS=1 WORKDIR /usr/src/labrinth diff --git a/migrations/20220928044123_payouts-scheduling.sql b/migrations/20220928044123_payouts-scheduling.sql new file mode 100644 index 000000000..e2e0d64c1 --- /dev/null +++ b/migrations/20220928044123_payouts-scheduling.sql @@ -0,0 +1,29 @@ +ALTER TABLE team_members DROP COLUMN payouts_split; +ALTER TABLE team_members ADD COLUMN payouts_split numeric(96, 48) NOT NULL DEFAULT 0; + +UPDATE team_members +SET payouts_split = 100 +WHERE role = 'Owner'; + +CREATE TABLE payouts_values ( + id bigserial PRIMARY KEY, + user_id bigint REFERENCES users NOT NULL, + mod_id bigint REFERENCES mods NULL, + amount numeric(96, 48) NOT NULL, + created timestamptz NOT NULL, + claimed BOOLEAN NOT NULL DEFAULT FALSE +); + +CREATE INDEX payouts_values_user_id + ON payouts_values (user_id); + +CREATE INDEX payouts_values_mod_id + ON payouts_values (mod_id); + +CREATE INDEX payouts_values_created + ON payouts_values (created); + +ALTER TABLE users ADD COLUMN midas_expires timestamptz NULL; +ALTER TABLE users ADD COLUMN is_overdue BOOLEAN NULL; +ALTER TABLE users ADD COLUMN stripe_customer_id varchar(255) NULL; +ALTER TABLE users ADD COLUMN paypal_email varchar(128) NULL; \ No newline at end of file diff --git a/sqlx-data.json b/sqlx-data.json index 658257d40..05b48cda3 100644 --- a/sqlx-data.json +++ b/sqlx-data.json @@ -99,7 +99,7 @@ { "name": "payouts_split", "ordinal": 5, - "type_info": "Float4" + "type_info": "Numeric" } ], "nullable": [ @@ -457,79 +457,17 @@ }, "query": "\n INSERT INTO report_types (name)\n VALUES ($1)\n ON CONFLICT (name) DO NOTHING\n RETURNING id\n " }, - "0dc684e5ef32880e360e0a624ccb80a2cc9c0ea7791f3cc3e07c1e280f9d2a18": { + "0f0244e77f60e69b3ab1320265749656e25da0b021b3df9013a2da470dbc8d46": { "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "github_id", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "name", - "ordinal": 2, - "type_info": "Varchar" - }, - { - "name": "email", - "ordinal": 3, - "type_info": "Varchar" - }, - { - "name": "avatar_url", - "ordinal": 4, - "type_info": "Varchar" - }, - { - "name": "username", - "ordinal": 5, - "type_info": "Varchar" - }, - { - "name": "bio", - "ordinal": 6, - "type_info": "Varchar" - }, - { - "name": "created", - "ordinal": 7, - "type_info": "Timestamptz" - }, - { - "name": "role", - "ordinal": 8, - "type_info": "Varchar" - }, - { - "name": "badges", - "ordinal": 9, - "type_info": "Int8" - } - ], - "nullable": [ - false, - true, - true, - true, - true, - false, - true, - false, - false, - false - ], + "columns": [], + "nullable": [], "parameters": { "Left": [ - "Int8Array" + "Int8" ] } }, - "query": "\n SELECT u.id, u.github_id, u.name, u.email,\n u.avatar_url, u.username, u.bio,\n u.created, u.role, u.badges\n FROM users u\n WHERE u.id = ANY($1)\n " + "query": "\n UPDATE payouts_values\n SET mod_id = NULL\n WHERE (mod_id = $1)\n " }, "0f29bb5ba767ebd0669c860994e48e3cb2674f0d53f6c4ab85c79d46b04cbb40": { "describe": { @@ -1029,6 +967,21 @@ }, "query": "\n SELECT id FROM loaders\n WHERE loader = $1\n " }, + "2576a47d17794598f9318d1b2d2892006c8af165a188a8695c0f0b4837082eb9": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Left": [ + "Int8", + "Int8", + "Numeric", + "Timestamptz" + ] + } + }, + "query": "\n INSERT INTO payouts_values (user_id, mod_id, amount, created)\n VALUES ($1, $2, $3, $4)\n " + }, "27a35fca63dfc3801f95958604f0ac27afd81800e2dc981382d6f923c4415d32": { "describe": { "columns": [], @@ -1072,7 +1025,7 @@ { "name": "payouts_split", "ordinal": 5, - "type_info": "Float4" + "type_info": "Numeric" } ], "nullable": [ @@ -1210,6 +1163,124 @@ }, "query": "DELETE FROM banned_users WHERE github_id = $1;" }, + "316dd63b0ffdd3e9fc30dcbe28a4da7c3c76f4f569e9cc6204dd884e17e0fe5c": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "github_id", + "ordinal": 1, + "type_info": "Int8" + }, + { + "name": "name", + "ordinal": 2, + "type_info": "Varchar" + }, + { + "name": "email", + "ordinal": 3, + "type_info": "Varchar" + }, + { + "name": "avatar_url", + "ordinal": 4, + "type_info": "Varchar" + }, + { + "name": "username", + "ordinal": 5, + "type_info": "Varchar" + }, + { + "name": "bio", + "ordinal": 6, + "type_info": "Varchar" + }, + { + "name": "created", + "ordinal": 7, + "type_info": "Timestamptz" + }, + { + "name": "role", + "ordinal": 8, + "type_info": "Varchar" + }, + { + "name": "badges", + "ordinal": 9, + "type_info": "Int8" + }, + { + "name": "paypal_email", + "ordinal": 10, + "type_info": "Varchar" + } + ], + "nullable": [ + false, + true, + true, + true, + true, + false, + true, + false, + false, + false, + true + ], + "parameters": { + "Left": [ + "Text" + ] + } + }, + "query": "\n SELECT u.id, u.github_id, u.name, u.email,\n u.avatar_url, u.username, u.bio,\n u.created, u.role, u.badges, u.paypal_email\n FROM users u\n WHERE LOWER(u.username) = LOWER($1)\n " + }, + "31a689dcba742809681e02ab2d8803fda64420572f36311c324ce94322bcf42b": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "user_id", + "ordinal": 1, + "type_info": "Int8" + }, + { + "name": "payouts_split", + "ordinal": 2, + "type_info": "Numeric" + }, + { + "name": "project_type", + "ordinal": 3, + "type_info": "Varchar" + } + ], + "nullable": [ + false, + false, + false, + false + ], + "parameters": { + "Left": [ + "Int8Array" + ] + } + }, + "query": "\n SELECT m.id id, tm.user_id user_id, tm.payouts_split payouts_split, pt.name project_type\n FROM mods m\n INNER JOIN team_members tm on m.team_id = tm.team_id\n INNER JOIN project_types pt ON pt.id = m.project_type\n WHERE m.id = ANY($1)\n " + }, "33a965c7dc615d3b701c05299889357db8dd36d378850625d2602ba471af4885": { "describe": { "columns": [], @@ -1235,6 +1306,26 @@ }, "query": "\n DELETE FROM loaders_versions\n WHERE loaders_versions.version_id = $1\n " }, + "34c0c25212dd8bc133f1e79b968d18d2b66eb537aeaba752e7ab2847a2214db4": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int8" + } + ], + "nullable": [ + false + ], + "parameters": { + "Left": [ + "Text" + ] + } + }, + "query": "\n SELECT u.id\n FROM users u\n WHERE u.stripe_customer_id = $1\n " + }, "371048e45dd74c855b84cdb8a6a565ccbef5ad166ec9511ab20621c336446da6": { "describe": { "columns": [], @@ -1545,6 +1636,44 @@ }, "query": "\n UPDATE mods\n SET title = $1\n WHERE (id = $2)\n " }, + "3eb4717d7c7e46dca288e99a8afa9c6b67ac2baa5132d9371ca557fdcdf3a7a3": { + "describe": { + "columns": [ + { + "name": "mod_id", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "created", + "ordinal": 1, + "type_info": "Timestamptz" + }, + { + "name": "claimed", + "ordinal": 2, + "type_info": "Bool" + }, + { + "name": "amount", + "ordinal": 3, + "type_info": "Numeric" + } + ], + "nullable": [ + true, + false, + false, + false + ], + "parameters": { + "Left": [ + "Int8" + ] + } + }, + "query": "\n SELECT pv.mod_id, pv.created, pv.claimed, pv.amount\n FROM payouts_values pv\n WHERE pv.user_id = $1\n ORDER BY pv.created DESC\n " + }, "3f2f05653552ce8c1be95ce0a922ab41f52f40f8ff6c91c6621481102c8f35e3": { "describe": { "columns": [], @@ -1558,6 +1687,122 @@ }, "query": "\n INSERT INTO game_versions_versions (game_version_id, joining_version_id)\n VALUES ($1, $2)\n " }, + "3f33b1a2d6003c4654a1de1fe9e4c784490768148ee5dc9303ccd7aa528e3e9c": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "team_id", + "ordinal": 1, + "type_info": "Int8" + }, + { + "name": "member_role", + "ordinal": 2, + "type_info": "Varchar" + }, + { + "name": "permissions", + "ordinal": 3, + "type_info": "Int8" + }, + { + "name": "accepted", + "ordinal": 4, + "type_info": "Bool" + }, + { + "name": "payouts_split", + "ordinal": 5, + "type_info": "Numeric" + }, + { + "name": "user_id", + "ordinal": 6, + "type_info": "Int8" + }, + { + "name": "github_id", + "ordinal": 7, + "type_info": "Int8" + }, + { + "name": "user_name", + "ordinal": 8, + "type_info": "Varchar" + }, + { + "name": "email", + "ordinal": 9, + "type_info": "Varchar" + }, + { + "name": "avatar_url", + "ordinal": 10, + "type_info": "Varchar" + }, + { + "name": "username", + "ordinal": 11, + "type_info": "Varchar" + }, + { + "name": "bio", + "ordinal": 12, + "type_info": "Varchar" + }, + { + "name": "created", + "ordinal": 13, + "type_info": "Timestamptz" + }, + { + "name": "user_role", + "ordinal": 14, + "type_info": "Varchar" + }, + { + "name": "badges", + "ordinal": 15, + "type_info": "Int8" + }, + { + "name": "paypal_email", + "ordinal": 16, + "type_info": "Varchar" + } + ], + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + false, + true, + false, + false, + false, + true + ], + "parameters": { + "Left": [ + "Int8Array" + ] + } + }, + "query": "\n SELECT tm.id id, tm.team_id team_id, tm.role member_role, tm.permissions permissions, tm.accepted accepted, tm.payouts_split payouts_split,\n u.id user_id, u.github_id github_id, u.name user_name, u.email email,\n u.avatar_url avatar_url, u.username username, u.bio bio,\n u.created created, u.role user_role, u.badges badges, u.paypal_email paypal_email\n FROM team_members tm\n INNER JOIN users u ON u.id = tm.user_id\n WHERE tm.team_id = ANY($1)\n ORDER BY tm.team_id\n " + }, "40f7c5bec98fe3503d6bd6db2eae5a4edb8d5d6efda9b9dc124f344ae5c60e08": { "describe": { "columns": [], @@ -1570,6 +1815,128 @@ }, "query": "\n DELETE FROM mods_categories\n WHERE joining_mod_id = $1 AND is_additional = TRUE\n " }, + "414951c52e3342b4009cd1d0169bc34b164ab00db0af8c2d446a178a52e5fd6c": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Left": [ + "Text" + ] + } + }, + "query": "\n UPDATE users\n SET stripe_customer_id = NULL, midas_expires = NULL, is_overdue = NULL\n WHERE (stripe_customer_id = $1)\n " + }, + "42241f8e3e482e5f9f31fb7ed81dc78a01aa435879e88cfb9eca8f458c26c4bc": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "member_role", + "ordinal": 1, + "type_info": "Varchar" + }, + { + "name": "permissions", + "ordinal": 2, + "type_info": "Int8" + }, + { + "name": "accepted", + "ordinal": 3, + "type_info": "Bool" + }, + { + "name": "payouts_split", + "ordinal": 4, + "type_info": "Numeric" + }, + { + "name": "user_id", + "ordinal": 5, + "type_info": "Int8" + }, + { + "name": "github_id", + "ordinal": 6, + "type_info": "Int8" + }, + { + "name": "user_name", + "ordinal": 7, + "type_info": "Varchar" + }, + { + "name": "email", + "ordinal": 8, + "type_info": "Varchar" + }, + { + "name": "avatar_url", + "ordinal": 9, + "type_info": "Varchar" + }, + { + "name": "username", + "ordinal": 10, + "type_info": "Varchar" + }, + { + "name": "bio", + "ordinal": 11, + "type_info": "Varchar" + }, + { + "name": "created", + "ordinal": 12, + "type_info": "Timestamptz" + }, + { + "name": "user_role", + "ordinal": 13, + "type_info": "Varchar" + }, + { + "name": "badges", + "ordinal": 14, + "type_info": "Int8" + }, + { + "name": "paypal_email", + "ordinal": 15, + "type_info": "Varchar" + } + ], + "nullable": [ + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + false, + true, + false, + false, + false, + true + ], + "parameters": { + "Left": [ + "Int8" + ] + } + }, + "query": "\n SELECT tm.id id, tm.role member_role, tm.permissions permissions, tm.accepted accepted, tm.payouts_split payouts_split,\n u.id user_id, u.github_id github_id, u.name user_name, u.email email,\n u.avatar_url avatar_url, u.username username, u.bio bio,\n u.created created, u.role user_role, u.badges badges, u.paypal_email paypal_email\n FROM team_members tm\n INNER JOIN users u ON u.id = tm.user_id\n WHERE tm.team_id = $1\n " + }, "4298552497a48adb9ace61c8dcf989c4d35866866b61c0cc4d45909b1d31c660": { "describe": { "columns": [ @@ -1717,7 +2084,7 @@ { "name": "payouts_split", "ordinal": 6, - "type_info": "Float4" + "type_info": "Numeric" } ], "nullable": [ @@ -1804,74 +2171,6 @@ }, "query": "\n INSERT INTO project_types (name)\n VALUES ($1)\n ON CONFLICT (name) DO NOTHING\n RETURNING id\n " }, - "4b734b2afeaee2025f489dbce25df3ef80eae17576e49d321cb8357b0327e4b7": { - "describe": { - "columns": [ - { - "name": "github_id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "name", - "ordinal": 1, - "type_info": "Varchar" - }, - { - "name": "email", - "ordinal": 2, - "type_info": "Varchar" - }, - { - "name": "avatar_url", - "ordinal": 3, - "type_info": "Varchar" - }, - { - "name": "username", - "ordinal": 4, - "type_info": "Varchar" - }, - { - "name": "bio", - "ordinal": 5, - "type_info": "Varchar" - }, - { - "name": "created", - "ordinal": 6, - "type_info": "Timestamptz" - }, - { - "name": "role", - "ordinal": 7, - "type_info": "Varchar" - }, - { - "name": "badges", - "ordinal": 8, - "type_info": "Int8" - } - ], - "nullable": [ - true, - true, - true, - true, - false, - true, - false, - false, - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT u.github_id, u.name, u.email,\n u.avatar_url, u.username, u.bio,\n u.created, u.role, u.badges\n FROM users u\n WHERE u.id = $1\n " - }, "4cfafb61d38608152743c38cb8fb9a9c35e788fcbefe6f7f81476a3f144af3f8": { "describe": { "columns": [ @@ -1979,6 +2278,80 @@ }, "query": "\n DELETE FROM game_versions_versions WHERE joining_version_id = $1\n " }, + "51a1ae25a419ecd73938206786dae34e0e53ef4ef2cb0112f185412ce7e52226": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "name", + "ordinal": 1, + "type_info": "Varchar" + }, + { + "name": "email", + "ordinal": 2, + "type_info": "Varchar" + }, + { + "name": "avatar_url", + "ordinal": 3, + "type_info": "Varchar" + }, + { + "name": "username", + "ordinal": 4, + "type_info": "Varchar" + }, + { + "name": "bio", + "ordinal": 5, + "type_info": "Varchar" + }, + { + "name": "created", + "ordinal": 6, + "type_info": "Timestamptz" + }, + { + "name": "role", + "ordinal": 7, + "type_info": "Varchar" + }, + { + "name": "badges", + "ordinal": 8, + "type_info": "Int8" + }, + { + "name": "paypal_email", + "ordinal": 9, + "type_info": "Varchar" + } + ], + "nullable": [ + false, + true, + true, + true, + false, + true, + false, + false, + false, + true + ], + "parameters": { + "Left": [ + "Int8" + ] + } + }, + "query": "\n SELECT u.id, u.name, u.email,\n u.avatar_url, u.username, u.bio,\n u.created, u.role, u.badges, u.paypal_email\n FROM users u\n WHERE u.github_id = $1\n " + }, "5295fba2053675c8414c0b37a59943535b9a438a642ea1c68045e987f05ade13": { "describe": { "columns": [ @@ -2102,110 +2475,6 @@ }, "query": "\n SELECT v.mod_id, v.author_id, v.name, v.version_number,\n v.changelog, v.changelog_url, v.date_published, v.downloads,\n v.version_type, v.featured\n FROM versions v\n WHERE v.id = $1\n " }, - "56b099001ed5799d71d8a5a7ffcdb826dd8185b03781445c4d63d59072f6bed1": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "member_role", - "ordinal": 1, - "type_info": "Varchar" - }, - { - "name": "permissions", - "ordinal": 2, - "type_info": "Int8" - }, - { - "name": "accepted", - "ordinal": 3, - "type_info": "Bool" - }, - { - "name": "payouts_split", - "ordinal": 4, - "type_info": "Float4" - }, - { - "name": "user_id", - "ordinal": 5, - "type_info": "Int8" - }, - { - "name": "github_id", - "ordinal": 6, - "type_info": "Int8" - }, - { - "name": "user_name", - "ordinal": 7, - "type_info": "Varchar" - }, - { - "name": "email", - "ordinal": 8, - "type_info": "Varchar" - }, - { - "name": "avatar_url", - "ordinal": 9, - "type_info": "Varchar" - }, - { - "name": "username", - "ordinal": 10, - "type_info": "Varchar" - }, - { - "name": "bio", - "ordinal": 11, - "type_info": "Varchar" - }, - { - "name": "created", - "ordinal": 12, - "type_info": "Timestamptz" - }, - { - "name": "user_role", - "ordinal": 13, - "type_info": "Varchar" - }, - { - "name": "badges", - "ordinal": 14, - "type_info": "Int8" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - false, - true, - false, - false, - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT tm.id id, tm.role member_role, tm.permissions permissions, tm.accepted accepted, tm.payouts_split payouts_split,\n u.id user_id, u.github_id github_id, u.name user_name, u.email email,\n u.avatar_url avatar_url, u.username username, u.bio bio,\n u.created created, u.role user_role, u.badges badges\n FROM team_members tm\n INNER JOIN users u ON u.id = tm.user_id\n WHERE tm.team_id = $1\n " - }, "57a38641fe5bdb273190e8d586f46284340b9ff11b6ae3177923631a37bb11eb": { "describe": { "columns": [], @@ -2540,80 +2809,6 @@ }, "query": "\n SELECT n.id, n.user_id, n.title, n.text, n.link, n.created, n.read, n.type notification_type,\n ARRAY_AGG(DISTINCT na.id || ' |||| ' || na.title || ' |||| ' || na.action_route || ' |||| ' || na.action_route_method) filter (where na.id is not null) actions\n FROM notifications n\n LEFT OUTER JOIN notifications_actions na on n.id = na.notification_id\n WHERE n.user_id = $1\n GROUP BY n.id, n.user_id;\n " }, - "5f4a3899e55b67ed096c6e0efd1f95ac27be7c81f1e4c5b2145c28fc8b28397a": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "github_id", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "name", - "ordinal": 2, - "type_info": "Varchar" - }, - { - "name": "email", - "ordinal": 3, - "type_info": "Varchar" - }, - { - "name": "avatar_url", - "ordinal": 4, - "type_info": "Varchar" - }, - { - "name": "username", - "ordinal": 5, - "type_info": "Varchar" - }, - { - "name": "bio", - "ordinal": 6, - "type_info": "Varchar" - }, - { - "name": "created", - "ordinal": 7, - "type_info": "Timestamptz" - }, - { - "name": "role", - "ordinal": 8, - "type_info": "Varchar" - }, - { - "name": "badges", - "ordinal": 9, - "type_info": "Int8" - } - ], - "nullable": [ - false, - true, - true, - true, - true, - false, - true, - false, - false, - false - ], - "parameters": { - "Left": [ - "Text" - ] - } - }, - "query": "\n SELECT u.id, u.github_id, u.name, u.email,\n u.avatar_url, u.username, u.bio,\n u.created, u.role, u.badges\n FROM users u\n WHERE LOWER(u.username) = LOWER($1)\n " - }, "5f94e9e767ec4be7f9136b991b4a29373dbe48feb2f61281e3212721095ed675": { "describe": { "columns": [], @@ -2861,6 +3056,19 @@ }, "query": "\n UPDATE dependencies\n SET dependency_id = $2\n WHERE id = ANY($1::bigint[])\n " }, + "71e9ffb27dbfad768d6109e8c77441b8c75c0278904305b7bbdf75548be9d577": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Left": [ + "Int8", + "Timestamptz" + ] + } + }, + "query": "\n UPDATE payouts_values\n SET claimed = TRUE\n WHERE (claimed = FALSE AND user_id = $1 AND created <= $2)\n " + }, "72ad6f4be40d7620a0ec557e3806da41ce95335aeaa910fe35aca2ec7c3f09b6": { "describe": { "columns": [ @@ -3302,6 +3510,18 @@ }, "query": "\n DELETE FROM project_types\n WHERE name = $1\n " }, + "8a7b2bc070e5e8308e2853ff125bc98f40b22c1d0deeb013dd90ce5768bd0ce8": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Left": [ + "Int8" + ] + } + }, + "query": "\n DELETE FROM payouts_values\n WHERE user_id = $1\n " + }, "8b2e65cec164bb84de6929b1c2afeee28b36d0e36edea75baceaf97d7574bdd7": { "describe": { "columns": [ @@ -3516,7 +3736,7 @@ { "name": "payouts_split", "ordinal": 6, - "type_info": "Float4" + "type_info": "Numeric" } ], "nullable": [ @@ -3706,6 +3926,38 @@ }, "query": "\n UPDATE dependencies\n SET dependency_id = $2\n WHERE dependency_id = $1\n " }, + "9dc32a9ef59f57fbad862520b6d3a4795a95d7d0db17e05eb8aedc3a2fe600dc": { + "describe": { + "columns": [ + { + "name": "stripe_customer_id", + "ordinal": 0, + "type_info": "Varchar" + } + ], + "nullable": [ + true + ], + "parameters": { + "Left": [ + "Int8" + ] + } + }, + "query": "\n SELECT u.stripe_customer_id\n FROM users u\n WHERE u.id = $1\n " + }, + "9e0620900b225d9ffa4015382843ce4cc02f9ecda6555c81089b43952510e7e7": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Left": [ + "Timestamptz" + ] + } + }, + "query": "\n DELETE FROM payouts_values\n WHERE created = $1\n " + }, "a0148ff25855202e7bb220b6a2bc9220a95e309fb0dae41d9a05afa86e6b33af": { "describe": { "columns": [], @@ -3730,98 +3982,61 @@ }, "query": "\n UPDATE mods\n SET approved = NOW()\n WHERE id = $1 AND approved IS NULL\n " }, - "a1e3ac170e45196e5fcca154c96a206f35be68a3219a0d493e1e149206590043": { + "a121d8e7e57dd94259e420e370513f738c72aacc7e9f342050cdd70cb3cb478e": { "describe": { "columns": [ { - "name": "id", + "name": "github_id", "ordinal": 0, "type_info": "Int8" }, { - "name": "team_id", + "name": "name", "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "member_role", - "ordinal": 2, - "type_info": "Varchar" - }, - { - "name": "permissions", - "ordinal": 3, - "type_info": "Int8" - }, - { - "name": "accepted", - "ordinal": 4, - "type_info": "Bool" - }, - { - "name": "payouts_split", - "ordinal": 5, - "type_info": "Float4" - }, - { - "name": "user_id", - "ordinal": 6, - "type_info": "Int8" - }, - { - "name": "github_id", - "ordinal": 7, - "type_info": "Int8" - }, - { - "name": "user_name", - "ordinal": 8, "type_info": "Varchar" }, { "name": "email", - "ordinal": 9, + "ordinal": 2, "type_info": "Varchar" }, { "name": "avatar_url", - "ordinal": 10, + "ordinal": 3, "type_info": "Varchar" }, { "name": "username", - "ordinal": 11, + "ordinal": 4, "type_info": "Varchar" }, { "name": "bio", - "ordinal": 12, + "ordinal": 5, "type_info": "Varchar" }, { "name": "created", - "ordinal": 13, + "ordinal": 6, "type_info": "Timestamptz" }, { - "name": "user_role", - "ordinal": 14, + "name": "role", + "ordinal": 7, "type_info": "Varchar" }, { "name": "badges", - "ordinal": 15, + "ordinal": 8, "type_info": "Int8" + }, + { + "name": "paypal_email", + "ordinal": 9, + "type_info": "Varchar" } ], "nullable": [ - false, - false, - false, - false, - false, - false, - false, true, true, true, @@ -3830,15 +4045,28 @@ true, false, false, - false + false, + true ], "parameters": { "Left": [ - "Int8Array" + "Int8" ] } }, - "query": "\n SELECT tm.id id, tm.team_id team_id, tm.role member_role, tm.permissions permissions, tm.accepted accepted, tm.payouts_split payouts_split,\n u.id user_id, u.github_id github_id, u.name user_name, u.email email,\n u.avatar_url avatar_url, u.username username, u.bio bio,\n u.created created, u.role user_role, u.badges badges\n FROM team_members tm\n INNER JOIN users u ON u.id = tm.user_id\n WHERE tm.team_id = ANY($1)\n ORDER BY tm.team_id\n " + "query": "\n SELECT u.github_id, u.name, u.email,\n u.avatar_url, u.username, u.bio,\n u.created, u.role, u.badges, u.paypal_email\n FROM users u\n WHERE u.id = $1\n " + }, + "a2c3f1dc8939a0df9cb62e7e751847b7681b96b4016389cf5f39ebd1deff6e5a": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Left": [ + "Int8" + ] + } + }, + "query": "\n UPDATE users\n SET is_overdue = TRUE\n WHERE (id = $1)\n " }, "a39ce28b656032f862b205cffa393a76b989f4803654a615477a94fda5f57354": { "describe": { @@ -3852,6 +4080,38 @@ }, "query": "\n DELETE FROM states\n WHERE id = $1\n " }, + "a3e27b758ca441fa82f6bcd42915b92fb23a7db19a7eb27db7ed92eeba4b566e": { + "describe": { + "columns": [ + { + "name": "mod_id", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "id", + "ordinal": 1, + "type_info": "Int8" + }, + { + "name": "times_depended", + "ordinal": 2, + "type_info": "Int8" + } + ], + "nullable": [ + false, + false, + null + ], + "parameters": { + "Left": [ + "Int8Array" + ] + } + }, + "query": "\n SELECT mv.mod_id, m.id, COUNT(m.id) times_depended FROM versions mv\n INNER JOIN dependencies d ON d.dependent_id = mv.id\n INNER JOIN versions v ON d.dependency_id = v.id\n INNER JOIN mods m ON v.mod_id = m.id OR d.mod_dependency_id = m.id\n WHERE mv.mod_id = ANY($1)\n group by mv.mod_id, m.id;\n " + }, "a647c282a276b63f36d2d8a253c32d0f627cea9cab8eb1b32b39875536bdfcbb": { "describe": { "columns": [], @@ -4020,7 +4280,7 @@ { "name": "payouts_split", "ordinal": 5, - "type_info": "Float4" + "type_info": "Numeric" } ], "nullable": [ @@ -4147,73 +4407,19 @@ }, "query": "\n DELETE FROM dependencies WHERE mod_dependency_id = NULL AND dependency_id = NULL AND dependency_file_name = NULL\n " }, - "af0d1c0b8a52cef5af2627e321e4f0d52f472d278fc52fb7f7fed3ab37d52608": { + "af4339fee915a3bca2faa1efe87afef33c7970794d1624626bcce9a3b5189518": { "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "name", - "ordinal": 1, - "type_info": "Varchar" - }, - { - "name": "email", - "ordinal": 2, - "type_info": "Varchar" - }, - { - "name": "avatar_url", - "ordinal": 3, - "type_info": "Varchar" - }, - { - "name": "username", - "ordinal": 4, - "type_info": "Varchar" - }, - { - "name": "bio", - "ordinal": 5, - "type_info": "Varchar" - }, - { - "name": "created", - "ordinal": 6, - "type_info": "Timestamptz" - }, - { - "name": "role", - "ordinal": 7, - "type_info": "Varchar" - }, - { - "name": "badges", - "ordinal": 8, - "type_info": "Int8" - } - ], - "nullable": [ - false, - true, - true, - true, - false, - true, - false, - false, - false - ], + "columns": [], + "nullable": [], "parameters": { "Left": [ - "Int8" + "Int8", + "Numeric", + "Timestamptz" ] } }, - "query": "\n SELECT u.id, u.name, u.email,\n u.avatar_url, u.username, u.bio,\n u.created, u.role, u.badges\n FROM users u\n WHERE u.github_id = $1\n " + "query": "\n INSERT INTO payouts_values (user_id, amount, created)\n VALUES ($1, $2, $3)\n " }, "b030a9e0fdb75eee8ee50aafdcb6063a073e2aa53cc70d40ed46437c1d0dfe80": { "describe": { @@ -4495,6 +4701,19 @@ }, "query": "\n DELETE FROM notifications_actions\n WHERE notification_id = ANY($1)\n " }, + "bba84e2856e9566f90130d99dc2a9338ac4efdb638c9830a9721c022f1fef5b7": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Left": [ + "Varchar", + "Int8" + ] + } + }, + "query": "\n UPDATE users\n SET paypal_email = $1\n WHERE (id = $2)\n " + }, "bbfb47ae2c972734785df6b7c3e62077dc544ef4ccf8bb89e9c22c2f50a933c1": { "describe": { "columns": [], @@ -4589,7 +4808,7 @@ { "name": "payouts_split", "ordinal": 6, - "type_info": "Float4" + "type_info": "Numeric" } ], "nullable": [ @@ -4718,7 +4937,7 @@ { "name": "payouts_split", "ordinal": 5, - "type_info": "Float4" + "type_info": "Numeric" } ], "nullable": [ @@ -4803,6 +5022,38 @@ }, "query": "\n UPDATE versions\n SET version_type = $1\n WHERE (id = $2)\n " }, + "c3cef0e5a0c22330376f34970a6906b80c9201a2f032ae686ff2a70500ccc59d": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "user_id", + "ordinal": 1, + "type_info": "Int8" + }, + { + "name": "payouts_split", + "ordinal": 2, + "type_info": "Numeric" + } + ], + "nullable": [ + false, + false, + false + ], + "parameters": { + "Left": [ + "Int8Array" + ] + } + }, + "query": "\n SELECT m.id id, tm.user_id user_id, tm.payouts_split payouts_split\n FROM mods m\n INNER JOIN team_members tm on m.team_id = tm.team_id\n WHERE m.id = ANY($1)\n " + }, "c3dcb5a8b798ea6c0922698a007dbc8ab549f5f85bad780da59163f4d6371238": { "describe": { "columns": [ @@ -4935,7 +5186,7 @@ { "name": "payouts_split", "ordinal": 5, - "type_info": "Float4" + "type_info": "Numeric" } ], "nullable": [ @@ -5049,6 +5300,32 @@ }, "query": "\n DELETE FROM reports\n WHERE mod_id = $1\n " }, + "cca6c762835178aec0b5bbf677f106a5463751083667c9376f7c17a2436b48c5": { + "describe": { + "columns": [ + { + "name": "paypal_email", + "ordinal": 0, + "type_info": "Varchar" + }, + { + "name": "amount", + "ordinal": 1, + "type_info": "Numeric" + } + ], + "nullable": [ + true, + null + ], + "parameters": { + "Left": [ + "Timestamptz" + ] + } + }, + "query": "\n SELECT u.paypal_email, SUM(pv.amount) amount\n FROM payouts_values pv\n INNER JOIN users u ON pv.user_id = u.id AND u.paypal_email IS NOT NULL\n WHERE pv.created <= $1 AND pv.claimed = FALSE\n GROUP BY u.paypal_email\n " + }, "ccd913bb2f3006ffe881ce2fc4ef1e721d18fe2eed6ac62627046c955129610c": { "describe": { "columns": [ @@ -5423,7 +5700,7 @@ "nullable": [], "parameters": { "Left": [ - "Float4", + "Numeric", "Int8", "Int8" ] @@ -5715,6 +5992,19 @@ }, "query": "SELECT EXISTS(SELECT 1 FROM team_members WHERE id=$1)" }, + "e876f64db82d618dce53b108509d67a1108aa747d16892499481fe9f8b95200b": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Left": [ + "Varchar", + "Int8" + ] + } + }, + "query": "\n UPDATE users\n SET stripe_customer_id = $1\n WHERE (id = $2)\n " + }, "e8ad94314ec2972c3102041b1bf06872c8e4c8a55156a17334a0e317fe41b784": { "describe": { "columns": [ @@ -6223,6 +6513,19 @@ }, "query": "\n UPDATE users\n SET bio = $1\n WHERE (id = $2)\n " }, + "f6eae06931e9cde0f18e7031bc93c33fa689de4d9676c1a8a3fc14a182d5fb08": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Left": [ + "Timestamptz", + "Text" + ] + } + }, + "query": "\n UPDATE users\n SET midas_expires = $1, is_overdue = FALSE\n WHERE (stripe_customer_id = $2)\n " + }, "f8be3053274b00ee9743e798886696062009c5f681baaf29dfc24cfbbda93742": { "describe": { "columns": [ @@ -6269,6 +6572,86 @@ }, "query": "\n SELECT short, name FROM donation_platforms\n WHERE id = $1\n " }, + "f962e4c6a8bb12afbe25636e26beef2775539c731cc41243b20d779a1fa71e06": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "github_id", + "ordinal": 1, + "type_info": "Int8" + }, + { + "name": "name", + "ordinal": 2, + "type_info": "Varchar" + }, + { + "name": "email", + "ordinal": 3, + "type_info": "Varchar" + }, + { + "name": "avatar_url", + "ordinal": 4, + "type_info": "Varchar" + }, + { + "name": "username", + "ordinal": 5, + "type_info": "Varchar" + }, + { + "name": "bio", + "ordinal": 6, + "type_info": "Varchar" + }, + { + "name": "created", + "ordinal": 7, + "type_info": "Timestamptz" + }, + { + "name": "role", + "ordinal": 8, + "type_info": "Varchar" + }, + { + "name": "badges", + "ordinal": 9, + "type_info": "Int8" + }, + { + "name": "paypal_email", + "ordinal": 10, + "type_info": "Varchar" + } + ], + "nullable": [ + false, + true, + true, + true, + true, + false, + true, + false, + false, + false, + true + ], + "parameters": { + "Left": [ + "Int8Array" + ] + } + }, + "query": "\n SELECT u.id, u.github_id, u.name, u.email,\n u.avatar_url, u.username, u.bio,\n u.created, u.role, u.badges, u.paypal_email\n FROM users u\n WHERE u.id = ANY($1)\n " + }, "fb955ca41b95120f66c98c0b528b1db10c4be4a55e9641bb104d772e390c9bb7": { "describe": { "columns": [ diff --git a/src/database/models/project_item.rs b/src/database/models/project_item.rs index ed81d18cd..1f3b4ad07 100644 --- a/src/database/models/project_item.rs +++ b/src/database/models/project_item.rs @@ -474,6 +474,17 @@ impl Project { .execute(&mut *transaction) .await?; + sqlx::query!( + " + UPDATE payouts_values + SET mod_id = NULL + WHERE (mod_id = $1) + ", + id as ProjectId, + ) + .execute(&mut *transaction) + .await?; + sqlx::query!( " DELETE FROM mods @@ -968,6 +979,7 @@ impl Project { .await } } + #[derive(Clone, Debug)] pub struct QueryProject { pub inner: Project, diff --git a/src/database/models/team_item.rs b/src/database/models/team_item.rs index edd3a07e0..dc53e3120 100644 --- a/src/database/models/team_item.rs +++ b/src/database/models/team_item.rs @@ -2,6 +2,7 @@ use super::ids::*; use crate::database::models::User; use crate::models::teams::Permissions; use crate::models::users::Badges; +use rust_decimal::Decimal; pub struct TeamBuilder { pub members: Vec, @@ -11,7 +12,7 @@ pub struct TeamMemberBuilder { pub role: String, pub permissions: Permissions, pub accepted: bool, - pub payouts_split: f32, + pub payouts_split: Decimal, } impl TeamBuilder { @@ -81,7 +82,7 @@ pub struct TeamMember { pub role: String, pub permissions: Permissions, pub accepted: bool, - pub payouts_split: f32, + pub payouts_split: Decimal, } /// A member of a team @@ -93,7 +94,7 @@ pub struct QueryTeamMember { pub role: String, pub permissions: Permissions, pub accepted: bool, - pub payouts_split: f32, + pub payouts_split: Decimal, } impl TeamMember { @@ -157,7 +158,7 @@ impl TeamMember { SELECT tm.id id, tm.role member_role, tm.permissions permissions, tm.accepted accepted, tm.payouts_split payouts_split, u.id user_id, u.github_id github_id, u.name user_name, u.email email, u.avatar_url avatar_url, u.username username, u.bio bio, - u.created created, u.role user_role, u.badges badges + u.created created, u.role user_role, u.badges badges, u.paypal_email paypal_email FROM team_members tm INNER JOIN users u ON u.id = tm.user_id WHERE tm.team_id = $1 @@ -185,6 +186,7 @@ impl TeamMember { created: m.created, role: m.user_role, badges: Badges::from_bits(m.badges as u64).unwrap_or_default(), + paypal_email: m.paypal_email }, payouts_split: m.payouts_split }))) @@ -219,7 +221,7 @@ impl TeamMember { SELECT tm.id id, tm.team_id team_id, tm.role member_role, tm.permissions permissions, tm.accepted accepted, tm.payouts_split payouts_split, u.id user_id, u.github_id github_id, u.name user_name, u.email email, u.avatar_url avatar_url, u.username username, u.bio bio, - u.created created, u.role user_role, u.badges badges + u.created created, u.role user_role, u.badges badges, u.paypal_email paypal_email FROM team_members tm INNER JOIN users u ON u.id = tm.user_id WHERE tm.team_id = ANY($1) @@ -248,6 +250,7 @@ impl TeamMember { created: m.created, role: m.user_role, badges: Badges::from_bits(m.badges as u64).unwrap_or_default(), + paypal_email: m.paypal_email }, payouts_split: m.payouts_split }))) @@ -540,7 +543,7 @@ impl TeamMember { new_permissions: Option, new_role: Option, new_accepted: Option, - new_payouts_split: Option, + new_payouts_split: Option, transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>, ) -> Result<(), super::DatabaseError> { if let Some(permissions) = new_permissions { diff --git a/src/database/models/user_item.rs b/src/database/models/user_item.rs index 514b9e247..8398f3d4e 100644 --- a/src/database/models/user_item.rs +++ b/src/database/models/user_item.rs @@ -13,6 +13,7 @@ pub struct User { pub created: DateTime, pub role: String, pub badges: Badges, + pub paypal_email: Option, } impl User { @@ -56,7 +57,7 @@ impl User { " SELECT u.github_id, u.name, u.email, u.avatar_url, u.username, u.bio, - u.created, u.role, u.badges + u.created, u.role, u.badges, u.paypal_email FROM users u WHERE u.id = $1 ", @@ -78,6 +79,7 @@ impl User { role: row.role, badges: Badges::from_bits(row.badges as u64) .unwrap_or_default(), + paypal_email: row.paypal_email, })) } else { Ok(None) @@ -95,7 +97,7 @@ impl User { " SELECT u.id, u.name, u.email, u.avatar_url, u.username, u.bio, - u.created, u.role, u.badges + u.created, u.role, u.badges, u.paypal_email FROM users u WHERE u.github_id = $1 ", @@ -117,6 +119,7 @@ impl User { role: row.role, badges: Badges::from_bits(row.badges as u64) .unwrap_or_default(), + paypal_email: row.paypal_email, })) } else { Ok(None) @@ -134,7 +137,7 @@ impl User { " SELECT u.id, u.github_id, u.name, u.email, u.avatar_url, u.username, u.bio, - u.created, u.role, u.badges + u.created, u.role, u.badges, u.paypal_email FROM users u WHERE LOWER(u.username) = LOWER($1) ", @@ -156,6 +159,7 @@ impl User { role: row.role, badges: Badges::from_bits(row.badges as u64) .unwrap_or_default(), + paypal_email: row.paypal_email, })) } else { Ok(None) @@ -177,7 +181,7 @@ impl User { " SELECT u.id, u.github_id, u.name, u.email, u.avatar_url, u.username, u.bio, - u.created, u.role, u.badges + u.created, u.role, u.badges, u.paypal_email FROM users u WHERE u.id = ANY($1) ", @@ -196,6 +200,7 @@ impl User { created: u.created, role: u.role, badges: Badges::from_bits(u.badges as u64).unwrap_or_default(), + paypal_email: u.paypal_email, })) }) .try_collect::>() @@ -352,6 +357,16 @@ impl User { .execute(&mut *transaction) .await?; + sqlx::query!( + " + DELETE FROM payouts_values + WHERE user_id = $1 + ", + id as UserId, + ) + .execute(&mut *transaction) + .await?; + sqlx::query!( " DELETE FROM users diff --git a/src/file_hosting/s3_host.rs b/src/file_hosting/s3_host.rs index fd84c117e..499d5ed21 100644 --- a/src/file_hosting/s3_host.rs +++ b/src/file_hosting/s3_host.rs @@ -21,7 +21,7 @@ impl S3Host { access_token: &str, secret: &str, ) -> Result { - let mut bucket = Bucket::new( + let bucket = Bucket::new( bucket_name, if bucket_region == "r2" { Region::R2 { diff --git a/src/main.rs b/src/main.rs index a4e9da44f..51b41c4ed 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,6 @@ use crate::util::env::{parse_strings_from_var, parse_var}; use actix_cors::Cors; use actix_web::{web, App, HttpServer}; use env_logger::Env; -use gumdrop::Options; use log::{error, info, warn}; use search::indexing::index_projects; use search::indexing::IndexingSettings; @@ -25,23 +24,6 @@ mod search; mod util; mod validate; -#[derive(Debug, Options)] -struct Config { - #[options(help = "Print help message")] - help: bool, - - #[options(no_short, help = "Skip indexing on startup")] - skip_first_index: bool, - #[options(no_short, help = "Reset the documents in the indices")] - reset_indices: bool, - - #[options( - no_short, - help = "Allow missing environment variables on startup. This is a bad idea, but it may work in some cases." - )] - allow_missing_vars: bool, -} - #[derive(Clone)] pub struct Pepper { pub pepper: String, @@ -53,40 +35,20 @@ async fn main() -> std::io::Result<()> { env_logger::Builder::from_env(Env::default().default_filter_or("info")) .init(); - let config = Config::parse_args_default_or_exit(); - if check_env_vars() { error!("Some environment variables are missing!"); - if !config.allow_missing_vars { - return Err(std::io::Error::new( - std::io::ErrorKind::Other, - "Missing required environment variables", - )); - } } - info!("Starting Labrinth on {}", dotenvy::var("BIND_ADDR").unwrap()); + info!( + "Starting Labrinth on {}", + dotenvy::var("BIND_ADDR").unwrap() + ); let search_config = search::SearchConfig { address: dotenvy::var("MEILISEARCH_ADDR").unwrap(), key: dotenvy::var("MEILISEARCH_KEY").unwrap(), }; - if config.reset_indices { - info!("Resetting indices"); - search::indexing::reset_indices(&search_config) - .await - .unwrap(); - return Ok(()); - } - - // Allow manually skipping the initial indexing for quicker iteration - // and startup times. - let skip_initial = config.skip_first_index; - if skip_initial { - info!("Skipping initial indexing"); - } - database::check_for_migrations() .await .expect("An error occurred while running migrations."); @@ -131,20 +93,12 @@ async fn main() -> std::io::Result<()> { parse_var("LOCAL_INDEX_INTERVAL").unwrap_or(3600), ); - let mut skip = skip_initial; let pool_ref = pool.clone(); let search_config_ref = search_config.clone(); scheduler.run(local_index_interval, move || { let pool_ref = pool_ref.clone(); let search_config_ref = search_config_ref.clone(); - let local_skip = skip; - if skip { - skip = false; - } async move { - if local_skip { - return; - } info!("Indexing local database"); let settings = IndexingSettings { index_local: true }; let result = @@ -183,7 +137,7 @@ async fn main() -> std::io::Result<()> { } }); - scheduler::schedule_versions(&mut scheduler, pool.clone(), skip_initial); + scheduler::schedule_versions(&mut scheduler, pool.clone()); let download_queue = Arc::new(DownloadQueue::new()); @@ -253,7 +207,9 @@ async fn main() -> std::io::Result<()> { }) .with_interval(std::time::Duration::from_secs(60)) .with_max_requests(300) - .with_ignore_key(dotenvy::var("RATE_LIMIT_IGNORE_KEY").ok()), + .with_ignore_key( + dotenvy::var("RATE_LIMIT_IGNORE_KEY").ok(), + ), ) .app_data(web::Data::new(pool.clone())) .app_data(web::Data::new(file_host.clone())) @@ -346,5 +302,8 @@ fn check_env_vars() -> bool { failed |= check_var::("ARIADNE_ADMIN_KEY"); failed |= check_var::("ARIADNE_URL"); + failed |= check_var::("STRIPE_TOKEN"); + failed |= check_var::("STRIPE_WEBHOOK_SECRET"); + failed } diff --git a/src/models/teams.rs b/src/models/teams.rs index 581a5ea3b..1b2d8f69e 100644 --- a/src/models/teams.rs +++ b/src/models/teams.rs @@ -1,6 +1,7 @@ use super::ids::Base62Id; use crate::database::models::team_item::QueryTeamMember; use crate::models::users::User; +use rust_decimal::Decimal; use serde::{Deserialize, Serialize}; /// The ID of a team @@ -59,9 +60,11 @@ pub struct TeamMember { pub permissions: Option, /// Whether the user has joined the team or is just invited to it pub accepted: bool, + + #[serde(with = "rust_decimal::serde::float_option")] /// Payouts split. This is a weighted average. For example. if a team has two members with this /// value set to 25.0 for both members, they split revenue 50/50 - pub payouts_split: Option, + pub payouts_split: Option, } impl TeamMember { diff --git a/src/models/users.rs b/src/models/users.rs index 1921fcd3f..ad547c95d 100644 --- a/src/models/users.rs +++ b/src/models/users.rs @@ -13,6 +13,7 @@ bitflags::bitflags! { #[derive(Serialize, Deserialize)] #[serde(transparent)] pub struct Badges: u64 { + // 1 << 0 unused - ignore + replace with something later const MIDAS = 1 << 0; const EARLY_MODPACK_ADOPTER = 1 << 1; const EARLY_RESPACK_ADOPTER = 1 << 2; @@ -44,6 +45,7 @@ pub struct User { pub created: DateTime, pub role: Role, pub badges: Badges, + pub paypal_email: Option, } use crate::database::models::user_item::User as DBUser; @@ -60,6 +62,7 @@ impl From for User { created: data.created, role: Role::from_string(&*data.role), badges: data.badges, + paypal_email: None, } } } diff --git a/src/routes/admin.rs b/src/routes/admin.rs index be83d8098..57f17c88a 100644 --- a/src/routes/admin.rs +++ b/src/routes/admin.rs @@ -1,11 +1,16 @@ use crate::models::ids::ProjectId; use crate::routes::ApiError; +use crate::util::auth::check_is_admin_from_headers; use crate::util::guards::admin_key_guard; +use crate::util::payout_calc::get_claimable_time; use crate::DownloadQueue; -use actix_web::{patch, web, HttpResponse}; +use actix_web::{get, patch, post, web, HttpRequest, HttpResponse}; +use chrono::{DateTime, Utc}; +use rust_decimal::Decimal; use serde::Deserialize; use serde_json::json; use sqlx::PgPool; +use std::collections::HashMap; use std::sync::Arc; #[derive(Deserialize)] @@ -80,5 +85,294 @@ pub async fn count_download( .await .ok(); - Ok(HttpResponse::Ok().body("")) + Ok(HttpResponse::NoContent().body("")) +} + +#[derive(Deserialize)] +pub struct PayoutData { + amount: Decimal, + date: DateTime, +} + +#[post("/_process_payout", guard = "admin_key_guard")] +pub async fn process_payout( + pool: web::Data, + data: web::Json, +) -> Result { + let start = data.date.date().and_hms(0, 0, 0); + + let client = reqwest::Client::new(); + let mut transaction = pool.begin().await?; + + #[derive(Deserialize)] + struct PayoutMultipliers { + sum: u64, + values: HashMap, + } + + let multipliers: PayoutMultipliers = client + .get(format!( + "{}multipliers?start_date=\"{}\"", + dotenvy::var("ARIADNE_URL")?, + start.to_rfc3339(), + )) + .header("Modrinth-Admin", dotenvy::var("ARIADNE_ADMIN_KEY")?) + .send() + .await + .map_err(|_| { + ApiError::Analytics( + "Error while fetching payout multipliers!".to_string(), + ) + })? + .json() + .await + .map_err(|_| { + ApiError::Analytics( + "Error while deserializing payout multipliers!".to_string(), + ) + })?; + + sqlx::query!( + " + DELETE FROM payouts_values + WHERE created = $1 + ", + start + ) + .execute(&mut *transaction) + .await?; + + struct Project { + project_type: String, + // user_id, payouts_split + team_members: Vec<(i64, Decimal)>, + // user_id, payouts_split + split_team_members: Vec<(i64, Decimal)>, + } + + let mut projects_map: HashMap = HashMap::new(); + + use futures::TryStreamExt; + sqlx::query!( + " + SELECT m.id id, tm.user_id user_id, tm.payouts_split payouts_split, pt.name project_type + FROM mods m + INNER JOIN team_members tm on m.team_id = tm.team_id + INNER JOIN project_types pt ON pt.id = m.project_type + WHERE m.id = ANY($1) + ", + &multipliers.values.keys().map(|x| *x).collect::>() + ) + .fetch_many(&mut *transaction) + .try_for_each(|e| { + if let Some(row) = e.right() { + if let Some(project) = projects_map.get_mut(&row.id) { + project.team_members.push((row.user_id, row.payouts_split)); + } else { + projects_map.insert(row.id, Project { + project_type: row.project_type, + team_members: vec![(row.user_id, row.payouts_split)], + split_team_members: Default::default() + }); + } + } + + futures::future::ready(Ok(())) + }) + .await?; + + // Specific Payout Conditions (ex: modpack payout split) + let mut projects_split_dependencies = Vec::new(); + + for (id, project) in &projects_map { + if project.project_type == "modpack" { + projects_split_dependencies.push(*id); + } + } + + if !projects_split_dependencies.is_empty() { + // (dependent_id, (dependency_id, times_depended)) + let mut project_dependencies: HashMap> = + HashMap::new(); + // dependency_ids to fetch team members from + let mut fetch_team_members: Vec = Vec::new(); + + sqlx::query!( + " + SELECT mv.mod_id, m.id, COUNT(m.id) times_depended FROM versions mv + INNER JOIN dependencies d ON d.dependent_id = mv.id + INNER JOIN versions v ON d.dependency_id = v.id + INNER JOIN mods m ON v.mod_id = m.id OR d.mod_dependency_id = m.id + WHERE mv.mod_id = ANY($1) + group by mv.mod_id, m.id; + ", + &projects_split_dependencies + ) + .fetch_many(&mut *transaction) + .try_for_each(|e| { + if let Some(row) = e.right() { + fetch_team_members.push(row.id); + + if let Some(project) = project_dependencies.get_mut(&row.mod_id) + { + project.push((row.id, row.times_depended.unwrap_or(0))); + } else { + project_dependencies.insert( + row.mod_id, + vec![(row.id, row.times_depended.unwrap_or(0))], + ); + } + } + + futures::future::ready(Ok(())) + }) + .await?; + + // (project_id, (user_id, payouts_split)) + let mut team_members: HashMap> = + HashMap::new(); + + sqlx::query!( + " + SELECT m.id id, tm.user_id user_id, tm.payouts_split payouts_split + FROM mods m + INNER JOIN team_members tm on m.team_id = tm.team_id + WHERE m.id = ANY($1) + ", + &*fetch_team_members + ) + .fetch_many(&mut *transaction) + .try_for_each(|e| { + if let Some(row) = e.right() { + if let Some(project) = team_members.get_mut(&row.id) { + project.push((row.user_id, row.payouts_split)); + } else { + team_members + .insert(row.id, vec![(row.user_id, row.payouts_split)]); + } + } + + futures::future::ready(Ok(())) + }) + .await?; + + for (project, dependencies) in project_dependencies { + let dep_sum: i64 = dependencies.iter().map(|x| x.1).sum(); + + let project = projects_map.get_mut(&project); + + if let Some(project) = project { + for dependency in dependencies { + let project_multiplier: Decimal = + Decimal::from(dependency.1) / Decimal::from(dep_sum); + + if let Some(members) = team_members.get(&dependency.0) { + let members_sum: Decimal = + members.iter().map(|x| x.1).sum(); + + for member in members { + let member_multiplier: Decimal = + member.1 / members_sum; + project.split_team_members.push(( + member.0, + member_multiplier * project_multiplier, + )); + } + } + } + } + } + } + + for (id, project) in projects_map { + if let Some(value) = &multipliers.values.get(&id) { + let project_multiplier: Decimal = + Decimal::from(**value) / Decimal::from(multipliers.sum); + + let default_split_given = Decimal::from(1); + let split_given = Decimal::from(1) / Decimal::from(5); + let split_retention = Decimal::from(4) / Decimal::from(5); + + let sum_splits: Decimal = + project.team_members.iter().map(|x| x.1).sum(); + let sum_tm_splits: Decimal = + project.split_team_members.iter().map(|x| x.1).sum(); + + for (user_id, split) in project.team_members { + let payout: Decimal = data.amount + * project_multiplier + * (split / sum_splits) + * (if !project.split_team_members.is_empty() { + &split_given + } else { + &default_split_given + }); + + sqlx::query!( + " + INSERT INTO payouts_values (user_id, mod_id, amount, created) + VALUES ($1, $2, $3, $4) + ", + user_id, + id, + payout, + start + ) + .execute(&mut *transaction) + .await?; + } + + for (user_id, split) in project.split_team_members { + let payout: Decimal = data.amount + * project_multiplier + * (split / sum_tm_splits) + * split_retention; + + sqlx::query!( + " + INSERT INTO payouts_values (user_id, amount, created) + VALUES ($1, $2, $3) + ", + user_id, + payout, + start + ) + .execute(&mut *transaction) + .await?; + } + } + } + + transaction.commit().await?; + + Ok(HttpResponse::NoContent().body("")) +} + +#[get("/_get-payout-data")] +pub async fn get_payout_data( + req: HttpRequest, + pool: web::Data, +) -> Result { + check_is_admin_from_headers(req.headers(), &**pool).await?; + + use futures::stream::TryStreamExt; + + let payouts = sqlx::query!( + " + SELECT u.paypal_email, SUM(pv.amount) amount + FROM payouts_values pv + INNER JOIN users u ON pv.user_id = u.id AND u.paypal_email IS NOT NULL + WHERE pv.created <= $1 AND pv.claimed = FALSE + GROUP BY u.paypal_email + ", + get_claimable_time(Utc::now(), false) + ) + .fetch_many(&**pool) + .try_filter_map(|e| async { + Ok(e.right().map(|r| (r.paypal_email.unwrap_or_default(), r.amount.unwrap_or_default()))) + }) + .try_collect::>() + .await?; + + Ok(HttpResponse::Ok().json(payouts)) } diff --git a/src/routes/auth.rs b/src/routes/auth.rs index 52c402a3e..77bcf78f1 100644 --- a/src/routes/auth.rs +++ b/src/routes/auth.rs @@ -273,6 +273,7 @@ pub async fn auth_callback( created: Utc::now(), role: Role::Developer.to_string(), badges: Badges::default(), + paypal_email: None, } .insert(&mut transaction) .await?; diff --git a/src/routes/midas.rs b/src/routes/midas.rs new file mode 100644 index 000000000..6eec8afa9 --- /dev/null +++ b/src/routes/midas.rs @@ -0,0 +1,336 @@ +use crate::models::users::UserId; +use crate::routes::ApiError; +use crate::util::auth::get_user_from_headers; +use actix_web::{post, web, HttpRequest, HttpResponse}; +use chrono::{DateTime, Duration, NaiveDateTime, Utc}; +use hmac::{Hmac, Mac, NewMac}; +use itertools::Itertools; +use serde::Deserialize; +use serde_json::{json, Value}; +use sqlx::PgPool; + +#[derive(Deserialize)] +pub struct CheckoutData { + pub price_id: String, +} + +#[post("/_stripe-init-checkout")] +pub async fn init_checkout( + req: HttpRequest, + pool: web::Data, + data: web::Json, +) -> Result { + let user = get_user_from_headers(req.headers(), &**pool).await?; + + let client = reqwest::Client::new(); + + #[derive(Deserialize)] + struct Session { + url: Option, + } + + let session = client + .post("https://api.stripe.com/v1/checkout/sessions") + .header( + "Authorization", + format!("Bearer {}", dotenvy::var("STRIPE_TOKEN")?), + ) + .form(&[ + ("mode", "subscription"), + ("line_items[0][price]", &*data.price_id), + ("line_items[0][quantity]", "1"), + ("success_url", "https://modrinth.com/welcome-to-midas"), + ("cancel_url", "https://modrinth.com/midas"), + ("metadata[user_id]", &user.id.to_string()), + ]) + .send() + .await + .map_err(|_| { + ApiError::Payments( + "Error while creating checkout session!".to_string(), + ) + })? + .json::() + .await + .map_err(|_| { + ApiError::Payments( + "Error while deserializing checkout response!".to_string(), + ) + })?; + + Ok(HttpResponse::Ok().json(json!( + { + "url": session.url + } + ))) +} + +#[post("/_stripe-init-portal")] +pub async fn init_customer_portal( + req: HttpRequest, + pool: web::Data, +) -> Result { + let user = get_user_from_headers(req.headers(), &**pool).await?; + + let customer_id = sqlx::query!( + " + SELECT u.stripe_customer_id + FROM users u + WHERE u.id = $1 + ", + user.id.0 as i64, + ) + .fetch_optional(&**pool) + .await? + .and_then(|x| x.stripe_customer_id) + .ok_or_else(|| { + ApiError::InvalidInput( + "User is not linked to stripe account!".to_string(), + ) + })?; + + let client = reqwest::Client::new(); + + #[derive(Deserialize)] + struct Session { + url: Option, + } + + let session = client + .post("https://api.stripe.com/v1/billing_portal/sessions") + .header( + "Authorization", + format!("Bearer {}", dotenvy::var("STRIPE_TOKEN")?), + ) + .form(&[ + ("customer", &*customer_id), + ("return_url", "https://modrinth.com/settings/billing"), + ]) + .send() + .await + .map_err(|_| { + ApiError::Payments( + "Error while creating billing session!".to_string(), + ) + })? + .json::() + .await + .map_err(|_| { + ApiError::Payments( + "Error while deserializing billing response!".to_string(), + ) + })?; + + Ok(HttpResponse::Ok().json(json!( + { + "url": session.url + } + ))) +} + +#[post("/_stripe-webook")] +pub async fn handle_stripe_webhook( + body: String, + req: HttpRequest, + pool: web::Data, +) -> Result { + if let Some(signature_raw) = req + .headers() + .get("Stripe-Signature") + .and_then(|x| x.to_str().ok()) + { + let mut timestamp = None; + let mut signature = None; + for val in signature_raw.split(',') { + let key_val = val.split('=').collect_vec(); + + if key_val.len() == 2 { + if key_val[0] == "v1" { + signature = hex::decode(key_val[1]).ok() + } else if key_val[0] == "t" { + timestamp = key_val[1].parse::().ok() + } + } + } + + if let Some(timestamp) = timestamp { + if let Some(signature) = signature { + type HmacSha256 = Hmac; + + let mut key = HmacSha256::new_from_slice(dotenvy::var("STRIPE_WEBHOOK_SECRET")?.as_bytes()).map_err(|_| { + ApiError::Crypto( + "Unable to initialize HMAC instance due to invalid key length!".to_string(), + ) + })?; + + key.update(format!("{}.{}", timestamp, body).as_bytes()); + + key.verify(&signature).map_err(|_| { + ApiError::Crypto( + "Unable to verify webhook signature!".to_string(), + ) + })?; + + if timestamp < (Utc::now() - Duration::minutes(5)).timestamp() + || timestamp + > (Utc::now() + Duration::minutes(5)).timestamp() + { + return Err(ApiError::Crypto( + "Webhook signature expired!".to_string(), + )); + } + } else { + return Err(ApiError::Crypto("Missing signature!".to_string())); + } + } else { + return Err(ApiError::Crypto("Missing timestamp!".to_string())); + } + } else { + return Err(ApiError::Crypto("Missing signature header!".to_string())); + } + + #[derive(Deserialize)] + struct StripeWebhookBody { + #[serde(rename = "type")] + type_: String, + data: StripeWebhookObject, + } + + #[derive(Deserialize)] + struct StripeWebhookObject { + object: Value, + } + + let webhook: StripeWebhookBody = serde_json::from_str(&*body)?; + + #[derive(Deserialize)] + struct CheckoutSession { + customer: String, + metadata: SessionMetadata, + } + + #[derive(Deserialize)] + struct SessionMetadata { + user_id: UserId, + } + + #[derive(Deserialize)] + struct Invoice { + customer: String, + // paid: bool, + lines: InvoiceLineItems, + } + + #[derive(Deserialize)] + struct InvoiceLineItems { + pub data: Vec, + } + + #[derive(Deserialize)] + struct InvoiceLineItem { + period: Period, + } + + #[derive(Deserialize)] + struct Period { + // start: i64, + end: i64, + } + + #[derive(Deserialize)] + struct Subscription { + customer: String, + } + + let mut transaction = pool.begin().await?; + + // TODO: Currently hardcoded to midas-only. When we add more stuff should include price IDs + match &*webhook.type_ { + "checkout.session.completed" => { + let session: CheckoutSession = + serde_json::from_value(webhook.data.object)?; + + sqlx::query!( + " + UPDATE users + SET stripe_customer_id = $1 + WHERE (id = $2) + ", + session.customer, + session.metadata.user_id.0 as i64, + ) + .execute(&mut *transaction) + .await?; + } + "invoice.paid" => { + let invoice: Invoice = serde_json::from_value(webhook.data.object)?; + + if let Some(item) = invoice.lines.data.first() { + let expires: DateTime = DateTime::from_utc( + NaiveDateTime::from_timestamp(item.period.end, 0), + Utc, + ) + Duration::days(1); + + sqlx::query!( + " + UPDATE users + SET midas_expires = $1, is_overdue = FALSE + WHERE (stripe_customer_id = $2) + ", + expires, + invoice.customer, + ) + .execute(&mut *transaction) + .await?; + } + } + "invoice.payment_failed" => { + let invoice: Invoice = serde_json::from_value(webhook.data.object)?; + + let customer_id = sqlx::query!( + " + SELECT u.id + FROM users u + WHERE u.stripe_customer_id = $1 + ", + invoice.customer, + ) + .fetch_optional(&**pool) + .await? + .map(|x| x.id); + + if let Some(user_id) = customer_id { + sqlx::query!( + " + UPDATE users + SET is_overdue = TRUE + WHERE (id = $1) + ", + user_id, + ) + .execute(&mut *transaction) + .await?; + } + } + "customer.subscription.deleted" => { + let session: Subscription = + serde_json::from_value(webhook.data.object)?; + + sqlx::query!( + " + UPDATE users + SET stripe_customer_id = NULL, midas_expires = NULL, is_overdue = NULL + WHERE (stripe_customer_id = $1) + ", + session.customer, + ) + .execute(&mut *transaction) + .await?; + } + _ => {} + }; + + transaction.commit().await?; + + Ok(HttpResponse::NoContent().body("")) +} diff --git a/src/routes/mod.rs b/src/routes/mod.rs index 100c82c35..5313d91e5 100644 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -6,6 +6,7 @@ mod auth; mod health; mod index; mod maven; +mod midas; mod moderation; mod not_found; mod notifications; @@ -41,7 +42,8 @@ pub fn v2_config(cfg: &mut web::ServiceConfig) { .configure(moderation_config) .configure(reports_config) .configure(notifications_config) - .configure(admin_config), + .configure(admin_config) + .configure(midas_config), ); } @@ -169,6 +171,15 @@ pub fn admin_config(cfg: &mut web::ServiceConfig) { cfg.service(web::scope("admin").service(admin::count_download)); } +pub fn midas_config(cfg: &mut web::ServiceConfig) { + cfg.service( + web::scope("midas") + .service(midas::init_checkout) + .service(midas::init_customer_portal) + .service(midas::handle_stripe_webhook), + ); +} + #[derive(thiserror::Error, Debug)] pub enum ApiError { #[error("Environment Error")] @@ -195,6 +206,12 @@ pub enum ApiError { Search(#[from] meilisearch_sdk::errors::Error), #[error("Indexing Error: {0}")] Indexing(#[from] crate::search::indexing::IndexingError), + #[error("Ariadne Error: {0}")] + Analytics(String), + #[error("Crypto Error: {0}")] + Crypto(String), + #[error("Payments Error: {0}")] + Payments(String), } impl actix_web::ResponseError for ApiError { @@ -234,6 +251,13 @@ impl actix_web::ResponseError for ApiError { ApiError::Validation(..) => { actix_web::http::StatusCode::BAD_REQUEST } + ApiError::Analytics(..) => { + actix_web::http::StatusCode::FAILED_DEPENDENCY + } + ApiError::Crypto(..) => actix_web::http::StatusCode::FORBIDDEN, + ApiError::Payments(..) => { + actix_web::http::StatusCode::FAILED_DEPENDENCY + } } } @@ -253,6 +277,9 @@ impl actix_web::ResponseError for ApiError { ApiError::FileHosting(..) => "file_hosting_error", ApiError::InvalidInput(..) => "invalid_input", ApiError::Validation(..) => "invalid_input", + ApiError::Analytics(..) => "analytics_error", + ApiError::Crypto(..) => "crypto_error", + ApiError::Payments(..) => "payments_error", }, description: &self.to_string(), }, diff --git a/src/routes/project_creation.rs b/src/routes/project_creation.rs index 82e2cca70..31ac02c19 100644 --- a/src/routes/project_creation.rs +++ b/src/routes/project_creation.rs @@ -17,6 +17,7 @@ use actix_web::web::Data; use actix_web::{post, HttpRequest, HttpResponse}; use chrono::Utc; use futures::stream::StreamExt; +use rust_decimal::Decimal; use serde::{Deserialize, Serialize}; use sqlx::postgres::PgPool; use std::sync::Arc; @@ -274,9 +275,7 @@ pub async fn project_create( // fix multipart error bug: payload.for_each(|_| ready(())).await; - if let Err(e) = undo_result { - return Err(e); - } + undo_result?; if let Err(e) = rollback_result { return Err(e.into()); } @@ -628,7 +627,7 @@ pub async fn project_create_inner( role: crate::models::teams::OWNER_ROLE.to_owned(), permissions: crate::models::teams::Permissions::ALL, accepted: true, - payouts_split: 100.0, + payouts_split: Decimal::from(100), }], }; @@ -793,7 +792,8 @@ pub async fn project_create_inner( let _project_id = project_builder.insert(&mut *transaction).await?; if status == ProjectStatus::Processing { - if let Ok(webhook_url) = dotenvy::var("MODERATION_DISCORD_WEBHOOK") { + if let Ok(webhook_url) = dotenvy::var("MODERATION_DISCORD_WEBHOOK") + { crate::util::webhook::send_discord_webhook( response.clone(), webhook_url, diff --git a/src/routes/teams.rs b/src/routes/teams.rs index 7e3f11947..86ad91bb7 100644 --- a/src/routes/teams.rs +++ b/src/routes/teams.rs @@ -8,6 +8,7 @@ use crate::models::users::UserId; use crate::routes::ApiError; use crate::util::auth::get_user_from_headers; use actix_web::{delete, get, patch, post, web, HttpRequest, HttpResponse}; +use rust_decimal::Decimal; use serde::{Deserialize, Serialize}; use sqlx::PgPool; @@ -216,7 +217,7 @@ pub struct NewTeamMember { #[serde(default = "Permissions::default")] pub permissions: Permissions, #[serde(default)] - pub payouts_split: f32, + pub payouts_split: Decimal, } #[post("{id}/members")] @@ -259,7 +260,9 @@ pub async fn add_team_member( )); } - if !(0.0..=5000.0).contains(&new_member.payouts_split) { + if new_member.payouts_split < Decimal::from(0) + || new_member.payouts_split > Decimal::from(5000) + { return Err(ApiError::InvalidInput( "Payouts split must be between 0 and 5000!".to_string(), )); @@ -360,7 +363,7 @@ pub async fn add_team_member( pub struct EditTeamMember { pub permissions: Option, pub role: Option, - pub payouts_split: Option, + pub payouts_split: Option, } #[patch("{id}/members/{user_id}")] @@ -419,7 +422,9 @@ pub async fn edit_team_member( } if let Some(payouts_split) = edit_member.payouts_split { - if !(0.0..=5000.0).contains(&payouts_split) { + if payouts_split < Decimal::from(0) + || payouts_split > Decimal::from(5000) + { return Err(ApiError::InvalidInput( "Payouts split must be between 0 and 5000!".to_string(), )); diff --git a/src/routes/users.rs b/src/routes/users.rs index 24bcae53f..5f559790b 100644 --- a/src/routes/users.rs +++ b/src/routes/users.rs @@ -1,16 +1,20 @@ use crate::database::models::User; use crate::file_hosting::FileHost; use crate::models::notifications::Notification; -use crate::models::projects::{Project, ProjectStatus}; +use crate::models::projects::{Project, ProjectId, ProjectStatus}; use crate::models::users::{Badges, Role, UserId}; use crate::routes::ApiError; -use crate::util::auth::get_user_from_headers; +use crate::util::auth::{check_is_admin_from_headers, get_user_from_headers}; +use crate::util::payout_calc::get_claimable_time; use crate::util::routes::read_from_payload; use crate::util::validate::validation_errors_to_string; use actix_web::{delete, get, patch, web, HttpRequest, HttpResponse}; +use chrono::{DateTime, Utc}; use lazy_static::lazy_static; use regex::Regex; +use rust_decimal::Decimal; use serde::{Deserialize, Serialize}; +use serde_json::json; use sqlx::PgPool; use std::sync::Arc; use validator::Validate; @@ -20,10 +24,8 @@ pub async fn user_auth_get( req: HttpRequest, pool: web::Data, ) -> Result { - Ok(HttpResponse::Ok().json( - get_user_from_headers(req.headers(), &mut *pool.acquire().await?) - .await?, - )) + Ok(HttpResponse::Ok() + .json(get_user_from_headers(req.headers(), &**pool).await?)) } #[derive(Serialize, Deserialize)] @@ -155,6 +157,8 @@ pub struct EditUser { pub bio: Option>, pub role: Option, pub badges: Option, + #[validate(email, length(max = 128))] + pub paypal_email: Option>, } #[patch("{id}")] @@ -299,6 +303,20 @@ pub async fn user_edit( .await?; } + if let Some(paypal_email) = &new_user.paypal_email { + sqlx::query!( + " + UPDATE users + SET paypal_email = $1 + WHERE (id = $2) + ", + paypal_email.as_deref(), + id as crate::database::models::ids::UserId, + ) + .execute(&mut *transaction) + .await?; + } + transaction.commit().await?; Ok(HttpResponse::NoContent().body("")) } else { @@ -542,3 +560,102 @@ pub async fn user_notifications( Ok(HttpResponse::NotFound().body("")) } } + +#[derive(Serialize)] +pub struct Payout { + pub claimed: bool, + pub claimable: bool, + pub created: DateTime, + pub project: Option, + pub amount: Decimal, +} + +#[get("{id}/payouts")] +pub async fn user_payouts( + req: HttpRequest, + info: web::Path<(String,)>, + pool: web::Data, +) -> Result { + let user = get_user_from_headers(req.headers(), &**pool).await?; + let id_option = + User::get_id_from_username_or_id(&*info.into_inner().0, &**pool) + .await?; + + if let Some(id) = id_option { + if !user.role.is_admin() && user.id != id.into() { + return Err(ApiError::CustomAuthentication( + "You do not have permission to see the payouts of this user!" + .to_string(), + )); + } + + use futures::TryStreamExt; + + let payouts: Vec = sqlx::query!( + " + SELECT pv.mod_id, pv.created, pv.claimed, pv.amount + FROM payouts_values pv + WHERE pv.user_id = $1 + ORDER BY pv.created DESC + ", + id as crate::database::models::UserId + ) + .fetch_many(&**pool) + .try_filter_map(|e| async { + Ok(e.right().map(|row| { + let claimable_time: DateTime = + get_claimable_time(row.created, true); + + Payout { + claimed: row.claimed, + claimable: Utc::now() > claimable_time, + created: row.created, + project: row.mod_id.map(|x| ProjectId(x as u64)), + amount: row.amount, + } + })) + }) + .try_collect::>() + .await?; + + Ok(HttpResponse::Ok().json(json!({ + "all_time": payouts.iter().map(|x| x.amount).sum::(), + "current_period": payouts.iter().filter(|x| !x.claimed && !x.claimable).map(|x| x.amount).sum::(), + "withdrawable": payouts.iter().filter(|x| x.claimable && !x.claimed).map(|x| x.amount).sum::(), + "payouts": payouts, + }))) + } else { + Ok(HttpResponse::NotFound().body("")) + } +} + +#[get("{id}/payouts")] +pub async fn finish_user_payout( + req: HttpRequest, + info: web::Path<(String,)>, + pool: web::Data, +) -> Result { + check_is_admin_from_headers(req.headers(), &**pool).await?; + + let id_option = + User::get_id_from_username_or_id(&*info.into_inner().0, &**pool) + .await?; + + if let Some(id) = id_option { + sqlx::query!( + " + UPDATE payouts_values + SET claimed = TRUE + WHERE (claimed = FALSE AND user_id = $1 AND created <= $2) + ", + id as crate::database::models::ids::UserId, + get_claimable_time(Utc::now(), false) + ) + .execute(&**pool) + .await?; + + Ok(HttpResponse::NoContent().body("")) + } else { + Ok(HttpResponse::NotFound().body("")) + } +} diff --git a/src/routes/v1/mods.rs b/src/routes/v1/mods.rs index ffc6cf825..77617f060 100644 --- a/src/routes/v1/mods.rs +++ b/src/routes/v1/mods.rs @@ -136,9 +136,7 @@ pub async fn mod_create( let undo_result = undo_uploads(&***file_host, &uploaded_files).await; let rollback_result = transaction.rollback().await; - if let Err(e) = undo_result { - return Err(e); - } + undo_result?; if let Err(e) = rollback_result { return Err(e.into()); } diff --git a/src/routes/v1/versions.rs b/src/routes/v1/versions.rs index 591a3af3d..25f9e3cb5 100644 --- a/src/routes/v1/versions.rs +++ b/src/routes/v1/versions.rs @@ -1,4 +1,4 @@ -use crate::file_hosting::FileHost; +use crate::database; use crate::models::ids::{ProjectId, UserId, VersionId}; use crate::models::projects::{ Dependency, GameVersion, Loader, Version, VersionFile, VersionType, @@ -7,12 +7,10 @@ use crate::models::teams::Permissions; use crate::routes::versions::{VersionIds, VersionListFilters}; use crate::routes::ApiError; use crate::util::auth::get_user_from_headers; -use crate::{database, models}; use actix_web::{delete, get, web, HttpRequest, HttpResponse}; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use sqlx::PgPool; -use std::sync::Arc; /// A specific version of a mod #[derive(Serialize, Deserialize)] @@ -286,7 +284,6 @@ pub async fn delete_file( req: HttpRequest, info: web::Path<(String,)>, pool: web::Data, - file_host: web::Data>, algorithm: web::Query, ) -> Result { let user = get_user_from_headers(req.headers(), &**pool).await?; diff --git a/src/routes/version_creation.rs b/src/routes/version_creation.rs index 04777dc3e..d87d292fa 100644 --- a/src/routes/version_creation.rs +++ b/src/routes/version_creation.rs @@ -92,9 +92,7 @@ pub async fn version_create( payload.for_each(|_| ready(())).await; - if let Err(e) = undo_result { - return Err(e); - } + undo_result?; if let Err(e) = rollback_result { return Err(e.into()); } @@ -461,9 +459,7 @@ pub async fn upload_file_to_version( payload.for_each(|_| ready(())).await; - if let Err(e) = undo_result { - return Err(e); - } + undo_result?; if let Err(e) = rollback_result { return Err(e.into()); } diff --git a/src/routes/version_file.rs b/src/routes/version_file.rs index 3651a8943..691caab40 100644 --- a/src/routes/version_file.rs +++ b/src/routes/version_file.rs @@ -1,6 +1,5 @@ use super::ApiError; use crate::database::models::{version_item::QueryVersion, DatabaseError}; -use crate::file_hosting::FileHost; use crate::models::projects::{GameVersion, Loader, Version}; use crate::models::teams::Permissions; use crate::util::auth::get_user_from_headers; @@ -10,7 +9,6 @@ use actix_web::{delete, get, post, web, HttpRequest, HttpResponse}; use serde::{Deserialize, Serialize}; use sqlx::PgPool; use std::collections::HashMap; -use std::sync::Arc; use tokio::sync::RwLock; #[derive(Deserialize)] @@ -114,7 +112,6 @@ pub async fn delete_file( req: HttpRequest, info: web::Path<(String,)>, pool: web::Data, - file_host: web::Data>, algorithm: web::Query, ) -> Result { let user = get_user_from_headers(req.headers(), &**pool).await?; diff --git a/src/scheduler.rs b/src/scheduler.rs index 2cf01c1c5..57565db4e 100644 --- a/src/scheduler.rs +++ b/src/scheduler.rs @@ -35,23 +35,14 @@ use log::{info, warn}; pub fn schedule_versions( scheduler: &mut Scheduler, pool: sqlx::Pool, - skip_initial: bool, ) { let version_index_interval = std::time::Duration::from_secs( parse_var("VERSION_INDEX_INTERVAL").unwrap_or(1800), ); - let mut skip = skip_initial; scheduler.run(version_index_interval, move || { let pool_ref = pool.clone(); - let local_skip = skip; - if skip { - skip = false; - } async move { - if local_skip { - return; - } info!("Indexing game versions list from Mojang"); let result = update_versions(&pool_ref).await; if let Err(e) = result { diff --git a/src/search/indexing/mod.rs b/src/search/indexing/mod.rs index e6c603fc3..35af419c6 100644 --- a/src/search/indexing/mod.rs +++ b/src/search/indexing/mod.rs @@ -62,15 +62,6 @@ pub async fn index_projects( Ok(()) } -pub async fn reset_indices(config: &SearchConfig) -> Result<(), IndexingError> { - let client = config.make_client(); - - client.delete_index("projects").await?; - client.delete_index("projects_filtered").await?; - - Ok(()) -} - async fn create_index( client: &Client, name: &'static str, diff --git a/src/util/auth.rs b/src/util/auth.rs index 47074d986..40153ec73 100644 --- a/src/util/auth.rs +++ b/src/util/auth.rs @@ -73,6 +73,7 @@ where created: result.created, role: Role::from_string(&result.role), badges: result.badges, + paypal_email: result.paypal_email, }), None => Err(AuthenticationError::InvalidCredentials), } diff --git a/src/util/mod.rs b/src/util/mod.rs index 8d648cbf6..d0f286843 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -2,6 +2,7 @@ pub mod auth; pub mod env; pub mod ext; pub mod guards; +pub mod payout_calc; pub mod routes; pub mod validate; pub mod webhook; diff --git a/src/util/payout_calc.rs b/src/util/payout_calc.rs new file mode 100644 index 000000000..178b21565 --- /dev/null +++ b/src/util/payout_calc.rs @@ -0,0 +1,22 @@ +use chrono::{DateTime, Datelike, NaiveDate, NaiveDateTime, NaiveTime, Utc}; + +pub fn get_claimable_time( + current: DateTime, + future: bool, +) -> DateTime { + let adder = if current.month() == 1 && !future { + (-1, 12) + } else if current.month() == 12 && future { + (1, 1) + } else { + (0, current.month()) + }; + + DateTime::from_utc( + NaiveDateTime::new( + NaiveDate::from_ymd(current.year() + adder.0, adder.1, 16), + NaiveTime::default(), + ), + Utc, + ) +} diff --git a/src/util/validate.rs b/src/util/validate.rs index 778a5163e..794295bcb 100644 --- a/src/util/validate.rs +++ b/src/util/validate.rs @@ -89,7 +89,7 @@ pub fn validate_deps( Ok(()) } -pub fn validate_url(value: &String) -> Result<(), validator::ValidationError> { +pub fn validate_url(value: &str) -> Result<(), validator::ValidationError> { let url = url::Url::parse(value) .ok() .ok_or_else(|| validator::ValidationError::new("invalid URL"))?;