feat(discord)!: Added string formatter

- Added string formatter
- Added Strings struct for passing strings from file
- Refactored /info and /quest * to use formatter

BREAKING CHANGE: Changed DiscordConfig fields
This commit is contained in:
Alexey 2025-12-16 16:42:18 +03:00
commit aec4ef8339
7 changed files with 386 additions and 84 deletions

View file

@ -1,4 +1,4 @@
use std::{future, path::Path, str::FromStr};
use std::{future, str::FromStr};
use poise::serenity_prelude::{CreateMessage, EditMessage, Message, futures::StreamExt};
use squad_quest::{SquadObject, quest::{Quest, QuestDifficulty}};
@ -24,16 +24,10 @@ async fn find_quest_message(ctx: Context<'_>, id: u16) -> Result<Option<Message>
Ok(messages.first().cloned())
}
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,
)
fn make_quest_message_content(ctx: Context<'_>, quest: &Quest) -> String {
let strings = &ctx.data().strings;
let formatter = strings.formatter().quest(quest);
formatter.fmt(&strings.quest.message_format)
}
#[poise::command(
@ -60,13 +54,12 @@ pub async fn list(
) -> Result<(), Error> {
let conf = &ctx.data().config;
let quests = conf.load_quests();
let mut reply_string = format!("Listing {} quests:", quests.len());
let strings = &ctx.data().strings;
let mut formatter = strings.formatter().value(quests.len());
let mut reply_string = formatter.fmt(&strings.quest.list);
for quest in quests {
reply_string.push_str(format!("\n#{}: {}\n\tDescription: {}",
quest.id,
quest.name,
quest.description,
).as_str());
formatter = formatter.quest(&quest);
reply_string.push_str(formatter.fmt(&strings.quest.list_item).as_str());
}
ctx.reply(reply_string).await?;
Ok(())
@ -168,7 +161,10 @@ pub async fn create(
let path = conf.full_quests_path();
quest.save(path)?;
let reply_string = format!("Created quest #{}", quest.id);
let strings = &ctx.data().strings;
let formatter = strings.formatter().quest(&quest);
let reply_string = formatter.fmt(&strings.quest.create);
ctx.reply(reply_string).await?;
@ -228,7 +224,6 @@ pub async fn update(
},
}
let new_quest = Quest {
id,
difficulty,
@ -241,23 +236,25 @@ pub async fn update(
deadline: dead_line,
};
let strings = &ctx.data().strings;
let formatter = strings.formatter().quest(&new_quest);
if new_quest.public {
let content = make_quest_message_content(&new_quest);
let content = make_quest_message_content(ctx, &new_quest);
let builder = EditMessage::new().content(content);
let message = find_quest_message(ctx, id).await?;
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 quest channel",
);
let reply_string = formatter.fmt(&strings.quest.message_not_found);
ctx.reply(reply_string).await?;
}
}
let path = conf.full_quests_path();
new_quest.save(path)?;
let reply_string = format!("Updated quest #{id}");
let reply_string = formatter.fmt(&strings.quest.update);
ctx.reply(reply_string).await?;
Ok(())
@ -286,7 +283,7 @@ pub async fn publish(
quest.public = true;
let content = make_quest_message_content(&quest);
let content = make_quest_message_content(ctx, &quest);
let builder = CreateMessage::new()
.content(content);
@ -297,19 +294,15 @@ pub async fn publish(
guard.quests_channel
};
let message = channel.send_message(ctx, builder).await?;
{
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())?
};
channel.send_message(ctx, builder).await?;
let quests_path = ctx.data().config.full_quests_path();
quest.save(quests_path)?;
let reply_string = format!("Published quest #{id}");
let strings = &ctx.data().strings;
let formatter = strings.formatter().quest(&quest);
let reply_string = formatter.fmt(&strings.quest.publish);
ctx.reply(reply_string).await?;
Ok(())
@ -342,7 +335,15 @@ pub async fn delete(
account.save(accounts_path.clone())?;
}
let reply_string = format!("Successfully deleted quest #{id}");
let mock_quest = Quest {
id,
..Default::default()
};
let strings = &ctx.data().strings;
let formatter = strings.formatter().quest(&mock_quest);
let reply_string = formatter.fmt(&strings.quest.delete);
ctx.reply(reply_string).await?;
Ok(())