diff options
| author | Fuwn <[email protected]> | 2020-10-26 19:03:53 -0700 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2020-10-26 19:03:53 -0700 |
| commit | 9742614a1dc4699c1f2c69d923d402237672335d (patch) | |
| tree | a49f7d834372f37cef06b30a28ff1b40bdfaa079 /src/db | |
| parent | Create README.md (diff) | |
| download | dep-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.rs | 511 | ||||
| -rw-r--r-- | src/db/models.rs | 253 | ||||
| -rw-r--r-- | src/db/schema.rs | 129 |
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(¬e) + .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, +); |