Compare commits
	
		
			3 Commits
		
	
	
		
			1.7.4
			...
			jellywx/gu
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| b0a04bb289 | |||
| eef1f6f3e8 | |||
| 3d08027325 | 
							
								
								
									
										92
									
								
								migration/05-restructure-guild-table.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								migration/05-restructure-guild-table.sql
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,92 @@
 | 
				
			|||||||
 | 
					SET foreign_key_checks = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					START TRANSACTION;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- drop existing constraints
 | 
				
			||||||
 | 
					ALTER TABLE channels DROP FOREIGN KEY `channels_ibfk_1`;
 | 
				
			||||||
 | 
					ALTER TABLE command_aliases DROP FOREIGN KEY `command_aliases_ibfk_1`;
 | 
				
			||||||
 | 
					ALTER TABLE events DROP FOREIGN KEY `events_ibfk_1`;
 | 
				
			||||||
 | 
					ALTER TABLE guild_users DROP FOREIGN KEY `guild_users_ibfk_1`;
 | 
				
			||||||
 | 
					ALTER TABLE macro DROP FOREIGN KEY `macro_ibfk_1`;
 | 
				
			||||||
 | 
					ALTER TABLE roles DROP FOREIGN KEY `roles_ibfk_1`;
 | 
				
			||||||
 | 
					ALTER TABLE todos DROP FOREIGN KEY `todos_ibfk_2`;
 | 
				
			||||||
 | 
					ALTER TABLE reminder_template DROP FOREIGN KEY `reminder_template_ibfk_1`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- update foreign key types
 | 
				
			||||||
 | 
					ALTER TABLE channels MODIFY `guild_id` BIGINT UNSIGNED;
 | 
				
			||||||
 | 
					ALTER TABLE command_aliases MODIFY `guild_id` BIGINT UNSIGNED;
 | 
				
			||||||
 | 
					ALTER TABLE events MODIFY `guild_id` BIGINT UNSIGNED;
 | 
				
			||||||
 | 
					ALTER TABLE guild_users MODIFY `guild` BIGINT UNSIGNED;
 | 
				
			||||||
 | 
					ALTER TABLE macro MODIFY `guild_id` BIGINT UNSIGNED;
 | 
				
			||||||
 | 
					ALTER TABLE roles MODIFY `guild_id` BIGINT UNSIGNED;
 | 
				
			||||||
 | 
					ALTER TABLE todos MODIFY `guild_id` BIGINT UNSIGNED;
 | 
				
			||||||
 | 
					ALTER TABLE reminder_template MODIFY `guild_id` BIGINT UNSIGNED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- update foreign key values
 | 
				
			||||||
 | 
					UPDATE channels SET `guild_id` = (SELECT `guild` FROM guilds WHERE guilds.`id` = `guild_id`);
 | 
				
			||||||
 | 
					UPDATE command_aliases SET `guild_id` = (SELECT `guild` FROM guilds WHERE guilds.`id` = `guild_id`);
 | 
				
			||||||
 | 
					UPDATE events SET `guild_id` = (SELECT `guild` FROM guilds WHERE guilds.`id` = `guild_id`);
 | 
				
			||||||
 | 
					UPDATE guild_users SET `guild` = (SELECT `guild` FROM guilds WHERE guilds.`id` = guild_users.`guild`);
 | 
				
			||||||
 | 
					UPDATE macro SET `guild_id` = (SELECT `guild` FROM guilds WHERE guilds.`id` = `guild_id`);
 | 
				
			||||||
 | 
					UPDATE roles SET `guild_id` = (SELECT `guild` FROM guilds WHERE guilds.`id` = `guild_id`);
 | 
				
			||||||
 | 
					UPDATE todos SET `guild_id` = (SELECT `guild` FROM guilds WHERE guilds.`id` = `guild_id`);
 | 
				
			||||||
 | 
					UPDATE reminder_template SET `guild_id` = (SELECT `guild` FROM guilds WHERE guilds.`id` = `guild_id`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- update guilds table
 | 
				
			||||||
 | 
					ALTER TABLE guilds MODIFY `id` BIGINT UNSIGNED NOT NULL;
 | 
				
			||||||
 | 
					UPDATE guilds SET `id` = `guild`;
 | 
				
			||||||
 | 
					ALTER TABLE guilds DROP COLUMN `guild`;
 | 
				
			||||||
 | 
					ALTER TABLE guilds ADD COLUMN `default_channel` BIGINT UNSIGNED;
 | 
				
			||||||
 | 
					ALTER TABLE guilds ADD CONSTRAINT `default_channel_fk`
 | 
				
			||||||
 | 
					    FOREIGN KEY (`default_channel`)
 | 
				
			||||||
 | 
					        REFERENCES channels(`channel`)
 | 
				
			||||||
 | 
					        ON DELETE SET NULL
 | 
				
			||||||
 | 
					        ON UPDATE CASCADE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- re-add constraints
 | 
				
			||||||
 | 
					ALTER TABLE channels ADD CONSTRAINT
 | 
				
			||||||
 | 
					    FOREIGN KEY (`guild_id`)
 | 
				
			||||||
 | 
					        REFERENCES guilds(`id`)
 | 
				
			||||||
 | 
					        ON DELETE CASCADE
 | 
				
			||||||
 | 
					        ON UPDATE CASCADE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ALTER TABLE command_aliases ADD CONSTRAINT
 | 
				
			||||||
 | 
					    FOREIGN KEY (`guild_id`)
 | 
				
			||||||
 | 
					        REFERENCES guilds(`id`)
 | 
				
			||||||
 | 
					        ON DELETE CASCADE
 | 
				
			||||||
 | 
					        ON UPDATE CASCADE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ALTER TABLE events ADD CONSTRAINT
 | 
				
			||||||
 | 
					    FOREIGN KEY (`guild_id`)
 | 
				
			||||||
 | 
					        REFERENCES guilds(`id`)
 | 
				
			||||||
 | 
					        ON DELETE CASCADE
 | 
				
			||||||
 | 
					        ON UPDATE CASCADE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ALTER TABLE guild_users ADD CONSTRAINT
 | 
				
			||||||
 | 
					    FOREIGN KEY (`guild`)
 | 
				
			||||||
 | 
					        REFERENCES guilds(`id`)
 | 
				
			||||||
 | 
					        ON DELETE CASCADE
 | 
				
			||||||
 | 
					        ON UPDATE CASCADE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ALTER TABLE macro ADD CONSTRAINT
 | 
				
			||||||
 | 
					    FOREIGN KEY (`guild_id`)
 | 
				
			||||||
 | 
					        REFERENCES guilds(`id`)
 | 
				
			||||||
 | 
					        ON DELETE CASCADE
 | 
				
			||||||
 | 
					        ON UPDATE CASCADE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ALTER TABLE roles ADD CONSTRAINT
 | 
				
			||||||
 | 
					    FOREIGN KEY (`guild_id`)
 | 
				
			||||||
 | 
					        REFERENCES guilds(`id`)
 | 
				
			||||||
 | 
					        ON DELETE CASCADE
 | 
				
			||||||
 | 
					        ON UPDATE CASCADE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ALTER TABLE todos ADD CONSTRAINT
 | 
				
			||||||
 | 
					    FOREIGN KEY (`guild_id`)
 | 
				
			||||||
 | 
					        REFERENCES guilds(`id`)
 | 
				
			||||||
 | 
					        ON DELETE CASCADE
 | 
				
			||||||
 | 
					        ON UPDATE CASCADE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					COMMIT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SET foreign_key_checks = 1;
 | 
				
			||||||
@@ -24,7 +24,7 @@ pub async fn macro_name_autocomplete(ctx: Context<'_>, partial: &str) -> Vec<Str
 | 
				
			|||||||
SELECT name
 | 
					SELECT name
 | 
				
			||||||
FROM macro
 | 
					FROM macro
 | 
				
			||||||
WHERE
 | 
					WHERE
 | 
				
			||||||
    guild_id = (SELECT id FROM guilds WHERE guild = ?)
 | 
					    guild_id = ?
 | 
				
			||||||
    AND name LIKE CONCAT(?, '%')",
 | 
					    AND name LIKE CONCAT(?, '%')",
 | 
				
			||||||
        ctx.guild_id().unwrap().0,
 | 
					        ctx.guild_id().unwrap().0,
 | 
				
			||||||
        partial,
 | 
					        partial,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,7 +17,7 @@ pub async fn delete_macro(
 | 
				
			|||||||
) -> Result<(), Error> {
 | 
					) -> Result<(), Error> {
 | 
				
			||||||
    match sqlx::query!(
 | 
					    match sqlx::query!(
 | 
				
			||||||
        "
 | 
					        "
 | 
				
			||||||
SELECT id FROM macro WHERE guild_id = (SELECT id FROM guilds WHERE guild = ?) AND name = ?",
 | 
					SELECT id FROM macro WHERE guild_id = ? AND name = ?",
 | 
				
			||||||
        ctx.guild_id().unwrap().0,
 | 
					        ctx.guild_id().unwrap().0,
 | 
				
			||||||
        name
 | 
					        name
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,7 +24,7 @@ pub async fn migrate_macro(ctx: Context<'_>) -> Result<(), Error> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    let aliases = sqlx::query_as!(
 | 
					    let aliases = sqlx::query_as!(
 | 
				
			||||||
        Alias,
 | 
					        Alias,
 | 
				
			||||||
        "SELECT name, command FROM command_aliases WHERE guild_id = (SELECT id FROM guilds WHERE guild = ?)",
 | 
					        "SELECT name, command FROM command_aliases WHERE guild_id = ?",
 | 
				
			||||||
        guild_id.0
 | 
					        guild_id.0
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    .fetch_all(&mut transaction)
 | 
					    .fetch_all(&mut transaction)
 | 
				
			||||||
@@ -36,7 +36,7 @@ pub async fn migrate_macro(ctx: Context<'_>) -> Result<(), Error> {
 | 
				
			|||||||
        match parse_text_command(guild_id, alias.name, &alias.command) {
 | 
					        match parse_text_command(guild_id, alias.name, &alias.command) {
 | 
				
			||||||
            Some(cmd_macro) => {
 | 
					            Some(cmd_macro) => {
 | 
				
			||||||
                sqlx::query!(
 | 
					                sqlx::query!(
 | 
				
			||||||
                    "INSERT INTO macro (guild_id, name, description, commands) VALUES ((SELECT id FROM guilds WHERE guild = ?), ?, ?, ?)",
 | 
					                    "INSERT INTO macro (guild_id, name, description, commands) VALUES (?, ?, ?, ?)",
 | 
				
			||||||
                    cmd_macro.guild_id.0,
 | 
					                    cmd_macro.guild_id.0,
 | 
				
			||||||
                    cmd_macro.name,
 | 
					                    cmd_macro.name,
 | 
				
			||||||
                    cmd_macro.description,
 | 
					                    cmd_macro.description,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,7 +31,7 @@ pub async fn record_macro(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    let row = sqlx::query!(
 | 
					    let row = sqlx::query!(
 | 
				
			||||||
        "
 | 
					        "
 | 
				
			||||||
SELECT 1 as _e FROM macro WHERE guild_id = (SELECT id FROM guilds WHERE guild = ?) AND name = ?",
 | 
					SELECT 1 as _e FROM macro WHERE guild_id = ? AND name = ?",
 | 
				
			||||||
        guild_id.0,
 | 
					        guild_id.0,
 | 
				
			||||||
        name
 | 
					        name
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
@@ -121,15 +121,15 @@ pub async fn finish_macro(ctx: Context<'_>) -> Result<(), Error> {
 | 
				
			|||||||
            let json = serde_json::to_string(&command_macro.commands).unwrap();
 | 
					            let json = serde_json::to_string(&command_macro.commands).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            sqlx::query!(
 | 
					            sqlx::query!(
 | 
				
			||||||
                "INSERT INTO macro (guild_id, name, description, commands) VALUES ((SELECT id FROM guilds WHERE guild = ?), ?, ?, ?)",
 | 
					                "INSERT INTO macro (guild_id, name, description, commands) VALUES (?, ?, ?, ?)",
 | 
				
			||||||
                command_macro.guild_id.0,
 | 
					                command_macro.guild_id.0,
 | 
				
			||||||
                command_macro.name,
 | 
					                command_macro.name,
 | 
				
			||||||
                command_macro.description,
 | 
					                command_macro.description,
 | 
				
			||||||
                json
 | 
					                json
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
                .execute(&ctx.data().database)
 | 
					            .execute(&ctx.data().database)
 | 
				
			||||||
                .await
 | 
					            .await
 | 
				
			||||||
                .unwrap();
 | 
					            .unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ctx.send(|m| {
 | 
					            ctx.send(|m| {
 | 
				
			||||||
                m.embed(|e| {
 | 
					                m.embed(|e| {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,7 @@ use chrono::offset::Utc;
 | 
				
			|||||||
use chrono_tz::{Tz, TZ_VARIANTS};
 | 
					use chrono_tz::{Tz, TZ_VARIANTS};
 | 
				
			||||||
use levenshtein::levenshtein;
 | 
					use levenshtein::levenshtein;
 | 
				
			||||||
use log::warn;
 | 
					use log::warn;
 | 
				
			||||||
 | 
					use poise::serenity_prelude::{ChannelId, Mentionable};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use super::autocomplete::timezone_autocomplete;
 | 
					use super::autocomplete::timezone_autocomplete;
 | 
				
			||||||
use crate::{consts::THEME_COLOR, models::CtxData, Context, Error};
 | 
					use crate::{consts::THEME_COLOR, models::CtxData, Context, Error};
 | 
				
			||||||
@@ -148,11 +149,51 @@ pub async fn unset_allowed_dm(ctx: Context<'_>) -> Result<(), Error> {
 | 
				
			|||||||
    Ok(())
 | 
					    Ok(())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Set defaults for commands
 | 
				
			||||||
 | 
					#[poise::command(
 | 
				
			||||||
 | 
					    slash_command,
 | 
				
			||||||
 | 
					    identifying_name = "default",
 | 
				
			||||||
 | 
					    default_member_permissions = "MANAGE_GUILD"
 | 
				
			||||||
 | 
					)]
 | 
				
			||||||
 | 
					pub async fn default(_ctx: Context<'_>) -> Result<(), Error> {
 | 
				
			||||||
 | 
					    Ok(())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Set a default channel for reminders to be sent to
 | 
				
			||||||
 | 
					#[poise::command(
 | 
				
			||||||
 | 
					    slash_command,
 | 
				
			||||||
 | 
					    guild_only = true,
 | 
				
			||||||
 | 
					    identifying_name = "default_channel",
 | 
				
			||||||
 | 
					    default_member_permissions = "MANAGE_GUILD"
 | 
				
			||||||
 | 
					)]
 | 
				
			||||||
 | 
					pub async fn default_channel(
 | 
				
			||||||
 | 
					    ctx: Context<'_>,
 | 
				
			||||||
 | 
					    #[description = "Channel to send reminders to by default"] channel: Option<ChannelId>,
 | 
				
			||||||
 | 
					) -> Result<(), Error> {
 | 
				
			||||||
 | 
					    if let Some(mut guild_data) = ctx.guild_data().await {
 | 
				
			||||||
 | 
					        guild_data.default_channel = channel.map(|c| c.0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        guild_data.commit_changes(&ctx.data().database).await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if let Some(channel) = channel {
 | 
				
			||||||
 | 
					            ctx.send(|r| {
 | 
				
			||||||
 | 
					                r.ephemeral(true).content(format!("Default channel set to {}", channel.mention()))
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .await?;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            ctx.send(|r| r.ephemeral(true).content("Default channel unset.")).await?;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok(())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// View the webhook being used to send reminders to this channel
 | 
					/// View the webhook being used to send reminders to this channel
 | 
				
			||||||
#[poise::command(
 | 
					#[poise::command(
 | 
				
			||||||
    slash_command,
 | 
					    slash_command,
 | 
				
			||||||
    identifying_name = "webhook_url",
 | 
					    identifying_name = "webhook_url",
 | 
				
			||||||
    required_permissions = "ADMINISTRATOR"
 | 
					    required_permissions = "ADMINISTRATOR",
 | 
				
			||||||
 | 
					    default_member_permissions = "ADMINISTRATOR"
 | 
				
			||||||
)]
 | 
					)]
 | 
				
			||||||
pub async fn webhook(ctx: Context<'_>) -> Result<(), Error> {
 | 
					pub async fn webhook(ctx: Context<'_>) -> Result<(), Error> {
 | 
				
			||||||
    match ctx.channel_data().await {
 | 
					    match ctx.channel_data().await {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -653,7 +653,9 @@ async fn create_reminder(
 | 
				
			|||||||
                let list = channels.map(|arg| parse_mention_list(&arg)).unwrap_or_default();
 | 
					                let list = channels.map(|arg| parse_mention_list(&arg)).unwrap_or_default();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if list.is_empty() {
 | 
					                if list.is_empty() {
 | 
				
			||||||
                    if ctx.guild_id().is_some() {
 | 
					                    if let Some(channel_id) = ctx.default_channel().await {
 | 
				
			||||||
 | 
					                        vec![ReminderScope::Channel(channel_id.0)]
 | 
				
			||||||
 | 
					                    } else if ctx.guild_id().is_some() {
 | 
				
			||||||
                        vec![ReminderScope::Channel(ctx.channel_id().0)]
 | 
					                        vec![ReminderScope::Channel(ctx.channel_id().0)]
 | 
				
			||||||
                    } else {
 | 
					                    } else {
 | 
				
			||||||
                        vec![ReminderScope::User(ctx.author().id.0)]
 | 
					                        vec![ReminderScope::User(ctx.author().id.0)]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,7 +47,7 @@ pub async fn todo_guild_add(
 | 
				
			|||||||
) -> Result<(), Error> {
 | 
					) -> Result<(), Error> {
 | 
				
			||||||
    sqlx::query!(
 | 
					    sqlx::query!(
 | 
				
			||||||
        "INSERT INTO todos (guild_id, value)
 | 
					        "INSERT INTO todos (guild_id, value)
 | 
				
			||||||
VALUES ((SELECT id FROM guilds WHERE guild = ?), ?)",
 | 
					VALUES (?, ?)",
 | 
				
			||||||
        ctx.guild_id().unwrap().0,
 | 
					        ctx.guild_id().unwrap().0,
 | 
				
			||||||
        task
 | 
					        task
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
@@ -70,9 +70,7 @@ VALUES ((SELECT id FROM guilds WHERE guild = ?), ?)",
 | 
				
			|||||||
)]
 | 
					)]
 | 
				
			||||||
pub async fn todo_guild_view(ctx: Context<'_>) -> Result<(), Error> {
 | 
					pub async fn todo_guild_view(ctx: Context<'_>) -> Result<(), Error> {
 | 
				
			||||||
    let values = sqlx::query!(
 | 
					    let values = sqlx::query!(
 | 
				
			||||||
        "SELECT todos.id, value FROM todos
 | 
					        "SELECT todos.id, value FROM todos WHERE guild_id = ?",
 | 
				
			||||||
INNER JOIN guilds ON todos.guild_id = guilds.id
 | 
					 | 
				
			||||||
WHERE guilds.guild = ?",
 | 
					 | 
				
			||||||
        ctx.guild_id().unwrap().0,
 | 
					        ctx.guild_id().unwrap().0,
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    .fetch_all(&ctx.data().database)
 | 
					    .fetch_all(&ctx.data().database)
 | 
				
			||||||
@@ -122,7 +120,7 @@ pub async fn todo_channel_add(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    sqlx::query!(
 | 
					    sqlx::query!(
 | 
				
			||||||
        "INSERT INTO todos (guild_id, channel_id, value)
 | 
					        "INSERT INTO todos (guild_id, channel_id, value)
 | 
				
			||||||
VALUES ((SELECT id FROM guilds WHERE guild = ?), (SELECT id FROM channels WHERE channel = ?), ?)",
 | 
					VALUES (?, (SELECT id FROM channels WHERE channel = ?), ?)",
 | 
				
			||||||
        ctx.guild_id().unwrap().0,
 | 
					        ctx.guild_id().unwrap().0,
 | 
				
			||||||
        ctx.channel_id().0,
 | 
					        ctx.channel_id().0,
 | 
				
			||||||
        task
 | 
					        task
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -222,9 +222,7 @@ WHERE channels.channel = ?",
 | 
				
			|||||||
                        .collect::<Vec<(usize, String)>>()
 | 
					                        .collect::<Vec<(usize, String)>>()
 | 
				
			||||||
                    } else {
 | 
					                    } else {
 | 
				
			||||||
                        sqlx::query!(
 | 
					                        sqlx::query!(
 | 
				
			||||||
                            "SELECT todos.id, value FROM todos
 | 
					                            "SELECT todos.id, value FROM todos WHERE guild_id = ?",
 | 
				
			||||||
INNER JOIN guilds ON todos.guild_id = guilds.id
 | 
					 | 
				
			||||||
WHERE guilds.guild = ?",
 | 
					 | 
				
			||||||
                            pager.guild_id,
 | 
					                            pager.guild_id,
 | 
				
			||||||
                        )
 | 
					                        )
 | 
				
			||||||
                        .fetch_all(&data.database)
 | 
					                        .fetch_all(&data.database)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,9 @@ use poise::{
 | 
				
			|||||||
    serenity_prelude::{model::application::interaction::Interaction, utils::shard_id},
 | 
					    serenity_prelude::{model::application::interaction::Interaction, utils::shard_id},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{component_models::ComponentDataModel, Data, Error, THEME_COLOR};
 | 
					use crate::{
 | 
				
			||||||
 | 
					    component_models::ComponentDataModel, models::guild_data::GuildData, Data, Error, THEME_COLOR,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub async fn listener(
 | 
					pub async fn listener(
 | 
				
			||||||
    ctx: &serenity::Context,
 | 
					    ctx: &serenity::Context,
 | 
				
			||||||
@@ -27,7 +29,7 @@ pub async fn listener(
 | 
				
			|||||||
            if *is_new {
 | 
					            if *is_new {
 | 
				
			||||||
                let guild_id = guild.id.as_u64().to_owned();
 | 
					                let guild_id = guild.id.as_u64().to_owned();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                sqlx::query!("INSERT IGNORE INTO guilds (guild) VALUES (?)", guild_id)
 | 
					                sqlx::query!("INSERT IGNORE INTO guilds (id) VALUES (?)", guild_id)
 | 
				
			||||||
                    .execute(&data.database)
 | 
					                    .execute(&data.database)
 | 
				
			||||||
                    .await?;
 | 
					                    .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -61,15 +63,27 @@ To stay up to date on the latest features and fixes, join our [Discord](https://
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        poise::Event::GuildDelete { incomplete, .. } => {
 | 
					        poise::Event::GuildDelete { incomplete, .. } => {
 | 
				
			||||||
            let _ = sqlx::query!("DELETE FROM guilds WHERE guild = ?", incomplete.id.0)
 | 
					            let _ = sqlx::query!("DELETE FROM guilds WHERE id = ?", incomplete.id.0)
 | 
				
			||||||
                .execute(&data.database)
 | 
					                .execute(&data.database)
 | 
				
			||||||
                .await;
 | 
					                .await;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        poise::Event::InteractionCreate { interaction } => {
 | 
					        poise::Event::InteractionCreate { interaction } => {
 | 
				
			||||||
            if let Interaction::MessageComponent(component) = interaction {
 | 
					            match interaction {
 | 
				
			||||||
                let component_model = ComponentDataModel::from_custom_id(&component.data.custom_id);
 | 
					                Interaction::ApplicationCommand(app_command) => {
 | 
				
			||||||
 | 
					                    if let Some(guild_id) = app_command.guild_id {
 | 
				
			||||||
 | 
					                        // check database guild exists
 | 
				
			||||||
 | 
					                        GuildData::from_guild(guild_id, &data.database).await?;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                component_model.act(ctx, data, component).await;
 | 
					                Interaction::MessageComponent(component) => {
 | 
				
			||||||
 | 
					                    let component_model =
 | 
				
			||||||
 | 
					                        ComponentDataModel::from_custom_id(&component.data.custom_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    component_model.act(ctx, data, component).await;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                _ => {}
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        _ => {}
 | 
					        _ => {}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -120,6 +120,10 @@ async fn _main(tx: Sender<()>) -> Result<(), Box<dyn StdError + Send + Sync>> {
 | 
				
			|||||||
                ],
 | 
					                ],
 | 
				
			||||||
                ..command_macro::macro_base()
 | 
					                ..command_macro::macro_base()
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
 | 
					            poise::Command {
 | 
				
			||||||
 | 
					                subcommands: vec![moderation_cmds::default_channel()],
 | 
				
			||||||
 | 
					                ..moderation_cmds::default()
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
            reminder_cmds::pause(),
 | 
					            reminder_cmds::pause(),
 | 
				
			||||||
            reminder_cmds::offset(),
 | 
					            reminder_cmds::offset(),
 | 
				
			||||||
            reminder_cmds::nudge(),
 | 
					            reminder_cmds::nudge(),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,7 +38,7 @@ SELECT id, name, nudge, blacklisted, webhook_id, webhook_token, paused, paused_u
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            sqlx::query!(
 | 
					            sqlx::query!(
 | 
				
			||||||
                "
 | 
					                "
 | 
				
			||||||
INSERT IGNORE INTO channels (channel, name, guild_id) VALUES (?, ?, (SELECT id FROM guilds WHERE guild = ?))
 | 
					INSERT IGNORE INTO channels (channel, name, guild_id) VALUES (?, ?, ?)
 | 
				
			||||||
                ",
 | 
					                ",
 | 
				
			||||||
                channel_id,
 | 
					                channel_id,
 | 
				
			||||||
                channel_name,
 | 
					                channel_name,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -43,7 +43,7 @@ pub async fn guild_command_macro(
 | 
				
			|||||||
) -> Option<CommandMacro<Data, Error>> {
 | 
					) -> Option<CommandMacro<Data, Error>> {
 | 
				
			||||||
    let row = sqlx::query!(
 | 
					    let row = sqlx::query!(
 | 
				
			||||||
        "
 | 
					        "
 | 
				
			||||||
SELECT * FROM macro WHERE guild_id = (SELECT id FROM guilds WHERE guild = ?) AND name = ?
 | 
					SELECT * FROM macro WHERE guild_id = ? AND name = ?
 | 
				
			||||||
        ",
 | 
					        ",
 | 
				
			||||||
        ctx.guild_id().unwrap().0,
 | 
					        ctx.guild_id().unwrap().0,
 | 
				
			||||||
        name
 | 
					        name
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										52
									
								
								src/models/guild_data.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/models/guild_data.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
				
			|||||||
 | 
					use sqlx::MySqlPool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::GuildId;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct GuildData {
 | 
				
			||||||
 | 
					    pub id: u64,
 | 
				
			||||||
 | 
					    pub default_channel: Option<u64>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl GuildData {
 | 
				
			||||||
 | 
					    pub async fn from_guild(guild: GuildId, pool: &MySqlPool) -> Result<Self, sqlx::Error> {
 | 
				
			||||||
 | 
					        let guild_id = guild.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if let Ok(row) = sqlx::query_as_unchecked!(
 | 
				
			||||||
 | 
					            Self,
 | 
				
			||||||
 | 
					            "
 | 
				
			||||||
 | 
					SELECT id, default_channel FROM guilds WHERE id = ?
 | 
				
			||||||
 | 
					            ",
 | 
				
			||||||
 | 
					            guild_id
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .fetch_one(pool)
 | 
				
			||||||
 | 
					        .await
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Ok(row)
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            sqlx::query!(
 | 
				
			||||||
 | 
					                "
 | 
				
			||||||
 | 
					INSERT IGNORE INTO guilds (id) VALUES (?)
 | 
				
			||||||
 | 
					                ",
 | 
				
			||||||
 | 
					                guild_id
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            .execute(&pool.clone())
 | 
				
			||||||
 | 
					            .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            Ok(Self { id: guild_id, default_channel: None })
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub async fn commit_changes(&self, pool: &MySqlPool) -> Result<(), sqlx::Error> {
 | 
				
			||||||
 | 
					        sqlx::query!(
 | 
				
			||||||
 | 
					            "
 | 
				
			||||||
 | 
					UPDATE guilds SET default_channel = ? WHERE id = ?
 | 
				
			||||||
 | 
					            ",
 | 
				
			||||||
 | 
					            self.default_channel,
 | 
				
			||||||
 | 
					            self.id
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        .execute(pool)
 | 
				
			||||||
 | 
					        .await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,28 +1,28 @@
 | 
				
			|||||||
pub mod channel_data;
 | 
					pub mod channel_data;
 | 
				
			||||||
pub mod command_macro;
 | 
					pub mod command_macro;
 | 
				
			||||||
 | 
					pub mod guild_data;
 | 
				
			||||||
pub mod reminder;
 | 
					pub mod reminder;
 | 
				
			||||||
pub mod timer;
 | 
					pub mod timer;
 | 
				
			||||||
pub mod user_data;
 | 
					pub mod user_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use chrono_tz::Tz;
 | 
					use chrono_tz::Tz;
 | 
				
			||||||
use poise::serenity_prelude::{async_trait, model::id::UserId};
 | 
					use log::warn;
 | 
				
			||||||
 | 
					use poise::serenity_prelude::{async_trait, model::id::UserId, ChannelId};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    models::{channel_data::ChannelData, user_data::UserData},
 | 
					    models::{channel_data::ChannelData, guild_data::GuildData, user_data::UserData},
 | 
				
			||||||
    CommandMacro, Context, Data, Error, GuildId,
 | 
					    CommandMacro, Context, Data, Error, GuildId,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[async_trait]
 | 
					#[async_trait]
 | 
				
			||||||
pub trait CtxData {
 | 
					pub trait CtxData {
 | 
				
			||||||
    async fn user_data<U: Into<UserId> + Send>(&self, user_id: U) -> Result<UserData, Error>;
 | 
					    async fn user_data<U: Into<UserId> + Send>(&self, user_id: U) -> Result<UserData, Error>;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    async fn author_data(&self) -> Result<UserData, Error>;
 | 
					    async fn author_data(&self) -> Result<UserData, Error>;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    async fn timezone(&self) -> Tz;
 | 
					    async fn timezone(&self) -> Tz;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    async fn channel_data(&self) -> Result<ChannelData, Error>;
 | 
					    async fn channel_data(&self) -> Result<ChannelData, Error>;
 | 
				
			||||||
 | 
					    async fn guild_data(&self) -> Option<GuildData>;
 | 
				
			||||||
    async fn command_macros(&self) -> Result<Vec<CommandMacro<Data, Error>>, Error>;
 | 
					    async fn command_macros(&self) -> Result<Vec<CommandMacro<Data, Error>>, Error>;
 | 
				
			||||||
 | 
					    async fn default_channel(&self) -> Option<ChannelId>;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[async_trait]
 | 
					#[async_trait]
 | 
				
			||||||
@@ -51,24 +51,55 @@ impl CtxData for Context<'_> {
 | 
				
			|||||||
    async fn command_macros(&self) -> Result<Vec<CommandMacro<Data, Error>>, Error> {
 | 
					    async fn command_macros(&self) -> Result<Vec<CommandMacro<Data, Error>>, Error> {
 | 
				
			||||||
        self.data().command_macros(self.guild_id().unwrap()).await
 | 
					        self.data().command_macros(self.guild_id().unwrap()).await
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async fn default_channel(&self) -> Option<ChannelId> {
 | 
				
			||||||
 | 
					        match self.guild_id() {
 | 
				
			||||||
 | 
					            Some(guild_id) => {
 | 
				
			||||||
 | 
					                let guild_data = GuildData::from_guild(guild_id, &self.data().database).await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                match guild_data {
 | 
				
			||||||
 | 
					                    Ok(data) => data.default_channel.map(|c| ChannelId(c)),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    Err(e) => {
 | 
				
			||||||
 | 
					                        warn!("SQL error: {:?}", e);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        None
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            None => None,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async fn guild_data(&self) -> Option<GuildData> {
 | 
				
			||||||
 | 
					        match self.guild_id() {
 | 
				
			||||||
 | 
					            Some(guild_id) => GuildData::from_guild(guild_id, &self.data().database).await.ok(),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            None => None,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Data {
 | 
					impl Data {
 | 
				
			||||||
    pub(crate) async fn command_macros(
 | 
					    pub async fn command_macros(
 | 
				
			||||||
        &self,
 | 
					        &self,
 | 
				
			||||||
        guild_id: GuildId,
 | 
					        guild_id: GuildId,
 | 
				
			||||||
    ) -> Result<Vec<CommandMacro<Data, Error>>, Error> {
 | 
					    ) -> Result<Vec<CommandMacro<Data, Error>>, Error> {
 | 
				
			||||||
        let rows = sqlx::query!(
 | 
					        let rows = sqlx::query!(
 | 
				
			||||||
            "SELECT name, description, commands FROM macro WHERE guild_id = (SELECT id FROM guilds WHERE guild = ?)",
 | 
					            "SELECT name, description, commands FROM macro WHERE guild_id = ?",
 | 
				
			||||||
            guild_id.0
 | 
					            guild_id.0
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        .fetch_all(&self.database)
 | 
					        .fetch_all(&self.database)
 | 
				
			||||||
        .await?.iter().map(|row| CommandMacro {
 | 
					        .await?
 | 
				
			||||||
 | 
					        .iter()
 | 
				
			||||||
 | 
					        .map(|row| CommandMacro {
 | 
				
			||||||
            guild_id,
 | 
					            guild_id,
 | 
				
			||||||
            name: row.name.clone(),
 | 
					            name: row.name.clone(),
 | 
				
			||||||
            description: row.description.clone(),
 | 
					            description: row.description.clone(),
 | 
				
			||||||
            commands: serde_json::from_str(&row.commands).unwrap(),
 | 
					            commands: serde_json::from_str(&row.commands).unwrap(),
 | 
				
			||||||
        }).collect();
 | 
					        })
 | 
				
			||||||
 | 
					        .collect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Ok(rows)
 | 
					        Ok(rows)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -245,7 +245,7 @@ LEFT JOIN
 | 
				
			|||||||
ON
 | 
					ON
 | 
				
			||||||
    reminders.set_by = users.id
 | 
					    reminders.set_by = users.id
 | 
				
			||||||
WHERE
 | 
					WHERE
 | 
				
			||||||
    channels.guild_id = (SELECT id FROM guilds WHERE guild = ?)
 | 
					    channels.guild_id = ?
 | 
				
			||||||
                ",
 | 
					                ",
 | 
				
			||||||
                    guild_id.as_u64()
 | 
					                    guild_id.as_u64()
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user