diff --git a/.sqlx/query-1619aac8983ad68177bd698393b24eefd77bada44bec1043972493146c09bb73.json b/.sqlx/query-1619aac8983ad68177bd698393b24eefd77bada44bec1043972493146c09bb73.json new file mode 100644 index 0000000..333739c --- /dev/null +++ b/.sqlx/query-1619aac8983ad68177bd698393b24eefd77bada44bec1043972493146c09bb73.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "DELETE FROM ignored_users WHERE id = ?", + "describe": { + "columns": [], + "parameters": { + "Right": 1 + }, + "nullable": [] + }, + "hash": "1619aac8983ad68177bd698393b24eefd77bada44bec1043972493146c09bb73" +} diff --git a/.sqlx/query-1bf34dddbe994d6124c9382c75e70e1347329e945de2eefad4bfcab5f81b73ce.json b/.sqlx/query-1bf34dddbe994d6124c9382c75e70e1347329e945de2eefad4bfcab5f81b73ce.json index 9c36779..35fa12f 100644 --- a/.sqlx/query-1bf34dddbe994d6124c9382c75e70e1347329e945de2eefad4bfcab5f81b73ce.json +++ b/.sqlx/query-1bf34dddbe994d6124c9382c75e70e1347329e945de2eefad4bfcab5f81b73ce.json @@ -6,7 +6,7 @@ { "name": "channel_id: i64", "ordinal": 0, - "type_info": "Int64" + "type_info": "Integer" }, { "name": "beatmap", @@ -16,7 +16,7 @@ { "name": "mode: u8", "ordinal": 2, - "type_info": "Int64" + "type_info": "Integer" } ], "parameters": { @@ -25,7 +25,7 @@ "nullable": [ false, false, - false + true ] }, "hash": "1bf34dddbe994d6124c9382c75e70e1347329e945de2eefad4bfcab5f81b73ce" diff --git a/.sqlx/query-235312a1aad1a58c2f7f2d817945bbac57c38ad2c51c1924683d13d045f21ad9.json b/.sqlx/query-235312a1aad1a58c2f7f2d817945bbac57c38ad2c51c1924683d13d045f21ad9.json index 344ffdd..20caec3 100644 --- a/.sqlx/query-235312a1aad1a58c2f7f2d817945bbac57c38ad2c51c1924683d13d045f21ad9.json +++ b/.sqlx/query-235312a1aad1a58c2f7f2d817945bbac57c38ad2c51c1924683d13d045f21ad9.json @@ -6,22 +6,22 @@ { "name": "beatmap_id: i64", "ordinal": 0, - "type_info": "Int64" + "type_info": "Integer" }, { "name": "mode: u8", "ordinal": 1, - "type_info": "Int64" + "type_info": "Integer" }, { "name": "user_id: i64", "ordinal": 2, - "type_info": "Int64" + "type_info": "Integer" }, { "name": "mods: i64", "ordinal": 3, - "type_info": "Int64" + "type_info": "Integer" }, { "name": "cached_at: DateTime", diff --git a/.sqlx/query-25dcc59341e6375ee6a55aa014aecc54be42e1e8787ae5a06a61bb8ba8e9c366.json b/.sqlx/query-25dcc59341e6375ee6a55aa014aecc54be42e1e8787ae5a06a61bb8ba8e9c366.json index 814d59b..592ce81 100644 --- a/.sqlx/query-25dcc59341e6375ee6a55aa014aecc54be42e1e8787ae5a06a61bb8ba8e9c366.json +++ b/.sqlx/query-25dcc59341e6375ee6a55aa014aecc54be42e1e8787ae5a06a61bb8ba8e9c366.json @@ -6,7 +6,7 @@ { "name": "user_id: i64", "ordinal": 0, - "type_info": "Int64" + "type_info": "Integer" }, { "name": "username", @@ -16,17 +16,17 @@ { "name": "id: i64", "ordinal": 2, - "type_info": "Int64" + "type_info": "Integer" }, { "name": "preferred_mode: u8", "ordinal": 3, - "type_info": "Int64" + "type_info": "Integer" }, { "name": "failures: u8", "ordinal": 4, - "type_info": "Int64" + "type_info": "Integer" } ], "parameters": { diff --git a/.sqlx/query-296c95c7ead4d747a4da007b4b6e28d3c6c1c4bb654c82cc40bf61390c3dad4b.json b/.sqlx/query-296c95c7ead4d747a4da007b4b6e28d3c6c1c4bb654c82cc40bf61390c3dad4b.json index 2e8b15f..82981ab 100644 --- a/.sqlx/query-296c95c7ead4d747a4da007b4b6e28d3c6c1c4bb654c82cc40bf61390c3dad4b.json +++ b/.sqlx/query-296c95c7ead4d747a4da007b4b6e28d3c6c1c4bb654c82cc40bf61390c3dad4b.json @@ -6,7 +6,7 @@ { "name": "beatmap_id: i64", "ordinal": 0, - "type_info": "Int64" + "type_info": "Integer" }, { "name": "cached_at: DateTime", diff --git a/.sqlx/query-4b033607229deba540f80e469753e2125b6d8134346144f462325dc025221044.json b/.sqlx/query-4b033607229deba540f80e469753e2125b6d8134346144f462325dc025221044.json index 91a9e25..a8b69b9 100644 --- a/.sqlx/query-4b033607229deba540f80e469753e2125b6d8134346144f462325dc025221044.json +++ b/.sqlx/query-4b033607229deba540f80e469753e2125b6d8134346144f462325dc025221044.json @@ -6,12 +6,12 @@ { "name": "beatmap_id: i64", "ordinal": 0, - "type_info": "Int64" + "type_info": "Integer" }, { "name": "mode: u8", "ordinal": 1, - "type_info": "Int64" + "type_info": "Integer" }, { "name": "cached_at: DateTime", diff --git a/.sqlx/query-54f54f669244fbdf1ad68664290d8f32f0bda74ceee62d10c84ac03b710c828c.json b/.sqlx/query-54f54f669244fbdf1ad68664290d8f32f0bda74ceee62d10c84ac03b710c828c.json index 8de5138..064fc63 100644 --- a/.sqlx/query-54f54f669244fbdf1ad68664290d8f32f0bda74ceee62d10c84ac03b710c828c.json +++ b/.sqlx/query-54f54f669244fbdf1ad68664290d8f32f0bda74ceee62d10c84ac03b710c828c.json @@ -6,7 +6,7 @@ { "name": "user_id: i64", "ordinal": 0, - "type_info": "Int64" + "type_info": "Integer" }, { "name": "username", @@ -16,17 +16,17 @@ { "name": "id: i64", "ordinal": 2, - "type_info": "Int64" + "type_info": "Integer" }, { "name": "preferred_mode: u8", "ordinal": 3, - "type_info": "Int64" + "type_info": "Integer" }, { "name": "failures: u8", "ordinal": 4, - "type_info": "Int64" + "type_info": "Integer" } ], "parameters": { diff --git a/.sqlx/query-95541f737a8dfc7f440840617bed87ebde6dabdd70e2ba7b110ebec91e7feda7.json b/.sqlx/query-95541f737a8dfc7f440840617bed87ebde6dabdd70e2ba7b110ebec91e7feda7.json index 3715e7c..24f5b4a 100644 --- a/.sqlx/query-95541f737a8dfc7f440840617bed87ebde6dabdd70e2ba7b110ebec91e7feda7.json +++ b/.sqlx/query-95541f737a8dfc7f440840617bed87ebde6dabdd70e2ba7b110ebec91e7feda7.json @@ -6,22 +6,22 @@ { "name": "beatmap_id: i64", "ordinal": 0, - "type_info": "Int64" + "type_info": "Integer" }, { "name": "mode: u8", "ordinal": 1, - "type_info": "Int64" + "type_info": "Integer" }, { "name": "user_id: i64", "ordinal": 2, - "type_info": "Int64" + "type_info": "Integer" }, { "name": "mods: i64", "ordinal": 3, - "type_info": "Int64" + "type_info": "Integer" }, { "name": "cached_at: DateTime", diff --git a/.sqlx/query-9c620436cfe463780fca2dc5497c3b787fa284a74b3e3d491755c88a693810e0.json b/.sqlx/query-9c620436cfe463780fca2dc5497c3b787fa284a74b3e3d491755c88a693810e0.json index f5ac4eb..68d6146 100644 --- a/.sqlx/query-9c620436cfe463780fca2dc5497c3b787fa284a74b3e3d491755c88a693810e0.json +++ b/.sqlx/query-9c620436cfe463780fca2dc5497c3b787fa284a74b3e3d491755c88a693810e0.json @@ -6,7 +6,7 @@ { "name": "id: i64", "ordinal": 0, - "type_info": "Int64" + "type_info": "Integer" } ], "parameters": { diff --git a/.sqlx/query-a247c7a73bdbf1042fdd8363da1f6b51e283c83b1ba7fa17e5cb056b220f7889.json b/.sqlx/query-a247c7a73bdbf1042fdd8363da1f6b51e283c83b1ba7fa17e5cb056b220f7889.json index bb0e861..8111b9c 100644 --- a/.sqlx/query-a247c7a73bdbf1042fdd8363da1f6b51e283c83b1ba7fa17e5cb056b220f7889.json +++ b/.sqlx/query-a247c7a73bdbf1042fdd8363da1f6b51e283c83b1ba7fa17e5cb056b220f7889.json @@ -6,7 +6,7 @@ { "name": "mode: u8", "ordinal": 0, - "type_info": "Int64" + "type_info": "Integer" }, { "name": "pp", @@ -21,12 +21,12 @@ { "name": "map_age", "ordinal": 3, - "type_info": "Int64" + "type_info": "Integer" }, { "name": "last_update: DateTime", "ordinal": 4, - "type_info": "Int64" + "type_info": "Integer" } ], "parameters": { diff --git a/.sqlx/query-d2c0856276174653a9dd428a2f89e7841b2083ee4b18ea83eedcd46bc4356599.json b/.sqlx/query-d2c0856276174653a9dd428a2f89e7841b2083ee4b18ea83eedcd46bc4356599.json index 77e4dc3..27b2b2a 100644 --- a/.sqlx/query-d2c0856276174653a9dd428a2f89e7841b2083ee4b18ea83eedcd46bc4356599.json +++ b/.sqlx/query-d2c0856276174653a9dd428a2f89e7841b2083ee4b18ea83eedcd46bc4356599.json @@ -6,12 +6,12 @@ { "name": "user_id: i64", "ordinal": 0, - "type_info": "Int64" + "type_info": "Integer" }, { "name": "mode: u8", "ordinal": 1, - "type_info": "Int64" + "type_info": "Integer" }, { "name": "pp", @@ -26,12 +26,12 @@ { "name": "map_age", "ordinal": 4, - "type_info": "Int64" + "type_info": "Integer" }, { "name": "last_update: DateTime", "ordinal": 5, - "type_info": "Int64" + "type_info": "Integer" } ], "parameters": { diff --git a/.sqlx/query-d7c91077f904543740a12185fac7756346aa50a63b911414ee8f7a4a0d6dd1cc.json b/.sqlx/query-d7c91077f904543740a12185fac7756346aa50a63b911414ee8f7a4a0d6dd1cc.json index f68b7a6..0659279 100644 --- a/.sqlx/query-d7c91077f904543740a12185fac7756346aa50a63b911414ee8f7a4a0d6dd1cc.json +++ b/.sqlx/query-d7c91077f904543740a12185fac7756346aa50a63b911414ee8f7a4a0d6dd1cc.json @@ -6,12 +6,12 @@ { "name": "beatmap_id: i64", "ordinal": 0, - "type_info": "Int64" + "type_info": "Integer" }, { "name": "mode: u8", "ordinal": 1, - "type_info": "Int64" + "type_info": "Integer" }, { "name": "cached_at: DateTime", diff --git a/.sqlx/query-db5960586bc418d2a6a31c18b4a63f4efcfe4685c0561e07a2c954538be4789b.json b/.sqlx/query-db5960586bc418d2a6a31c18b4a63f4efcfe4685c0561e07a2c954538be4789b.json new file mode 100644 index 0000000..f357b1b --- /dev/null +++ b/.sqlx/query-db5960586bc418d2a6a31c18b4a63f4efcfe4685c0561e07a2c954538be4789b.json @@ -0,0 +1,32 @@ +{ + "db_name": "SQLite", + "query": "SELECT\n id,\n username,\n ignored_since as \"ignored_since: DateTime\"\n FROM ignored_users\n ORDER BY id ASC", + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Integer" + }, + { + "name": "username", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "ignored_since: DateTime", + "ordinal": 2, + "type_info": "Datetime" + } + ], + "parameters": { + "Right": 0 + }, + "nullable": [ + false, + false, + false + ] + }, + "hash": "db5960586bc418d2a6a31c18b4a63f4efcfe4685c0561e07a2c954538be4789b" +} diff --git a/.sqlx/query-dbb948ade9139445faf17c1c6bece242a241d3499a6b973ecf5f6c6588b077ad.json b/.sqlx/query-dbb948ade9139445faf17c1c6bece242a241d3499a6b973ecf5f6c6588b077ad.json new file mode 100644 index 0000000..3c447a8 --- /dev/null +++ b/.sqlx/query-dbb948ade9139445faf17c1c6bece242a241d3499a6b973ecf5f6c6588b077ad.json @@ -0,0 +1,32 @@ +{ + "db_name": "SQLite", + "query": "INSERT INTO ignored_users(id, username) VALUES (?, ?)\n ON CONFLICT (id) DO UPDATE SET username = excluded.username\n RETURNING id,\n username,\n ignored_since as \"ignored_since: DateTime\"", + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Integer" + }, + { + "name": "username", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "ignored_since: DateTime", + "ordinal": 2, + "type_info": "Datetime" + } + ], + "parameters": { + "Right": 2 + }, + "nullable": [ + false, + false, + false + ] + }, + "hash": "dbb948ade9139445faf17c1c6bece242a241d3499a6b973ecf5f6c6588b077ad" +} diff --git a/.sqlx/query-e313b2e91d0da80a94e9a1030f94cf30b025c9ac0ac4d5bcc12656459c5e083a.json b/.sqlx/query-e313b2e91d0da80a94e9a1030f94cf30b025c9ac0ac4d5bcc12656459c5e083a.json index d851042..3432b59 100644 --- a/.sqlx/query-e313b2e91d0da80a94e9a1030f94cf30b025c9ac0ac4d5bcc12656459c5e083a.json +++ b/.sqlx/query-e313b2e91d0da80a94e9a1030f94cf30b025c9ac0ac4d5bcc12656459c5e083a.json @@ -6,7 +6,7 @@ { "name": "user_id: i64", "ordinal": 0, - "type_info": "Int64" + "type_info": "Integer" }, { "name": "username", @@ -16,17 +16,17 @@ { "name": "id: i64", "ordinal": 2, - "type_info": "Int64" + "type_info": "Integer" }, { "name": "preferred_mode: u8", "ordinal": 3, - "type_info": "Int64" + "type_info": "Integer" }, { "name": "failures: u8", "ordinal": 4, - "type_info": "Int64" + "type_info": "Integer" } ], "parameters": { diff --git a/Cargo.lock b/Cargo.lock index b5281bc..90729c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -38,19 +38,6 @@ dependencies = [ "cpufeatures", ] -[[package]] -name = "ahash" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42cd52102d3df161c77a887b608d7a4897d7cc112886a9537b738a887a03aaff" -dependencies = [ - "cfg-if", - "getrandom", - "once_cell", - "version_check", - "zerocopy", -] - [[package]] name = "aho-corasick" version = "1.1.2" @@ -116,16 +103,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "atomic-write-file" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edcdbedc2236483ab103a53415653d6b4442ea6141baf1ffa85df29635e88436" -dependencies = [ - "nix", - "rand", -] - [[package]] name = "atty" version = "0.2.14" @@ -287,12 +264,13 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.83" +version = "1.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a" dependencies = [ "jobserver", "libc", + "shlex", ] [[package]] @@ -351,6 +329,15 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "const-oid" version = "0.9.6" @@ -610,9 +597,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", "windows-sys 0.52.0", @@ -640,15 +627,20 @@ dependencies = [ [[package]] name = "event-listener" -version = "2.5.3" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] [[package]] name = "fastrand" -version = "2.0.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "finl_unicode" @@ -696,6 +688,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "foreign-types" version = "0.3.2" @@ -847,10 +845,22 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "wasm-bindgen", ] +[[package]] +name = "getrandom" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", +] + [[package]] name = "gimli" version = "0.28.1" @@ -893,34 +903,32 @@ name = "hashbrown" version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" -dependencies = [ - "ahash", - "allocator-api2", -] [[package]] name = "hashbrown" version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] [[package]] name = "hashlink" -version = "0.8.4" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" dependencies = [ - "hashbrown 0.14.3", + "hashbrown 0.15.2", ] [[package]] name = "heck" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -dependencies = [ - "unicode-segmentation", -] +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" @@ -1147,15 +1155,6 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "1.0.10" @@ -1164,9 +1163,9 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "jobserver" -version = "0.1.28" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" dependencies = [ "libc", ] @@ -1206,9 +1205,9 @@ checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" [[package]] name = "libm" @@ -1218,9 +1217,9 @@ checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "libsqlite3-sys" -version = "0.27.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" dependencies = [ "cc", "pkg-config", @@ -1235,9 +1234,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" [[package]] name = "lock_api" @@ -1302,12 +1301,6 @@ dependencies = [ "triomphe", ] -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - [[package]] name = "miniz_oxide" version = "0.7.2" @@ -1324,7 +1317,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.48.0", ] @@ -1334,7 +1327,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" dependencies = [ - "getrandom", + "getrandom 0.2.12", ] [[package]] @@ -1355,27 +1348,6 @@ dependencies = [ "tempfile", ] -[[package]] -name = "nix" -version = "0.27.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" -dependencies = [ - "bitflags 2.4.2", - "cfg-if", - "libc", -] - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -1514,6 +1486,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + [[package]] name = "parking_lot" version = "0.12.1" @@ -1710,6 +1688,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + [[package]] name = "rand" version = "0.8.5" @@ -1737,7 +1721,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.12", ] [[package]] @@ -1832,7 +1816,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" dependencies = [ "cc", - "getrandom", + "getrandom 0.2.12", "libc", "spin 0.9.8", "untrusted", @@ -1935,9 +1919,9 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.31" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +checksum = "e56a18552996ac8d29ecc3b190b4fdbb2d91ca4ec396de7bbffaf43f3d637e96" dependencies = [ "bitflags 2.4.2", "errno", @@ -2234,6 +2218,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signature" version = "2.2.0" @@ -2283,6 +2273,9 @@ name = "smallvec" version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +dependencies = [ + "serde", +] [[package]] name = "socket2" @@ -2319,22 +2312,11 @@ dependencies = [ "der", ] -[[package]] -name = "sqlformat" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce81b7bd7c4493975347ef60d8c7e8b742d4694f4c49f93e0a12ea263938176c" -dependencies = [ - "itertools", - "nom", - "unicode_categories", -] - [[package]] name = "sqlx" -version = "0.7.3" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dba03c279da73694ef99763320dea58b51095dfe87d001b1d4b5fe78ba8763cf" +checksum = "4410e73b3c0d8442c5f99b425d7a435b5ee0ae4167b3196771dd3f7a01be745f" dependencies = [ "sqlx-core", "sqlx-macros", @@ -2345,39 +2327,32 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.7.3" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d84b0a3c3739e220d94b3239fd69fb1f74bc36e16643423bd99de3b43c21bfbd" +checksum = "6a007b6936676aa9ab40207cde35daab0a04b823be8ae004368c0793b96a61e0" dependencies = [ - "ahash", - "atoi", - "byteorder", "bytes", "chrono", "crc", "crossbeam-queue", - "dotenvy", "either", "event-listener", - "futures-channel", "futures-core", "futures-intrusive", "futures-io", "futures-util", + "hashbrown 0.15.2", "hashlink", - "hex", "indexmap 2.7.0", "log", "memchr", "once_cell", - "paste", "percent-encoding", "serde", "serde_json", "sha2", "smallvec", - "sqlformat", - "thiserror 1.0.57", + "thiserror 2.0.9", "tokio", "tokio-stream", "tracing", @@ -2386,24 +2361,23 @@ dependencies = [ [[package]] name = "sqlx-macros" -version = "0.7.3" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89961c00dc4d7dffb7aee214964b065072bff69e36ddb9e2c107541f75e4f2a5" +checksum = "3112e2ad78643fef903618d78cf0aec1cb3134b019730edb039b69eaf531f310" dependencies = [ "proc-macro2", "quote", "sqlx-core", "sqlx-macros-core", - "syn 1.0.109", + "syn 2.0.93", ] [[package]] name = "sqlx-macros-core" -version = "0.7.3" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0bd4519486723648186a08785143599760f7cc81c52334a55d6a83ea1e20841" +checksum = "4e9f90acc5ab146a99bf5061a7eb4976b573f560bc898ef3bf8435448dd5e7ad" dependencies = [ - "atomic-write-file", "dotenvy", "either", "heck", @@ -2418,7 +2392,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 1.0.109", + "syn 2.0.93", "tempfile", "tokio", "url", @@ -2426,12 +2400,12 @@ dependencies = [ [[package]] name = "sqlx-mysql" -version = "0.7.3" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e37195395df71fd068f6e2082247891bc11e3289624bbc776a0cdfa1ca7f1ea4" +checksum = "4560278f0e00ce64938540546f59f590d60beee33fffbd3b9cd47851e5fff233" dependencies = [ "atoi", - "base64 0.21.7", + "base64 0.22.1", "bitflags 2.4.2", "byteorder", "bytes", @@ -2462,19 +2436,19 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 1.0.57", + "thiserror 2.0.9", "tracing", "whoami", ] [[package]] name = "sqlx-postgres" -version = "0.7.3" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6ac0ac3b7ccd10cc96c7ab29791a7dd236bd94021f31eec7ba3d46a74aa1c24" +checksum = "c5b98a57f363ed6764d5b3a12bfedf62f07aa16e1856a7ddc2a0bb190a959613" dependencies = [ "atoi", - "base64 0.21.7", + "base64 0.22.1", "bitflags 2.4.2", "byteorder", "chrono", @@ -2483,7 +2457,6 @@ dependencies = [ "etcetera", "futures-channel", "futures-core", - "futures-io", "futures-util", "hex", "hkdf", @@ -2497,21 +2470,20 @@ dependencies = [ "rand", "serde", "serde_json", - "sha1", "sha2", "smallvec", "sqlx-core", "stringprep", - "thiserror 1.0.57", + "thiserror 2.0.9", "tracing", "whoami", ] [[package]] name = "sqlx-sqlite" -version = "0.7.3" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "210976b7d948c7ba9fced8ca835b11cbb2d677c59c79de41ac0d397e14547490" +checksum = "f85ca71d3a5b24e64e1d08dd8fe36c6c95c339a896cc33068148906784620540" dependencies = [ "atoi", "chrono", @@ -2525,10 +2497,10 @@ dependencies = [ "log", "percent-encoding", "serde", + "serde_urlencoded", "sqlx-core", "tracing", "url", - "urlencoding", ] [[package]] @@ -2617,12 +2589,13 @@ checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" [[package]] name = "tempfile" -version = "3.10.0" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67" +checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" dependencies = [ - "cfg-if", "fastrand", + "getrandom 0.3.2", + "once_cell", "rustix", "windows-sys 0.52.0", ] @@ -3006,18 +2979,6 @@ dependencies = [ "tinyvec", ] -[[package]] -name = "unicode-segmentation" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" - -[[package]] -name = "unicode_categories" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" - [[package]] name = "untrusted" version = "0.9.0" @@ -3036,12 +2997,6 @@ dependencies = [ "serde", ] -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - [[package]] name = "utf-8" version = "0.7.6" @@ -3097,6 +3052,15 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "wasite" version = "0.1.0" @@ -3399,6 +3363,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags 2.4.2", +] + [[package]] name = "yaml-rust" version = "0.4.5" @@ -3453,12 +3426,14 @@ dependencies = [ "dashmap 5.5.3", "flume 0.10.14", "futures-util", + "poise", "rand", "serde", "serenity", "static_assertions", "tokio", "youmubot-db", + "youmubot-db-sql", "youmubot-prelude", ] @@ -3531,26 +3506,6 @@ dependencies = [ "youmubot-db-sql", ] -[[package]] -name = "zerocopy" -version = "0.7.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.93", -] - [[package]] name = "zeroize" version = "1.7.0" diff --git a/youmubot-core/Cargo.toml b/youmubot-core/Cargo.toml index 8b8f26c..ac00c6b 100644 --- a/youmubot-core/Cargo.toml +++ b/youmubot-core/Cargo.toml @@ -19,6 +19,8 @@ futures-util = "0.3.21" tokio = { version = "1.19.2", features = ["time"] } flume = "0.10.13" dashmap = "5.3.4" +poise = { git = "https://github.com/serenity-rs/poise", branch = "current" } youmubot-db = { path = "../youmubot-db" } +youmubot-db-sql = { path = "../youmubot-db-sql" } youmubot-prelude = { path = "../youmubot-prelude" } diff --git a/youmubot-core/src/admin/ignore.rs b/youmubot-core/src/admin/ignore.rs new file mode 100644 index 0000000..379bf0e --- /dev/null +++ b/youmubot-core/src/admin/ignore.rs @@ -0,0 +1,152 @@ +use std::sync::Arc; + +use chrono::{DateTime, Utc}; +use dashmap::DashMap; +use serenity::all::User; +use youmubot_db_sql::models::ignore_list as model; +use youmubot_prelude::*; + +use crate::HasCoreEnv; + +// Should we ignore this user? +pub fn should_ignore(env: &impl HasCoreEnv, id: UserId) -> bool { + env.core_env().ignore.query(id).is_some() +} + +/// Ignore: make Youmu ignore all commands from an user. +#[poise::command( + slash_command, + subcommands("add", "remove", "list"), + owners_only, + install_context = "User", + interaction_context = "Guild|BotDm" +)] +pub async fn ignore(_ctx: CmdContext<'_, U>) -> Result<()> { + Ok(()) +} + +/// Add an user to ignore list. +#[poise::command(slash_command, owners_only)] +async fn add( + ctx: CmdContext<'_, U>, + #[description = "Discord username"] discord_name: User, +) -> Result<()> { + let env = ctx.data().core_env(); + ctx.defer().await?; + let msg = format!("User **{}** ignored!", discord_name.name); + env.ignore + .add(&env.prelude, UserId(discord_name.id), discord_name.name) + .await?; + ctx.say(msg).await?; + Ok(()) +} + +/// Remove an user from ignore list. +#[poise::command(slash_command, owners_only)] +async fn remove( + ctx: CmdContext<'_, U>, + #[description = "Discord username"] discord_name: User, +) -> Result<()> { + let env = ctx.data().core_env(); + ctx.defer().await?; + env.ignore + .remove(&env.prelude, UserId(discord_name.id)) + .await?; + let msg = format!("User **{}** removed from ignore list!", discord_name.name); + ctx.say(msg).await?; + Ok(()) +} + +/// List ignored users. +#[poise::command(slash_command, owners_only)] +async fn list(ctx: CmdContext<'_, U>) -> Result<()> { + let env = ctx.data().core_env(); + let is_dm = ctx.guild_id().is_none(); + ctx.defer().await?; + let users = env + .ignore + .list + .clone() + .iter() + .map(|v| { + format!( + "- {} ({}), since ", + v.username, + if is_dm { + v.id.0.mention().to_string() + } else { + format!("`{}`", v.id.0.get()) + }, + v.ignored_since.timestamp(), + ) + }) + .collect::>() + .join("\n"); + let users = if users == "" { + "No one is being ignored!" + } else { + &users[..] + }; + + let msg = format!("Ignored users:\n{}", users); + ctx.say(msg).await?; + Ok(()) +} + +#[derive(Debug, Clone)] +pub(crate) struct IgnoredUsers { + list: Arc>, +} + +impl IgnoredUsers { + pub async fn from_db(env: &Env) -> Result { + let list = model::IgnoredUser::get_all(&env.sql).await?; + let mp: DashMap<_, _> = list + .into_iter() + .map(|v| { + let id = (v.id as u64).into(); + ( + id, + IgnoredUser { + id, + username: v.username, + ignored_since: v.ignored_since, + }, + ) + }) + .collect(); + Ok(Self { list: Arc::new(mp) }) + } + + pub fn query<'a>( + &'a self, + id: UserId, + ) -> Option + 'a> { + self.list.get(&id) + } + + pub async fn add(&self, env: &Env, id: UserId, username: String) -> Result<()> { + let iu = model::IgnoredUser::add(&env.sql, id.0.get() as i64, username).await?; + self.list.insert( + id, + IgnoredUser { + id, + username: iu.username, + ignored_since: iu.ignored_since, + }, + ); + Ok(()) + } + + pub async fn remove(&self, env: &Env, id: UserId) -> Result { + model::IgnoredUser::remove(&env.sql, id.0.get() as i64).await?; + Ok(self.list.remove(&id).is_some()) + } +} + +#[derive(Debug, Clone)] +pub(crate) struct IgnoredUser { + pub id: UserId, + pub username: String, + pub ignored_since: DateTime, +} diff --git a/youmubot-core/src/admin/mod.rs b/youmubot-core/src/admin/mod.rs index 2c766e2..6680c0a 100644 --- a/youmubot-core/src/admin/mod.rs +++ b/youmubot-core/src/admin/mod.rs @@ -13,6 +13,8 @@ use youmubot_prelude::*; mod soft_ban; pub use soft_ban::watch_soft_bans; +pub mod ignore; + #[group] #[description = "Administrative commands for the server."] #[commands(clean, ban, kick, soft_ban, soft_ban_init)] diff --git a/youmubot-core/src/lib.rs b/youmubot-core/src/lib.rs index ce32b17..00f2783 100644 --- a/youmubot-core/src/lib.rs +++ b/youmubot-core/src/lib.rs @@ -17,11 +17,32 @@ pub mod community; mod db; pub mod fun; +#[derive(Debug, Clone)] +pub struct CoreEnv { + pub(crate) prelude: Env, + pub(crate) ignore: admin::ignore::IgnoredUsers, +} + +impl CoreEnv { + async fn new(prelude: Env) -> Result { + let ignore = admin::ignore::IgnoredUsers::from_db(&prelude).await?; + Ok(Self { prelude, ignore }) + } +} + +/// Gets an [CoreEnv] from the current environment. +pub trait HasCoreEnv: Send + Sync { + fn core_env(&self) -> &CoreEnv; +} + +impl + Send + Sync> HasCoreEnv for T { + fn core_env(&self) -> &CoreEnv { + self.as_ref() + } +} + /// Sets up all databases in the client. -pub fn setup( - path: &std::path::Path, - data: &mut TypeMap, -) -> serenity::framework::standard::CommandResult { +pub async fn setup(path: &std::path::Path, data: &mut TypeMap, prelude: Env) -> Result { db::SoftBans::insert_into(&mut *data, &path.join("soft_bans.yaml"))?; db::load_role_list( &mut *data, @@ -32,7 +53,7 @@ pub fn setup( // Start reaction handlers data.insert::(community::ReactionWatchers::new(&*data)?); - Ok(()) + CoreEnv::new(prelude).await } pub fn ready_hook(ctx: &Context) -> CommandResult { diff --git a/youmubot-db-sql/.sqlx/query-25dcc59341e6375ee6a55aa014aecc54be42e1e8787ae5a06a61bb8ba8e9c366.json b/youmubot-db-sql/.sqlx/query-25dcc59341e6375ee6a55aa014aecc54be42e1e8787ae5a06a61bb8ba8e9c366.json deleted file mode 100644 index 814d59b..0000000 --- a/youmubot-db-sql/.sqlx/query-25dcc59341e6375ee6a55aa014aecc54be42e1e8787ae5a06a61bb8ba8e9c366.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "db_name": "SQLite", - "query": "SELECT\n user_id as \"user_id: i64\",\n username,\n id as \"id: i64\",\n preferred_mode as \"preferred_mode: u8\",\n failures as \"failures: u8\"\n FROM osu_users WHERE user_id = ?", - "describe": { - "columns": [ - { - "name": "user_id: i64", - "ordinal": 0, - "type_info": "Int64" - }, - { - "name": "username", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "id: i64", - "ordinal": 2, - "type_info": "Int64" - }, - { - "name": "preferred_mode: u8", - "ordinal": 3, - "type_info": "Int64" - }, - { - "name": "failures: u8", - "ordinal": 4, - "type_info": "Int64" - } - ], - "parameters": { - "Right": 1 - }, - "nullable": [ - false, - true, - false, - false, - false - ] - }, - "hash": "25dcc59341e6375ee6a55aa014aecc54be42e1e8787ae5a06a61bb8ba8e9c366" -} diff --git a/youmubot-db-sql/.sqlx/query-54f54f669244fbdf1ad68664290d8f32f0bda74ceee62d10c84ac03b710c828c.json b/youmubot-db-sql/.sqlx/query-54f54f669244fbdf1ad68664290d8f32f0bda74ceee62d10c84ac03b710c828c.json deleted file mode 100644 index 8de5138..0000000 --- a/youmubot-db-sql/.sqlx/query-54f54f669244fbdf1ad68664290d8f32f0bda74ceee62d10c84ac03b710c828c.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "db_name": "SQLite", - "query": "SELECT\n user_id as \"user_id: i64\",\n username,\n id as \"id: i64\",\n preferred_mode as \"preferred_mode: u8\",\n failures as \"failures: u8\"\n FROM osu_users", - "describe": { - "columns": [ - { - "name": "user_id: i64", - "ordinal": 0, - "type_info": "Int64" - }, - { - "name": "username", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "id: i64", - "ordinal": 2, - "type_info": "Int64" - }, - { - "name": "preferred_mode: u8", - "ordinal": 3, - "type_info": "Int64" - }, - { - "name": "failures: u8", - "ordinal": 4, - "type_info": "Int64" - } - ], - "parameters": { - "Right": 0 - }, - "nullable": [ - false, - true, - false, - false, - false - ] - }, - "hash": "54f54f669244fbdf1ad68664290d8f32f0bda74ceee62d10c84ac03b710c828c" -} diff --git a/youmubot-db-sql/.sqlx/query-b9c63ef764711088cfbb58ce2ed1f46e3521357ec1d7c062bef762d3e4267378.json b/youmubot-db-sql/.sqlx/query-b9c63ef764711088cfbb58ce2ed1f46e3521357ec1d7c062bef762d3e4267378.json deleted file mode 100644 index 2b1820b..0000000 --- a/youmubot-db-sql/.sqlx/query-b9c63ef764711088cfbb58ce2ed1f46e3521357ec1d7c062bef762d3e4267378.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "INSERT\n INTO osu_users(user_id, username, id, preferred_mode, failures)\n VALUES(?, ?, ?, ?, ?)\n ON CONFLICT (user_id) WHERE id = ? DO UPDATE\n SET\n username = excluded.username,\n preferred_mode = excluded.preferred_mode,\n failures = excluded.failures\n ", - "describe": { - "columns": [], - "parameters": { - "Right": 6 - }, - "nullable": [] - }, - "hash": "b9c63ef764711088cfbb58ce2ed1f46e3521357ec1d7c062bef762d3e4267378" -} diff --git a/youmubot-db-sql/.sqlx/query-e313b2e91d0da80a94e9a1030f94cf30b025c9ac0ac4d5bcc12656459c5e083a.json b/youmubot-db-sql/.sqlx/query-e313b2e91d0da80a94e9a1030f94cf30b025c9ac0ac4d5bcc12656459c5e083a.json deleted file mode 100644 index d851042..0000000 --- a/youmubot-db-sql/.sqlx/query-e313b2e91d0da80a94e9a1030f94cf30b025c9ac0ac4d5bcc12656459c5e083a.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "db_name": "SQLite", - "query": "SELECT\n user_id as \"user_id: i64\",\n username,\n id as \"id: i64\",\n preferred_mode as \"preferred_mode: u8\",\n failures as \"failures: u8\"\n FROM osu_users WHERE id = ?", - "describe": { - "columns": [ - { - "name": "user_id: i64", - "ordinal": 0, - "type_info": "Int64" - }, - { - "name": "username", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "id: i64", - "ordinal": 2, - "type_info": "Int64" - }, - { - "name": "preferred_mode: u8", - "ordinal": 3, - "type_info": "Int64" - }, - { - "name": "failures: u8", - "ordinal": 4, - "type_info": "Int64" - } - ], - "parameters": { - "Right": 1 - }, - "nullable": [ - false, - true, - false, - false, - false - ] - }, - "hash": "e313b2e91d0da80a94e9a1030f94cf30b025c9ac0ac4d5bcc12656459c5e083a" -} diff --git a/youmubot-db-sql/Cargo.toml b/youmubot-db-sql/Cargo.toml index 30b640c..4c5b9b8 100644 --- a/youmubot-db-sql/Cargo.toml +++ b/youmubot-db-sql/Cargo.toml @@ -10,7 +10,7 @@ workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -sqlx = { version = "0.7", features = ["runtime-tokio", "sqlite", "chrono"] } +sqlx = { version = "0.8", features = ["runtime-tokio", "sqlite", "chrono"] } thiserror = "1.0.31" chrono = "0.4.19" futures-util = "0.3.21" diff --git a/youmubot-db-sql/migrations/20250327105109_ignored_users.sql b/youmubot-db-sql/migrations/20250327105109_ignored_users.sql new file mode 100644 index 0000000..7bf13e5 --- /dev/null +++ b/youmubot-db-sql/migrations/20250327105109_ignored_users.sql @@ -0,0 +1,7 @@ +-- Add migration script here + +CREATE TABLE ignored_users ( + id BIGINT NOT NULL PRIMARY KEY, + username TEXT NOT NULL UNIQUE, + ignored_since DATETIME NOT NULL DEFAULT (DATETIME('now')) +); diff --git a/youmubot-db-sql/src/models/ignore_list.rs b/youmubot-db-sql/src/models/ignore_list.rs new file mode 100644 index 0000000..7f28471 --- /dev/null +++ b/youmubot-db-sql/src/models/ignore_list.rs @@ -0,0 +1,60 @@ +use super::*; +use sqlx::Executor; + +/// An ignored user in the ignored user list. +#[derive(Clone, Debug)] +pub struct IgnoredUser { + pub id: i64, + pub username: String, + pub ignored_since: DateTime, +} + +impl IgnoredUser { + /// Returns a list of all ignored users. + pub async fn get_all<'a, E>(conn: E) -> Result> + where + E: Executor<'a, Database = Database>, + { + Ok(query_as!( + IgnoredUser, + r#"SELECT + id, + username, + ignored_since as "ignored_since: DateTime" + FROM ignored_users + ORDER BY id ASC"# + ) + .fetch_all(conn) + .await?) + } + + /// Add an user to ignore list. + pub async fn add<'a, E>(conn: E, user_id: i64, username: String) -> Result + where + E: Executor<'a, Database = Database>, + { + Ok(query_as!( + IgnoredUser, + r#"INSERT INTO ignored_users(id, username) VALUES (?, ?) + ON CONFLICT (id) DO UPDATE SET username = excluded.username + RETURNING id, + username, + ignored_since as "ignored_since: DateTime""#, + user_id, + username + ) + .fetch_one(conn) + .await?) + } + + // Remove an user from ignore list. + pub async fn remove<'a, E>(conn: E, user_id: i64) -> Result<()> + where + E: Executor<'a, Database = Database>, + { + query!(r#"DELETE FROM ignored_users WHERE id = ?"#, user_id) + .execute(conn) + .await?; + Ok(()) + } +} diff --git a/youmubot-db-sql/src/models/mod.rs b/youmubot-db-sql/src/models/mod.rs index 59f7ecf..8f05c93 100644 --- a/youmubot-db-sql/src/models/mod.rs +++ b/youmubot-db-sql/src/models/mod.rs @@ -4,5 +4,6 @@ use sqlx::{query, query_as, Executor}; /// The DateTime used in the package. pub type DateTime = chrono::DateTime; +pub mod ignore_list; pub mod osu; pub mod osu_user; diff --git a/youmubot-prelude/src/args.rs b/youmubot-prelude/src/args.rs index c6410ce..6803dfa 100644 --- a/youmubot-prelude/src/args.rs +++ b/youmubot-prelude/src/args.rs @@ -189,9 +189,15 @@ mod ids { use super::ParseError; /// An `UserId` parsed the old way. - #[derive(Debug, Clone, Copy, PartialEq, Eq)] + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct UserId(pub id::UserId); + impl From for UserId { + fn from(value: u64) -> Self { + Self(id::UserId::new(value)) + } + } + impl FromStr for UserId { type Err = ParseError; diff --git a/youmubot/src/main.rs b/youmubot/src/main.rs index 9404011..ca2d25a 100644 --- a/youmubot/src/main.rs +++ b/youmubot/src/main.rs @@ -53,6 +53,8 @@ struct Env { prelude: youmubot_prelude::Env, #[cfg(feature = "osu")] osu: youmubot_osu::discord::OsuEnv, + #[cfg(feature = "core")] + core: youmubot_core::CoreEnv, } impl AsRef for Env { @@ -68,6 +70,13 @@ impl AsRef for Env { } } +#[cfg(feature = "core")] +impl AsRef for Env { + fn as_ref(&self) -> &youmubot_core::CoreEnv { + &self.core + } +} + impl TypeMapKey for Env { type Value = Env; } @@ -219,7 +228,9 @@ async fn main() { let prelude = setup::setup_prelude(&db_path, sql_path, &mut data).await; // Setup core #[cfg(feature = "core")] - youmubot_core::setup(&db_path, &mut data).expect("Setup db should succeed"); + let core = youmubot_core::setup(&db_path, &mut data, prelude.clone()) + .await + .expect("Setup db should succeed"); // osu! #[cfg(feature = "osu")] let osu = youmubot_osu::discord::setup(&mut data, prelude.clone(), &mut announcers) @@ -233,6 +244,8 @@ async fn main() { prelude, #[cfg(feature = "osu")] osu, + #[cfg(feature = "core")] + core, } }; @@ -266,20 +279,49 @@ async fn main() { case_insensitive_commands: true, ..Default::default() }, + command_check: Some(|ctx| { + Box::pin(command_check(ctx.data(), UserId(ctx.author().id)).map(Ok)) + }), on_error: |err| { Box::pin(async move { - if let poise::FrameworkError::Command { error, ctx, .. } = err { - let reply = format!( - "Command '{}' returned error: {:?}", - ctx.invoked_command_name(), - error - ); - eprintln!("{}\n{:?}", reply, error); - ctx.send(poise::CreateReply::default().content(reply).ephemeral(true)) + match err { + poise::FrameworkError::Command { error, ctx, .. } => { + let reply = format!( + "Command '{}' returned error: {:?}", + ctx.invoked_command_name(), + error + ); + eprintln!("{}\n{:?}", reply, error); + ctx.send(poise::CreateReply::default().content(reply).ephemeral(true)) + .await + .pls_ok(); + } + poise::FrameworkError::NotAnOwner { ctx, .. } => { + ctx.send( + poise::CreateReply::default() + .content("You have to be an owner to run this command!") + .ephemeral(true), + ) .await .pls_ok(); - } else { - eprintln!("Poise error: {:?}", err) + } + poise::FrameworkError::CommandCheckFailed { error: _, ctx, .. } + | poise::FrameworkError::CooldownHit { + remaining_cooldown: _, + ctx, + .. + } => { + ctx.send( + poise::CreateReply::default() + .content("You are being rate-limited, please try again later!") + .ephemeral(true), + ) + .await + .pls_ok(); + } + _ => { + eprintln!("Poise error: {:?}", err) + } } }) }, @@ -287,6 +329,8 @@ async fn main() { poise_register(), #[cfg(feature = "osu")] youmubot_osu::discord::osu_command(), + #[cfg(feature = "core")] + youmubot_core::admin::ignore::ignore(), ], ..Default::default() }) @@ -398,25 +442,37 @@ async fn poise_register(ctx: CmdContext<'_, Env>) -> Result<()> { Ok(()) } +async fn command_check(env: &Env, author: UserId) -> bool { + #[cfg(feature = "core")] + if youmubot_core::admin::ignore::should_ignore(env, author) { + tracing::info!("User is in ignore list, skipping..."); + return false; + } + true +} + // Hooks! #[hook] -async fn before_hook(_: &Context, msg: &Message, command_name: &str) -> bool { - println!( +async fn before_hook(ctx: &Context, msg: &Message, command_name: &str) -> bool { + let env = ctx.data.read().await; + let env = env.get::().unwrap(); + tracing::info!( "Got command '{}' by user '{}'", - command_name, msg.author.name + command_name, + msg.author.name ); - true + command_check(env, UserId(msg.author.id)).await } #[hook] async fn after_hook(ctx: &Context, msg: &Message, command_name: &str, error: CommandResult) { match error { - Ok(()) => println!("Processed command '{}'", command_name), + Ok(()) => tracing::info!("Processed command '{}'", command_name), Err(why) => { let reply = format!("Command '{}' returned error {:?}", command_name, why); msg.reply(&ctx, &reply).await.ok(); - println!("{}", reply) + tracing::info!("{}", reply) } } } @@ -441,6 +497,9 @@ async fn on_dispatch_error(ctx: &Context, msg: &Message, error: DispatchError, _ max, given ), DispatchError::OnlyForGuilds => "🔇 This command cannot be used in DMs.".to_owned(), + DispatchError::OnlyForOwners => { + "🔇 This command can only be used by bot owners.".to_owned() + } _ => return, }, )