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
This commit is contained in:
Alexey 2025-12-18 13:33:42 +03:00
commit 60aa5fcb34
8 changed files with 191 additions and 22 deletions

View file

@ -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();

View file

@ -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<String>,
#[description = "Attachment answer to the quest"]
#[name_localized("ru", "файл1")]
#[description_localized("ru", "Вложение к ответу на квест")]
file1: Option<Attachment>,
#[description = "Attachment answer to the quest"]
#[name_localized("ru", "файл2")]
#[description_localized("ru", "Вложение к ответу на квест")]
file2: Option<Attachment>,
#[description = "Attachment answer to the quest"]
#[name_localized("ru", "файл3")]
#[description_localized("ru", "Вложение к ответу на квест")]
file3: Option<Attachment>,
) -> Result<(), Error> {
let mut account = fetch_or_init_account(&ctx.data().config, ctx.author().id.to_string());

View file

@ -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();

View file

@ -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;

View file

@ -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;

View file

@ -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<DifficultyWrapper> for QuestDifficulty {
fn from(value: DifficultyWrapper) -> Self {
match &value {
@ -105,28 +108,47 @@ impl From<DateWrapper> 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<DateWrapper>,
#[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<DateWrapper>,
*/
) -> 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<DifficultyWrapper>,
#[description = "Reward for the quest"]
#[name_localized("ru", "награда")]
#[description_localized("ru", "Награда за квест")]
reward: Option<u32>,
#[description = "Quest name"]
#[name_localized("ru", "название")]
#[description_localized("ru", "Название квеста")]
name: Option<String>,
#[description = "Quest description"]
#[name_localized("ru", "описание")]
#[description_localized("ru", "Описание квеста")]
description: Option<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: Option<String>,
#[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<DateWrapper>,
/*
#[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<DateWrapper>,
#[description = "Clear availability and deadline if checked"]
#[rename = "override"]
should_override: Option<bool>,
#[description = "Reset availability and deadline if checked"]
#[description_localized("ru", "Если выбрано, сбросить доступность и дедлайн")]
*/
#[description = "Reset availability if checked"]
#[description_localized("ru", "Если выбрано, сбросить доступность")]
#[name_localized("ru", "сброс")]
reset: Option<bool>,
) -> Result<(), Error> {
let conf = &ctx.data().config;
let quests = conf.load_quests();
@ -211,16 +260,16 @@ pub async fn update(
};
let available_on: Option<Date>;
let dead_line: Option<Date>;
//let dead_line: Option<Date>;
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? {

View file

@ -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<ChannelId>,
#[description = "User to message to"]
#[name_localized("ru", "пользователь")]
#[description_localized("ru", "Пользователь, которому отправится сообщение")]
user: Option<UserId>,
#[description = "Message text"]
#[name_localized("ru", "содержание")]
#[description_localized("ru", "Текст сообщения")]
content: Option<String>,
#[description = "Message attachment"]
#[name_localized("ru", "файл")]
#[description_localized("ru", "Вложение к сообщению")]
file: Option<Attachment>,
) -> 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<ChannelId>,
#[description = "User, who received DM"]
#[name_localized("ru", "пользователь")]
#[description_localized("ru", "Пользователь, получивший ЛС")]
user: Option<UserId>,
#[description = "New message text"]
#[name_localized("ru", "содержание")]
#[description_localized("ru", "Новый текст сообщения")]
content: Option<String>,
#[description = "New file (overrides existing if specified)"]
#[name_localized("ru", "файл")]
#[description_localized("ru", "Новое вложение (заменит предыдущее если указано)")]
file: Option<Attachment>,
) -> 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<ChannelId>,
#[description = "User, who received DM"]
#[name_localized("ru", "пользователь")]
#[description_localized("ru", "Пользователь, получивший ЛС")]
user: Option<UserId>,
) -> Result<(), Error> {

View file

@ -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)),