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, #[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(), 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 = 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 = 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(()) }