Updated fortune commands with templates
+ Clippy + fmt
This commit is contained in:
+24
-1
@@ -4,6 +4,7 @@ use serenity::model::prelude::UserId;
|
||||
use serenity::prelude::TypeMapKey;
|
||||
use std::path::{Path, PathBuf};
|
||||
use structopt::StructOpt;
|
||||
use tera::Tera;
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
#[structopt(name = "fren", about = "Friend Bot")]
|
||||
@@ -45,9 +46,10 @@ impl BotConfig {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BotState {
|
||||
pub accepted_nsfw: Option<UserId>,
|
||||
pub fortune_templates: Tera,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -57,6 +59,27 @@ pub struct GlobalData {
|
||||
pub bot_state: BotState,
|
||||
}
|
||||
|
||||
impl GlobalData {
|
||||
pub fn new(args: Args, cfg: BotConfig) -> Self {
|
||||
let mut fortune_templates = Tera::default();
|
||||
|
||||
for (idx, fortune) in cfg.fortunes.iter().enumerate() {
|
||||
fortune_templates
|
||||
.add_raw_template(&idx.to_string(), fortune)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
Self {
|
||||
args,
|
||||
cfg,
|
||||
bot_state: BotState {
|
||||
accepted_nsfw: None,
|
||||
fortune_templates,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeMapKey for GlobalData {
|
||||
type Value = GlobalData;
|
||||
}
|
||||
|
||||
+1
-35
@@ -1,8 +1,6 @@
|
||||
use crate::config::AlbumConfig;
|
||||
use crate::error::Error;
|
||||
use crate::imgur::Image;
|
||||
use crate::{command, group, imgur, GlobalData};
|
||||
use rand::prelude::SliceRandom;
|
||||
use serenity::client::Context;
|
||||
use serenity::framework::standard::{Args, CommandResult};
|
||||
use serenity::model::channel::Message;
|
||||
@@ -132,7 +130,7 @@ pub async fn parse_album(
|
||||
.find(|album| album.name.to_lowercase() == album_name);
|
||||
|
||||
if let Some(album) = album {
|
||||
match get_image(album, global_data, tags).await {
|
||||
match imgur::get_image(album, global_data, tags).await {
|
||||
Ok(image) => {
|
||||
if let Some(image) = image {
|
||||
msg.reply(&ctx.http, &image.link).await?;
|
||||
@@ -149,35 +147,3 @@ pub async fn parse_album(
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_image(
|
||||
album_config: &AlbumConfig,
|
||||
global_data: &GlobalData,
|
||||
tags: Vec<&str>,
|
||||
) -> Result<Option<Image>, Error> {
|
||||
let album =
|
||||
imgur::get_album_images(&global_data.cfg.imgur_client_id, &album_config.album_id).await?;
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let album = if tags.is_empty() {
|
||||
album
|
||||
} else {
|
||||
album
|
||||
.iter()
|
||||
.filter(|img| {
|
||||
for tag in &tags {
|
||||
if let Some(desc) = &img.description {
|
||||
if desc.to_lowercase().contains(&tag.to_lowercase()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
})
|
||||
.cloned()
|
||||
.collect()
|
||||
};
|
||||
|
||||
Ok(album.choose(&mut rng).cloned())
|
||||
}
|
||||
|
||||
+51
-8
@@ -1,11 +1,14 @@
|
||||
use crate::error::Error;
|
||||
use crate::imgur::get_image;
|
||||
use crate::{command, group, GlobalData};
|
||||
use rand::prelude::SliceRandom;
|
||||
use rand::prelude::IteratorRandom;
|
||||
use rand::thread_rng;
|
||||
use reqwest::Client;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serenity::client::Context;
|
||||
use serenity::framework::standard::{Args, CommandResult};
|
||||
use serenity::model::channel::Message;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
struct DadJoke {
|
||||
@@ -38,23 +41,63 @@ async fn dad_joke(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct FortuneCtx {
|
||||
user: serenity::model::guild::Member,
|
||||
random_image: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl FortuneCtx {
|
||||
pub async fn new(
|
||||
user: serenity::model::guild::Member,
|
||||
global_data: &GlobalData,
|
||||
) -> Result<Self, Error> {
|
||||
let mut random_image: HashMap<String, String> = HashMap::new();
|
||||
|
||||
for album in &global_data.cfg.albums {
|
||||
let image = get_image(album, global_data, Vec::new()).await?;
|
||||
|
||||
if let Some(image) = image {
|
||||
random_image.insert(album.name.clone(), image.link);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Self { user, random_image })
|
||||
}
|
||||
}
|
||||
|
||||
#[command]
|
||||
#[only_in(guilds)]
|
||||
#[aliases("8ball")]
|
||||
#[description("Ask your dad")]
|
||||
#[description("Use as your own risk")]
|
||||
async fn fortune(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
|
||||
let data = ctx.data.read().await;
|
||||
let global_data = data.get::<GlobalData>().unwrap();
|
||||
|
||||
let fortune = {
|
||||
let fortune_template = {
|
||||
let mut rng = thread_rng();
|
||||
|
||||
global_data.cfg.fortunes.choose(&mut rng)
|
||||
global_data
|
||||
.bot_state
|
||||
.fortune_templates
|
||||
.get_template_names()
|
||||
.choose(&mut rng)
|
||||
};
|
||||
|
||||
let reply = match fortune {
|
||||
None => "Sorry kid, all out of fortunes.".to_string(),
|
||||
Some(msg) => msg.clone(),
|
||||
let guild_member = msg
|
||||
.guild(&ctx.cache)
|
||||
.unwrap()
|
||||
.member(&ctx.http, msg.author.id)
|
||||
.await?;
|
||||
|
||||
let fortune_ctx = FortuneCtx::new(guild_member, global_data).await?;
|
||||
|
||||
let reply = if let Some(fortune_template) = fortune_template {
|
||||
global_data.bot_state.fortune_templates.render(
|
||||
fortune_template,
|
||||
&tera::Context::from_serialize(&fortune_ctx)?,
|
||||
)?
|
||||
} else {
|
||||
"Sorry kid, all out of fortunes.".to_string()
|
||||
};
|
||||
|
||||
msg.reply(&ctx.http, reply).await?;
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
use crate::imgur::ImgurError;
|
||||
use serde::ser::StdError;
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
#[allow(dead_code)]
|
||||
pub enum Error {
|
||||
ConfigError(config::ConfigError),
|
||||
ImgurError(ImgurError),
|
||||
SerenityError(serenity::Error),
|
||||
TeraError(tera::Error),
|
||||
}
|
||||
|
||||
impl StdError for Error {}
|
||||
|
||||
impl From<config::ConfigError> for Error {
|
||||
fn from(e: config::ConfigError) -> Self {
|
||||
Self::ConfigError(e)
|
||||
@@ -33,6 +38,7 @@ impl Display for Error {
|
||||
Error::ConfigError(e) => write!(f, "Config error: {}", e),
|
||||
Error::ImgurError(e) => write!(f, "Imgur error: {}", e),
|
||||
Error::SerenityError(e) => write!(f, "Discord error: {}", e),
|
||||
Error::TeraError(e) => write!(f, "Tera error: {}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
use crate::config::AlbumConfig;
|
||||
use crate::error::Error;
|
||||
use crate::GlobalData;
|
||||
use rand::prelude::SliceRandom;
|
||||
use reqwest::Client;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{Display, Formatter};
|
||||
@@ -71,3 +75,34 @@ pub async fn get_album_images(client_id: &str, album_hash: &str) -> Result<Vec<I
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_image(
|
||||
album_config: &AlbumConfig,
|
||||
global_data: &GlobalData,
|
||||
tags: Vec<&str>,
|
||||
) -> Result<Option<Image>, Error> {
|
||||
let album = get_album_images(&global_data.cfg.imgur_client_id, &album_config.album_id).await?;
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let album = if tags.is_empty() {
|
||||
album
|
||||
} else {
|
||||
album
|
||||
.iter()
|
||||
.filter(|img| {
|
||||
for tag in &tags {
|
||||
if let Some(desc) = &img.description {
|
||||
if desc.to_lowercase().contains(&tag.to_lowercase()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
})
|
||||
.cloned()
|
||||
.collect()
|
||||
};
|
||||
|
||||
Ok(album.choose(&mut rng).cloned())
|
||||
}
|
||||
|
||||
+2
-6
@@ -3,7 +3,7 @@ mod discord;
|
||||
mod error;
|
||||
mod imgur;
|
||||
|
||||
use crate::config::{Args, BotConfig, BotState, GlobalData};
|
||||
use crate::config::{Args, BotConfig, GlobalData};
|
||||
use crate::discord::unrecognised_command_hook;
|
||||
use serenity::framework::standard::macros::{command, group, help, hook};
|
||||
use serenity::framework::standard::StandardFramework;
|
||||
@@ -22,11 +22,7 @@ async fn main() {
|
||||
}
|
||||
};
|
||||
|
||||
let global_data = GlobalData {
|
||||
args,
|
||||
cfg,
|
||||
bot_state: BotState::default(),
|
||||
};
|
||||
let global_data = GlobalData::new(args, cfg);
|
||||
|
||||
let framework = StandardFramework::new()
|
||||
.configure(|c| c.with_whitespace(true).prefix("!").ignore_bots(true))
|
||||
|
||||
Reference in New Issue
Block a user