squad-quest/discord/src/commands/answer.rs
2ndbeam d188bba16e feat: Implemented guild check
- Also added more error logging
2025-12-24 17:46:22 +03:00

163 lines
5.6 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use poise::serenity_prelude::{Attachment, ComponentInteractionCollector, CreateActionRow, CreateAttachment, CreateButton, CreateMessage, EditMessage};
use squad_quest::SquadObject;
use crate::{Context, Error, account::fetch_or_init_account, commands::guild};
/// Send an answer to the quest for review
#[poise::command(
prefix_command,
slash_command,
guild_only,
check = "guild",
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(), Some(ctx.author()));
if let Some(_) = account.quests_completed.iter().find(|qid| **qid == quest_id) {
return Err(Error::QuestIsCompleted(quest_id));
}
let quests = ctx.data().config.load_quests();
let Some(quest) = quests.iter()
.filter(|q| q.public)
.find(|q| q.id == quest_id) else {
return Err(Error::QuestNotFound(quest_id));
};
let mut files: Vec<Attachment> = Vec::new();
for file in [file1, file2, file3] {
if let Some(f) = file {
files.push(f);
}
}
if text.is_none() && files.len() == 0 {
return Err(Error::NoContent);
}
let strings = &ctx.data().strings;
let mut formatter = strings.formatter()
.user(ctx.author())
.quest(quest);
let text_ans = match text {
Some(text) => {
formatter = formatter.text(text);
formatter.fmt(&strings.answer.text)
},
None => String::new(),
};
let attachment_notice = if files.len() == 0 { String::new() } else {
formatter.fmt(&strings.answer.attachment_notice)
};
let content = [
formatter.fmt(&strings.answer.from),
formatter.fmt(&strings.answer.quest),
formatter.fmt(&strings.answer.expected),
text_ans,
attachment_notice,
].join("");
let mut attachments: Vec<CreateAttachment> = Vec::new();
for file in files {
let attachment = CreateAttachment::url(ctx, &file.url).await?;
attachments.push(attachment);
}
let ctx_id = ctx.id();
let approve_id = format!("{ctx_id}approve");
let reject_id = format!("{ctx_id}reject");
let components = CreateActionRow::Buttons(vec![
CreateButton::new(&approve_id).label("Approve".to_string()),
CreateButton::new(&reject_id).label("Reject".to_string()),
]);
let ans_channel = {
let discord = ctx.data().discord.clone();
let guard = discord.lock().expect("should not be locked");
guard.answers_channel
};
let builder = CreateMessage::new()
.content(content.clone())
.files(attachments)
.components(vec![components]);
let mut message = ans_channel.send_message(ctx, builder).await?;
let reply_string = formatter.fmt(&strings.answer.reply.initial);
ctx.reply(reply_string).await?;
if let Some(press) = ComponentInteractionCollector::new(ctx)
.filter(move |press| press.data.custom_id.starts_with(&ctx_id.to_string()))
.await
{
let admin = press.user;
formatter = formatter.user(&admin).text(&content);
let is_approved = press.data.custom_id == approve_id;
let content = if is_approved {
formatter.fmt(&strings.answer.accepted_by)
} else {
formatter.fmt(&strings.answer.rejected_by)
};
let builder = EditMessage::new().content(content).components(Vec::new());
message.edit(ctx, builder).await?;
let content: String;
if is_approved {
let mut no_errors = true;
if let Err(error) = quest.complete_for_account(&mut account) {
eprintln!("{error}");
no_errors = false;
};
let path = ctx.data().config.full_accounts_path();
if let Err(error) = account.save(path) {
eprintln!("{error}");
no_errors = false;
};
formatter = formatter.current_balance(&account);
if no_errors {
content = formatter.fmt(&strings.answer.reply.accepted);
} else {
content = formatter.fmt(&strings.answer.reply.error);
}
} else {
content = formatter.fmt(&strings.answer.reply.rejected);
};
let dm_builder = CreateMessage::new().content(content);
ctx.author().dm(ctx, dm_builder).await?;
}
Ok(())
}