removed all remaining instances of UserData::response. languagemanager now loads from string compiled into executable. languagemanager falls back properly. removed unnecessary param from language_of

This commit is contained in:
jellywx 2020-11-22 01:31:50 +00:00
parent 6a7491d094
commit d8bf0240e4
9 changed files with 371 additions and 346 deletions

View File

@ -16,7 +16,9 @@ Reminder Bot can be built by running `cargo build --release` in the top level di
#### Compilation environment variables
These environment variables must be provided when compiling the bot
* `DATABASE_URL` - the URL of your MySQL database (`mysql://user[:password]@domain/database`)
* `WEBHOOK_AVATAR` - accepts the name of an image file located in `$CARGO_MANIFEST_DIR/assets/` to be used as the avatar when creating webhooks. **IMPORTANT: image file must be 128x128 or smaller in size**
* `STRINGS_FILE` - accepts the name of a compiled strings file located in `$CARGO_MANIFEST_DIR/assets/` to be used for creating messages. Compiled string files can be generated with `compile.py` at https://github.com/reminder-bot/languages
### Setting up Python
Reminder Bot by default looks for a venv within it's working directory to run Python out of. To set up a venv, install `python3-venv` and run `python3 -m venv venv`. Then, run `source venv/bin/activate` to activate the venv, and do `pip install dateparser` to install the required library

View File

