From 60aa5fcb3484dd83baa326fe0397f55d7e206107 Mon Sep 17 00:00:00 2001 From: 2ndbeam <2ndbeam@disroot.org> Date: Thu, 18 Dec 2025 13:33:42 +0300 Subject: [PATCH] feat(discord): Commands description - Added english commands description - Added russian commands description - Changed override option on /quest update to reset dates - Commented out all deadline functionality --- discord/src/commands/account.rs | 28 ++++++++++ discord/src/commands/answer.rs | 13 +++++ discord/src/commands/init.rs | 10 +++- discord/src/commands/map.rs | 12 +++++ discord/src/commands/mod.rs | 3 ++ discord/src/commands/quest.rs | 95 +++++++++++++++++++++++++++------ discord/src/commands/social.rs | 46 ++++++++++++++++ discord/src/main.rs | 6 +-- 8 files changed, 191 insertions(+), 22 deletions(-) diff --git a/discord/src/commands/account.rs b/discord/src/commands/account.rs index 7dc5cb2..5f2896e 100644 --- a/discord/src/commands/account.rs +++ b/discord/src/commands/account.rs @@ -21,14 +21,20 @@ async fn account_balance_string( formatter.fmt(&strings.scoreboard.line_format) } +/// Reset user account, including balance, unlocked rooms and completed quests #[poise::command( prefix_command, slash_command, guild_only, required_permissions = "ADMINISTRATOR", + name_localized("ru", "сбросить"), + description_localized("ru", "Сбросить аккаунт пользователя, вкл. баланс, открытые комнаты и пройденные квесты"), )] pub async fn reset( ctx: Context<'_>, + #[description = "The user to reset"] + #[name_localized("ru", "кого")] + #[description_localized("ru", "Сбрасываемый пользователь")] who: User, ) -> Result<(), Error> { let accounts = ctx.data().config.load_accounts(); @@ -52,10 +58,13 @@ pub async fn reset( Ok(()) } +/// Show scoreboard #[poise::command( prefix_command, slash_command, guild_only, + name_localized("ru", "счёт"), + description_localized("ru", "Отобразить таблицу лидеров"), )] pub async fn scoreboard( ctx: Context<'_>, @@ -98,6 +107,7 @@ pub async fn scoreboard( slash_command, guild_only, subcommands("give", "set"), + name_localized("ru", "баланс"), )] pub async fn balance( _ctx: Context<'_>, @@ -105,14 +115,23 @@ pub async fn balance( Ok(()) } +/// Give points to another user #[poise::command( prefix_command, slash_command, guild_only, + name_localized("ru", "передать"), + description_localized("ru", "Передать очки другому пользователю"), )] pub async fn give( ctx: Context<'_>, + #[description = "Recipient"] + #[name_localized("ru", "кому")] + #[description_localized("ru", "Получатель")] who: User, + #[description = "Amount of the points to give"] + #[name_localized("ru", "количество")] + #[description_localized("ru", "Количество очков для передачи")] amount: u32, ) -> Result<(), Error> { if ctx.author() == &who { @@ -153,15 +172,24 @@ pub async fn give( Ok(()) } +/// Set current user balance #[poise::command( prefix_command, slash_command, guild_only, required_permissions = "ADMINISTRATOR", + name_localized("ru", "установить"), + description_localized("ru", "Устанавливает текущий баланс пользователя"), )] pub async fn set( ctx: Context<'_>, + #[description = "User, whose balance will be modified"] + #[name_localized("ru", "чей")] + #[description_localized("ru", "Пользователь, чей баланс будет изменён")] who: User, + #[description = "New balance of the user"] + #[name_localized("ru", "количество")] + #[description_localized("ru", "Новый баланс пользователя")] amount: u32, ) -> Result<(), Error> { let mut accounts = ctx.data().config.load_accounts(); diff --git a/discord/src/commands/answer.rs b/discord/src/commands/answer.rs index f01b9c7..1f6445e 100644 --- a/discord/src/commands/answer.rs +++ b/discord/src/commands/answer.rs @@ -3,22 +3,35 @@ use squad_quest::SquadObject; use crate::{Context, Error, account::fetch_or_init_account}; +/// Send an answer to the quest for review #[poise::command( prefix_command, slash_command, guild_only, + name_localized("ru", "ответить"), + description_localized("ru", "Отправить ответ на квест на проверку"), )] pub async fn answer( ctx: Context<'_>, #[description = "Identifier of the quest to answer to"] + #[name_localized("ru", "ид_квеста")] + #[description_localized("ru", "Идентификатор квеста для ответа")] quest_id: u16, #[description = "Text answer to the quest"] + #[name_localized("ru", "текст")] + #[description_localized("ru", "Текст ответа на квест")] text: Option, #[description = "Attachment answer to the quest"] + #[name_localized("ru", "файл1")] + #[description_localized("ru", "Вложение к ответу на квест")] file1: Option, #[description = "Attachment answer to the quest"] + #[name_localized("ru", "файл2")] + #[description_localized("ru", "Вложение к ответу на квест")] file2: Option, #[description = "Attachment answer to the quest"] + #[name_localized("ru", "файл3")] + #[description_localized("ru", "Вложение к ответу на квест")] file3: Option, ) -> Result<(), Error> { let mut account = fetch_or_init_account(&ctx.data().config, ctx.author().id.to_string()); diff --git a/discord/src/commands/init.rs b/discord/src/commands/init.rs index aac39a2..bfd7998 100644 --- a/discord/src/commands/init.rs +++ b/discord/src/commands/init.rs @@ -5,18 +5,24 @@ use squad_quest::SquadObject; use crate::{Context, Error}; - +/// Set channels to post quests and answers to #[poise::command( prefix_command, slash_command, required_permissions = "ADMINISTRATOR", guild_only, + name_localized("ru", "инит"), + description_localized("ru", "Установить каналы для публикации квестов и ответов"), )] pub async fn init( ctx: Context<'_>, #[description = "Channel to post quests to"] + #[name_localized("ru", "канал_квестов")] + #[description_localized("ru", "Канал для публикации квестов")] quests_channel: ChannelId, - #[description = "Channel to post answers to check"] + #[description = "Channel to post answers for review"] + #[name_localized("ru", "канал_ответов")] + #[description_localized("ru", "Канал для публикации ответов на проверку")] answers_channel: ChannelId, ) -> Result<(), Error> { let dc = ctx.data().discord.clone(); diff --git a/discord/src/commands/map.rs b/discord/src/commands/map.rs index 38c6a0c..4313132 100644 --- a/discord/src/commands/map.rs +++ b/discord/src/commands/map.rs @@ -2,13 +2,19 @@ use squad_quest::{SquadObject, map::Map}; use crate::{Context, account::fetch_or_init_account, error::Error}; +/// Unlock specified room if it is reachable and you have required amount of points #[poise::command( prefix_command, slash_command, guild_only, + name_localized("ru", "открыть"), + description_localized("ru", "Открывает указанную комнату, если хватает очков и до нее можно добраться"), )] pub async fn unlock( ctx: Context<'_>, + #[description = "Room identifier"] + #[name_localized("ru", "идентификатор")] + #[description_localized("ru", "Идентификатор комнаты")] id: u16, ) -> Result<(), Error> { let conf = &ctx.data().config; @@ -44,13 +50,19 @@ pub async fn unlock( Ok(()) } +/// Move to another unlocked room #[poise::command( prefix_command, slash_command, guild_only, + name_localized("ru", "пойти"), + description_localized("ru", "Переместиться в другую разблокированную комнату"), )] pub async fn r#move( ctx: Context<'_>, + #[description = "Identifier of the room to move to"] + #[name_localized("ru", "идентификатор")] + #[description_localized("ru", "Идентификатор комнаты, куда переместиться")] id: u16, ) -> Result<(), Error> { let conf = &ctx.data().config; diff --git a/discord/src/commands/mod.rs b/discord/src/commands/mod.rs index bc59244..4a0ba13 100644 --- a/discord/src/commands/mod.rs +++ b/discord/src/commands/mod.rs @@ -16,9 +16,12 @@ pub async fn register(ctx: Context<'_>) -> Result<(), Error> { Ok(()) } +/// Show bot info, such as version and link to web map #[poise::command( prefix_command, slash_command, + name_localized("ru", "инфо"), + description_localized("ru", "Получить информацию о боте и ссылку на веб карту"), )] pub async fn info(ctx: Context<'_>) -> Result<(), Error> { let strings = &ctx.data().strings; diff --git a/discord/src/commands/quest.rs b/discord/src/commands/quest.rs index fd6c8b6..ad61e1a 100644 --- a/discord/src/commands/quest.rs +++ b/discord/src/commands/quest.rs @@ -36,6 +36,7 @@ fn make_quest_message_content(ctx: Context<'_>, quest: &Quest) -> String { guild_only, subcommands("list", "create", "update", "publish", "delete"), required_permissions = "ADMINISTRATOR", + name_localized("ru", "квесты"), )] pub async fn quest( _ctx: Context<'_>, @@ -43,11 +44,14 @@ pub async fn quest( Ok(()) } +/// List all quests #[poise::command( prefix_command, slash_command, guild_only, required_permissions = "ADMINISTRATOR", + name_localized("ru", "список"), + description_localized("ru", "Вывести все квесты") )] pub async fn list( ctx: Context<'_>, @@ -73,7 +77,6 @@ pub enum DifficultyWrapper { Secret, } - impl From for QuestDifficulty { fn from(value: DifficultyWrapper) -> Self { match &value { @@ -105,28 +108,47 @@ impl From for Date { } } +/// Create quest and print its identifier #[poise::command( prefix_command, slash_command, required_permissions = "ADMINISTRATOR", guild_only, + name_localized("ru", "создать"), + description_localized("ru", "Создать квест и получить его идентификатор"), )] pub async fn create( ctx: Context<'_>, #[description = "Quest difficulty"] + #[name_localized("ru", "сложность")] + #[description_localized("ru", "Сложность квеста")] difficulty: DifficultyWrapper, #[description = "Reward for the quest"] + #[name_localized("ru", "награда")] + #[description_localized("ru", "Награда за квест")] reward: u32, #[description = "Quest name"] + #[name_localized("ru", "название")] + #[description_localized("ru", "Название квеста")] name: String, #[description = "Quest description"] + #[name_localized("ru", "описание")] + #[description_localized("ru", "Описание квеста")] description: String, - #[description = "Quest answer, visible to admins"] + #[description = "Expected answer, visible when user posts their answer for review"] + #[name_localized("ru", "ответ")] + #[description_localized("ru", "Ожидаемый результат, отображаемый при проверке ответа игрока")] answer: String, - #[description = "Optional date of publication (in format of YYYY-MM-DD, e.g. 2025-12-24)"] + #[description = "Date of publication (in format of YYYY-MM-DD, e.g. 2025-12-24)"] + #[name_localized("ru", "доступен")] + #[description_localized("ru", "Дата публикации (в формате ГГГГ-ММ-ДД, напр. 2025-12-24)")] available: Option, - #[description = "Optional deadline (in format of YYYY-MM-DD, e.g. 2025-12-24)"] + /* + #[description = "Deadline (in format of YYYY-MM-DD, e.g. 2025-12-24)"] + #[name_localized("ru", "дедлайн")] + #[description_localized("ru", "Дедлайн (в формате ГГГГ-ММ-ДД), напр. 2025-12-24")] deadline: Option, + */ ) -> Result<(), Error> { let conf = &ctx.data().config; let mut quests = conf.load_quests(); @@ -141,10 +163,12 @@ pub async fn create( None => None, }; + /* let deadline = match deadline { Some(dl) => Some(dl.into()), None => None, }; + */ let quest = Quest { id: next_id, @@ -155,7 +179,8 @@ pub async fn create( answer, public: false, available_on, - deadline, + //deadline, + ..Default::default() }; let path = conf.full_quests_path(); @@ -171,33 +196,57 @@ pub async fn create( Ok(()) } +/// Update quest values by its identifier and new given values #[poise::command( prefix_command, slash_command, required_permissions = "ADMINISTRATOR", guild_only, + name_localized("ru", "обновить"), + description_localized("ru", "Обновить выбранные значения указанного квеста"), )] pub async fn update( ctx: Context<'_>, #[description = "Quest identifier"] + #[name_localized("ru", "идентификатор")] + #[description_localized("ru", "Идентификатор квеста")] id: u16, #[description = "Quest difficulty"] + #[name_localized("ru", "сложность")] + #[description_localized("ru", "Сложность квеста")] difficulty: Option, #[description = "Reward for the quest"] + #[name_localized("ru", "награда")] + #[description_localized("ru", "Награда за квест")] reward: Option, #[description = "Quest name"] + #[name_localized("ru", "название")] + #[description_localized("ru", "Название квеста")] name: Option, #[description = "Quest description"] + #[name_localized("ru", "описание")] + #[description_localized("ru", "Описание квеста")] description: Option, - #[description = "Quest answer, visible to admins"] + #[description = "Expected answer, visible when user posts their answer for review"] + #[name_localized("ru", "ответ")] + #[description_localized("ru", "Ожидаемый результат, отображаемый при проверке ответа игрока")] answer: Option, #[description = "Date of publication (in format of YYYY-MM-DD, e.g. 2025-12-24)"] + #[name_localized("ru", "доступен")] + #[description_localized("ru", "Дата публикации (в формате ГГГГ-ММ-ДД, напр. 2025-12-24")] available: Option, + /* #[description = "Quest deadline (in format of YYYY-MM-DD, e.g. 2025-12-24)"] + #[name_localized("ru", "дедлайн")] + #[description_localized("ru", "Дедлайн (в формате ГГГГ-ММ-ДД, напр. 2025-12-24)")] deadline: Option, - #[description = "Clear availability and deadline if checked"] - #[rename = "override"] - should_override: Option, + #[description = "Reset availability and deadline if checked"] + #[description_localized("ru", "Если выбрано, сбросить доступность и дедлайн")] + */ + #[description = "Reset availability if checked"] + #[description_localized("ru", "Если выбрано, сбросить доступность")] + #[name_localized("ru", "сброс")] + reset: Option, ) -> Result<(), Error> { let conf = &ctx.data().config; let quests = conf.load_quests(); @@ -211,16 +260,16 @@ pub async fn update( }; let available_on: Option; - let dead_line: Option; + //let dead_line: Option; - match should_override.unwrap_or(false) { + match reset.unwrap_or(false) { true => { - available_on = available.map(|v| v.into()); - dead_line = deadline.map(|v| v.into()); + available_on = None; + //dead_line = None; }, false => { available_on = available.map_or_else(|| quest.available_on.clone(), |v| Some(v.into())); - dead_line = deadline.map_or_else(|| quest.deadline.clone(), |v| Some(v.into())); + //dead_line = deadline.map_or_else(|| quest.deadline.clone(), |v| Some(v.into())); }, } @@ -233,7 +282,8 @@ pub async fn update( answer: answer.unwrap_or(quest.answer.clone()), public: quest.public, available_on, - deadline: dead_line, + //deadline: dead_line, + ..Default::default() }; let strings = &ctx.data().strings; @@ -260,15 +310,20 @@ pub async fn update( Ok(()) } +/// Mark quest as public and send its message in quests channel #[poise::command( prefix_command, slash_command, required_permissions = "ADMINISTRATOR", - guild_only + guild_only, + name_localized("ru", "опубликовать"), + description_localized("ru", "Отметить квест как публичный и отправить его сообщение в канал квестов"), )] pub async fn publish( ctx: Context<'_>, - #[description = "Identifier of the quest to publish"] + #[description = "Quest identifier"] + #[name_localized("ru", "идентификатор")] + #[description_localized("ru", "Идентификатор квеста")] id: u16, ) -> Result<(), Error> { let mut quests = ctx.data().config.load_quests(); @@ -308,14 +363,20 @@ pub async fn publish( Ok(()) } +/// Delete quest (and its message, if published) #[poise::command( prefix_command, slash_command, required_permissions = "ADMINISTRATOR", guild_only, + name_localized("ru", "удалить"), + description_localized("ru", "Удалить квест (и его сообщение, если он был опубликован)"), )] pub async fn delete( ctx: Context<'_>, + #[description = "Quest identifier"] + #[name_localized("ru", "идентификатор")] + #[description_localized("ru", "Идентификатор квеста")] id: u16, ) -> Result<(), Error> { if let Some(msg) = find_quest_message(ctx, id).await? { diff --git a/discord/src/commands/social.rs b/discord/src/commands/social.rs index 33cb2d5..d2f22cb 100644 --- a/discord/src/commands/social.rs +++ b/discord/src/commands/social.rs @@ -8,22 +8,38 @@ use crate::{Context, Error}; required_permissions = "ADMINISTRATOR", guild_only, subcommands("msg", "edit", "undo"), + name_localized("ru", "сообщение"), )] pub async fn social( _ctx: Context<'_> ) -> Result<(), Error> { Ok(()) } +/// Send message to channel or user #[poise::command( prefix_command, slash_command, required_permissions = "ADMINISTRATOR", guild_only, + name_localized("ru", "написать"), + description_localized("ru", "Отправить сообщение пользователю или в канал"), )] pub async fn msg ( ctx: Context<'_>, + #[description = "Channel to message to"] + #[name_localized("ru", "канал")] + #[description_localized("ru", "Канал, в который отправится сообщение")] channel: Option, + #[description = "User to message to"] + #[name_localized("ru", "пользователь")] + #[description_localized("ru", "Пользователь, которому отправится сообщение")] user: Option, + #[description = "Message text"] + #[name_localized("ru", "содержание")] + #[description_localized("ru", "Текст сообщения")] content: Option, + #[description = "Message attachment"] + #[name_localized("ru", "файл")] + #[description_localized("ru", "Вложение к сообщению")] file: Option, ) -> Result<(), Error> { @@ -76,19 +92,37 @@ pub async fn msg ( Ok(()) } +/// Edit sent channel or DM message #[poise::command( prefix_command, slash_command, required_permissions = "ADMINISTRATOR", guild_only, + name_localized("ru", "редактировать"), + description_localized("ru", "Редактировать сообщение в канале или в ЛС"), )] pub async fn edit ( ctx: Context<'_>, + #[description = "Identifier of the message to edit"] + #[name_localized("ru", "сообщение")] + #[description_localized("ru", "Идентификатор редактируемого сообщения")] #[rename = "message"] message_id: MessageId, + #[description = "Channel where the message is"] + #[name_localized("ru", "канал")] + #[description_localized("ru", "Канал, где находится сообщение")] channel: Option, + #[description = "User, who received DM"] + #[name_localized("ru", "пользователь")] + #[description_localized("ru", "Пользователь, получивший ЛС")] user: Option, + #[description = "New message text"] + #[name_localized("ru", "содержание")] + #[description_localized("ru", "Новый текст сообщения")] content: Option, + #[description = "New file (overrides existing if specified)"] + #[name_localized("ru", "файл")] + #[description_localized("ru", "Новое вложение (заменит предыдущее если указано)")] file: Option, ) -> Result<(), Error> { if channel.is_none() && user.is_none() { @@ -137,17 +171,29 @@ pub async fn edit ( Ok(()) } +/// Delete message in channel or DM #[poise::command( prefix_command, slash_command, required_permissions = "ADMINISTRATOR", guild_only, + name_localized("ru", "удалить"), + description_localized("ru", "Удалить сообщение в канале или в ЛС"), )] pub async fn undo( ctx: Context<'_>, + #[description = "Identifier of the message to delete"] + #[name_localized("ru", "сообщение")] + #[description_localized("ru", "Идентификатор удаляемого сообщения")] #[rename = "message"] message_id: MessageId, + #[description = "Channel where the message is"] + #[name_localized("ru", "канал")] + #[description_localized("ru", "Канал, где находится сообщение")] channel: Option, + #[description = "User, who received DM"] + #[name_localized("ru", "пользователь")] + #[description_localized("ru", "Пользователь, получивший ЛС")] user: Option, ) -> Result<(), Error> { diff --git a/discord/src/main.rs b/discord/src/main.rs index 70b6625..f65b4fc 100644 --- a/discord/src/main.rs +++ b/discord/src/main.rs @@ -43,8 +43,8 @@ async fn main() { .options(poise::FrameworkOptions { on_error: |err| Box::pin(error_handler(err)), commands: vec![ + //commands::register(), commands::quest::quest(), - commands::register(), commands::info(), commands::init::init(), commands::answer::answer(), @@ -57,9 +57,9 @@ async fn main() { ], ..Default::default() }) - .setup(|ctx, _ready, framework| { + .setup(|ctx, _ready, _framework| { Box::pin(async move { - poise::builtins::register_globally(ctx, &framework.options().commands).await?; + //poise::builtins::register_globally(ctx, &framework.options().commands).await?; Ok(Data { config, discord: Arc::new(Mutex::new(discord)),