163 lines
5.6 KiB
Rust
163 lines
5.6 KiB
Rust
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(())
|
||
}
|