aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/commands/meme/create.rs14
-rw-r--r--src/commands/meme/delete.rs4
-rw-r--r--src/commands/meme/history.rs23
-rw-r--r--src/commands/meme/invoke.rs40
-rw-r--r--src/commands/meme/mod.rs2
-rw-r--r--src/db/mod.rs59
-rw-r--r--src/db/models.rs24
7 files changed, 98 insertions, 68 deletions
diff --git a/src/commands/meme/create.rs b/src/commands/meme/create.rs
index 11af7e9..dce5213 100644
--- a/src/commands/meme/create.rs
+++ b/src/commands/meme/create.rs
@@ -54,7 +54,7 @@ pub fn addmeme(ctx: &mut Context, msg: &Message, args: Args) -> Result<()> {
let text = if text.is_empty() { None } else { Some(text) };
- let conn = connection()?;
+ let mut conn = connection()?;
let image = msg.attachments.first();
@@ -65,7 +65,7 @@ pub fn addmeme(ctx: &mut Context, msg: &Message, args: Args) -> Result<()> {
let image_id = image.map(|att| {
let data = att.download()?;
- Image::create(&conn, &att.filename, data, msg.author.id.0)
+ Image::create(&mut conn, &att.filename, data, msg.author.id.0)
}).transpose()?;
let save_result = NewMeme {
@@ -74,7 +74,7 @@ pub fn addmeme(ctx: &mut Context, msg: &Message, args: Args) -> Result<()> {
image_id,
audio_id: None,
metadata_id: 0,
- }.save(&conn, msg.author.id.0).map(|_| {});
+ }.save(&mut conn, msg.author.id.0).map(|_| {});
use diesel::result::DatabaseErrorKind;
match save_result {
@@ -147,13 +147,13 @@ pub fn addaudiomeme(ctx: &mut Context, msg: &Message, args: Args) -> Result<()>
let text = args.rest().to_owned();
let text = if text.is_empty() { None } else { Some(text) };
- let conn = connection()?;
+ let mut conn = connection()?;
let image = msg.attachments.first()
.ok_or(anyhow!("no attachment"))
.and_then(|att| {
let data = att.download()?;
- Image::create(&conn, &att.filename, data, msg.author.id.0)
+ Image::create(&mut conn, &att.filename, data, msg.author.id.0)
})
.ok();
@@ -165,7 +165,7 @@ pub fn addaudiomeme(ctx: &mut Context, msg: &Message, args: Args) -> Result<()>
return ctx.send(msg.channel_id, "🔇🔇🔇🔕🔕🔕🔕🔕🔇🔕🔕🔇🔕🔕📣📢📣📢📣", msg.tts);
}
- let audio_id = Audio::create(&conn, audio_data, msg.author.id.0)?;
+ let audio_id = Audio::create(&mut conn, audio_data, msg.author.id.0)?;
let save_result = NewMeme {
title,
@@ -173,7 +173,7 @@ pub fn addaudiomeme(ctx: &mut Context, msg: &Message, args: Args) -> Result<()>
image_id: image,
audio_id: Some(audio_id),
metadata_id: 0,
- }.save(&conn, msg.author.id.0).map(|_| {});
+ }.save(&mut conn, msg.author.id.0).map(|_| {});
use diesel::result::DatabaseErrorKind;
match save_result {
diff --git a/src/commands/meme/delete.rs b/src/commands/meme/delete.rs
index e5e4333..7eafc80 100644
--- a/src/commands/meme/delete.rs
+++ b/src/commands/meme/delete.rs
@@ -26,9 +26,9 @@ use crate::{
pub fn delmeme(ctx: &mut Context, msg: &Message, mut args: Args) -> Result<()> {
let title = args.single_quoted::<String>()?;
- let conn = connection()?;
+ let mut conn = connection()?;
- match delete_meme(&conn, &title, msg.author.id.0) {
+ match delete_meme(&mut conn, &title, msg.author.id.0) {
Ok(_) => msg.react(ctx, "💀"),
Err(e) => {
if let Some(NotFound) = e.downcast_ref::<DieselError>() {
diff --git a/src/commands/meme/history.rs b/src/commands/meme/history.rs
index 8186f57..f9e8851 100644
--- a/src/commands/meme/history.rs
+++ b/src/commands/meme/history.rs
@@ -51,9 +51,9 @@ static CLEAN_DATE_FORMAT: &'static str = "%b %-e %Y";
#[command]
#[aliases("what")]
pub fn wat(ctx: &mut Context, msg: &Message, _: Args) -> Result<()> {
- let conn = connection()?;
+ let mut conn = connection()?;
- let record = match InvocationRecord::last(&conn) {
+ let record = match InvocationRecord::last(&mut conn) {
Ok(x) => x,
Err(e) => {
if let Some(NotFound) = e.downcast_ref::<DieselError>() {
@@ -66,11 +66,11 @@ pub fn wat(ctx: &mut Context, msg: &Message, _: Args) -> Result<()> {
},
};
- let meme = Meme::find(&conn, record.meme_id);
+ let meme = Meme::find(&mut conn, record.meme_id);
match meme {
Ok(ref meme) => {
- let metadata = Metadata::find(&conn, meme.metadata_id)?;
+ let metadata = Metadata::find(&mut conn, meme.metadata_id)?;
let author = CONFIG.discord.guild().member(&ctx, metadata.created_by as u64)?;
ctx.send(msg.channel_id,
@@ -95,7 +95,7 @@ pub fn wat(ctx: &mut Context, msg: &Message, _: Args) -> Result<()> {
pub fn history(ctx: &mut Context, msg: &Message, mut args: Args) -> Result<()> {
use itertools::Itertools;
- let conn = connection()?;
+ let mut conn = connection()?;
let n = args.single_quoted::<usize>().unwrap_or(CONFIG.default_hist);
@@ -106,7 +106,7 @@ pub fn history(ctx: &mut Context, msg: &Message, mut args: Args) -> Result<()> {
let n = n.min(CONFIG.max_hist);
- let records = InvocationRecord::last_n(&conn, n)?;
+ let records = InvocationRecord::last_n(&mut conn, n)?;
if records.len() == 0 {
info!("no memes in history");
@@ -123,9 +123,9 @@ pub fn history(ctx: &mut Context, msg: &Message, mut args: Args) -> Result<()> {
let ago = TIME_FORMATTER.convert((chrono::Utc::now() - dt).to_std().unwrap());
let rand = if rec.random { "R, " } else { "" };
- Meme::find(&conn, rec.meme_id)
+ Meme::find(&mut conn, rec.meme_id)
.and_then(|meme| {
- Metadata::find(&conn, meme.metadata_id).map(|metadata| (metadata, meme))
+ Metadata::find(&mut conn, meme.metadata_id).map(|metadata| (metadata, meme))
})
.map(|(metadata, meme)| {
let author_name = CONFIG.discord.guild().member(&ctx, metadata.created_by as u64).map(|m| m.display_name().into_owned()).unwrap_or("???".to_owned());
@@ -157,8 +157,8 @@ pub fn stats(ctx: &mut Context, msg: &Message, _: Args) -> Result<()> {
user::User,
};
- let conn = connection()?;
- let stats = db::stats(&conn)?;
+ let mut conn = connection()?;
+ let stats = db::stats(&mut conn)?;
debug!("reporting stats");
@@ -332,5 +332,6 @@ pub fn query(ctx: &mut Context, msg: &Message, mut args: Args) -> Result<()> {
return ctx.send(msg.channel_id, "no match".to_owned(), msg.tts);
}
+
ctx.send(msg.channel_id, &result, msg.tts)
-} \ No newline at end of file
+}
diff --git a/src/commands/meme/invoke.rs b/src/commands/meme/invoke.rs
index c5ca502..de0272f 100644
--- a/src/commands/meme/invoke.rs
+++ b/src/commands/meme/invoke.rs
@@ -38,6 +38,18 @@ pub fn omen(ctx: &mut Context, msg: &Message, _args: Args) -> Result<()> {
}
#[command]
+pub fn silentomen(ctx: &mut Context, msg: &Message, _args: Args) -> Result<()> {
+ let args = Args::new("", &[]);
+ _meme(ctx, msg, args, AudioPlayback::Prohibited)
+}
+
+#[command]
+pub fn audioomen(ctx: &mut Context, msg: &Message, _args: Args) -> Result<()> {
+ let args = Args::new("", &[]);
+ _meme(ctx, msg, args, AudioPlayback::Required)
+}
+
+#[command]
#[aliases("audiomeme", "audiomem")]
pub fn audio_meme(ctx: &mut Context, msg: &Message, args: Args) -> Result<()> {
_meme(ctx, msg, args, AudioPlayback::Required)
@@ -63,10 +75,10 @@ fn _meme(ctx: &mut Context, msg: &Message, args: Args, audio_playback: AudioPlay
let search = args.raw().join(" ");
- let conn = connection()?;
- let mem = match find_meme(&conn, search) {
+ let mut conn = connection()?;
+ let mem = match find_meme(&mut conn, search) {
Ok(x) => {
- InvocationRecord::create(&conn, msg.author.id.0, msg.id.0, x.id, false)?;
+ InvocationRecord::create(&mut conn, msg.author.id.0, msg.id.0, x.id, false)?;
x
},
@@ -81,24 +93,24 @@ fn _meme(ctx: &mut Context, msg: &Message, args: Args, audio_playback: AudioPlay
},
};
- send_meme(ctx, &mem, &conn, msg)
+ send_meme(ctx, &mem, &mut conn, msg)
}
fn rand_meme(ctx: &Context, message: &Message, audio_playback: AudioPlayback) -> Result<()> {
- let conn = connection()?;
+ let mut conn = connection()?;
let should_audio = ctx.users_listening()?;
let mem = match audio_playback {
- AudioPlayback::Required => db::rand_audio_meme(&conn),
- AudioPlayback::Optional => db::rand_meme(&conn, should_audio),
- AudioPlayback::Prohibited => db::rand_silent_meme(&conn),
+ AudioPlayback::Required => db::rand_audio_meme(&mut conn),
+ AudioPlayback::Optional => db::rand_meme(&mut conn, should_audio),
+ AudioPlayback::Prohibited => db::rand_silent_meme(&mut conn),
};
match mem {
Ok(mem) => {
- InvocationRecord::create(&conn, message.author.id.0, message.id.0, mem.id, true)?;
- send_meme(ctx, &mem, &conn, message)?;
+ InvocationRecord::create(&mut conn, message.author.id.0, message.id.0, mem.id, true)?;
+ send_meme(ctx, &mem, &mut conn, message)?;
Ok(())
},
Err(e) => {
@@ -121,13 +133,13 @@ fn rand_meme(ctx: &Context, message: &Message, audio_playback: AudioPlayback) ->
pub fn rare_meme(ctx: &mut Context, msg: &Message, _args: Args) -> Result<()> {
let should_audio = ctx.users_listening()?;
- let conn = connection()?;
- let meme = db::rare_meme(&conn, should_audio);
+ let mut conn = connection()?;
+ let meme = db::rare_meme(&mut conn, should_audio);
match meme {
Ok(meme) => {
- InvocationRecord::create(&conn, msg.author.id.0, msg.id.0, meme.id, true)?;
- send_meme(ctx, &meme, &conn, msg)
+ InvocationRecord::create(&mut conn, msg.author.id.0, msg.id.0, meme.id, true)?;
+ send_meme(ctx, &meme, &mut conn, msg)
},
Err(e) => {
match e.downcast_ref::<DieselError>() {
diff --git a/src/commands/meme/mod.rs b/src/commands/meme/mod.rs
index ee39d55..d816a93 100644
--- a/src/commands/meme/mod.rs
+++ b/src/commands/meme/mod.rs
@@ -51,7 +51,7 @@ group!({
],
});
-fn send_meme(ctx: &Context, t: &Meme, conn: &PgConnection, msg: &Message) -> Result<()> {
+fn send_meme(ctx: &Context, t: &Meme, conn: &mut PgConnection, msg: &Message) -> Result<()> {
let should_tts = t.content.as_ref().map(|t| t.len() > 0).unwrap_or(false) &&
thread_rng().gen::<u32>() % 25 == 0;
diff --git a/src/db/mod.rs b/src/db/mod.rs
index 180012d..483665e 100644
--- a/src/db/mod.rs
+++ b/src/db/mod.rs
@@ -26,6 +26,7 @@ use r2d2_postgres::{
use anyhow::anyhow;
use lazy_static::lazy_static;
+use diesel_migrations::MigrationHarness;
use crate::{Error, Result};
@@ -35,6 +36,9 @@ use self::schema::*;
mod schema;
mod models;
+const MIGRATIONS: diesel_migrations::EmbeddedMigrations = diesel_migrations::embed_migrations!();
+static MIGRATE: std::sync::Once = std::sync::Once::new();
+
lazy_static! {
static ref DB_URL: String = env::var("DATABASE_URL").expect("no database url in environment").into();
static ref DB_CONFIG: Config = Config::from_str(&DB_URL).expect("parsing db url as config");
@@ -42,20 +46,33 @@ lazy_static! {
static ref RAW_CONN_MGR: RawPgConnMgr<NoTls> = RawPgConnMgr::new(DB_CONFIG.clone(), NoTls);
}
+
#[inline]
pub fn connection() -> Result<PgConnection> {
- CONN_MGR.connect().map_err(Error::from)
+ CONN_MGR.connect()
+ .map(|mut conn| {
+ MIGRATE.call_once(|| {
+ log::info!("running migrations");
+ conn.run_pending_migrations(MIGRATIONS).expect("failed running migrations");
+ });
+
+ conn
+ })
+ .map_err(Error::from)
}
#[inline]
fn raw_connection() -> Result<RawPgConn> {
- RAW_CONN_MGR.connect().map_err(Error::from)
-}
+ // HACK
+ if !MIGRATE.is_completed() {
+ connection()?;
+ }
-pub fn find_meme<T: AsRef<str>>(conn: &PgConnection, search: T) -> Result<Meme> {
- use diesel::dsl::sql;
- use diesel::sql_types::Text;
+ RAW_CONN_MGR.connect()
+ .map_err(Error::from)
+}
+pub fn find_meme<T: AsRef<str>>(conn: &mut PgConnection, search: T) -> Result<Meme> {
let search = search.as_ref();
let mut meme = memes::table
@@ -67,7 +84,7 @@ pub fn find_meme<T: AsRef<str>>(conn: &PgConnection, search: T) -> Result<Meme>
let format_search = format!("%{}%", search);
meme = memes::table
- .filter(memes::title.ilike(&format_search).or(sql("content ILIKE ").bind::<Text, _>(&format_search)))
+ .filter(memes::title.ilike(&format_search).or(memes::content.ilike(&format_search)))
.limit(1)
.first::<Meme>(conn);
}
@@ -121,26 +138,26 @@ pub fn query_meme<T: AsRef<str>>(search: T, user_id: Option<u64>, age_desc: bool
Ok(result)
}
-pub fn delete_meme<T: AsRef<str>>(conn: &PgConnection, search: T, deleted_by: u64) -> Result<()> {
- conn.transaction::<(), Error, _>(|| {
+pub fn delete_meme<T: AsRef<str>>(conn: &mut PgConnection, search: T, deleted_by: u64) -> Result<()> {
+ conn.transaction::<(), Error, _>(|tx| {
let deleted = memes::table
.filter(memes::title.eq(search.as_ref()))
- .first::<Meme>(conn)?;
+ .first::<Meme>(tx)?;
::diesel::delete(memes::table)
.filter(memes::id.eq(deleted.id))
- .execute(conn)?;
+ .execute(tx)?;
if let Some(image_id) = deleted.image_id {
let count = memes::table
.filter(memes::image_id.eq(image_id))
.count()
- .execute(conn)?;
+ .execute(tx)?;
if count == 0 {
::diesel::delete(images::table)
.filter(images::id.eq(image_id))
- .execute(conn)?;
+ .execute(tx)?;
}
}
@@ -148,12 +165,12 @@ pub fn delete_meme<T: AsRef<str>>(conn: &PgConnection, search: T, deleted_by: u6
let count = memes::table
.select(::diesel::dsl::count_star())
.filter(memes::audio_id.eq(audio_id))
- .execute(conn)?;
+ .execute(tx)?;
if count == 0 {
::diesel::delete(audio::table)
.filter(audio::id.eq(audio_id))
- .execute(conn)?;
+ .execute(tx)?;
}
}
@@ -165,13 +182,13 @@ pub fn delete_meme<T: AsRef<str>>(conn: &PgConnection, search: T, deleted_by: u6
let _ = ::diesel::insert_into(tombstones::table)
.values(&tombstone)
- .execute(conn)?;
+ .execute(tx)?;
Ok(())
})
}
-pub fn rare_meme(conn: &PgConnection, audio: bool) -> Result<Meme> {
+pub fn rare_meme(conn: &mut PgConnection, audio: bool) -> Result<Meme> {
use rand::prelude::*;
let mut raw_conn = raw_connection()?;
@@ -227,7 +244,7 @@ pub fn rare_meme(conn: &PgConnection, audio: bool) -> Result<Meme> {
Meme::find(conn, meme_id)
}
-pub fn rand_meme(conn: &PgConnection, audio: bool) -> Result<Meme> {
+pub fn rand_meme(conn: &mut PgConnection, audio: bool) -> Result<Meme> {
use rand::{thread_rng, seq::SliceRandom};
let ids: Vec<i32> = if audio {
@@ -256,7 +273,7 @@ pub fn rand_meme(conn: &PgConnection, audio: bool) -> Result<Meme> {
.map_err(Error::from)
}
-pub fn rand_audio_meme(conn: &PgConnection) -> Result<Meme> {
+pub fn rand_audio_meme(conn: &mut PgConnection) -> Result<Meme> {
use rand::{thread_rng, seq::SliceRandom};
let ids: Vec<i32> = memes::table
@@ -274,7 +291,7 @@ pub fn rand_audio_meme(conn: &PgConnection) -> Result<Meme> {
.map_err(Error::from)
}
-pub fn rand_silent_meme(conn: &PgConnection) -> Result<Meme> {
+pub fn rand_silent_meme(conn: &mut PgConnection) -> Result<Meme> {
use rand::{thread_rng, seq::SliceRandom};
let ids: Vec<i32> = memes::table
@@ -323,7 +340,7 @@ pub struct Stats {
pub most_popular_meme_overall_count: usize,
}
-pub fn stats(conn: &PgConnection) -> Result<Stats> {
+pub fn stats(conn: &mut PgConnection) -> Result<Stats> {
use diesel::dsl::{count_star, count};
use chrono::{
NaiveDateTime,
diff --git a/src/db/models.rs b/src/db/models.rs
index 95acb16..54e8ce2 100644
--- a/src/db/models.rs
+++ b/src/db/models.rs
@@ -24,15 +24,15 @@ pub struct Meme {
}
impl Meme {
- pub fn image(&self, conn: &PgConnection) -> Option<Result<Image>> {
+ pub fn image(&self, conn: &mut PgConnection) -> Option<Result<Image>> {
self.image_id.map(|x: i32| images::table.filter(images::id.eq(x)).first(conn).map_err(Error::from))
}
- pub fn audio(&self, conn: &PgConnection) -> Option<Result<Audio>> {
+ pub fn audio(&self, conn: &mut PgConnection) -> Option<Result<Audio>> {
self.audio_id.map(|x: i32| audio::table.filter(audio::id.eq(x)).first(conn).map_err(Error::from))
}
- pub fn find(conn: &PgConnection, id: i32) -> Result<Meme> {
+ pub fn find(conn: &mut PgConnection, id: i32) -> Result<Meme> {
memes::table.find(id).get_result(conn).map_err(Error::from)
}
}
@@ -48,7 +48,7 @@ pub struct NewMeme {
}
impl NewMeme {
- pub fn save(mut self, conn: &PgConnection, by_user: u64) -> Result<Meme> {
+ pub fn save(mut self, conn: &mut PgConnection, by_user: u64) -> Result<Meme> {
let metadata = Metadata::create(conn, by_user)?;
self.metadata_id = metadata.id;
@@ -71,7 +71,7 @@ pub struct Audio {
}
impl Audio {
- pub fn create(conn: &PgConnection, data: Vec<u8>, by_user: u64) -> Result<i32> {
+ pub fn create(conn: &mut PgConnection, data: Vec<u8>, by_user: u64) -> Result<i32> {
let mut data_hash = ::sha1::Sha1::new();
data_hash.update(&data);
let data_hash = data_hash.digest().bytes().to_vec();
@@ -121,7 +121,7 @@ pub struct Image {
}
impl Image {
- pub fn create(conn: &PgConnection, filename: &str, data: Vec<u8>, by_user: u64) -> Result<i32> {
+ pub fn create(conn: &mut PgConnection, filename: &str, data: Vec<u8>, by_user: u64) -> Result<i32> {
let mut data_hash = ::sha1::Sha1::new();
data_hash.update(&data);
let data_hash = data_hash.digest().bytes().to_vec();
@@ -171,7 +171,7 @@ pub struct Metadata {
}
impl Metadata {
- pub fn create(conn: &PgConnection, by_user: u64) -> Result<Metadata> {
+ pub fn create(conn: &mut PgConnection, by_user: u64) -> Result<Metadata> {
::diesel::insert_into(metadata::table)
.values(&NewMetadata {
created_by: by_user as i64,
@@ -180,7 +180,7 @@ impl Metadata {
.map_err(Error::from)
}
- pub fn find(conn: &PgConnection, id: i32) -> Result<Metadata> {
+ pub fn find(conn: &mut PgConnection, id: i32) -> Result<Metadata> {
metadata::table.find(id)
.get_result::<Metadata>(conn)
.map_err(Error::from)
@@ -204,7 +204,7 @@ pub struct AuditRecord {
}
impl AuditRecord {
- pub fn create(conn: &PgConnection, metadata: i32, by_user: u64) -> Result<AuditRecord> {
+ pub fn create(conn: &mut PgConnection, metadata: i32, by_user: u64) -> Result<AuditRecord> {
::diesel::insert_into(audit_records::table)
.values(&NewAuditRecord {
updated_by: by_user as i64,
@@ -262,7 +262,7 @@ pub struct NewInvocationRecord {
}
impl InvocationRecord {
- pub fn create(conn: &PgConnection, user_id: u64, message_id: u64, meme_id: i32, random: bool) -> Result<Self> {
+ pub fn create(conn: &mut PgConnection, user_id: u64, message_id: u64, meme_id: i32, random: bool) -> Result<Self> {
::diesel::insert_into(invocation_records::table)
.values(&NewInvocationRecord {
user_id: user_id as i64,
@@ -274,14 +274,14 @@ impl InvocationRecord {
.map_err(Error::from)
}
- pub fn last(conn: &PgConnection) -> Result<Self> {
+ pub fn last(conn: &mut PgConnection) -> Result<Self> {
invocation_records::table
.order(invocation_records::time.desc())
.first(conn)
.map_err(Error::from)
}
- pub fn last_n(conn: &PgConnection, n: usize) -> Result<Vec<Self>> {
+ pub fn last_n(conn: &mut PgConnection, n: usize) -> Result<Vec<Self>> {
invocation_records::table
.order(invocation_records::time.desc())
.limit(n as i64)