From 7d490774e0fda4deb1dcc0a4d8cf10a4b95d6271 Mon Sep 17 00:00:00 2001 From: Natsu Kagami Date: Thu, 31 Oct 2024 14:04:08 +0100 Subject: [PATCH] osu: make commands aware of user's preferred mode (#54) * Add preferred_mode to sql database * Update username and preferred mode * Make commands aware of preferred mode * Fetch user extras to display information * Show user information on forcesave --- ...70e1347329e945de2eefad4bfcab5f81b73ce.json | 0 ...5bbac57c38ad2c51c1924683d13d045f21ad9.json | 0 ...eba14a004ed503c174073a1db184d902ee393.json | 0 ...ecc54be42e1e8787ae5a06a61bb8ba8e9c366.json | 44 +++ ...e28d3c6c1c4bb654c82cc40bf61390c3dad4b.json | 0 ...3e2125b6d8134346144f462325dc025221044.json | 0 ...956d1bf358f2c1e35c4eb5730388ce0c2fe09.json | 0 ...d8f32f0bda74ceee62d10c84ac03b710c828c.json | 12 +- ...5e49942ddf6068a16f000dd0750ab8a9d52c2.json | 0 ...936ba2ee8d3864e2a43b43db78afc32a47384.json | 0 ...ee08264810e49c28bd8ddffaa9f444cada1b5.json | 0 ...d87ebde6dabdd70e2ba7b110ebec91e7feda7.json | 0 ...c3b787fa284a74b3e3d491755c88a693810e0.json | 0 ...f6b51e283c83b1ba7fa17e5cb056b220f7889.json | 0 ...0ef57cae1cf6338523fd2b801b482164d54fa.json | 0 ...1f46e3521357ec1d7c062bef762d3e4267378.json | 12 + ...e5283a5b0e8a03696ae479b3d275b81b8af83.json | 0 ...9e7841b2083ee4b18ea83eedcd46bc4356599.json | 0 ...6cdee0862df09faaa6c1fa09869d79438e427.json | 0 ...7756346aa50a63b911414ee8f7a4a0d6dd1cc.json | 0 ...4cf30b025c9ac0ac4d5bcc12656459c5e083a.json | 12 +- ...f66defcfbe67a7c4ccac16dd41508bc2d829d.json | 0 ...ecc54be42e1e8787ae5a06a61bb8ba8e9c366.json | 44 +++ ...d8f32f0bda74ceee62d10c84ac03b710c828c.json | 44 +++ ...1a90861788ca84221baaaf19cd159ed3062c9.json | 12 - ...1f46e3521357ec1d7c062bef762d3e4267378.json | 12 + ...cf30b025c9ac0ac4d5bcc12656459c5e083a.json} | 12 +- ...144136_add_preferred_mode_to_osu_users.sql | 4 + youmubot-db-sql/src/models/osu_user.rs | 12 +- youmubot-osu/src/discord/announcer.rs | 4 + youmubot-osu/src/discord/db.rs | 12 + youmubot-osu/src/discord/embeds.rs | 16 +- youmubot-osu/src/discord/interaction.rs | 5 +- youmubot-osu/src/discord/mod.rs | 310 ++++++++++-------- youmubot-osu/src/models/mod.rs | 4 +- youmubot-osu/src/models/rosu.rs | 1 + youmubot-osu/src/request.rs | 8 +- 37 files changed, 410 insertions(+), 170 deletions(-) rename {youmubot-db-sql/.sqlx => .sqlx}/query-1bf34dddbe994d6124c9382c75e70e1347329e945de2eefad4bfcab5f81b73ce.json (100%) rename {youmubot-db-sql/.sqlx => .sqlx}/query-235312a1aad1a58c2f7f2d817945bbac57c38ad2c51c1924683d13d045f21ad9.json (100%) rename {youmubot-db-sql/.sqlx => .sqlx}/query-25077e7b2657eb918fa49acc16ceba14a004ed503c174073a1db184d902ee393.json (100%) create mode 100644 .sqlx/query-25dcc59341e6375ee6a55aa014aecc54be42e1e8787ae5a06a61bb8ba8e9c366.json rename {youmubot-db-sql/.sqlx => .sqlx}/query-296c95c7ead4d747a4da007b4b6e28d3c6c1c4bb654c82cc40bf61390c3dad4b.json (100%) rename {youmubot-db-sql/.sqlx => .sqlx}/query-4b033607229deba540f80e469753e2125b6d8134346144f462325dc025221044.json (100%) rename {youmubot-db-sql/.sqlx => .sqlx}/query-5210e3e5610bb968b0b11411b99956d1bf358f2c1e35c4eb5730388ce0c2fe09.json (100%) rename youmubot-db-sql/.sqlx/query-246e26a34c042872a77f53a84d62da31db069cced20e3b0f96a40c3c7dd99783.json => .sqlx/query-54f54f669244fbdf1ad68664290d8f32f0bda74ceee62d10c84ac03b710c828c.json (68%) rename {youmubot-db-sql/.sqlx => .sqlx}/query-6125c1c187029c7ac6e1e9519445e49942ddf6068a16f000dd0750ab8a9d52c2.json (100%) rename {youmubot-db-sql/.sqlx => .sqlx}/query-6bfd02cb36c9b74ed4c69eb694e936ba2ee8d3864e2a43b43db78afc32a47384.json (100%) rename {youmubot-db-sql/.sqlx => .sqlx}/query-8b9ad43442b7fa520f2eae498d2ee08264810e49c28bd8ddffaa9f444cada1b5.json (100%) rename {youmubot-db-sql/.sqlx => .sqlx}/query-95541f737a8dfc7f440840617bed87ebde6dabdd70e2ba7b110ebec91e7feda7.json (100%) rename {youmubot-db-sql/.sqlx => .sqlx}/query-9c620436cfe463780fca2dc5497c3b787fa284a74b3e3d491755c88a693810e0.json (100%) rename {youmubot-db-sql/.sqlx => .sqlx}/query-a247c7a73bdbf1042fdd8363da1f6b51e283c83b1ba7fa17e5cb056b220f7889.json (100%) rename {youmubot-db-sql/.sqlx => .sqlx}/query-aa6db751abe51922548d6c040d40ef57cae1cf6338523fd2b801b482164d54fa.json (100%) create mode 100644 .sqlx/query-b9c63ef764711088cfbb58ce2ed1f46e3521357ec1d7c062bef762d3e4267378.json rename {youmubot-db-sql/.sqlx => .sqlx}/query-c83421661626cffd81d5590035ae5283a5b0e8a03696ae479b3d275b81b8af83.json (100%) rename {youmubot-db-sql/.sqlx => .sqlx}/query-d2c0856276174653a9dd428a2f89e7841b2083ee4b18ea83eedcd46bc4356599.json (100%) rename {youmubot-db-sql/.sqlx => .sqlx}/query-d428568e88b653317cbe2c5336e6cdee0862df09faaa6c1fa09869d79438e427.json (100%) rename {youmubot-db-sql/.sqlx => .sqlx}/query-d7c91077f904543740a12185fac7756346aa50a63b911414ee8f7a4a0d6dd1cc.json (100%) rename youmubot-db-sql/.sqlx/query-9b7788f4d7144fe00f4bc9004c88dc8562ff3d7a931fc3f1dc039cc55fe3195a.json => .sqlx/query-e313b2e91d0da80a94e9a1030f94cf30b025c9ac0ac4d5bcc12656459c5e083a.json (67%) rename {youmubot-db-sql/.sqlx => .sqlx}/query-f356ab7ef8b7c320d29ad9cce03f66defcfbe67a7c4ccac16dd41508bc2d829d.json (100%) create mode 100644 youmubot-db-sql/.sqlx/query-25dcc59341e6375ee6a55aa014aecc54be42e1e8787ae5a06a61bb8ba8e9c366.json create mode 100644 youmubot-db-sql/.sqlx/query-54f54f669244fbdf1ad68664290d8f32f0bda74ceee62d10c84ac03b710c828c.json delete mode 100644 youmubot-db-sql/.sqlx/query-a5d8dccaaf80b2673c5c0e689c01a90861788ca84221baaaf19cd159ed3062c9.json create mode 100644 youmubot-db-sql/.sqlx/query-b9c63ef764711088cfbb58ce2ed1f46e3521357ec1d7c062bef762d3e4267378.json rename youmubot-db-sql/.sqlx/{query-ae7f57eb92e0bec8439e682ab3ca10732991ffe803d05b09e908ecb4a74c0566.json => query-e313b2e91d0da80a94e9a1030f94cf30b025c9ac0ac4d5bcc12656459c5e083a.json} (67%) create mode 100644 youmubot-db-sql/migrations/20241030144136_add_preferred_mode_to_osu_users.sql diff --git a/youmubot-db-sql/.sqlx/query-1bf34dddbe994d6124c9382c75e70e1347329e945de2eefad4bfcab5f81b73ce.json b/.sqlx/query-1bf34dddbe994d6124c9382c75e70e1347329e945de2eefad4bfcab5f81b73ce.json similarity index 100% rename from youmubot-db-sql/.sqlx/query-1bf34dddbe994d6124c9382c75e70e1347329e945de2eefad4bfcab5f81b73ce.json rename to .sqlx/query-1bf34dddbe994d6124c9382c75e70e1347329e945de2eefad4bfcab5f81b73ce.json diff --git a/youmubot-db-sql/.sqlx/query-235312a1aad1a58c2f7f2d817945bbac57c38ad2c51c1924683d13d045f21ad9.json b/.sqlx/query-235312a1aad1a58c2f7f2d817945bbac57c38ad2c51c1924683d13d045f21ad9.json similarity index 100% rename from youmubot-db-sql/.sqlx/query-235312a1aad1a58c2f7f2d817945bbac57c38ad2c51c1924683d13d045f21ad9.json rename to .sqlx/query-235312a1aad1a58c2f7f2d817945bbac57c38ad2c51c1924683d13d045f21ad9.json diff --git a/youmubot-db-sql/.sqlx/query-25077e7b2657eb918fa49acc16ceba14a004ed503c174073a1db184d902ee393.json b/.sqlx/query-25077e7b2657eb918fa49acc16ceba14a004ed503c174073a1db184d902ee393.json similarity index 100% rename from youmubot-db-sql/.sqlx/query-25077e7b2657eb918fa49acc16ceba14a004ed503c174073a1db184d902ee393.json rename to .sqlx/query-25077e7b2657eb918fa49acc16ceba14a004ed503c174073a1db184d902ee393.json diff --git a/.sqlx/query-25dcc59341e6375ee6a55aa014aecc54be42e1e8787ae5a06a61bb8ba8e9c366.json b/.sqlx/query-25dcc59341e6375ee6a55aa014aecc54be42e1e8787ae5a06a61bb8ba8e9c366.json new file mode 100644 index 0000000..814d59b --- /dev/null +++ b/.sqlx/query-25dcc59341e6375ee6a55aa014aecc54be42e1e8787ae5a06a61bb8ba8e9c366.json @@ -0,0 +1,44 @@ +{ + "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-296c95c7ead4d747a4da007b4b6e28d3c6c1c4bb654c82cc40bf61390c3dad4b.json b/.sqlx/query-296c95c7ead4d747a4da007b4b6e28d3c6c1c4bb654c82cc40bf61390c3dad4b.json similarity index 100% rename from youmubot-db-sql/.sqlx/query-296c95c7ead4d747a4da007b4b6e28d3c6c1c4bb654c82cc40bf61390c3dad4b.json rename to .sqlx/query-296c95c7ead4d747a4da007b4b6e28d3c6c1c4bb654c82cc40bf61390c3dad4b.json diff --git a/youmubot-db-sql/.sqlx/query-4b033607229deba540f80e469753e2125b6d8134346144f462325dc025221044.json b/.sqlx/query-4b033607229deba540f80e469753e2125b6d8134346144f462325dc025221044.json similarity index 100% rename from youmubot-db-sql/.sqlx/query-4b033607229deba540f80e469753e2125b6d8134346144f462325dc025221044.json rename to .sqlx/query-4b033607229deba540f80e469753e2125b6d8134346144f462325dc025221044.json diff --git a/youmubot-db-sql/.sqlx/query-5210e3e5610bb968b0b11411b99956d1bf358f2c1e35c4eb5730388ce0c2fe09.json b/.sqlx/query-5210e3e5610bb968b0b11411b99956d1bf358f2c1e35c4eb5730388ce0c2fe09.json similarity index 100% rename from youmubot-db-sql/.sqlx/query-5210e3e5610bb968b0b11411b99956d1bf358f2c1e35c4eb5730388ce0c2fe09.json rename to .sqlx/query-5210e3e5610bb968b0b11411b99956d1bf358f2c1e35c4eb5730388ce0c2fe09.json diff --git a/youmubot-db-sql/.sqlx/query-246e26a34c042872a77f53a84d62da31db069cced20e3b0f96a40c3c7dd99783.json b/.sqlx/query-54f54f669244fbdf1ad68664290d8f32f0bda74ceee62d10c84ac03b710c828c.json similarity index 68% rename from youmubot-db-sql/.sqlx/query-246e26a34c042872a77f53a84d62da31db069cced20e3b0f96a40c3c7dd99783.json rename to .sqlx/query-54f54f669244fbdf1ad68664290d8f32f0bda74ceee62d10c84ac03b710c828c.json index 1ad9d55..8de5138 100644 --- a/youmubot-db-sql/.sqlx/query-246e26a34c042872a77f53a84d62da31db069cced20e3b0f96a40c3c7dd99783.json +++ b/.sqlx/query-54f54f669244fbdf1ad68664290d8f32f0bda74ceee62d10c84ac03b710c828c.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "SELECT\n user_id as \"user_id: i64\",\n username,\n id as \"id: i64\",\n failures as \"failures: u8\"\n FROM osu_users", + "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": [ { @@ -19,9 +19,14 @@ "type_info": "Int64" }, { - "name": "failures: u8", + "name": "preferred_mode: u8", "ordinal": 3, "type_info": "Int64" + }, + { + "name": "failures: u8", + "ordinal": 4, + "type_info": "Int64" } ], "parameters": { @@ -31,8 +36,9 @@ false, true, false, + false, false ] }, - "hash": "246e26a34c042872a77f53a84d62da31db069cced20e3b0f96a40c3c7dd99783" + "hash": "54f54f669244fbdf1ad68664290d8f32f0bda74ceee62d10c84ac03b710c828c" } diff --git a/youmubot-db-sql/.sqlx/query-6125c1c187029c7ac6e1e9519445e49942ddf6068a16f000dd0750ab8a9d52c2.json b/.sqlx/query-6125c1c187029c7ac6e1e9519445e49942ddf6068a16f000dd0750ab8a9d52c2.json similarity index 100% rename from youmubot-db-sql/.sqlx/query-6125c1c187029c7ac6e1e9519445e49942ddf6068a16f000dd0750ab8a9d52c2.json rename to .sqlx/query-6125c1c187029c7ac6e1e9519445e49942ddf6068a16f000dd0750ab8a9d52c2.json diff --git a/youmubot-db-sql/.sqlx/query-6bfd02cb36c9b74ed4c69eb694e936ba2ee8d3864e2a43b43db78afc32a47384.json b/.sqlx/query-6bfd02cb36c9b74ed4c69eb694e936ba2ee8d3864e2a43b43db78afc32a47384.json similarity index 100% rename from youmubot-db-sql/.sqlx/query-6bfd02cb36c9b74ed4c69eb694e936ba2ee8d3864e2a43b43db78afc32a47384.json rename to .sqlx/query-6bfd02cb36c9b74ed4c69eb694e936ba2ee8d3864e2a43b43db78afc32a47384.json diff --git a/youmubot-db-sql/.sqlx/query-8b9ad43442b7fa520f2eae498d2ee08264810e49c28bd8ddffaa9f444cada1b5.json b/.sqlx/query-8b9ad43442b7fa520f2eae498d2ee08264810e49c28bd8ddffaa9f444cada1b5.json similarity index 100% rename from youmubot-db-sql/.sqlx/query-8b9ad43442b7fa520f2eae498d2ee08264810e49c28bd8ddffaa9f444cada1b5.json rename to .sqlx/query-8b9ad43442b7fa520f2eae498d2ee08264810e49c28bd8ddffaa9f444cada1b5.json diff --git a/youmubot-db-sql/.sqlx/query-95541f737a8dfc7f440840617bed87ebde6dabdd70e2ba7b110ebec91e7feda7.json b/.sqlx/query-95541f737a8dfc7f440840617bed87ebde6dabdd70e2ba7b110ebec91e7feda7.json similarity index 100% rename from youmubot-db-sql/.sqlx/query-95541f737a8dfc7f440840617bed87ebde6dabdd70e2ba7b110ebec91e7feda7.json rename to .sqlx/query-95541f737a8dfc7f440840617bed87ebde6dabdd70e2ba7b110ebec91e7feda7.json diff --git a/youmubot-db-sql/.sqlx/query-9c620436cfe463780fca2dc5497c3b787fa284a74b3e3d491755c88a693810e0.json b/.sqlx/query-9c620436cfe463780fca2dc5497c3b787fa284a74b3e3d491755c88a693810e0.json similarity index 100% rename from youmubot-db-sql/.sqlx/query-9c620436cfe463780fca2dc5497c3b787fa284a74b3e3d491755c88a693810e0.json rename to .sqlx/query-9c620436cfe463780fca2dc5497c3b787fa284a74b3e3d491755c88a693810e0.json diff --git a/youmubot-db-sql/.sqlx/query-a247c7a73bdbf1042fdd8363da1f6b51e283c83b1ba7fa17e5cb056b220f7889.json b/.sqlx/query-a247c7a73bdbf1042fdd8363da1f6b51e283c83b1ba7fa17e5cb056b220f7889.json similarity index 100% rename from youmubot-db-sql/.sqlx/query-a247c7a73bdbf1042fdd8363da1f6b51e283c83b1ba7fa17e5cb056b220f7889.json rename to .sqlx/query-a247c7a73bdbf1042fdd8363da1f6b51e283c83b1ba7fa17e5cb056b220f7889.json diff --git a/youmubot-db-sql/.sqlx/query-aa6db751abe51922548d6c040d40ef57cae1cf6338523fd2b801b482164d54fa.json b/.sqlx/query-aa6db751abe51922548d6c040d40ef57cae1cf6338523fd2b801b482164d54fa.json similarity index 100% rename from youmubot-db-sql/.sqlx/query-aa6db751abe51922548d6c040d40ef57cae1cf6338523fd2b801b482164d54fa.json rename to .sqlx/query-aa6db751abe51922548d6c040d40ef57cae1cf6338523fd2b801b482164d54fa.json diff --git a/.sqlx/query-b9c63ef764711088cfbb58ce2ed1f46e3521357ec1d7c062bef762d3e4267378.json b/.sqlx/query-b9c63ef764711088cfbb58ce2ed1f46e3521357ec1d7c062bef762d3e4267378.json new file mode 100644 index 0000000..2b1820b --- /dev/null +++ b/.sqlx/query-b9c63ef764711088cfbb58ce2ed1f46e3521357ec1d7c062bef762d3e4267378.json @@ -0,0 +1,12 @@ +{ + "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-c83421661626cffd81d5590035ae5283a5b0e8a03696ae479b3d275b81b8af83.json b/.sqlx/query-c83421661626cffd81d5590035ae5283a5b0e8a03696ae479b3d275b81b8af83.json similarity index 100% rename from youmubot-db-sql/.sqlx/query-c83421661626cffd81d5590035ae5283a5b0e8a03696ae479b3d275b81b8af83.json rename to .sqlx/query-c83421661626cffd81d5590035ae5283a5b0e8a03696ae479b3d275b81b8af83.json diff --git a/youmubot-db-sql/.sqlx/query-d2c0856276174653a9dd428a2f89e7841b2083ee4b18ea83eedcd46bc4356599.json b/.sqlx/query-d2c0856276174653a9dd428a2f89e7841b2083ee4b18ea83eedcd46bc4356599.json similarity index 100% rename from youmubot-db-sql/.sqlx/query-d2c0856276174653a9dd428a2f89e7841b2083ee4b18ea83eedcd46bc4356599.json rename to .sqlx/query-d2c0856276174653a9dd428a2f89e7841b2083ee4b18ea83eedcd46bc4356599.json diff --git a/youmubot-db-sql/.sqlx/query-d428568e88b653317cbe2c5336e6cdee0862df09faaa6c1fa09869d79438e427.json b/.sqlx/query-d428568e88b653317cbe2c5336e6cdee0862df09faaa6c1fa09869d79438e427.json similarity index 100% rename from youmubot-db-sql/.sqlx/query-d428568e88b653317cbe2c5336e6cdee0862df09faaa6c1fa09869d79438e427.json rename to .sqlx/query-d428568e88b653317cbe2c5336e6cdee0862df09faaa6c1fa09869d79438e427.json diff --git a/youmubot-db-sql/.sqlx/query-d7c91077f904543740a12185fac7756346aa50a63b911414ee8f7a4a0d6dd1cc.json b/.sqlx/query-d7c91077f904543740a12185fac7756346aa50a63b911414ee8f7a4a0d6dd1cc.json similarity index 100% rename from youmubot-db-sql/.sqlx/query-d7c91077f904543740a12185fac7756346aa50a63b911414ee8f7a4a0d6dd1cc.json rename to .sqlx/query-d7c91077f904543740a12185fac7756346aa50a63b911414ee8f7a4a0d6dd1cc.json diff --git a/youmubot-db-sql/.sqlx/query-9b7788f4d7144fe00f4bc9004c88dc8562ff3d7a931fc3f1dc039cc55fe3195a.json b/.sqlx/query-e313b2e91d0da80a94e9a1030f94cf30b025c9ac0ac4d5bcc12656459c5e083a.json similarity index 67% rename from youmubot-db-sql/.sqlx/query-9b7788f4d7144fe00f4bc9004c88dc8562ff3d7a931fc3f1dc039cc55fe3195a.json rename to .sqlx/query-e313b2e91d0da80a94e9a1030f94cf30b025c9ac0ac4d5bcc12656459c5e083a.json index 9f4d11e..d851042 100644 --- a/youmubot-db-sql/.sqlx/query-9b7788f4d7144fe00f4bc9004c88dc8562ff3d7a931fc3f1dc039cc55fe3195a.json +++ b/.sqlx/query-e313b2e91d0da80a94e9a1030f94cf30b025c9ac0ac4d5bcc12656459c5e083a.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "SELECT\n user_id as \"user_id: i64\",\n username,\n id as \"id: i64\",\n failures as \"failures: u8\"\n FROM osu_users WHERE id = ?", + "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": [ { @@ -19,9 +19,14 @@ "type_info": "Int64" }, { - "name": "failures: u8", + "name": "preferred_mode: u8", "ordinal": 3, "type_info": "Int64" + }, + { + "name": "failures: u8", + "ordinal": 4, + "type_info": "Int64" } ], "parameters": { @@ -31,8 +36,9 @@ false, true, false, + false, false ] }, - "hash": "9b7788f4d7144fe00f4bc9004c88dc8562ff3d7a931fc3f1dc039cc55fe3195a" + "hash": "e313b2e91d0da80a94e9a1030f94cf30b025c9ac0ac4d5bcc12656459c5e083a" } diff --git a/youmubot-db-sql/.sqlx/query-f356ab7ef8b7c320d29ad9cce03f66defcfbe67a7c4ccac16dd41508bc2d829d.json b/.sqlx/query-f356ab7ef8b7c320d29ad9cce03f66defcfbe67a7c4ccac16dd41508bc2d829d.json similarity index 100% rename from youmubot-db-sql/.sqlx/query-f356ab7ef8b7c320d29ad9cce03f66defcfbe67a7c4ccac16dd41508bc2d829d.json rename to .sqlx/query-f356ab7ef8b7c320d29ad9cce03f66defcfbe67a7c4ccac16dd41508bc2d829d.json diff --git a/youmubot-db-sql/.sqlx/query-25dcc59341e6375ee6a55aa014aecc54be42e1e8787ae5a06a61bb8ba8e9c366.json b/youmubot-db-sql/.sqlx/query-25dcc59341e6375ee6a55aa014aecc54be42e1e8787ae5a06a61bb8ba8e9c366.json new file mode 100644 index 0000000..814d59b --- /dev/null +++ b/youmubot-db-sql/.sqlx/query-25dcc59341e6375ee6a55aa014aecc54be42e1e8787ae5a06a61bb8ba8e9c366.json @@ -0,0 +1,44 @@ +{ + "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 new file mode 100644 index 0000000..8de5138 --- /dev/null +++ b/youmubot-db-sql/.sqlx/query-54f54f669244fbdf1ad68664290d8f32f0bda74ceee62d10c84ac03b710c828c.json @@ -0,0 +1,44 @@ +{ + "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-a5d8dccaaf80b2673c5c0e689c01a90861788ca84221baaaf19cd159ed3062c9.json b/youmubot-db-sql/.sqlx/query-a5d8dccaaf80b2673c5c0e689c01a90861788ca84221baaaf19cd159ed3062c9.json deleted file mode 100644 index df1a510..0000000 --- a/youmubot-db-sql/.sqlx/query-a5d8dccaaf80b2673c5c0e689c01a90861788ca84221baaaf19cd159ed3062c9.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "INSERT\n INTO osu_users(user_id, username, id, failures)\n VALUES(?, ?, ?, ?)\n ON CONFLICT (user_id) WHERE id = ? DO UPDATE\n SET\n username = excluded.username,\n failures = excluded.failures\n ", - "describe": { - "columns": [], - "parameters": { - "Right": 5 - }, - "nullable": [] - }, - "hash": "a5d8dccaaf80b2673c5c0e689c01a90861788ca84221baaaf19cd159ed3062c9" -} diff --git a/youmubot-db-sql/.sqlx/query-b9c63ef764711088cfbb58ce2ed1f46e3521357ec1d7c062bef762d3e4267378.json b/youmubot-db-sql/.sqlx/query-b9c63ef764711088cfbb58ce2ed1f46e3521357ec1d7c062bef762d3e4267378.json new file mode 100644 index 0000000..2b1820b --- /dev/null +++ b/youmubot-db-sql/.sqlx/query-b9c63ef764711088cfbb58ce2ed1f46e3521357ec1d7c062bef762d3e4267378.json @@ -0,0 +1,12 @@ +{ + "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-ae7f57eb92e0bec8439e682ab3ca10732991ffe803d05b09e908ecb4a74c0566.json b/youmubot-db-sql/.sqlx/query-e313b2e91d0da80a94e9a1030f94cf30b025c9ac0ac4d5bcc12656459c5e083a.json similarity index 67% rename from youmubot-db-sql/.sqlx/query-ae7f57eb92e0bec8439e682ab3ca10732991ffe803d05b09e908ecb4a74c0566.json rename to youmubot-db-sql/.sqlx/query-e313b2e91d0da80a94e9a1030f94cf30b025c9ac0ac4d5bcc12656459c5e083a.json index 02e0cc0..d851042 100644 --- a/youmubot-db-sql/.sqlx/query-ae7f57eb92e0bec8439e682ab3ca10732991ffe803d05b09e908ecb4a74c0566.json +++ b/youmubot-db-sql/.sqlx/query-e313b2e91d0da80a94e9a1030f94cf30b025c9ac0ac4d5bcc12656459c5e083a.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "SELECT\n user_id as \"user_id: i64\",\n username,\n id as \"id: i64\",\n failures as \"failures: u8\"\n FROM osu_users WHERE user_id = ?", + "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": [ { @@ -19,9 +19,14 @@ "type_info": "Int64" }, { - "name": "failures: u8", + "name": "preferred_mode: u8", "ordinal": 3, "type_info": "Int64" + }, + { + "name": "failures: u8", + "ordinal": 4, + "type_info": "Int64" } ], "parameters": { @@ -31,8 +36,9 @@ false, true, false, + false, false ] }, - "hash": "ae7f57eb92e0bec8439e682ab3ca10732991ffe803d05b09e908ecb4a74c0566" + "hash": "e313b2e91d0da80a94e9a1030f94cf30b025c9ac0ac4d5bcc12656459c5e083a" } diff --git a/youmubot-db-sql/migrations/20241030144136_add_preferred_mode_to_osu_users.sql b/youmubot-db-sql/migrations/20241030144136_add_preferred_mode_to_osu_users.sql new file mode 100644 index 0000000..9930623 --- /dev/null +++ b/youmubot-db-sql/migrations/20241030144136_add_preferred_mode_to_osu_users.sql @@ -0,0 +1,4 @@ +-- Add migration script here + +ALTER TABLE osu_users + ADD COLUMN preferred_mode INT NOT NULL DEFAULT 0 CHECK (preferred_mode >= 0 AND preferred_mode < 4); diff --git a/youmubot-db-sql/src/models/osu_user.rs b/youmubot-db-sql/src/models/osu_user.rs index 9ac6c0a..7327086 100644 --- a/youmubot-db-sql/src/models/osu_user.rs +++ b/youmubot-db-sql/src/models/osu_user.rs @@ -9,6 +9,7 @@ pub struct OsuUser { pub username: Option, // should always be there pub id: i64, pub modes: Map, + pub preferred_mode: u8, /// Number of consecutive update failures pub failures: u8, } @@ -97,6 +98,7 @@ mod raw { pub user_id: i64, pub username: Option, // should always be there pub id: i64, + pub preferred_mode: u8, pub failures: u8, } } @@ -108,6 +110,7 @@ impl OsuUser { username: r.username, id: r.id, modes, + preferred_mode: r.preferred_mode, failures: r.failures, } } @@ -119,6 +122,7 @@ impl OsuUser { user_id as "user_id: i64", username, id as "id: i64", + preferred_mode as "preferred_mode: u8", failures as "failures: u8" FROM osu_users WHERE user_id = ?"#, user_id @@ -141,6 +145,7 @@ impl OsuUser { user_id as "user_id: i64", username, id as "id: i64", + preferred_mode as "preferred_mode: u8", failures as "failures: u8" FROM osu_users WHERE id = ?"#, osu_id @@ -164,6 +169,7 @@ impl OsuUser { user_id as "user_id: i64", username, id as "id: i64", + preferred_mode as "preferred_mode: u8", failures as "failures: u8" FROM osu_users"#, ) @@ -200,16 +206,18 @@ impl OsuUser { query!( r#"INSERT - INTO osu_users(user_id, username, id, failures) - VALUES(?, ?, ?, ?) + INTO osu_users(user_id, username, id, preferred_mode, failures) + VALUES(?, ?, ?, ?, ?) ON CONFLICT (user_id) WHERE id = ? DO UPDATE SET username = excluded.username, + preferred_mode = excluded.preferred_mode, failures = excluded.failures "#, self.user_id, self.username, self.id, + self.preferred_mode, self.failures, self.user_id, ) diff --git a/youmubot-osu/src/discord/announcer.rs b/youmubot-osu/src/discord/announcer.rs index a725daa..8fb5561 100644 --- a/youmubot-osu/src/discord/announcer.rs +++ b/youmubot-osu/src/discord/announcer.rs @@ -122,6 +122,10 @@ impl Announcer { .unwrap_or(0), last_update: now, }; + if u.username != user.username { + user.username = u.username.clone().into(); + } + user.preferred_mode = u.preferred_mode; let last = user.modes.insert(mode, stats); // broadcast diff --git a/youmubot-osu/src/discord/db.rs b/youmubot-osu/src/discord/db.rs index a828af7..efe640a 100644 --- a/youmubot-osu/src/discord/db.rs +++ b/youmubot-osu/src/discord/db.rs @@ -113,6 +113,7 @@ pub struct OsuUser { pub username: Cow<'static, str>, pub id: u64, pub modes: Map, + pub preferred_mode: Mode, /// More than 5 failures => gone pub failures: u8, } @@ -136,6 +137,7 @@ impl From for model::OsuUser { .into_iter() .map(|(k, v)| (k as u8, v.into())) .collect(), + preferred_mode: u.preferred_mode as u8, failures: u.failures, } } @@ -152,11 +154,21 @@ impl From for OsuUser { .into_iter() .map(|(k, v)| (k.into(), v.into())) .collect(), + preferred_mode: u.preferred_mode.into(), failures: u.failures, } } } +impl From for crate::models::UserHeader { + fn from(value: OsuUser) -> Self { + Self { + id: value.id as u64, + username: value.username.to_string(), + } + } +} + impl From for model::OsuUserMode { fn from(m: OsuUserMode) -> Self { Self { diff --git a/youmubot-osu/src/discord/embeds.rs b/youmubot-osu/src/discord/embeds.rs index 1781997..796a780 100644 --- a/youmubot-osu/src/discord/embeds.rs +++ b/youmubot-osu/src/discord/embeds.rs @@ -1,6 +1,6 @@ -use super::BeatmapWithMode; +use super::{BeatmapWithMode, UserExtras}; use crate::{ - discord::oppai_cache::{Accuracy, BeatmapContent, BeatmapInfo, BeatmapInfoWithPP}, + discord::oppai_cache::{Accuracy, BeatmapContent, BeatmapInfoWithPP}, models::{Beatmap, Difficulty, Mode, Mods, Rank, Score, User}, UserHeader, }; @@ -479,13 +479,13 @@ impl<'a> ScoreEmbedBuilder<'a> { } } -pub(crate) fn user_embed( - u: User, - map_length: f64, - map_age: i64, - best: Option<(Score, BeatmapWithMode, BeatmapInfo)>, -) -> CreateEmbed { +pub(crate) fn user_embed(u: User, ex: UserExtras) -> CreateEmbed { let mut stats = Vec::<(&'static str, String, bool)>::new(); + let UserExtras { + map_length, + map_age, + best_score: best, + } = ex; if map_length > 0.0 { stats.push(( "Weighted Map Length", diff --git a/youmubot-osu/src/discord/interaction.rs b/youmubot-osu/src/discord/interaction.rs index 1b8a533..ba6fc9e 100644 --- a/youmubot-osu/src/discord/interaction.rs +++ b/youmubot-osu/src/discord/interaction.rs @@ -8,7 +8,7 @@ use serenity::all::{ }; use youmubot_prelude::*; -use crate::Mods; +use crate::{Mods, UserHeader}; use super::{ display::ScoreListStyle, @@ -70,8 +70,9 @@ pub fn handle_check_button<'a>( return Ok(()); } }; + let header = UserHeader::from(user.clone()); - let scores = super::do_check(&env, &bm, Mods::NOMOD, &crate::UserID::ID(user.id)).await?; + let scores = super::do_check(&env, &bm, Mods::NOMOD, &header).await?; if scores.is_empty() { comp.create_followup( &ctx, diff --git a/youmubot-osu/src/discord/mod.rs b/youmubot-osu/src/discord/mod.rs index fe3cec8..7af36f7 100644 --- a/youmubot-osu/src/discord/mod.rs +++ b/youmubot-osu/src/discord/mod.rs @@ -1,7 +1,6 @@ use std::{borrow::Borrow, collections::HashMap as Map, str::FromStr, sync::Arc}; use chrono::Utc; -use future::try_join; use futures_util::join; use interaction::{beatmap_components, score_components}; use rand::seq::IteratorRandom; @@ -33,7 +32,7 @@ use crate::{ models::{Beatmap, Mode, Mods, Score, User}, mods::UnparsedMods, request::{BeatmapRequestKind, UserID}, - OsuClient as OsuHttpClient, + OsuClient as OsuHttpClient, UserHeader, }; mod announcer; @@ -141,6 +140,7 @@ pub async fn setup( #[prefix = "osu"] #[description = "osu! related commands."] #[commands( + user, std, taiko, catch, @@ -156,9 +156,19 @@ pub async fn setup( show_leaderboard, clean_cache )] -#[default_command(std)] +#[default_command(user)] + struct Osu; +#[command] +#[description = "Receive information about an user in their preferred mode."] +#[usage = "[username or user_id = your saved username]"] +#[max_args(1)] +pub async fn user(ctx: &Context, msg: &Message, args: Args) -> CommandResult { + let env = ctx.data.read().await.get::().unwrap().clone(); + get_user(ctx, &env, msg, args, None).await +} + #[command] #[aliases("osu", "osu!")] #[description = "Receive information about an user in osu!std mode."] @@ -235,7 +245,13 @@ pub async fn save(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult } }; async fn find_score(client: &OsuHttpClient, u: &User) -> Result> { - for mode in &[Mode::Std, Mode::Taiko, Mode::Catch, Mode::Mania] { + for mode in &[ + u.preferred_mode, + Mode::Std, + Mode::Taiko, + Mode::Catch, + Mode::Mania, + ] { let scores = client .user_best(UserID::ID(u.id), |f| f.mode(*mode)) .await?; @@ -269,10 +285,11 @@ pub async fn save(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult let reply = msg.reply( &ctx, format!( - "To set your osu username, please make your most recent play \ + "To set your osu username to **{}**, please make your most recent play \ be the following map: `/b/{}` in **{}** mode! \ It does **not** have to be a pass, and **NF** can be used! \ React to this message with 👌 within 5 minutes when you're done!", + u.username, score.beatmap_id, mode.as_str_new_site() ), @@ -306,7 +323,7 @@ pub async fn save(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult .message_id(reply.id) .author_id(msg.author.id) .filter(move |r| r.emoji == emoji) - .timeout(std::time::Duration::from_secs(300)) + .timeout(std::time::Duration::from_secs(300) + beatmap.difficulty.total_length) .next() .await; if let Some(ur) = user_reaction { @@ -319,20 +336,41 @@ pub async fn save(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult } }; if !completed { + reply + .edit( + &ctx, + EditMessage::new() + .content(format!( + "Setting username to **{}** failed due to timeout. Please try again!", + u.username + )) + .embeds(vec![]) + .components(vec![]), + ) + .await?; reaction.delete(&ctx).await?; return Ok(()); } let username = u.username.clone(); - add_user(msg.author.id, u, &env).await?; - msg.reply( - &ctx, - MessageBuilder::new() - .push("user has been set to ") - .push_mono_safe(username) - .build(), - ) - .await?; + add_user(msg.author.id, &u, &env).await?; + let ex = UserExtras::from_user(&env, &u, mode).await?; + msg.channel_id + .send_message( + &ctx, + CreateMessage::new() + .reference_message(msg) + .content( + MessageBuilder::new() + .push("Youmu is now tracking user ") + .push(msg.author.mention().to_string()) + .push(" with osu! account ") + .push_bold_safe(username) + .build(), + ) + .add_embed(user_embed(u, ex)), + ) + .await?; Ok(()) } @@ -355,15 +393,24 @@ pub async fn forcesave(ctx: &Context, msg: &Message, mut args: Args) -> CommandR .await?; match user { Some(u) => { - add_user(target, u, &env).await?; - msg.reply( - &ctx, - MessageBuilder::new() - .push("user has been set to ") - .push_mono_safe(username) - .build(), - ) - .await?; + add_user(target, &u, &env).await?; + let ex = UserExtras::from_user(&env, &u, u.preferred_mode).await?; + msg.channel_id + .send_message( + &ctx, + CreateMessage::new() + .reference_message(msg) + .content( + MessageBuilder::new() + .push("Youmu is now tracking user ") + .push(target.mention().to_string()) + .push(" with osu! account ") + .push_bold_safe(username) + .build(), + ) + .embed(user_embed(u, ex)), + ) + .await?; } None => { msg.reply(&ctx, "user not found...").await?; @@ -372,49 +419,34 @@ pub async fn forcesave(ctx: &Context, msg: &Message, mut args: Args) -> CommandR Ok(()) } -async fn add_user(target: serenity::model::id::UserId, user: User, env: &OsuEnv) -> Result<()> { +async fn add_user(target: serenity::model::id::UserId, user: &User, env: &OsuEnv) -> Result<()> { let modes = [Mode::Std, Mode::Taiko, Mode::Catch, Mode::Mania] .into_iter() - .map(|mode| async move { - let pp = async { - env.client - .user(&UserID::ID(user.id), |f| f.mode(mode)) - .await - .pls_ok() - .unwrap_or(None) - .and_then(|u| u.pp) - }; - let map_length_age = async { - let scores = env - .client - .user_best(UserID::ID(user.id), |f| f.mode(mode).limit(100)) - .await - .pls_ok() - .unwrap_or_else(std::vec::Vec::new); - - ( - calculate_weighted_map_length(&scores, &env.beatmaps, mode) + .map(|mode| { + let mode = mode.clone(); + async move { + let pp = async { + env.client + .user(&UserID::ID(user.id), |f| f.mode(mode)) .await - .pls_ok(), - calculate_weighted_map_age(&scores, &env.beatmaps, mode) - .await - .pls_ok(), - ) - }; - let (pp, (map_length, map_age)) = join!(pp, map_length_age); - pp.zip(map_length) - .zip(map_age) - .map(|((pp, map_length), map_age)| { + .pls_ok() + .unwrap_or(None) + .and_then(|u| u.pp) + }; + let map_length_age = UserExtras::from_user(env, user, mode); + let (pp, ex) = join!(pp, map_length_age); + pp.zip(ex.ok()).map(|(pp, ex)| { ( mode, OsuUserMode { pp, - map_length, - map_age, + map_length: ex.map_length, + map_age: ex.map_age, last_update: Utc::now(), }, ) }) + } }) .collect::>() .filter_map(future::ready) @@ -423,7 +455,8 @@ async fn add_user(target: serenity::model::id::UserId, user: User, env: &OsuEnv) let u = OsuUser { user_id: target, - username: user.username.into(), + username: user.username.clone().into(), + preferred_mode: user.preferred_mode, id: user.id, failures: 0, modes, @@ -432,6 +465,47 @@ async fn add_user(target: serenity::model::id::UserId, user: User, env: &OsuEnv) Ok(()) } +/// Stores extra information to create an user embed. +pub(crate) struct UserExtras { + pub map_length: f64, + pub map_age: i64, + pub best_score: Option<(Score, BeatmapWithMode, BeatmapInfo)>, +} + +impl UserExtras { + // Collect UserExtras from the given user. + pub async fn from_user(env: &OsuEnv, user: &User, mode: Mode) -> Result { + let scores = env + .client + .user_best(UserID::ID(user.id), |f| f.mode(mode).limit(100)) + .await + .pls_ok() + .unwrap_or_else(std::vec::Vec::new); + + let (length, age) = join!( + calculate_weighted_map_length(&scores, &env.beatmaps, mode), + calculate_weighted_map_age(&scores, &env.beatmaps, mode) + ); + let best = if let Some(s) = scores.into_iter().next() { + let beatmap = env.beatmaps.get_beatmap(s.beatmap_id, mode).await?; + let info = env + .oppai + .get_beatmap(s.beatmap_id) + .await? + .get_info_with(mode, &s.mods)?; + Some((s, BeatmapWithMode(beatmap, mode), info)) + } else { + None + }; + + Ok(Self { + map_length: length.unwrap_or(0.0), + map_age: age.unwrap_or(0), + best_score: best, + }) + } +} + #[derive(Debug, Clone)] struct ModeArg(Mode); @@ -448,24 +522,6 @@ impl FromStr for ModeArg { } } -async fn to_user_id_query( - s: Option, - env: &OsuEnv, - author: serenity::all::UserId, -) -> Result { - let id = match s { - Some(UsernameArg::Raw(s)) => return Ok(UserID::from_string(s)), - Some(UsernameArg::Tagged(r)) => r, - None => author, - }; - - env.saved_users - .by_user_id(id) - .await? - .map(|u| UserID::Username(u.username.to_string())) - .ok_or_else(|| Error::msg("No saved account found")) -} - #[derive(Debug, Clone, Default)] enum Nth { #[default] @@ -496,7 +552,7 @@ struct ListingArgs { pub nth: Nth, pub style: ScoreListStyle, pub mode: Mode, - pub user: UserID, + pub user: UserHeader, } impl ListingArgs { @@ -508,13 +564,10 @@ impl ListingArgs { ) -> Result { let nth = args.single::().unwrap_or(Nth::All); let style = args.single::().unwrap_or(default_style); - let mode = args.single::().unwrap_or(ModeArg(Mode::Std)).0; - let user = to_user_id_query( - args.quoted().trimmed().single::().ok(), - &env, - msg.author.id, - ) - .await?; + let mode_override = args.single::().map(|v| v.0).ok(); + let (mode, user) = + user_header_from_args(args.single::().ok(), env, msg).await?; + let mode = mode_override.unwrap_or(mode); Ok(Self { nth, style, @@ -524,6 +577,35 @@ impl ListingArgs { } } +async fn user_header_from_args( + arg: Option, + env: &OsuEnv, + msg: &Message, +) -> Result<(Mode, UserHeader)> { + let (mode, user) = match arg { + Some(UsernameArg::Raw(r)) => { + let user = env + .client + .user(&UserID::Username(r), |f| f) + .await? + .ok_or(Error::msg("User not found"))?; + (user.preferred_mode, user.into()) + } + Some(UsernameArg::Tagged(t)) => { + let user = env.saved_users.by_user_id(t).await?.ok_or_else(|| { + Error::msg(format!("{} does not have a saved account!", t.mention())) + })?; + (user.preferred_mode, user.into()) + } + None => { + let user = env.saved_users.by_user_id(msg.author.id).await? + .ok_or(Error::msg("You do not have a saved account! Use `osu save` command to save your osu! account."))?; + (user.preferred_mode, user.into()) + } + }; + Ok((mode, user)) +} + #[command] #[aliases("rs", "rc", "r")] #[description = "Gets an user's recent play"] @@ -542,11 +624,6 @@ pub async fn recent(ctx: &Context, msg: &Message, mut args: Args) -> CommandResu } = ListingArgs::parse(&env, msg, &mut args, ScoreListStyle::Table).await?; let osu_client = &env.client; - - let user = osu_client - .user(&user, |f| f.mode(mode)) - .await? - .ok_or_else(|| Error::msg("User not found"))?; let plays = osu_client .user_recent(UserID::ID(user.id), |f| f.mode(mode).limit(50)) .await?; @@ -581,7 +658,7 @@ pub async fn recent(ctx: &Context, msg: &Message, mut args: Args) -> CommandResu CreateMessage::new() .content("Here is the play that you requested".to_string()) .embed( - score_embed(play, &beatmap_mode, &content, &user) + score_embed(play, &beatmap_mode, &content, user) .footer(format!("Attempt #{}", attempts)) .build(), ) @@ -616,10 +693,6 @@ pub async fn pins(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult let osu_client = &env.client; - let user = osu_client - .user(&user, |f| f.mode(mode)) - .await? - .ok_or_else(|| Error::msg("User not found"))?; let plays = osu_client .user_pins(UserID::ID(user.id), |f| f.mode(mode).limit(50)) .await?; @@ -648,7 +721,7 @@ pub async fn pins(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult &ctx, CreateMessage::new() .content("Here is the play that you requested".to_string()) - .embed(score_embed(play, &beatmap_mode, &content, &user).build()) + .embed(score_embed(play, &beatmap_mode, &content, user).build()) .components(vec![score_components(msg.guild_id)]) .reference_message(msg), ) @@ -803,7 +876,7 @@ pub async fn check(ctx: &Context, msg: &Message, mut args: Args) -> CommandResul .single::() .unwrap_or(ScoreListStyle::Grid); let username_arg = args.single::().ok(); - let user = to_user_id_query(username_arg, &env, msg.author.id).await?; + let (_, user) = user_header_from_args(username_arg, &env, msg).await?; let scores = do_check(&env, &bm, &mods, &user).await?; @@ -816,7 +889,7 @@ pub async fn check(ctx: &Context, msg: &Message, mut args: Args) -> CommandResul &ctx, format!( "Here are the scores by `{}` on `{}`!", - &user, + &user.username, bm.short_link(&mods) ), ) @@ -832,16 +905,12 @@ pub(crate) async fn do_check( env: &OsuEnv, bm: &BeatmapWithMode, mods: &Mods, - user: &UserID, + user: &UserHeader, ) -> Result> { let BeatmapWithMode(b, m) = bm; let osu_client = &env.client; - let user = osu_client - .user(user, |f| f) - .await? - .ok_or_else(|| Error::msg("User not found"))?; let mut scores = osu_client .scores(b.beatmap_id, |f| f.user(UserID::ID(user.id)).mode(*m)) .await? @@ -871,10 +940,6 @@ pub async fn top(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult user, } = ListingArgs::parse(&env, msg, &mut args, ScoreListStyle::default()).await?; let osu_client = &env.client; - let user = osu_client - .user(&user, |f| f.mode(mode)) - .await? - .ok_or_else(|| Error::msg("User not found"))?; let plays = osu_client .user_best(UserID::ID(user.id), |f| f.mode(mode).limit(100)) @@ -898,7 +963,7 @@ pub async fn top(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult msg.author )) .embed( - score_embed(&play, &beatmap, &content, &user) + score_embed(&play, &beatmap, &content, user) .top_record(nth + 1) .build(), ) @@ -945,33 +1010,18 @@ async fn get_user( env: &OsuEnv, msg: &Message, mut args: Args, - mode: Mode, + mode_override: impl Into>, ) -> CommandResult { - let user = to_user_id_query(args.single::().ok(), env, msg.author.id).await?; - let osu_client = &env.client; - let meta_cache = &env.beatmaps; - let user = osu_client.user(&user, |f| f.mode(mode)).await?; + let (mode, user) = user_header_from_args(args.single::().ok(), env, msg).await?; + let mode = mode_override.into().unwrap_or(mode); + let user = env + .client + .user(&UserID::ID(user.id), |f| f.mode(mode)) + .await?; match user { Some(u) => { - let bests = osu_client - .user_best(UserID::ID(u.id), |f| f.limit(100).mode(mode)) - .await?; - let map_length = calculate_weighted_map_length(&bests, meta_cache, mode); - let map_age = calculate_weighted_map_age(&bests, meta_cache, mode); - let (map_length, map_age) = try_join(map_length, map_age).await?; - let best = match bests.into_iter().next() { - Some(m) => { - let beatmap = meta_cache.get_beatmap(m.beatmap_id, mode).await?; - let info = env - .oppai - .get_beatmap(m.beatmap_id) - .await? - .get_info_with(mode, &m.mods)?; - Some((m, BeatmapWithMode(beatmap, mode), info)) - } - None => None, - }; + let ex = UserExtras::from_user(env, &u, mode).await?; msg.channel_id .send_message( &ctx, @@ -980,7 +1030,7 @@ async fn get_user( "{}: here is the user that you requested", msg.author )) - .embed(user_embed(u, map_length, map_age, best)), + .embed(user_embed(u, ex)), ) .await?; } diff --git a/youmubot-osu/src/models/mod.rs b/youmubot-osu/src/models/mod.rs index a510ec6..48fedb7 100644 --- a/youmubot-osu/src/models/mod.rs +++ b/youmubot-osu/src/models/mod.rs @@ -488,7 +488,6 @@ impl UserEvent { pub struct UserHeader { pub id: u64, pub username: String, - pub country: String, } #[derive(Clone, Debug)] @@ -497,6 +496,7 @@ pub struct User { pub username: String, pub joined: DateTime, pub country: String, + pub preferred_mode: Mode, // History pub count_300: u64, pub count_100: u64, @@ -544,7 +544,6 @@ impl<'a> From<&'a User> for UserHeader { Self { id: u.id, username: u.username.clone(), - country: u.country.clone(), } } } @@ -554,7 +553,6 @@ impl From for UserHeader { Self { id: u.id, username: u.username, - country: u.country, } } } diff --git a/youmubot-osu/src/models/rosu.rs b/youmubot-osu/src/models/rosu.rs index a861401..3f2f935 100644 --- a/youmubot-osu/src/models/rosu.rs +++ b/youmubot-osu/src/models/rosu.rs @@ -80,6 +80,7 @@ impl User { username: user.username.into_string(), joined: time_to_utc(user.join_date), country: user.country_code.to_string(), + preferred_mode: user.mode.into(), count_300: 0, // why do we even want this count_100: 0, // why do we even want this count_50: 0, // why do we even want this diff --git a/youmubot-osu/src/request.rs b/youmubot-osu/src/request.rs index 87e52d3..7ef76f0 100644 --- a/youmubot-osu/src/request.rs +++ b/youmubot-osu/src/request.rs @@ -132,8 +132,8 @@ pub mod builders { } } - pub fn mode(&mut self, mode: Mode) -> &mut Self { - self.mode = Some(mode); + pub fn mode(&mut self, mode: impl Into>) -> &mut Self { + self.mode = mode.into(); self } @@ -185,8 +185,8 @@ pub mod builders { self } - pub fn mode(&mut self, mode: Mode) -> &mut Self { - self.mode = Some(mode); + pub fn mode(&mut self, mode: impl Into>) -> &mut Self { + self.mode = mode.into(); self }