@ -41,7 +41,7 @@ async fn help(ctx: &Context, msg: &Message, _args: String) {
let lm = data.get::<LanguageManager>().unwrap();
let language = UserData::language_of(&msg.author, &ctx, &pool).await;
let language = UserData::language_of(&msg.author, &pool).await;
let desc = lm.get(&language, "help");
@ -75,7 +75,7 @@ async fn info(ctx: &Context, msg: &Message, _args: String) {
let lm = data.get::<LanguageManager>().unwrap();
let language = UserData::language_of(&msg.author, &ctx, &pool).await;
let language = UserData::language_of(&msg.author, &pool).await;
let guild_data = GuildData::from_guild(msg.guild(&ctx).await.unwrap(), &pool)
.await
.unwrap();
@ -116,7 +116,7 @@ async fn donate(ctx: &Context, msg: &Message, _args: String) {
let lm = data.get::<LanguageManager>().unwrap();
let language = UserData::language_of(&msg.author, &ctx, &pool).await;
let language = UserData::language_of(&msg.author, &pool).await;
let desc = lm.get(&language, "donate");
let _ = msg
@ -161,28 +161,26 @@ async fn dashboard(ctx: &Context, msg: &Message, _args: String) {
#[command]
async fn clock(ctx: &Context, msg: &Message, args: String) {
let pool = ctx
.data
.read()
.await
let data = ctx.data.read().await;
let pool = data
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
let lm = data.get::<LanguageManager>().unwrap();
let user_data = UserData::from_user(&msg.author, &ctx, &pool).await.unwrap();
let now = Utc::now().with_timezone(&user_data.timezone());
let clock_display = lm.get(&user_data.language, "clock/time");
if args == "12" {
let _ = msg
.channel_id
.say(
&ctx,
user_data.response(&pool, "clock/time").await.replacen(
"{}",
&now.format("%I:%M:%S %p").to_string(),
1,
),
clock_display.replacen("{}", &now.format("%I:%M:%S %p").to_string(), 1),
)
.await;
} else {
@ -190,11 +188,7 @@ async fn clock(ctx: &Context, msg: &Message, args: String) {
.channel_id
.say(
&ctx,
user_data.response(&pool, "clock/time").await.replacen(
"{}",
&now.format("%H:%M:%S").to_string(),
1,
),
clock_display.replacen("{}", &now.format("%H:%M:%S").to_string(), 1),
)
.await;
}

View File

@ -19,6 +19,7 @@ use crate::{
FrameworkCtx, SQLPool,
};
use crate::language_manager::LanguageManager;
use serenity::model::id::ChannelId;
use std::iter;
@ -27,13 +28,19 @@ use std::iter;
#[permission_level(Restricted)]
#[can_blacklist(false)]
async fn blacklist(ctx: &Context, msg: &Message, args: String) {
let pool = ctx
.data
.read()
.await
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
let pool;
let lm;
{
let data = ctx.data.read().await;
pool = data
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
lm = data.get::<LanguageManager>().cloned().unwrap();
}
let user_data = UserData::from_user(&msg.author, &ctx, &pool).await.unwrap();
@ -64,30 +71,24 @@ async fn blacklist(ctx: &Context, msg: &Message, args: String) {
if local {
let _ = msg
.channel_id
.say(&ctx, user_data.response(&pool, "blacklist/added").await)
.say(&ctx, lm.get(&user_data.language, "blacklist/added"))
.await;
} else {
let _ = msg
.channel_id
.say(
&ctx,
user_data.response(&pool, "blacklist/added_from").await,
)
.say(&ctx, lm.get(&user_data.language, "blacklist/added_from"))
.await;
}
} else {
if local {
let _ = msg
.channel_id
.say(&ctx, user_data.response(&pool, "blacklist/removed").await)
.say(&ctx, lm.get(&user_data.language, "blacklist/removed"))
.await;
} else {
let _ = msg
.channel_id
.say(
&ctx,
user_data.response(&pool, "blacklist/removed_from").await,
)
.say(&ctx, lm.get(&user_data.language, "blacklist/removed_from"))
.await;
}
}
@ -95,13 +96,19 @@ async fn blacklist(ctx: &Context, msg: &Message, args: String) {
#[command]
async fn timezone(ctx: &Context, msg: &Message, args: String) {
let pool = ctx
.data
.read()
.await
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
let pool;
let lm;
{
let data = ctx.data.read().await;
pool = data
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
lm = data.get::<LanguageManager>().cloned().unwrap();
}
let mut user_data = UserData::from_user(&msg.author, &ctx, &pool).await.unwrap();
@ -113,9 +120,8 @@ async fn timezone(ctx: &Context, msg: &Message, args: String) {
let now = Utc::now().with_timezone(&user_data.timezone());
let content = user_data
.response(&pool, "timezone/set_p")
.await
let content = lm
.get(&user_data.language, "timezone/set_p")
.replacen("{timezone}", &user_data.timezone, 1)
.replacen("{time}", &now.format("%H:%M").to_string(), 1);
@ -125,17 +131,13 @@ async fn timezone(ctx: &Context, msg: &Message, args: String) {
Err(_) => {
let _ = msg
.channel_id
.say(
&ctx,
user_data.response(&pool, "timezone/no_timezone").await,
)
.say(&ctx, lm.get(&user_data.language, "timezone/no_timezone"))
.await;
}
}
} else {
let content = user_data
.response(&pool, "timezone/no_argument")
.await
let content = lm
.get(&user_data.language, "timezone/no_argument")
.replace(
"{prefix}",
&GuildData::prefix_from_id(msg.guild_id, &pool).await,
@ -148,57 +150,43 @@ async fn timezone(ctx: &Context, msg: &Message, args: String) {
#[command]
async fn language(ctx: &Context, msg: &Message, args: String) {
let pool = ctx
.data
.read()
.await
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
let pool;
let lm;
{
let data = ctx.data.read().await;
pool = data
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
lm = data.get::<LanguageManager>().cloned().unwrap();
}
let mut user_data = UserData::from_user(&msg.author, &ctx, &pool).await.unwrap();
match sqlx::query!(
"
SELECT code FROM languages WHERE code = ? OR name = ?
",
args,
args
)
.fetch_one(&pool)
.await
{
Ok(row) => {
user_data.language = row.code;
match lm.get_language(&args) {
Some(row) => {
user_data.language = row.to_string();
user_data.commit_changes(&pool).await;
let _ = msg
.channel_id
.say(&ctx, user_data.response(&pool, "lang/set_p").await)
.say(&ctx, lm.get(&user_data.language, "lang/set_p"))
.await;
}
Err(_) => {
let language_codes = sqlx::query!("SELECT name, code FROM languages")
.fetch_all(&pool)
.await
.unwrap()
.iter()
.map(|language| {
format!(
"{} ({})",
language.name.to_title_case(),
language.code.to_uppercase()
)
})
None => {
let language_codes = lm
.all_languages()
.map(|(k, v)| format!("{} ({})", v.to_title_case(), k.to_uppercase()))
.collect::<Vec<String>>()
.join("\n");
let content =
user_data
.response(&pool, "lang/invalid")
.await
lm.get(&user_data.language, "lang/invalid")
.replacen("{}", &language_codes, 1);
let _ = msg.channel_id.say(&ctx, content).await;
@ -210,13 +198,19 @@ SELECT code FROM languages WHERE code = ? OR name = ?
#[supports_dm(false)]
#[permission_level(Restricted)]
async fn prefix(ctx: &Context, msg: &Message, args: String) {
let pool = ctx
.data
.read()
.await
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
let pool;
let lm;
{
let data = ctx.data.read().await;
pool = data
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
lm = data.get::<LanguageManager>().cloned().unwrap();
}
let mut guild_data = GuildData::from_guild(msg.guild(&ctx).await.unwrap(), &pool)
.await
@ -226,18 +220,18 @@ async fn prefix(ctx: &Context, msg: &Message, args: String) {
if args.len() > 5 {
let _ = msg
.channel_id
.say(&ctx, user_data.response(&pool, "prefix/too_long").await)
.say(&ctx, lm.get(&user_data.language, "prefix/too_long"))
.await;
} else if args.is_empty() {
let _ = msg
.channel_id
.say(&ctx, user_data.response(&pool, "prefix/no_argument").await)
.say(&ctx, lm.get(&user_data.language, "prefix/no_argument"))
.await;
} else {
guild_data.prefix = args;
guild_data.commit_changes(&pool).await;
let content = user_data.response(&pool, "prefix/success").await.replacen(
let content = lm.get(&user_data.language, "prefix/success").replacen(
"{prefix}",
&guild_data.prefix,
1,
@ -251,13 +245,19 @@ async fn prefix(ctx: &Context, msg: &Message, args: String) {
#[supports_dm(false)]
#[permission_level(Restricted)]
async fn restrict(ctx: &Context, msg: &Message, args: String) {
let pool = ctx
.data
.read()
.await
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
let pool;
let lm;
{
let data = ctx.data.read().await;
pool = data
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
lm = data.get::<LanguageManager>().cloned().unwrap();
}
let user_data = UserData::from_user(&msg.author, &ctx, &pool).await.unwrap();
let guild_data = GuildData::from_guild(msg.guild(&ctx).await.unwrap(), &pool)
@ -292,7 +292,7 @@ DELETE FROM command_restrictions WHERE role_id = (SELECT id FROM roles WHERE rol
if commands.is_empty() {
let _ = msg
.channel_id
.say(&ctx, user_data.response(&pool, "restrict/disabled").await)
.say(&ctx, lm.get(&user_data.language, "restrict/disabled"))
.await;
} else {
let _ = sqlx::query!(
@ -317,10 +317,11 @@ INSERT INTO command_restrictions (role_id, command) VALUES ((SELECT id FROM role
if res.is_err() {
println!("{:?}", res);
let content = user_data
.response(&pool, "restrict/failure")
.await
.replacen("{command}", &command, 1);
let content = lm.get(&user_data.language, "restrict/failure").replacen(
"{command}",
&command,
1,
);
let _ = msg.channel_id.say(&ctx, content).await;
}
@ -328,7 +329,7 @@ INSERT INTO command_restrictions (role_id, command) VALUES ((SELECT id FROM role
let _ = msg
.channel_id
.say(&ctx, user_data.response(&pool, "restrict/enabled").await)
.say(&ctx, lm.get(&user_data.language, "restrict/enabled"))
.await;
}
}
@ -359,16 +360,15 @@ WHERE
.map(|row| format!("<@&{}> can use {}", row.role, row.command))
.collect::<Vec<String>>()
.join("\n");
let display = user_data
.response(&pool, "restrict/allowed")
.await
.replacen("{}", &display_inner, 1);
let display =
lm.get(&user_data.language, "restrict/allowed")
.replacen("{}", &display_inner, 1);
let _ = msg.channel_id.say(&ctx, display).await;
} else {
let _ = msg
.channel_id
.say(&ctx, user_data.response(&pool, "restrict/help").await)
.say(&ctx, lm.get(&user_data.language, "restrict/help"))
.await;
}
}
@ -377,13 +377,19 @@ WHERE
#[supports_dm(false)]
#[permission_level(Managed)]
async fn alias(ctx: &Context, msg: &Message, args: String) {
let pool = ctx
.data
.read()
.await
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
let pool;
let lm;
{
let data = ctx.data.read().await;
pool = data
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
lm = data.get::<LanguageManager>().cloned().unwrap();
}
let user_data = UserData::from_user(&msg.author, &ctx, &pool).await.unwrap();
@ -437,16 +443,15 @@ DELETE FROM command_aliases WHERE name = ? AND guild_id = (SELECT id FROM guilds
.await
.unwrap();
let content = user_data
.response(&pool, "alias/removed")
.await
let content = lm
.get(&user_data.language, "alias/removed")
.replace("{count}", &deleted_count.count.to_string());
let _ = msg.channel_id.say(&ctx, content).await;
} else {
let _ = msg
.channel_id
.say(&ctx, user_data.response(&pool, "alias/help").await)
.say(&ctx, lm.get(&user_data.language, "alias/help"))
.await;
}
}
@ -470,9 +475,8 @@ UPDATE command_aliases SET command = ? WHERE guild_id = (SELECT id FROM guilds W
.unwrap();
}
let content = user_data
.response(&pool, "alias/created")
.await
let content = lm
.get(&user_data.language, "alias/created")
.replace("{name}", name);
let _ = msg.channel_id.say(&ctx, content).await;
@ -495,7 +499,7 @@ SELECT command FROM command_aliases WHERE guild_id = (SELECT id FROM guilds WHER
},
Err(_) => {
let content = user_data.response(&pool, "alias/not_found").await.replace("{name}", name);
let content = lm.get(&user_data.language, "alias/not_found").replace("{name}", name);
let _ = msg.channel_id.say(&ctx, content).await;
},
@ -505,9 +509,8 @@ SELECT command FROM command_aliases WHERE guild_id = (SELECT id FROM guilds WHER
}
} else {
let prefix = GuildData::prefix_from_id(msg.guild_id, &pool).await;
let content = user_data
.response(&pool, "alias/help")
.await
let content = lm
.get(&user_data.language, "alias/help")
.replace("{prefix}", &prefix);
let _ = msg.channel_id.say(&ctx, content).await;

View File

@ -50,6 +50,7 @@ use std::{
time::{SystemTime, UNIX_EPOCH},
};
use crate::language_manager::LanguageManager;
use regex::RegexBuilder;
fn shorthand_displacement(seconds: u64) -> String {
@ -113,13 +114,19 @@ async fn create_webhook(
#[supports_dm(false)]
#[permission_level(Restricted)]
async fn pause(ctx: &Context, msg: &Message, args: String) {
let pool = ctx
.data
.read()
.await
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
let pool;
let lm;
{
let data = ctx.data.read().await;
pool = data
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
lm = data.get::<LanguageManager>().cloned().unwrap();
}
let user_data = UserData::from_user(&msg.author, &ctx, &pool).await.unwrap();
let mut channel = ChannelData::from_channel(msg.channel(&ctx).await.unwrap(), &pool)
@ -135,19 +142,16 @@ async fn pause(ctx: &Context, msg: &Message, args: String) {
if channel.paused {
let _ = msg
.channel_id
.say(
&ctx,
user_data.response(&pool, "pause/paused_indefinite").await,
)
.say(&ctx, lm.get(&user_data.language, "pause/paused_indefinite"))
.await;
} else {
let _ = msg
.channel_id
.say(&ctx, user_data.response(&pool, "pause/unpaused").await)
.say(&ctx, lm.get(&user_data.language, "pause/unpaused"))
.await;
}
} else {
let parser = TimeParser::new(args, user_data.timezone.parse().unwrap());
let parser = TimeParser::new(args, user_data.timezone());
let pause_until = parser.timestamp();
match pause_until {
@ -159,17 +163,14 @@ async fn pause(ctx: &Context, msg: &Message, args: String) {
channel.commit_changes(&pool).await;
let content = user_data
.response(&pool, "pause/paused_until")
.await
.replace(
"{}",
&user_data
.timezone()
.timestamp(timestamp, 0)
.format("%Y-%m-%d %H:%M:%S")
.to_string(),
);
let content = lm.get(&user_data.language, "pause/paused_until").replace(
"{}",
&user_data
.timezone()
.timestamp(timestamp, 0)
.format("%Y-%m-%d %H:%M:%S")
.to_string(),
);
let _ = msg.channel_id.say(&ctx, content).await;
}
@ -177,7 +178,7 @@ async fn pause(ctx: &Context, msg: &Message, args: String) {
Err(_) => {
let _ = msg
.channel_id
.say(&ctx, user_data.response(&pool, "pause/invalid_time").await)
.say(&ctx, lm.get(&user_data.language, "pause/invalid_time"))
.await;
}
}
@ -187,20 +188,26 @@ async fn pause(ctx: &Context, msg: &Message, args: String) {
#[command]
#[permission_level(Restricted)]
async fn offset(ctx: &Context, msg: &Message, args: String) {
let pool = ctx
.data
.read()
.await
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
let pool;
let lm;
{
let data = ctx.data.read().await;
pool = data
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
lm = data.get::<LanguageManager>().cloned().unwrap();
}
let user_data = UserData::from_user(&msg.author, &ctx, &pool).await.unwrap();
if args.is_empty() {
let _ = msg
.channel_id
.say(&ctx, user_data.response(&pool, "offset/help").await)
.say(&ctx, lm.get(&user_data.language, "offset/help"))
.await;
} else {
let parser = TimeParser::new(args, user_data.timezone());
@ -237,7 +244,7 @@ UPDATE reminders SET `time` = `time` + ? WHERE reminders.channel_id = ?
.unwrap();
}
let response = user_data.response(&pool, "offset/success").await.replacen(
let response = lm.get(&user_data.language, "offset/success").replacen(
"{}",
&displacement.to_string(),
1,
@ -247,7 +254,7 @@ UPDATE reminders SET `time` = `time` + ? WHERE reminders.channel_id = ?
} else {
let _ = msg
.channel_id
.say(&ctx, user_data.response(&pool, "offset/invalid_time").await)
.say(&ctx, lm.get(&user_data.language, "offset/invalid_time"))
.await;
}
}
@ -256,13 +263,19 @@ UPDATE reminders SET `time` = `time` + ? WHERE reminders.channel_id = ?
#[command]
#[permission_level(Restricted)]
async fn nudge(ctx: &Context, msg: &Message, args: String) {
let pool = ctx
.data
.read()
.await
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
let pool;
let lm;
{
let data = ctx.data.read().await;
pool = data
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
lm = data.get::<LanguageManager>().cloned().unwrap();
}
let user_data = UserData::from_user(&msg.author, &ctx, &pool).await.unwrap();
let mut channel = ChannelData::from_channel(msg.channel(&ctx).await.unwrap(), &pool)
@ -270,9 +283,8 @@ async fn nudge(ctx: &Context, msg: &Message, args: String) {
.unwrap();
if args.is_empty() {
let content = user_data
.response(&pool, "nudge/no_argument")
.await
let content = lm
.get(&user_data.language, "nudge/no_argument")
.replace("{nudge}", &format!("{}s", &channel.nudge.to_string()));
let _ = msg.channel_id.say(&ctx, content).await;
@ -285,14 +297,14 @@ async fn nudge(ctx: &Context, msg: &Message, args: String) {
if displacement < i16::MIN as i64 || displacement > i16::MAX as i64 {
let _ = msg
.channel_id
.say(&ctx, user_data.response(&pool, "nudge/invalid_time").await)
.say(&ctx, lm.get(&user_data.language, "nudge/invalid_time"))
.await;
} else {
channel.nudge = displacement as i16;
channel.commit_changes(&pool).await;
let response = user_data.response(&pool, "nudge/success").await.replacen(
let response = lm.get(&user_data.language, "nudge/success").replacen(
"{}",
&displacement.to_string(),
1,
@ -305,7 +317,7 @@ async fn nudge(ctx: &Context, msg: &Message, args: String) {
Err(_) => {
let _ = msg
.channel_id
.say(&ctx, user_data.response(&pool, "nudge/invalid_time").await)
.say(&ctx, lm.get(&user_data.language, "nudge/invalid_time"))
.await;
}
}
@ -399,13 +411,19 @@ impl LookReminder {
#[command("look")]
#[permission_level(Managed)]
async fn look(ctx: &Context, msg: &Message, args: String) {
let pool = ctx
.data
.read()
.await
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
let pool;
let lm;
{
let data = ctx.data.read().await;
pool = data
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
lm = data.get::<LanguageManager>().cloned().unwrap();
}
let user_data = UserData::from_user(&msg.author, &ctx, &pool).await.unwrap();
@ -531,10 +549,10 @@ LIMIT
if reminders.is_empty() {
let _ = msg
.channel_id
.say(&ctx, user_data.response(&pool, "look/no_reminders").await)
.say(&ctx, lm.get(&user_data.language, "look/no_reminders"))
.await;
} else {
let inter = user_data.response(&pool, "look/inter").await;
let inter = lm.get(&user_data.language, "look/inter");
let display = reminders.iter().map(|reminder| {
let time_display = match flags.time_display {
@ -568,19 +586,25 @@ LIMIT
#[command("del")]
#[permission_level(Managed)]
async fn delete(ctx: &Context, msg: &Message, _args: String) {
let pool = ctx
.data
.read()
.await
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
let pool;
let lm;
{
let data = ctx.data.read().await;
pool = data
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
lm = data.get::<LanguageManager>().cloned().unwrap();
}
let user_data = UserData::from_user(&msg.author, &ctx, &pool).await.unwrap();
let _ = msg
.channel_id
.say(&ctx, user_data.response(&pool, "del/listing").await)
.say(&ctx, lm.get(&user_data.language, "del/listing"))
.await;
let reminders = if let Some(guild_id) = msg.guild_id.map(|f| f.as_u64().to_owned()) {
@ -658,7 +682,7 @@ WHERE
let _ = msg.channel_id.say_lines(&ctx, enumerated_reminders).await;
let _ = msg
.channel_id
.say(&ctx, user_data.response(&pool, "del/listed").await)
.say(&ctx, lm.get(&user_data.language, "del/listed"))
.await;
let reply = msg
@ -721,7 +745,7 @@ INSERT INTO events (event_name, bulk_count, guild_id, user_id) VALUES ('delete',
.await;
}
let content = user_data.response(&pool, "del/count").await.replacen(
let content = lm.get(&user_data.language, "del/count").replacen(
"{}",
&count_row.count.to_string(),
1,
@ -729,9 +753,8 @@ INSERT INTO events (event_name, bulk_count, guild_id, user_id) VALUES ('delete',
let _ = msg.channel_id.say(&ctx, content).await;
} else {
let content = user_data
.response(&pool, "del/count")
.await
let content = lm
.get(&user_data.language, "del/count")
.replacen("{}", "0", 1);
let _ = msg.channel_id.say(&ctx, content).await;
@ -757,15 +780,21 @@ async fn timer(ctx: &Context, msg: &Message, args: String) {
format!("{:02}:{:02}:{:02}", hours, minutes, seconds)
}
let pool = ctx
.data
.read()
.await
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
let pool;
let lm;
let user_data = UserData::from_user(&msg.author, &ctx, &pool).await.unwrap();
{
let data = ctx.data.read().await;
pool = data
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
lm = data.get::<LanguageManager>().cloned().unwrap();
}
let language = UserData::language_of(&msg.author, &pool).await;
let mut args_iter = args.splitn(2, ' ');
@ -796,7 +825,7 @@ async fn timer(ctx: &Context, msg: &Message, args: String) {
if count >= 25 {
let _ = msg
.channel_id
.say(&ctx, user_data.response(&pool, "timer/limit").await)
.say(&ctx, lm.get(&language, "timer/limit"))
.await;
} else {
let name = args_iter
@ -808,7 +837,7 @@ async fn timer(ctx: &Context, msg: &Message, args: String) {
let _ = msg
.channel_id
.say(&ctx, user_data.response(&pool, "timer/success").await)
.say(&ctx, lm.get(&language, "timer/success"))
.await;
}
}
@ -839,18 +868,18 @@ DELETE FROM timers WHERE owner = ? AND name = ?
let _ = msg
.channel_id
.say(&ctx, user_data.response(&pool, "timer/deleted").await)
.say(&ctx, lm.get(&language, "timer/deleted"))
.await;
} else {
let _ = msg
.channel_id
.say(&ctx, user_data.response(&pool, "timer/not_found").await)
.say(&ctx, lm.get(&language, "timer/not_found"))
.await;
}
} else {
let _ = msg
.channel_id
.say(&ctx, user_data.response(&pool, "timer/help").await)
.say(&ctx, lm.get(&language, "timer/help"))
.await;
}
}
@ -858,7 +887,7 @@ DELETE FROM timers WHERE owner = ? AND name = ?
_ => {
let _ = msg
.channel_id
.say(&ctx, user_data.response(&pool, "timer/help").await)
.say(&ctx, lm.get(&language, "timer/help"))
.await;
}
}
@ -1026,13 +1055,19 @@ async fn remind_command(ctx: &Context, msg: &Message, args: String, command: Rem
}
}
let pool = ctx
.data
.read()
.await
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
let pool;
let lm;
{
let data = ctx.data.read().await;
pool = data
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
lm = data.get::<LanguageManager>().cloned().unwrap();
}
let user_data = UserData::from_user(&msg.author, &ctx, &pool).await.unwrap();
@ -1092,9 +1127,8 @@ async fn remind_command(ctx: &Context, msg: &Message, args: String, command: Rem
.flatten()
.unwrap_or(0) as u64;
let str_response = user_data
.response(&pool, &response.to_response())
.await
let str_response = lm
.get(&user_data.language, &response.to_response())
.replace(
"{prefix}",
&GuildData::prefix_from_id(msg.guild_id, &pool).await,
@ -1110,13 +1144,19 @@ async fn remind_command(ctx: &Context, msg: &Message, args: String, command: Rem
#[command("natural")]
#[permission_level(Managed)]
async fn natural(ctx: &Context, msg: &Message, args: String) {
let pool = ctx
.data
.read()
.await
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
let pool;
let lm;
{
let data = ctx.data.read().await;
pool = data
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
lm = data.get::<LanguageManager>().cloned().unwrap();
}
let now = SystemTime::now();
let since_epoch = now
@ -1125,9 +1165,9 @@ async fn natural(ctx: &Context, msg: &Message, args: String) {
let user_data = UserData::from_user(&msg.author, &ctx, &pool).await.unwrap();
let send_str = user_data.response(&pool, "natural/send").await;
let to_str = user_data.response(&pool, "natural/to").await;
let every_str = user_data.response(&pool, "natural/every").await;
let send_str = lm.get(&user_data.language, "natural/send");
let to_str = lm.get(&user_data.language, "natural/to");
let every_str = lm.get(&user_data.language, "natural/every");
let mut args_iter = args.splitn(2, &send_str);
@ -1241,9 +1281,8 @@ async fn natural(ctx: &Context, msg: &Message, args: String) {
let offset = timestamp as u64 - since_epoch.as_secs();
let str_response = user_data
.response(&pool, &res.to_response_natural())
.await
let str_response = lm
.get(&user_data.language, &res.to_response_natural())
.replace(
"{prefix}",
&GuildData::prefix_from_id(msg.guild_id, &pool).await,
@ -1275,9 +1314,8 @@ async fn natural(ctx: &Context, msg: &Message, args: String) {
}
}
let content = user_data
.response(&pool, "natural/bulk_set")
.await
let content = lm
.get(&user_data.language, "natural/bulk_set")
.replace("{}", &ok_count.to_string());
let _ = msg.channel_id.say(&ctx, content).await;
@ -1291,9 +1329,8 @@ async fn natural(ctx: &Context, msg: &Message, args: String) {
} else {
let prefix = GuildData::prefix_from_id(msg.guild_id, &pool).await;
let resp = user_data
.response(&pool, "natural/no_argument")
.await
let resp = lm
.get(&user_data.language, "natural/no_argument")
.replace("{prefix}", &prefix);
let _ = msg

View File

@ -18,6 +18,7 @@ use crate::{
use sqlx::MySqlPool;
use std::convert::TryFrom;
use crate::language_manager::LanguageManager;
use async_trait::async_trait;
#[derive(Debug)]
@ -235,13 +236,19 @@ DELETE FROM todos WHERE user_id = (SELECT id FROM users WHERE user = ?) AND guil
}
async fn execute(&self, ctx: &Context, msg: &Message, subcommand: SubCommand, extra: String) {
let pool = ctx
.data
.read()
.await
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
let pool;
let lm;
{
let data = ctx.data.read().await;
pool = data
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
lm = data.get::<LanguageManager>().cloned().unwrap();
}
let user_data = UserData::from_user(&msg.author, &ctx, &pool).await.unwrap();
let prefix = GuildData::prefix_from_id(msg.guild_id, &pool).await;
@ -279,9 +286,8 @@ DELETE FROM todos WHERE user_id = (SELECT id FROM users WHERE user = ?) AND guil
}
SubCommand::Add => {
let content = user_data
.response(&pool, "todo/added")
.await
let content = lm
.get(&user_data.language, "todo/added")
.replacen("{name}", &extra, 1);
self.add(extra, pool).await.unwrap();
@ -290,35 +296,35 @@ DELETE FROM todos WHERE user_id = (SELECT id FROM users WHERE user = ?) AND guil
}
SubCommand::Remove => {
let _ = if let Ok(num) = extra.parse::<usize>() {
if let Ok(num) = extra.parse::<usize>() {
if let Ok(todo) = self.remove(num - 1, &pool).await {
let content = user_data.response(&pool, "todo/removed").await.replacen(
let content = lm.get(&user_data.language, "todo/removed").replacen(
"{}",
&todo.value,
1,
);
msg.channel_id.say(&ctx, content)
let _ = msg.channel_id.say(&ctx, content).await;
} else {
msg.channel_id
.say(&ctx, user_data.response(&pool, "todo/error_index").await)
let _ = msg
.channel_id
.say(&ctx, lm.get(&user_data.language, "todo/error_index"))
.await;
}
} else {
let content = user_data
.response(&pool, "todo/error_value")
.await
let content = lm
.get(&user_data.language, "todo/error_value")
.replacen("{prefix}", &prefix, 1)
.replacen("{command}", &self.command(Some(subcommand)), 1);
msg.channel_id.say(&ctx, content)
let _ = msg.channel_id.say(&ctx, content).await;
}
.await;
}
SubCommand::Clear => {
self.clear(&pool).await.unwrap();
let content = user_data.response(&pool, "todo/cleared").await;
let content = lm.get(&user_data.language, "todo/cleared");
let _ = msg.channel_id.say(&ctx, content).await;
}
@ -435,20 +441,25 @@ async fn todo_guild(ctx: &Context, msg: &Message, args: String) {
}
async fn show_help(ctx: &Context, msg: &Message, target: Option<TodoTarget>) {
let pool = ctx
.data
.read()
.await
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
let pool;
let lm;
{
let data = ctx.data.read().await;
pool = data
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
lm = data.get::<LanguageManager>().cloned().unwrap();
}
let user_data = UserData::from_user(&msg.author, &ctx, &pool).await.unwrap();
let prefix = GuildData::prefix_from_id(msg.guild_id, &pool).await;
let content = user_data
.response(&pool, "todo/help")
.await
let content = lm
.get(&user_data.language, "todo/help")
.replace("{prefix}", &prefix)
.replace(
"{command}",

View File

@ -20,6 +20,7 @@ use regex::{Match, Regex, RegexBuilder};
use std::{collections::HashMap, fmt};
use crate::language_manager::LanguageManager;
use crate::models::{GuildData, UserData};
use crate::{models::ChannelData, SQLPool};
@ -354,16 +355,16 @@ impl Framework for RegexFramework {
{
if let Some(full_match) = self.command_matcher.captures(&msg.content) {
if check_prefix(&ctx, &guild, full_match.name("prefix")).await {
let pool = ctx
.data
.read()
.await
let data = ctx.data.read().await;
let pool = data
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
let user_data = UserData::from_user(&msg.author, &ctx, &pool).await.unwrap();
let guild_data = GuildData::from_guild(guild.clone(), &pool).await.unwrap();
let lm = data.get::<LanguageManager>().unwrap();
let language = UserData::language_of(&msg.author, &pool).await;
match check_self_permissions(&ctx, &guild, &channel).await {
Ok(perms) => match perms {
@ -380,9 +381,6 @@ impl Framework for RegexFramework {
.await
.unwrap();
// required due to a small bug resulting in some channels being detached from their guild ids
channel_data.update_guild_id(guild_data.id, &pool).await;
if !command.can_blacklist || !channel_data.blacklisted {
let args = full_match
.name("args")
@ -398,29 +396,18 @@ impl Framework for RegexFramework {
{
let _ = msg
.channel_id
.say(
&ctx,
user_data
.response(&pool, "no_perms_restricted")
.await,
)
.say(&ctx, lm.get(&language, "no_perms_restricted"))
.await;
} else if command.required_perms == PermissionLevel::Managed {
let _ = msg
.channel_id
.say(
&ctx,
user_data
.response(&pool, "no_perms_managed")
.await
.replace(
"{prefix}",
&GuildData::prefix_from_id(
msg.guild_id,
&pool,
)
lm.get(&language, "no_perms_managed").replace(
"{prefix}",
&GuildData::prefix_from_id(msg.guild_id, &pool)
.await,
),
),
)
.await;
}
@ -428,9 +415,8 @@ impl Framework for RegexFramework {
}
PermissionCheck::Basic(manage_webhooks, embed_links) => {
let response = user_data
.response(&pool, "no_perms_general")
.await
let response = lm
.get(&language, "no_perms_general")
.replace(
"{manage_webhooks}",
if manage_webhooks { "" } else { "" },

View File

@ -1,12 +1,10 @@
use std::collections::HashMap;
use serde::Deserialize;
use serde_json::from_reader;
use serde_json::from_str;
use serenity::prelude::TypeMapKey;
use std::error::Error;
use std::fs::File;
use std::io::BufReader;
use std::path::Path;
use std::{collections::HashMap, error::Error, sync::Arc};
use crate::consts::LOCAL_LANGUAGE;
#[derive(Deserialize)]
pub struct LanguageManager {
@ -15,34 +13,41 @@ pub struct LanguageManager {
}
impl LanguageManager {
pub(crate) fn from_compiled<P>(path: P) -> Result<Self, Box<dyn Error + Send + Sync>>
where
P: AsRef<Path>,
{
let file = File::open(path)?;
let reader = BufReader::new(file);
let new: Self = from_reader(reader)?;
pub fn from_compiled(content: &'static str) -> Result<Self, Box<dyn Error + Send + Sync>> {
let new: Self = from_str(content.as_ref())?;
Ok(new)
}
pub(crate) fn get(&self, language: &str, name: &'static str) -> &str {
pub fn get(&self, language: &str, name: &str) -> &str {
self.strings
.get(language)
.map(|sm| sm.get(name))
.expect(&format!(r#"Language does not exist: "{}""#, language))
.expect(&format!(r#"String does not exist: "{}""#, name))
.unwrap_or_else(|| {
self.strings
.get(&*LOCAL_LANGUAGE)
.map(|sm| {
sm.get(name)
.expect(&format!(r#"String does not exist: "{}""#, name))
})
.expect("LOCAL_LANGUAGE is not available")
})
}
fn all_languages(&self) -> Vec<(&str, &str)> {
pub fn get_language(&self, language: &str) -> Option<&str> {
self.languages
.iter()
.map(|(k, v)| (k.as_str(), v.as_str()))
.collect()
.filter(|(k, v)| k.to_lowercase() == language || v.to_lowercase() == language)
.map(|(k, _)| k.as_str())
.next()
}
pub fn all_languages(&self) -> impl Iterator<Item = (&str, &str)> {
self.languages.iter().map(|(k, v)| (k.as_str(), v.as_str()))
}
}
impl TypeMapKey for LanguageManager {
type Value = Self;
type Value = Arc<Self>;
}

View File

@ -231,14 +231,18 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
.await
.unwrap();
let language_manager = LanguageManager::from_compiled("out.json")?;
let language_manager = LanguageManager::from_compiled(include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/assets/",
env!("STRINGS_FILE")
)))?;
let mut data = client.data.write().await;
data.insert::<SQLPool>(pool);
data.insert::<ReqwestClient>(Arc::new(reqwest::Client::new()));
data.insert::<FrameworkCtx>(framework_arc);
data.insert::<LanguageManager>(language_manager)
data.insert::<LanguageManager>(Arc::new(language_manager))
}
if let Ok((Some(lower), Some(upper))) = env::var("SHARD_RANGE").map(|sr| {

View File

@ -158,19 +158,6 @@ SELECT id, name, nudge, blacklisted, webhook_id, webhook_token, paused, paused_u
}
}
pub async fn update_guild_id(&self, id: u32, pool: &MySqlPool) {
sqlx::query!(
"
UPDATE channels SET guild_id = ? WHERE id = ?
",
id,
self.id
)
.execute(pool)
.await
.unwrap();
}
pub async fn commit_changes(&self, pool: &MySqlPool) {
sqlx::query!(
"
@ -191,7 +178,7 @@ pub struct UserData {
}
impl UserData {
pub async fn language_of(user: &User, ctx: impl CacheHttp, pool: &MySqlPool) -> String {
pub async fn language_of(user: &User, pool: &MySqlPool) -> String {
let user_id = user.id.as_u64().to_owned();
match sqlx::query!(
@ -285,10 +272,6 @@ UPDATE users SET name = ?, language = ?, timezone = ? WHERE id = ?
.unwrap();
}
pub async fn response(&self, _pool: &MySqlPool, _name: &str) -> String {
unimplemented!()
}
pub fn timezone(&self) -> Tz {
self.timezone.parse().unwrap()
}