feat: Added publish command

- /quest update also updates quest message if published
This commit is contained in:
Alexey 2025-12-11 13:06:21 +03:00
commit 85e8070daa

View file

@ -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::<Vec<_>>().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(())
}