From 85e8070daa9f9cccbccfb15ed24734dd18b951b2 Mon Sep 17 00:00:00 2001 From: 2ndbeam <2ndbeam@disroot.org> Date: Thu, 11 Dec 2025 13:06:21 +0300 Subject: [PATCH] feat: Added publish command - /quest update also updates quest message if published --- discord/src/commands/quest.rs | 117 +++++++++++++++++++++++++++++++++- 1 file changed, 115 insertions(+), 2 deletions(-) diff --git a/discord/src/commands/quest.rs b/discord/src/commands/quest.rs index fa5172f..733be65 100644 --- a/discord/src/commands/quest.rs +++ b/discord/src/commands/quest.rs @@ -1,13 +1,26 @@ -use std::str::FromStr; +use std::{future, path::Path, str::FromStr}; +use poise::serenity_prelude::{CreateMessage, EditMessage, Mentionable, futures::StreamExt}; use squad_quest::{SquadObject, quest::{Quest, QuestDifficulty}}; use toml::value::Date; use crate::{Context, Error, commands::ERROR_MSG}; +fn make_quest_message_content(quest: &Quest) -> String { + format!("### `#{id}` {name} (+{reward})\n\ + Difficulty: *{difficulty:?}*\n\ + {description}", + id = quest.id, + name = quest.name, + reward = quest.reward, + difficulty = quest.difficulty, + description = quest.description, + ) +} + #[poise::command( prefix_command, slash_command, - subcommands("list", "create", "update"), + subcommands("list", "create", "update", "publish"), )] pub async fn quest( _ctx: Context<'_>, @@ -199,6 +212,7 @@ pub async fn update( }, } + let new_quest = Quest { id, difficulty, @@ -211,6 +225,37 @@ pub async fn update( deadline: dead_line, }; + if new_quest.public { + let content = make_quest_message_content(&new_quest); + let builder = EditMessage::new().content(content); + + let channel = { + let dc = ctx.data().discord.clone(); + let guard = dc.lock().expect("shouldn't be locked"); + guard.quests_channel + }; + let message = { + let messages = channel.messages_iter(ctx) + .filter_map(|m| async move { if m.is_ok() { Some(m.unwrap()) } else { + eprintln!("{}", m.unwrap_err()); + None + } }) + .filter(|m| { + future::ready(m.content.contains(&format!("#{id}"))) + }) + .collect::>().await; + messages.first().cloned() + }; + if let Some(mut message) = message { + message.edit(ctx, builder).await?; + } else { + let reply_string = format!("Quest #{id} is public, but its message was not found in the {channel}", + channel = channel.mention() + ); + ctx.reply(reply_string).await?; + } + } + let path = conf.full_quests_path(); let reply_string = match new_quest.save(path) { Err(error) => { @@ -223,3 +268,71 @@ pub async fn update( Ok(()) } + +#[poise::command( + prefix_command, + slash_command, + required_permissions = "ADMINISTRATOR", + guild_only +)] +pub async fn publish( + ctx: Context<'_>, + #[description = "Identifier of the quest to publish"] + id: u16, +) -> Result<(), Error> { + let mut quests = ctx.data().config.load_quests(); + + let Some(quest) = quests.iter_mut().find(|q| q.id == id) else { + let reply_string = format!("Quest #{id} not found"); + ctx.reply(reply_string).await?; + return Ok(()); + }; + + if quest.public { + let reply_string = format!("Quest #{id} is already public"); + ctx.reply(reply_string).await?; + return Ok(()); + } + + quest.public = true; + + let content = make_quest_message_content(&quest); + + let builder = CreateMessage::new() + .content(content); + + let dc = ctx.data().discord.clone(); + let channel = { + let guard = dc.lock().expect("shouldn't be locked"); + guard.quests_channel + }; + + let message = channel.send_message(ctx, builder).await?; + + let result = { + let mut guard = dc.lock().expect("shouldn't be locked"); + guard.quests_messages.push(message.id); + let path = ctx.data().config.full_impl_path().unwrap(); + guard.save(path.parent().unwrap_or(Path::new("")).to_owned()) + }; + + if let Err(error) = result { + eprintln!("{error}"); + let reply_string = ERROR_MSG.to_string(); + ctx.reply(reply_string).await?; + return Ok(()) + } + + let quests_path = ctx.data().config.full_quests_path(); + if let Err(error) = quest.save(quests_path) { + eprintln!("{error}"); + let reply_string = ERROR_MSG.to_string(); + ctx.reply(reply_string).await?; + return Ok(()) + } + + let reply_string = format!("Published quest #{id}"); + ctx.reply(reply_string).await?; + + Ok(()) +}