wOxlf/src/messages/mod.rs

173 lines
5.9 KiB
Rust

use crate::config::MessageConfig;
use crate::game::player_data::PlayerData;
use crate::GlobalData;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use serenity::model::guild::Member;
use serenity::prelude::Mentionable;
use std::collections::HashMap;
use tera::{Tera, Value};
type TeraFnRet = Box<dyn Fn(&HashMap<String, Value>) -> tera::Result<Value> + Send + Sync>;
fn time_to_discord_time(time_flag: &str) -> TeraFnRet {
let time_flag = time_flag.to_string();
Box::new(
move |args: &HashMap<String, Value>| -> tera::Result<Value> {
match args.get("time") {
Some(val) => match tera::from_value::<String>(val.clone()) {
Ok(v) => {
let time = v.parse::<DateTime<Utc>>().unwrap();
Ok(
tera::to_value(format!("<t:{}:{}>", time.timestamp(), time_flag))
.unwrap(),
)
}
Err(_) => Err("Failed to parse value as time".into()),
},
None => Err("Missing parameter".into()),
}
},
)
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DiscordUser {
pub(crate) display_name: String,
pub(crate) mention: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Tally {
target: String,
votes: u64,
}
impl From<&Member> for DiscordUser {
fn from(m: &Member) -> Self {
Self {
display_name: m.display_name().to_string(),
mention: m.mention().to_string(),
}
}
}
#[derive(Debug, Clone)]
pub struct MessageTemplates {
templates: Tera,
}
impl MessageTemplates {
pub fn build_welcome_message(
&self,
global_data: &GlobalData,
discord_user: &DiscordUser,
player_data: &PlayerData,
) -> Result<String, tera::Error> {
let mut context = tera::Context::new();
context.insert("game_cfg", global_data.game_cfg().unwrap());
context.insert("game_state", global_data.game_state().unwrap());
context.insert("discord_user", discord_user);
context.insert("player_data", player_data);
let mut msg = self.templates.render("welcome_message", &context)?;
msg.push_str(&self.templates.render("status_message", &context)?);
Ok(msg)
}
pub fn build_satus_message(&self, global_data: &GlobalData) -> Result<String, tera::Error> {
let mut context = tera::Context::new();
context.insert("game_cfg", global_data.game_cfg().unwrap());
context.insert("game_state", global_data.game_state().unwrap());
self.templates.render("status_message", &context)
}
pub fn build_announcement(
&self,
global_data: &GlobalData,
message: &str,
) -> Result<String, tera::Error> {
let mut context = tera::Context::new();
context.insert("game_cfg", global_data.game_cfg().unwrap());
context.insert("game_state", global_data.game_state().unwrap());
context.insert("message", message);
self.templates.render("announcement", &context)
}
pub fn build_vote_tally(&self, global_data: &GlobalData) -> Result<String, tera::Error> {
let mut context = tera::Context::new();
context.insert("game_cfg", global_data.game_cfg().unwrap());
context.insert("game_state", global_data.game_state().unwrap());
context.insert(
"tallies",
&global_data.game_state().unwrap().get_vote_tallies(),
);
self.templates.render("tally_message", &context)
}
pub fn build_vote_message(
&self,
global_data: &GlobalData,
player: &PlayerData,
target: &PlayerData,
) -> Result<String, tera::Error> {
let mut context = tera::Context::new();
context.insert("game_cfg", global_data.game_cfg().unwrap());
context.insert("game_state", global_data.game_state().unwrap());
context.insert("player_data", player);
context.insert("target_data", target);
self.templates.render("vote_message", &context)
}
pub fn build_phase_extend_message(
&self,
global_data: &GlobalData,
) -> Result<String, tera::Error> {
let mut context = tera::Context::new();
context.insert("game_cfg", global_data.game_cfg().unwrap());
context.insert("game_state", global_data.game_state().unwrap());
self.templates.render("phase_extend_message", &context)
}
pub fn build_name(
&self,
global_data: &GlobalData,
first_name: Option<String>,
last_name: Option<String>,
) -> Result<String, tera::Error> {
let mut context = tera::Context::new();
context.insert("game_cfg", global_data.game_cfg().unwrap());
context.insert("first_name", &first_name);
context.insert("last_name", &last_name);
self.templates.render("name_format", &context)
}
}
impl TryFrom<MessageConfig> for MessageTemplates {
type Error = tera::Error;
fn try_from(config: MessageConfig) -> Result<Self, Self::Error> {
let mut templates = Tera::default();
templates.register_function("to_countdown", time_to_discord_time("R"));
templates.register_function("to_local_time", time_to_discord_time("f"));
templates.add_raw_template("welcome_message", &config.welcome_message)?;
templates.add_raw_template("status_message", &config.status_message)?;
templates.add_raw_template("announcement", &config.announcement_format)?;
templates.add_raw_template("tally_message", &config.tally_message)?;
templates.add_raw_template("vote_message", &config.vote_message)?;
templates.add_raw_template("phase_extend_message", &config.phase_extend_message)?;
templates.add_raw_template("name_format", &config.name_format)?;
Ok(Self { templates })
}
}