aboutsummaryrefslogtreecommitdiff
path: root/src/db
diff options
context:
space:
mode:
authorFuwn <[email protected]>2020-10-26 19:03:53 -0700
committerFuwn <[email protected]>2020-10-26 19:03:53 -0700
commit9742614a1dc4699c1f2c69d923d402237672335d (patch)
treea49f7d834372f37cef06b30a28ff1b40bdfaa079 /src/db
parentCreate README.md (diff)
downloaddep-core-next-9742614a1dc4699c1f2c69d923d402237672335d.tar.xz
dep-core-next-9742614a1dc4699c1f2c69d923d402237672335d.zip
repo: push main from local to remote
Diffstat (limited to 'src/db')
-rw-r--r--src/db/mod.rs511
-rw-r--r--src/db/models.rs253
-rw-r--r--src/db/schema.rs129
3 files changed, 893 insertions, 0 deletions
diff --git a/src/db/mod.rs b/src/db/mod.rs
new file mode 100644
index 0000000..78f6030
--- /dev/null
+++ b/src/db/mod.rs
@@ -0,0 +1,511 @@
+//! A set of abstractions for manipulating a PgSQL database relevant to Wisp's stored data.
+pub mod models;
+mod schema;
+
+use chrono::offset::Utc;
+use diesel::pg::PgConnection;
+use diesel::pg::upsert::excluded;
+use diesel::prelude::*;
+use diesel::r2d2::{
+ ConnectionManager,
+ Pool,
+ PooledConnection
+};
+use diesel;
+use self::models::*;
+use self::schema::*;
+use std::env;
+use std::ops::Deref;
+
+/// While the struct itself and the connection are public, Database cannot be manually
+/// instantiated. Use Database::connect() to start it.
+pub struct Database {
+ pub pool: Pool<ConnectionManager<PgConnection>>,
+ _hidden: (),
+}
+
+impl Database {
+ /// Create a new database with a connection.
+ /// Returns a new Database.
+ pub fn connect() -> Self {
+ let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
+ let manager = ConnectionManager::<PgConnection>::new(database_url);
+ let pool = Pool::builder()
+ .max_size(10)
+ .build(manager)
+ .expect("Failed to make connection pool");
+
+ Database {
+ pool,
+ _hidden: (),
+ }
+ }
+
+ /// Request a connection from the connection pool
+ fn conn(&self) -> PooledConnection<ConnectionManager<PgConnection>> {
+ self.pool.clone().get().expect("Attempt to get connection timed out")
+ }
+
+ // Guild Tools
+ /// Add a guild with a given ID.
+ /// Returns the Ok(Some(Guild)) on success or Ok(None) if there is a conflict.
+ /// May return Err(DatabaseError) in the event of some other failure.
+ pub fn new_guild(&self, id: i64) -> QueryResult<Option<Guild>> {
+ let guild = NewGuild {
+ id,
+ };
+ diesel::insert_into(guilds::table)
+ .values(&guild)
+ .on_conflict_do_nothing()
+ .get_result(self.conn().deref())
+ .optional()
+ }
+ /// Add multiple guilds with a vector of IDs
+ /// Does nothing on conflict
+ /// Returns Result<count, err>
+ pub fn new_guilds(&self, ids: &[i64]) -> QueryResult<usize> {
+ let guilds = {
+ ids.iter().map(|e| {
+ NewGuild {
+ id: *e,
+ }
+ }).collect::<Vec<NewGuild>>()
+ };
+ diesel::insert_into(guilds::table)
+ .values(&guilds)
+ .on_conflict_do_nothing()
+ .execute(self.conn().deref())
+ }
+ /// Delete a guild by the ID.
+ /// Returns Result<guild_id, err>
+ pub fn del_guild(&self, g_id: i64) -> QueryResult<i64> {
+ use crate::db::schema::guilds::columns::id;
+ diesel::delete(guilds::table)
+ .filter(id.eq(&g_id))
+ .returning(id)
+ .get_result(self.conn().deref())
+ }
+ /// Select a guild
+ /// Returns Result<Guild, Err>
+ pub fn get_guild(&self, g_id: i64) -> QueryResult<Guild> {
+ guilds::table.find(&g_id)
+ .first(self.conn().deref())
+ }
+ /// Update a guild
+ /// Returns Result<Guild, Err>
+ pub fn update_guild(&self, g_id: i64, guild: Guild) -> QueryResult<Guild> {
+ let target = guilds::table.find(&g_id);
+ diesel::update(target)
+ .set(&guild)
+ .get_result(self.conn().deref())
+ }
+ /// Get the count of guilds in the database
+ pub fn count_guilds(&self) -> QueryResult<i64> {
+ use diesel::dsl::count_star;
+ guilds::table.select(count_star())
+ .get_result(self.conn().deref())
+ }
+
+ // User Tools
+ /// Add a user with a given user ID and guild ID.
+ /// Returns the User on success.
+ pub fn new_user(&self, id: i64, guild_id: i64) -> QueryResult<User<Utc>> {
+ let user = NewUser {
+ id,
+ guild_id,
+ };
+ diesel::insert_into(users::table)
+ .values(&user)
+ .get_result(self.conn().deref())
+ }
+ /// Delete a user by user ID and guild ID.
+ /// Returns the ID on success.
+ pub fn del_user(&self, u_id: i64, g_id: i64) -> QueryResult<i64> {
+ use crate::db::schema::users::columns::{id, guild_id};
+ diesel::delete(users::table)
+ .filter(id.eq(&u_id))
+ .filter(guild_id.eq(&g_id))
+ .returning(id)
+ .get_result(self.conn().deref())
+ }
+ /// Select a user
+ /// Returns the user on success
+ pub fn get_user(&self, u_id: i64, g_id: i64) -> QueryResult<User<Utc>> {
+ users::table.find((u_id, g_id))
+ .first(self.conn().deref())
+ }
+ /// Select all users in a guild
+ /// Returns a vector of users on success
+ pub fn get_users(&self, g_id: i64) -> QueryResult<Vec<User<Utc>>> {
+ use crate::db::schema::users::columns::guild_id;
+ users::table.filter(guild_id.eq(&g_id))
+ .get_results(self.conn().deref())
+ }
+ /// Update a user
+ /// Returns the new user on success
+ pub fn update_user(&self, u_id: i64, g_id: i64, user: User<Utc>) -> QueryResult<User<Utc>> {
+ let target = users::table.find((u_id, g_id));
+ diesel::update(target)
+ .set(&user)
+ .get_result(self.conn().deref())
+ }
+ /// Upsert a user
+ /// Returns the new user on success
+ pub fn upsert_user(&self, user: UserUpdate) -> QueryResult<User<Utc>> {
+ use crate::db::schema::users::columns::{id, guild_id};
+ diesel::insert_into(users::table)
+ .values(&user)
+ .on_conflict((id, guild_id))
+ .do_update()
+ .set(&user)
+ .get_result(self.conn().deref())
+ }
+ /// Upserts multiple users with a vector of UserUpdates
+ /// Returns Result<count, err>
+ pub fn upsert_users(&self, users: &[UserUpdate]) -> QueryResult<usize> {
+ use crate::db::schema::users::columns::*;
+ diesel::insert_into(users::table)
+ .values(users)
+ .on_conflict((id, guild_id))
+ .do_update()
+ .set((nickname.eq(excluded(nickname)),
+ username.eq(excluded(username)),
+ roles.eq(excluded(roles))))
+ .execute(self.conn().deref())
+ }
+ /// Get the count of users in the database
+ pub fn count_users(&self) -> QueryResult<i64> {
+ use diesel::dsl::count_star;
+ users::table.select(count_star())
+ .get_result(self.conn().deref())
+ }
+
+ // Role Tools
+ /// Add a role with the given role ID, guild ID, and optionally a category and aliases.
+ /// Returns the Role on success.
+ pub fn new_role(&self, id: i64, guild_id: i64, category: Option<String>, aliases: Option<Vec<String>>) -> QueryResult<Role> {
+ let role = NewRole {
+ id,
+ guild_id,
+ category,
+ aliases,
+ };
+ diesel::insert_into(roles::table)
+ .values(&role)
+ .get_result(self.conn().deref())
+ }
+ /// Delete a role by role ID and guild ID.
+ /// Returns the ID on success.
+ pub fn del_role(&self, r_id: i64, g_id: i64) -> QueryResult<i64> {
+ use crate::db::schema::roles::columns::{id, guild_id};
+ diesel::delete(roles::table)
+ .filter(id.eq(&r_id))
+ .filter(guild_id.eq(&g_id))
+ .returning(id)
+ .get_result(self.conn().deref())
+ }
+ /// Select a role
+ /// Returns the role on success
+ pub fn get_role(&self, r_id: i64, g_id: i64) -> QueryResult<Role> {
+ roles::table.find((r_id, g_id))
+ .first(self.conn().deref())
+ }
+ /// Select all roles by guild id
+ /// Returns a vector of roles on success
+ pub fn get_roles(&self, g_id: i64) -> QueryResult<Vec<Role>> {
+ use crate::db::schema::roles::columns::guild_id;
+ roles::table.filter(guild_id.eq(&g_id))
+ .get_results(self.conn().deref())
+ }
+ /// Update a role
+ /// Returns the new role on success
+ pub fn update_role(&self, r_id: i64, g_id: i64, role: Role) -> QueryResult<Role> {
+ let target = roles::table.find((r_id, g_id));
+ diesel::update(target)
+ .set(&role)
+ .get_result(self.conn().deref())
+ }
+ /// Get the count of roles in the database
+ pub fn count_roles(&self) -> QueryResult<i64> {
+ use diesel::dsl::count_star;
+ roles::table.select(count_star())
+ .get_result(self.conn().deref())
+ }
+
+ // Note Tools
+ /// Add a note to the given user in the given guild by a given moderator
+ /// Returns the Note on success.
+ pub fn new_note(&self, user_id: i64, guild_id: i64, note: String, moderator: i64) -> QueryResult<Note<Utc>> {
+ let note = NewNote {
+ user_id,
+ guild_id,
+ note,
+ moderator,
+ };
+ diesel::insert_into(notes::table)
+ .values(&note)
+ .get_result(self.conn().deref())
+ }
+ /// Delete a note by index, user ID, and guild ID.
+ /// Returns the Note.note on success.
+ pub fn del_note(&self, n_id: i32, u_id: i64, g_id: i64) -> QueryResult<String> {
+ use crate::db::schema::notes::columns::{user_id, guild_id, id, note};
+ diesel::delete(notes::table)
+ .filter(user_id.eq(&u_id))
+ .filter(guild_id.eq(&g_id))
+ .filter(id.eq(&n_id))
+ .returning(note)
+ .get_result(self.conn().deref())
+ }
+ /*
+ /// Select a note
+ /// Returns the note on success
+ pub fn get_note(&self, n_id: i32, u_id: i64, g_id: i64) -> QueryResult<Note<Utc>> {
+ notes::table.find((n_id, u_id, g_id))
+ .first(self.conn().deref())
+ }*/
+ /// Select all notes for a user
+ /// Returns a vec of notes on success
+ pub fn get_notes(&self, u_id: i64, g_id: i64) -> QueryResult<Vec<Note<Utc>>> {
+ use crate::db::schema::notes::columns::{user_id, guild_id};
+ notes::table.filter(user_id.eq(&u_id))
+ .filter(guild_id.eq(&g_id))
+ .get_results(self.conn().deref())
+ }
+ /// Get the count of notes in the database
+ pub fn count_notes(&self) -> QueryResult<i64> {
+ use diesel::dsl::count_star;
+ notes::table.select(count_star())
+ .get_result(self.conn().deref())
+ }
+
+ // Timer Tools
+ /// Add a timer
+ /// Returns the timer on success.
+ pub fn new_timer(&self, starttime: i64, endtime: i64, data: String) -> QueryResult<Timer> {
+ let timer = NewTimer {
+ starttime,
+ endtime,
+ data,
+ };
+ diesel::insert_into(timers::table)
+ .values(&timer)
+ .get_result(self.conn().deref())
+ }
+ /// Delete a timer with the given ID.
+ /// Returns the note data on success.
+ pub fn del_timer(&self, t_id: i32) -> QueryResult<String> {
+ use crate::db::schema::timers::columns::{id, data};
+ diesel::delete(timers::table)
+ .filter(id.eq(&t_id))
+ .returning(data)
+ .get_result(self.conn().deref())
+ }
+ /*
+ /// Select a timer
+ /// Returns the timer on success
+ pub fn get_timer(&self, t_id: i32) -> QueryResult<Timer> {
+ timers::table.find(t_id)
+ .first(self.conn().deref())
+ }*/
+ /// Select all timers
+ /// Returns a vec of timers on success
+ pub fn get_timers(&self) -> QueryResult<Vec<Timer>> {
+ timers::table.get_results(self.conn().deref())
+ }
+ /// Get the count of timers in the database
+ pub fn count_timers(&self) -> QueryResult<i64> {
+ use diesel::dsl::count_star;
+ timers::table.select(count_star())
+ .get_result(self.conn().deref())
+ }
+ /// Get the timer with the closest expiration time to the present
+ pub fn get_earliest_timer(&self) -> QueryResult<Timer> {
+ use crate::db::schema::timers::{all_columns, columns::endtime};
+ timers::table.select(all_columns)
+ .order(endtime.asc())
+ .first(self.conn().deref())
+ }
+
+ // Case Tools
+ /// Add a Case
+ /// Returns the Case on success
+ pub fn new_case(&self, user_id: i64, guild_id: i64, casetype: String, reason: Option<String>, moderator: i64) -> QueryResult<Case<Utc>> {
+ let case = NewCase {
+ user_id,
+ guild_id,
+ casetype,
+ reason,
+ moderator,
+ };
+ diesel::insert_into(cases::table)
+ .values(&case)
+ .get_result(self.conn().deref())
+ }
+ /*
+ /// Delete a case
+ /// Returns the case on success.
+ pub fn del_case(&self, c_id: i32, u_id: i64, g_id: i64) -> QueryResult<Case<Utc>> {
+ use db::schema::cases::columns::{id, user_id, guild_id};
+ diesel::delete(cases)
+ .filter(id.eq(&c_id))
+ .filter(user_id.eq(&u_id))
+ .filter(guild_id.eq(&g_id))
+ .get_result(self.conn().deref())
+ }
+ /// Select a case
+ /// Returns the case on success
+ pub fn get_case(&self, c_id: i32, u_id: i64, g_id: i64) -> QueryResult<Case<Utc>> {
+ cases::table.find((c_id, u_id, g_id))
+ .first(self.conn().deref())
+ }*/
+ /// Select all cases for a user
+ /// Returns a vector of cases on success
+ pub fn get_cases(&self, u_id: i64, g_id: i64) -> QueryResult<Vec<Case<Utc>>> {
+ use crate::db::schema::cases::columns::{guild_id, user_id};
+ cases::table.filter(user_id.eq(&u_id))
+ .filter(guild_id.eq(&g_id))
+ .get_results(self.conn().deref())
+ }
+ /// Get the count of cases in the database
+ pub fn count_cases(&self) -> QueryResult<i64> {
+ use diesel::dsl::count_star;
+ cases::table.select(count_star())
+ .get_result(self.conn().deref())
+ }
+
+ // Tag Tools
+ /// Add a Tag
+ /// Returns the Tag on success
+ pub fn new_tag(&self, author: i64, guild_id: i64, name: String, data: String) -> QueryResult<Tag> {
+ let tag = NewTag {
+ author,
+ guild_id,
+ name,
+ data,
+ };
+ diesel::insert_into(tags::table)
+ .values(&tag)
+ .get_result(self.conn().deref())
+ }
+ /// Delete a Tag
+ /// Returns the Tag on success.
+ pub fn del_tag(&self, g_id: i64, nm: String) -> QueryResult<Tag> {
+ use crate::db::schema::tags::columns::{name, guild_id};
+ diesel::delete(tags::table)
+ .filter(name.eq(&nm))
+ .filter(guild_id.eq(&g_id))
+ .get_result(self.conn().deref())
+ }
+ /// Select a Tag
+ /// Returns the Tag on success
+ pub fn get_tag(&self, g_id: i64, nm: String) -> QueryResult<Tag> {
+ tags::table.find((g_id, nm))
+ .first(self.conn().deref())
+ }
+ /// Select all tags by guild
+ /// Returns Vec<Tag> on success on success
+ pub fn get_tags(&self, g_id: i64) -> QueryResult<Vec<Tag>> {
+ use crate::db::schema::tags::columns::guild_id;
+ tags::table.filter(guild_id.eq(&g_id))
+ .get_results(self.conn().deref())
+ }
+ /// Update a tag
+ /// Returns the new tag on success
+ pub fn update_tag(&self, g_id: i64, nm: String, tag: Tag) -> QueryResult<Tag> {
+ let target = tags::table.find((g_id, nm));
+ diesel::update(target)
+ .set(&tag)
+ .get_result(self.conn().deref())
+ }
+ /// Get the count of tags in the database
+ pub fn count_tags(&self) -> QueryResult<i64> {
+ use diesel::dsl::count_star;
+ tags::table.select(count_star())
+ .get_result(self.conn().deref())
+ }
+
+ // Premium Tools
+ /// Add premium with a given guild ID.
+ /// Returns the PremiumSettings on success.
+ pub fn new_premium(&self, id: i64) -> QueryResult<PremiumSettings> {
+ let prem = NewPremium {
+ id,
+ };
+ diesel::insert_into(premium::table)
+ .values(&prem)
+ .get_result(self.conn().deref())
+ }
+ /// Delete premium by a guild ID.
+ /// Returns the ID on success.
+ pub fn del_premium(&self, g_id: i64) -> QueryResult<i64> {
+ use crate::db::schema::premium::columns::id;
+ diesel::delete(premium::table)
+ .filter(id.eq(&g_id))
+ .returning(id)
+ .get_result(self.conn().deref())
+ }
+ /// Select PremiumSettings by guild ID
+ /// Returns the settings on success
+ /// Will return Err if the guild is not premium
+ pub fn get_premium(&self, g_id: i64) -> QueryResult<PremiumSettings> {
+ premium::table.find(&g_id)
+ .first(self.conn().deref())
+ }
+ /// Update PremiumSettings
+ /// Returns the new settings on success
+ pub fn update_premium(&self, g_id: i64, settings: PremiumSettings) -> QueryResult<PremiumSettings> {
+ let target = premium::table.find(&g_id);
+ diesel::update(target)
+ .set(&settings)
+ .get_result(self.conn().deref())
+ }
+ /// Get the count of guilds with premium in the database
+ pub fn count_premium(&self) -> QueryResult<i64> {
+ use diesel::dsl::count_star;
+ premium::table.select(count_star())
+ .get_result(self.conn().deref())
+ }
+
+ // Tag Tools
+ /// Add a Hackban
+ /// Returns the Hackban on success
+ pub fn new_hackban(&self, id: i64, guild_id: i64, reason: Option<String>) -> QueryResult<Hackban> {
+ let hb = Hackban {
+ id,
+ guild_id,
+ reason,
+ };
+ diesel::insert_into(hackbans::table)
+ .values(&hb)
+ .get_result(self.conn().deref())
+ }
+ /// Delete a Hackban
+ /// Returns the Hackban on success.
+ pub fn del_hackban(&self, h_id: i64, g_id: i64) -> QueryResult<Hackban> {
+ use crate::db::schema::hackbans::columns::{id, guild_id};
+ diesel::delete(hackbans::table)
+ .filter(id.eq(&h_id))
+ .filter(guild_id.eq(&g_id))
+ .get_result(self.conn().deref())
+ }
+ /// Select a Hackban
+ /// Returns the Hackban on success
+ pub fn get_hackban(&self, id: i64, g_id: i64) -> QueryResult<Hackban> {
+ hackbans::table.find((id, g_id))
+ .first(self.conn().deref())
+ }
+ /// Select all hackbans by guild
+ /// Returns Vec<Hackban> on success on success
+ pub fn get_hackbans(&self, g_id: i64) -> QueryResult<Vec<Hackban>> {
+ use crate::db::schema::hackbans::columns::guild_id;
+ hackbans::table.filter(guild_id.eq(&g_id))
+ .get_results(self.conn().deref())
+ }
+ /// Get the count of hackbans in the database
+ pub fn count_hackbans(&self) -> QueryResult<i64> {
+ use diesel::dsl::count_star;
+ hackbans::table.select(count_star())
+ .get_result(self.conn().deref())
+ }
+}
diff --git a/src/db/models.rs b/src/db/models.rs
new file mode 100644
index 0000000..2e6a460
--- /dev/null
+++ b/src/db/models.rs
@@ -0,0 +1,253 @@
+use chrono::{DateTime, TimeZone, Utc};
+use serenity::model::id::{UserId, RoleId};
+use std::fmt::{Display, Formatter, Result as FmtResult};
+use super::schema::*;
+
+// Query-ables
+#[derive(Queryable, Identifiable, AsChangeset, Debug)]
+#[primary_key(id)]
+pub struct Guild {
+ pub id: i64,
+ pub admin_roles: Vec<i64>,
+ pub audit: bool,
+ pub audit_channel: i64,
+ pub audit_threshold: i16,
+ pub autorole: bool,
+ pub autoroles: Vec<i64>,
+ pub ignored_channels: Vec<i64>,
+ pub ignore_level: i16,
+ pub introduction: bool,
+ pub introduction_channel: i64,
+ pub introduction_message: String,
+ pub introduction_type: String,
+ pub mod_roles: Vec<i64>,
+ pub modlog: bool,
+ pub modlog_channel: i64,
+ pub mute_setup: bool,
+ pub prefix: String,
+ pub welcome: bool,
+ pub welcome_channel: i64,
+ pub welcome_message: String,
+ pub welcome_type: String,
+ pub goodbye: bool,
+ pub goodbye_channel: i64,
+ pub goodbye_message: String,
+ pub goodbye_type: String,
+ pub commands: Vec<String>,
+ pub logging: Vec<String>,
+}
+
+// Deprecated fields: nickname, roles
+#[derive(Queryable, Identifiable, AsChangeset, Debug)]
+#[primary_key(id, guild_id)]
+pub struct User<Tz: TimeZone> {
+ pub id: i64,
+ pub guild_id: i64,
+ pub username: String,
+ pub nickname: String,
+ pub roles: Vec<i64>,
+ pub watchlist: bool,
+ pub xp: i64,
+ pub last_message: DateTime<Tz>,
+ pub registered: Option<DateTime<Tz>>,
+}
+
+#[derive(Queryable, Identifiable, AsChangeset, Debug)]
+#[primary_key(id, user_id, guild_id)]
+pub struct Note<Tz: TimeZone> {
+ pub id: i32,
+ pub user_id: i64,
+ pub guild_id: i64,
+ pub note: String,
+ pub moderator: i64,
+ pub timestamp: DateTime<Tz>,
+}
+
+#[derive(Queryable, Identifiable, AsChangeset, Debug)]
+#[primary_key(id, guild_id)]
+pub struct Role {
+ pub id: i64,
+ pub guild_id: i64,
+ pub category: String,
+ pub aliases: Vec<String>,
+ pub required_roles: Vec<i64>,
+ pub forbidden_roles: Vec<i64>,
+}
+
+#[derive(Queryable, Identifiable, AsChangeset, Debug)]
+#[primary_key(id)]
+pub struct Timer {
+ pub id: i32,
+ pub starttime: i64,
+ pub endtime: i64,
+ pub data: String,
+}
+
+#[derive(Queryable, Identifiable, AsChangeset, Debug)]
+#[primary_key(id, user_id, guild_id)]
+pub struct Case<Tz: TimeZone> {
+ pub id: i32,
+ pub user_id: i64,
+ pub guild_id: i64,
+ pub casetype: String,
+ pub reason: String,
+ pub moderator: i64,
+ pub timestamp: DateTime<Tz>
+}
+
+#[derive(Queryable, Identifiable, AsChangeset, Debug)]
+#[primary_key(guild_id, name)]
+pub struct Tag {
+ pub author: i64,
+ pub guild_id: i64,
+ pub name: String,
+ pub data: String,
+}
+
+#[derive(Queryable, Identifiable, AsChangeset, Debug)]
+#[table_name="premium"]
+pub struct PremiumSettings {
+ pub id: i64,
+ pub tier: i32,
+ pub register_member_role: Option<i64>,
+ pub register_cooldown_role: Option<i64>,
+ pub register_cooldown_duration: Option<i32>,
+ pub cooldown_restricted_roles: Vec<i64>,
+}
+
+// This one would be the same for insertable or queryable, so it has both
+#[derive(Queryable, Identifiable, AsChangeset, Insertable, Clone, Debug)]
+#[primary_key(id, guild_id)]
+pub struct Hackban {
+ pub id: i64,
+ pub guild_id: i64,
+ pub reason: Option<String>,
+}
+// End Query-ables
+
+// Insertables
+#[derive(Insertable)]
+#[table_name="guilds"]
+pub struct NewGuild {
+ pub id: i64,
+}
+
+#[derive(Insertable)]
+#[table_name="users"]
+pub struct NewUser {
+ pub id: i64,
+ pub guild_id: i64,
+}
+
+#[derive(Insertable)]
+#[table_name="notes"]
+pub struct NewNote {
+ pub user_id: i64,
+ pub guild_id: i64,
+ pub note: String,
+ pub moderator: i64,
+}
+
+#[derive(Insertable)]
+#[table_name="roles"]
+pub struct NewRole {
+ pub id: i64,
+ pub guild_id: i64,
+ pub category: Option<String>,
+ pub aliases: Option<Vec<String>>,
+}
+
+#[derive(Insertable)]
+#[table_name="timers"]
+pub struct NewTimer {
+ pub starttime: i64,
+ pub endtime: i64,
+ pub data: String,
+}
+
+#[derive(Insertable)]
+#[table_name="cases"]
+pub struct NewCase {
+ pub user_id: i64,
+ pub guild_id: i64,
+ pub casetype: String,
+ pub reason: Option<String>,
+ pub moderator: i64,
+}
+
+#[derive(Insertable)]
+#[table_name="tags"]
+pub struct NewTag {
+ pub author: i64,
+ pub guild_id: i64,
+ pub name: String,
+ pub data: String,
+}
+
+#[derive(Insertable, Debug)]
+#[table_name="premium"]
+pub struct NewPremium {
+ pub id: i64,
+}
+// End Insertables
+
+// Other Stuff
+#[derive(Insertable, AsChangeset, Debug)]
+#[table_name="users"]
+#[primary_key(id, guild_id)]
+pub struct UserUpdate {
+ pub id: i64,
+ pub guild_id: i64,
+ pub username: String,
+}
+
+impl Display for Guild {
+ fn fmt(&self, f: &mut Formatter) -> FmtResult {
+ write!(f, "**Admin Roles:** {}\n**Audit:** {}\n**Audit Channel:** {}\n**Audit Threshold:** {}\n**Autorole:** {}\n**Autoroles:** {}\n**Ignored Channels:** {}\n**Ignore Level:** {}\n**Introduction:** {}\n**Introduction Channel:** {}\n**Introduction Type:** {}\n**Introduction Message:** {}\n**Mod Roles: ** {}\n**Modlog:** {}\n**Modlog Channel:** {}\n**Mute Setup:** {}\n**Prefix:** {}\n**Welcome:** {}\n**Welcome Channel:** {}\n**Welcome Type:** {}\n**Welcome Message:** {}\n**Disabled Commands:** {}\n**Disabled Log Types:** {}",
+ self.admin_roles.iter().map(|e| match RoleId(*e as u64).to_role_cached() {
+ Some(role) => role.name,
+ None => format!("{}", e),
+ }).collect::<Vec<String>>().join(", "),
+ self.audit,
+ format!("<#{}>", self.audit_channel),
+ self.audit_threshold,
+ self.autorole,
+ self.autoroles.iter().map(|e| match RoleId(*e as u64).to_role_cached() {
+ Some(role) => role.name,
+ None => format!("{}", e),
+ }).collect::<Vec<String>>().join(", "),
+ self.ignored_channels.iter().map(|e| format!("<#{}>", e)).collect::<Vec<String>>().join(", "),
+ self.ignore_level,
+ self.introduction,
+ format!("<#{}>", self.introduction_channel),
+ self.introduction_type,
+ self.introduction_message,
+ self.mod_roles.iter().map(|e| match RoleId(*e as u64).to_role_cached() {
+ Some(role) => role.name,
+ None => format!("{}", e),
+ }).collect::<Vec<String>>().join(", "),
+ self.modlog,
+ format!("<#{}>", self.modlog_channel),
+ self.mute_setup,
+ self.prefix,
+ self.welcome,
+ format!("<#{}>", self.welcome_channel),
+ self.welcome_type,
+ self.welcome_message,
+ self.commands.join(", "),
+ self.logging.join(", ")
+ )}
+}
+
+impl Display for Note<Utc> {
+ fn fmt(&self, f: &mut Formatter) -> FmtResult {
+ write!(f, "{} wrote on {} (ID: {})\n`{}`",
+ match UserId(self.moderator as u64).to_user() {
+ Ok(user) => user.tag(),
+ Err(_) => format!("{}", self.moderator),
+ },
+ self.timestamp.format("%a, %d %h %Y @ %H:%M:%S").to_string(),
+ self.id,
+ self.note)
+ }
+}
diff --git a/src/db/schema.rs b/src/db/schema.rs
new file mode 100644
index 0000000..25f16ab
--- /dev/null
+++ b/src/db/schema.rs
@@ -0,0 +1,129 @@
+table! {
+ cases (id, user_id, guild_id) {
+ id -> Int4,
+ user_id -> Int8,
+ guild_id -> Int8,
+ casetype -> Text,
+ reason -> Text,
+ moderator -> Int8,
+ timestamp -> Timestamptz,
+ }
+}
+
+table! {
+ guilds (id) {
+ id -> Int8,
+ admin_roles -> Array<Int8>,
+ audit -> Bool,
+ audit_channel -> Int8,
+ audit_threshold -> Int2,
+ autorole -> Bool,
+ autoroles -> Array<Int8>,
+ ignored_channels -> Array<Int8>,
+ ignore_level -> Int2,
+ introduction -> Bool,
+ introduction_channel -> Int8,
+ introduction_message -> Text,
+ introduction_type -> Text,
+ mod_roles -> Array<Int8>,
+ modlog -> Bool,
+ modlog_channel -> Int8,
+ mute_setup -> Bool,
+ prefix -> Text,
+ welcome -> Bool,
+ welcome_channel -> Int8,
+ welcome_message -> Text,
+ welcome_type -> Text,
+ goodbye -> Bool,
+ goodbye_channel -> Int8,
+ goodbye_message -> Text,
+ goodbye_type -> Text,
+ commands -> Array<Text>,
+ logging -> Array<Text>,
+ }
+}
+
+table! {
+ hackbans (id, guild_id) {
+ id -> Int8,
+ guild_id -> Int8,
+ reason -> Nullable<Text>,
+ }
+}
+
+table! {
+ notes (id, user_id, guild_id) {
+ id -> Int4,
+ user_id -> Int8,
+ guild_id -> Int8,
+ note -> Text,
+ moderator -> Int8,
+ timestamp -> Timestamptz,
+ }
+}
+
+table! {
+ premium (id) {
+ id -> Int8,
+ tier -> Int4,
+ register_member_role -> Nullable<Int8>,
+ register_cooldown_role -> Nullable<Int8>,
+ register_cooldown_duration -> Nullable<Int4>,
+ cooldown_restricted_roles -> Array<Int8>,
+ }
+}
+
+table! {
+ roles (id, guild_id) {
+ id -> Int8,
+ guild_id -> Int8,
+ category -> Text,
+ aliases -> Array<Text>,
+ required_roles -> Array<Int8>,
+ forbidden_roles -> Array<Int8>,
+ }
+}
+
+table! {
+ tags (guild_id, name) {
+ author -> Int8,
+ guild_id -> Int8,
+ name -> Text,
+ data -> Text,
+ }
+}
+
+table! {
+ timers (id) {
+ id -> Int4,
+ starttime -> Int8,
+ endtime -> Int8,
+ data -> Text,
+ }
+}
+
+table! {
+ users (id, guild_id) {
+ id -> Int8,
+ guild_id -> Int8,
+ username -> Text,
+ nickname -> Text,
+ roles -> Array<Int8>,
+ watchlist -> Bool,
+ xp -> Int8,
+ last_message -> Timestamptz,
+ registered -> Nullable<Timestamptz>,
+ }
+}
+
+allow_tables_to_appear_in_same_query!(
+ cases,
+ guilds,
+ hackbans,
+ notes,
+ premium,
+ roles,
+ tags,
+ timers,
+ users,
+);