Ported randoms to the DB
+ Also added commands for adding and listing randoms + fmt, clippy failing in a library...
This commit is contained in:
parent
766dc6f171
commit
95b965a4a9
@ -13,7 +13,6 @@ use std::collections::HashMap;
|
|||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
use tera::Tera;
|
|
||||||
use tokio::sync::mpsc::{channel, Receiver, Sender};
|
use tokio::sync::mpsc::{channel, Receiver, Sender};
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
@ -29,12 +28,6 @@ pub struct AlbumConfig {
|
|||||||
pub album_id: String,
|
pub album_id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
|
||||||
pub struct RandomConfig {
|
|
||||||
pub name: String,
|
|
||||||
pub responses: Vec<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||||
pub struct MotivationConfig {
|
pub struct MotivationConfig {
|
||||||
pub album: Vec<String>,
|
pub album: Vec<String>,
|
||||||
@ -57,9 +50,6 @@ pub struct BotConfig {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub albums: Vec<AlbumConfig>,
|
pub albums: Vec<AlbumConfig>,
|
||||||
|
|
||||||
#[serde(default)]
|
|
||||||
pub randoms: Vec<RandomConfig>,
|
|
||||||
|
|
||||||
pub motivation: MotivationConfig,
|
pub motivation: MotivationConfig,
|
||||||
|
|
||||||
pub insults: Vec<InsultComplimentTemplate>,
|
pub insults: Vec<InsultComplimentTemplate>,
|
||||||
@ -88,7 +78,6 @@ impl BotConfig {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct BotState {
|
pub struct BotState {
|
||||||
pub accepted_nsfw: Option<UserId>,
|
pub accepted_nsfw: Option<UserId>,
|
||||||
pub templates: HashMap<String, Tera>,
|
|
||||||
pub albums: HashMap<String, Vec<Image>>,
|
pub albums: HashMap<String, Vec<Image>>,
|
||||||
pub bad_apple_running: bool,
|
pub bad_apple_running: bool,
|
||||||
}
|
}
|
||||||
@ -96,18 +85,6 @@ pub struct BotState {
|
|||||||
impl BotState {
|
impl BotState {
|
||||||
pub async fn new(cfg: &BotConfig) -> Result<Self, Error> {
|
pub async fn new(cfg: &BotConfig) -> Result<Self, Error> {
|
||||||
let mut albums: HashMap<String, Vec<Image>> = HashMap::new();
|
let mut albums: HashMap<String, Vec<Image>> = HashMap::new();
|
||||||
let mut templates = HashMap::new();
|
|
||||||
|
|
||||||
for random_config in cfg.randoms.iter() {
|
|
||||||
let mut templates_set = Tera::default();
|
|
||||||
for (idx, response) in random_config.responses.iter().enumerate() {
|
|
||||||
templates_set
|
|
||||||
.add_raw_template(&idx.to_string(), response)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
templates.insert(random_config.name.clone(), templates_set);
|
|
||||||
}
|
|
||||||
|
|
||||||
for album in &cfg.albums {
|
for album in &cfg.albums {
|
||||||
albums.insert(
|
albums.insert(
|
||||||
@ -118,7 +95,6 @@ impl BotState {
|
|||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
accepted_nsfw: None,
|
accepted_nsfw: None,
|
||||||
templates,
|
|
||||||
albums,
|
albums,
|
||||||
bad_apple_running: false,
|
bad_apple_running: false,
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
|
use crate::models::random::RandomConfig;
|
||||||
use crate::{command, group, GlobalData, BAD_APPLE};
|
use crate::{command, group, GlobalData, BAD_APPLE};
|
||||||
use rand::prelude::IteratorRandom;
|
use rand::prelude::IteratorRandom;
|
||||||
use rand::thread_rng;
|
use rand::thread_rng;
|
||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serenity::client::Context;
|
use serenity::client::Context;
|
||||||
|
use serenity::constants::MESSAGE_CODE_LIMIT;
|
||||||
use serenity::framework::standard::{Args, CommandResult};
|
use serenity::framework::standard::{Args, CommandResult};
|
||||||
use serenity::model::channel::Message;
|
use serenity::model::channel::Message;
|
||||||
use serenity::utils::MessageBuilder;
|
use serenity::utils::MessageBuilder;
|
||||||
@ -12,7 +14,7 @@ use std::collections::HashMap;
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
#[group]
|
#[group]
|
||||||
#[commands(dad_joke, roll, bad_apple, insult)]
|
#[commands(dad_joke, roll, bad_apple, insult, add_random, list_random)]
|
||||||
pub struct Joke;
|
pub struct Joke;
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
@ -49,10 +51,7 @@ struct RandomCtx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RandomCtx {
|
impl RandomCtx {
|
||||||
pub async fn new(
|
pub fn new(user_name: &str, global_data: &GlobalData) -> Result<Self, Error> {
|
||||||
user: serenity::model::guild::Member,
|
|
||||||
global_data: &GlobalData,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let mut random_image: HashMap<String, String> = HashMap::new();
|
let mut random_image: HashMap<String, String> = HashMap::new();
|
||||||
|
|
||||||
for album in &global_data.cfg.albums {
|
for album in &global_data.cfg.albums {
|
||||||
@ -64,28 +63,42 @@ impl RandomCtx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
user: (*user.display_name()).clone(),
|
user: user_name.to_string(),
|
||||||
random_image,
|
random_image,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn render_random(
|
||||||
|
author_name: &str,
|
||||||
|
global_data: &GlobalData,
|
||||||
|
template: &str,
|
||||||
|
) -> Result<String, Error> {
|
||||||
|
let random_ctx = RandomCtx::new(author_name, global_data)?;
|
||||||
|
|
||||||
|
Ok(tera::Tera::one_off(
|
||||||
|
template,
|
||||||
|
&tera::Context::from_serialize(&random_ctx)?,
|
||||||
|
false,
|
||||||
|
)?)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn random(ctx: &Context, msg: &Message, random_name: &str) -> CommandResult {
|
pub async fn random(ctx: &Context, msg: &Message, random_name: &str) -> CommandResult {
|
||||||
let data = ctx.data.read().await;
|
let data = ctx.data.read().await;
|
||||||
let global_data = data.get::<GlobalData>().unwrap();
|
let global_data = data.get::<GlobalData>().unwrap();
|
||||||
|
|
||||||
let templates = global_data.bot_state.templates.get(random_name);
|
let random = match RandomConfig::get_random(&global_data.db, random_name)? {
|
||||||
|
None => return Ok(()),
|
||||||
let templates = if let Some(templates) = templates {
|
Some(r) => r,
|
||||||
templates
|
|
||||||
} else {
|
|
||||||
return Ok(());
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let template = {
|
let response_template_str = match random.get_response()? {
|
||||||
let mut rng = thread_rng();
|
None => {
|
||||||
|
msg.reply(&ctx, format!("I'm all out of material for {}", random_name))
|
||||||
templates.get_template_names().choose(&mut rng)
|
.await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
Some(resp) => resp,
|
||||||
};
|
};
|
||||||
|
|
||||||
let guild_member = msg
|
let guild_member = msg
|
||||||
@ -94,13 +107,11 @@ pub async fn random(ctx: &Context, msg: &Message, random_name: &str) -> CommandR
|
|||||||
.member(&ctx.http, msg.author.id)
|
.member(&ctx.http, msg.author.id)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let random_ctx = RandomCtx::new(guild_member, global_data).await?;
|
let reply = render_random(
|
||||||
|
&guild_member.display_name(),
|
||||||
let reply = if let Some(template) = template {
|
global_data,
|
||||||
templates.render(template, &tera::Context::from_serialize(&random_ctx)?)?
|
response_template_str,
|
||||||
} else {
|
)?;
|
||||||
"Sorry kid, all out of messages.".to_string()
|
|
||||||
};
|
|
||||||
|
|
||||||
msg.reply(&ctx.http, reply).await?;
|
msg.reply(&ctx.http, reply).await?;
|
||||||
|
|
||||||
@ -108,7 +119,87 @@ pub async fn random(ctx: &Context, msg: &Message, random_name: &str) -> CommandR
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
#[only_in(guilds)]
|
#[example("8ball Funny Response haha")]
|
||||||
|
pub async fn add_random(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
|
||||||
|
if args.len() < 2 {
|
||||||
|
msg.reply(
|
||||||
|
&ctx.http,
|
||||||
|
"Look kid, you need to provide both the random name and response",
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = ctx.data.read().await;
|
||||||
|
let global_data = data.get::<GlobalData>().unwrap();
|
||||||
|
|
||||||
|
let random_name = args.parse::<String>()?;
|
||||||
|
args.advance();
|
||||||
|
let random_response = args.rest();
|
||||||
|
|
||||||
|
if let Err(err) = render_random(&msg.author.name, global_data, random_response) {
|
||||||
|
msg.reply(
|
||||||
|
&ctx.http,
|
||||||
|
format!("Template failed test render, try again: {}", err),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
} else {
|
||||||
|
RandomConfig::add_random(&global_data.db, &random_name, random_response)?;
|
||||||
|
msg.reply(&ctx.http, "New random added!").await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[command]
|
||||||
|
#[example("8ball Funny Response haha")]
|
||||||
|
pub async fn list_random(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
||||||
|
if args.len() < 1 {
|
||||||
|
msg.reply(
|
||||||
|
&ctx.http,
|
||||||
|
"Look kid, you need to provide both the random name",
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = ctx.data.read().await;
|
||||||
|
let global_data = data.get::<GlobalData>().unwrap();
|
||||||
|
|
||||||
|
let random_name = args.parse::<String>()?;
|
||||||
|
|
||||||
|
let random = RandomConfig::get_random(&global_data.db, &random_name)?;
|
||||||
|
|
||||||
|
if let Some(random) = random {
|
||||||
|
let mut msg_builder = MessageBuilder::new();
|
||||||
|
msg_builder.push_line(format!("All possible responses for {}:", random_name));
|
||||||
|
|
||||||
|
for resp in random.responses {
|
||||||
|
let line_msg = format!("* {}", resp);
|
||||||
|
|
||||||
|
if (msg_builder.0.len() + line_msg.len()) > MESSAGE_CODE_LIMIT {
|
||||||
|
msg.channel_id.say(&ctx.http, msg_builder.build()).await?;
|
||||||
|
msg_builder.0.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
msg_builder.push_line(line_msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !msg_builder.0.is_empty() {
|
||||||
|
msg.channel_id.say(&ctx.http, msg_builder.build()).await?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
msg.reply(
|
||||||
|
&ctx.http,
|
||||||
|
"*glances to the back room*, nope we ain't got that random",
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[command]
|
||||||
#[aliases("roll")]
|
#[aliases("roll")]
|
||||||
#[description("Roll a die!")]
|
#[description("Roll a die!")]
|
||||||
async fn roll(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
async fn roll(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
||||||
@ -168,7 +259,6 @@ async fn bad_apple(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
|
|||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
#[aliases("compliment")]
|
#[aliases("compliment")]
|
||||||
#[only_in(guilds)]
|
|
||||||
async fn insult(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
async fn insult(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
||||||
let data = ctx.data.read().await;
|
let data = ctx.data.read().await;
|
||||||
let global = data.get::<GlobalData>().unwrap();
|
let global = data.get::<GlobalData>().unwrap();
|
||||||
|
|||||||
@ -4,6 +4,7 @@ mod error;
|
|||||||
mod imgur;
|
mod imgur;
|
||||||
mod insult_compliment;
|
mod insult_compliment;
|
||||||
mod inventory;
|
mod inventory;
|
||||||
|
mod models;
|
||||||
mod user;
|
mod user;
|
||||||
|
|
||||||
use crate::config::{Args, BotConfig, Channel, GlobalData};
|
use crate::config::{Args, BotConfig, Channel, GlobalData};
|
||||||
|
|||||||
1
src/models/mod.rs
Normal file
1
src/models/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub mod random;
|
||||||
60
src/models/random.rs
Normal file
60
src/models/random.rs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
use crate::error::Error;
|
||||||
|
use j_db::database::Database;
|
||||||
|
use j_db::model::JdbModel;
|
||||||
|
use rand::prelude::SliceRandom;
|
||||||
|
use rand::thread_rng;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||||
|
pub struct RandomConfig {
|
||||||
|
id: Option<u64>,
|
||||||
|
pub name: String,
|
||||||
|
pub responses: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JdbModel for RandomConfig {
|
||||||
|
fn id(&self) -> Option<u64> {
|
||||||
|
self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_id(&mut self, id: u64) {
|
||||||
|
self.id = Some(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tree() -> String {
|
||||||
|
"randoms".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_unique(&self, other: &Self) -> bool {
|
||||||
|
!self.name.eq_ignore_ascii_case(&other.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RandomConfig {
|
||||||
|
pub fn add_random(db: &Database, name: &str, response: &str) -> Result<(), Error> {
|
||||||
|
let mut random = match Self::get_random(db, name)? {
|
||||||
|
None => db.insert::<RandomConfig>(Self {
|
||||||
|
id: None,
|
||||||
|
name: name.to_string(),
|
||||||
|
responses: vec![],
|
||||||
|
})?,
|
||||||
|
Some(random) => random,
|
||||||
|
};
|
||||||
|
|
||||||
|
random.responses.push(response.to_string());
|
||||||
|
|
||||||
|
db.insert::<RandomConfig>(random)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_random(db: &Database, name: &str) -> Result<Option<Self>, Error> {
|
||||||
|
Ok(db
|
||||||
|
.filter(|_, random: &RandomConfig| random.name.eq_ignore_ascii_case(name))?
|
||||||
|
.next())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_response(&self) -> Result<Option<&String>, Error> {
|
||||||
|
Ok(self.responses.choose(&mut thread_rng()))
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user