macro stuff
This commit is contained in:
		
							
								
								
									
										10
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								README.md
									
									
									
									
									
								
							| @@ -38,3 +38,13 @@ __Other Variables__ | |||||||
| * `SHARD_COUNT` - default `None`, accepts the number of shards that are being ran | * `SHARD_COUNT` - default `None`, accepts the number of shards that are being ran | ||||||
| * `SHARD_RANGE` - default `None`, if `SHARD_COUNT` is specified, specifies what range of shards to start on this process  | * `SHARD_RANGE` - default `None`, if `SHARD_COUNT` is specified, specifies what range of shards to start on this process  | ||||||
| * `DM_ENABLED` - default `1`, if `1`, Reminder Bot will respond to direct messages | * `DM_ENABLED` - default `1`, if `1`, Reminder Bot will respond to direct messages | ||||||
|  |  | ||||||
|  | ### Todo List | ||||||
|  |  | ||||||
|  | * Implement remainder of the `macro` command | ||||||
|  | * Convert aliases to macros | ||||||
|  | * Block users from interacting with another users' components | ||||||
|  | * Split out framework | ||||||
|  | * Help command | ||||||
|  | * Change all db keys to be discord IDs | ||||||
|  | * Test everything | ||||||
|   | |||||||
| @@ -2,11 +2,14 @@ use chrono::offset::Utc; | |||||||
| use chrono_tz::{Tz, TZ_VARIANTS}; | use chrono_tz::{Tz, TZ_VARIANTS}; | ||||||
| use levenshtein::levenshtein; | use levenshtein::levenshtein; | ||||||
| use regex_command_attr::command; | use regex_command_attr::command; | ||||||
| use serenity::{client::Context, model::misc::Mentionable}; | use serenity::{ | ||||||
|  |     client::Context, | ||||||
|  |     model::{id::GuildId, misc::Mentionable}, | ||||||
|  | }; | ||||||
|  |  | ||||||
| use crate::{ | use crate::{ | ||||||
|     component_models::{ComponentDataModel, Restrict}, |     component_models::{pager::Pager, ComponentDataModel, Restrict}, | ||||||
|     consts::THEME_COLOR, |     consts::{EMBED_DESCRIPTION_MAX_LENGTH, THEME_COLOR}, | ||||||
|     framework::{CommandInvoke, CommandOptions, CreateGenericResponse, OptionValue}, |     framework::{CommandInvoke, CommandOptions, CreateGenericResponse, OptionValue}, | ||||||
|     hooks::{CHECK_GUILD_PERMISSIONS_HOOK, CHECK_MANAGED_PERMISSIONS_HOOK}, |     hooks::{CHECK_GUILD_PERMISSIONS_HOOK, CHECK_MANAGED_PERMISSIONS_HOOK}, | ||||||
|     models::{channel_data::ChannelData, command_macro::CommandMacro, CtxData}, |     models::{channel_data::ChannelData, command_macro::CommandMacro, CtxData}, | ||||||
| @@ -335,11 +338,11 @@ async fn macro_cmd(ctx: &Context, invoke: &mut CommandInvoke, args: CommandOptio | |||||||
|                     &ctx, |                     &ctx, | ||||||
|                     CreateGenericResponse::new().ephemeral().embed(|e| { |                     CreateGenericResponse::new().ephemeral().embed(|e| { | ||||||
|                         e |                         e | ||||||
|                                     .title("Macro Recording Started") |                             .title("Macro Recording Started") | ||||||
|                                     .description( |                             .description( | ||||||
| "Run up to 5 commands, or type `/macro finish` to stop at any point. | "Run up to 5 commands, or type `/macro finish` to stop at any point. | ||||||
| Any commands ran as part of recording will be inconsequential") | Any commands ran as part of recording will be inconsequential") | ||||||
|                                     .color(*THEME_COLOR) |                             .color(*THEME_COLOR) | ||||||
|                     }), |                     }), | ||||||
|                 ) |                 ) | ||||||
|                 .await; |                 .await; | ||||||
| @@ -396,7 +399,13 @@ Any commands ran as part of recording will be inconsequential") | |||||||
|                 lock.remove(&key); |                 lock.remove(&key); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         "list" => {} |         "list" => { | ||||||
|  |             let macros = CommandMacro::from_guild(ctx, invoke.guild_id().unwrap()).await; | ||||||
|  |  | ||||||
|  |             let resp = show_macro_page(¯os, 0, invoke.guild_id().unwrap()); | ||||||
|  |  | ||||||
|  |             invoke.respond(&ctx, resp).await; | ||||||
|  |         } | ||||||
|         "run" => { |         "run" => { | ||||||
|             let macro_name = args.get("name").unwrap().to_string(); |             let macro_name = args.get("name").unwrap().to_string(); | ||||||
|  |  | ||||||
| @@ -435,7 +444,137 @@ Any commands ran as part of recording will be inconsequential") | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         "delete" => {} |         "delete" => { | ||||||
|  |             let macro_name = args.get("name").unwrap().to_string(); | ||||||
|  |  | ||||||
|  |             match sqlx::query!( | ||||||
|  |                 "SELECT id FROM macro WHERE guild_id = ? AND name = ?", | ||||||
|  |                 invoke.guild_id().unwrap().0, | ||||||
|  |                 macro_name | ||||||
|  |             ) | ||||||
|  |             .fetch_one(&pool) | ||||||
|  |             .await | ||||||
|  |             { | ||||||
|  |                 Ok(row) => { | ||||||
|  |                     sqlx::query!("DELETE FROM macro WHERE id = ?", row.id).execute(&pool).await; | ||||||
|  |  | ||||||
|  |                     let _ = invoke | ||||||
|  |                         .respond( | ||||||
|  |                             &ctx, | ||||||
|  |                             CreateGenericResponse::new() | ||||||
|  |                                 .content(format!("Macro \"{}\" deleted", macro_name)), | ||||||
|  |                         ) | ||||||
|  |                         .await; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 Err(sqlx::Error::RowNotFound) => { | ||||||
|  |                     let _ = invoke | ||||||
|  |                         .respond( | ||||||
|  |                             &ctx, | ||||||
|  |                             CreateGenericResponse::new() | ||||||
|  |                                 .content(format!("Macro \"{}\" not found", macro_name)), | ||||||
|  |                         ) | ||||||
|  |                         .await; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 Err(e) => { | ||||||
|  |                     panic!("{}", e); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|         _ => {} |         _ => {} | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | pub fn max_macro_page(macros: &[CommandMacro]) -> usize { | ||||||
|  |     let mut skipped_char_count = 0; | ||||||
|  |  | ||||||
|  |     macros | ||||||
|  |         .iter() | ||||||
|  |         .map(|m| { | ||||||
|  |             if let Some(description) = &m.description { | ||||||
|  |                 format!("**{}**\n- *{}*\n- Has {} commands", m.name, description, m.commands.len()) | ||||||
|  |             } else { | ||||||
|  |                 format!("**{}**\n- Has {} commands", m.name, m.commands.len()) | ||||||
|  |             } | ||||||
|  |         }) | ||||||
|  |         .fold(1, |mut pages, p| { | ||||||
|  |             skipped_char_count += p.len(); | ||||||
|  |  | ||||||
|  |             if skipped_char_count > EMBED_DESCRIPTION_MAX_LENGTH { | ||||||
|  |                 skipped_char_count = p.len(); | ||||||
|  |                 pages += 1; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             pages | ||||||
|  |         }) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | fn show_macro_page( | ||||||
|  |     macros: &[CommandMacro], | ||||||
|  |     page: usize, | ||||||
|  |     guild_id: GuildId, | ||||||
|  | ) -> CreateGenericResponse { | ||||||
|  |     let pager = Pager::new(page, guild_id); | ||||||
|  |  | ||||||
|  |     if macros.is_empty() { | ||||||
|  |         return CreateGenericResponse::new().embed(|e| { | ||||||
|  |             e.title("Macros") | ||||||
|  |                 .description("No Macros Set Up. Use `/macro record` to get started.") | ||||||
|  |                 .color(*THEME_COLOR) | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     let pages = max_macro_page(macros); | ||||||
|  |  | ||||||
|  |     let mut page = page; | ||||||
|  |     if page >= pages { | ||||||
|  |         page = pages - 1; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     let mut char_count = 0; | ||||||
|  |     let mut skipped_char_count = 0; | ||||||
|  |  | ||||||
|  |     let mut skipped_pages = 0; | ||||||
|  |  | ||||||
|  |     let display_vec: Vec<String> = macros | ||||||
|  |         .iter() | ||||||
|  |         .map(|m| { | ||||||
|  |             if let Some(description) = &m.description { | ||||||
|  |                 format!("**{}**\n- *{}*\n- Has {} commands", m.name, description, m.commands.len()) | ||||||
|  |             } else { | ||||||
|  |                 format!("**{}**\n- Has {} commands", m.name, m.commands.len()) | ||||||
|  |             } | ||||||
|  |         }) | ||||||
|  |         .skip_while(|p| { | ||||||
|  |             skipped_char_count += p.len(); | ||||||
|  |  | ||||||
|  |             if skipped_char_count > EMBED_DESCRIPTION_MAX_LENGTH { | ||||||
|  |                 skipped_char_count = p.len(); | ||||||
|  |                 skipped_pages += 1; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             skipped_pages < page | ||||||
|  |         }) | ||||||
|  |         .take_while(|p| { | ||||||
|  |             char_count += p.len(); | ||||||
|  |  | ||||||
|  |             char_count < EMBED_DESCRIPTION_MAX_LENGTH | ||||||
|  |         }) | ||||||
|  |         .collect::<Vec<String>>(); | ||||||
|  |  | ||||||
|  |     let display = display_vec.join("\n"); | ||||||
|  |  | ||||||
|  |     CreateGenericResponse::new() | ||||||
|  |         .embed(|e| { | ||||||
|  |             e.title("Macros") | ||||||
|  |                 .description(display) | ||||||
|  |                 .footer(|f| f.text(format!("Page {} of {}", page + 1, pages))) | ||||||
|  |                 .color(*THEME_COLOR) | ||||||
|  |         }) | ||||||
|  |         .components(|comp| { | ||||||
|  |             pager.create_button_row(pages, comp); | ||||||
|  |  | ||||||
|  |             comp | ||||||
|  |         }) | ||||||
|  | } | ||||||
|   | |||||||
| @@ -8,7 +8,11 @@ use chrono::NaiveDateTime; | |||||||
| use chrono_tz::Tz; | use chrono_tz::Tz; | ||||||
| use num_integer::Integer; | use num_integer::Integer; | ||||||
| use regex_command_attr::command; | use regex_command_attr::command; | ||||||
| use serenity::{builder::CreateEmbed, client::Context, model::channel::Channel}; | use serenity::{ | ||||||
|  |     builder::CreateEmbed, | ||||||
|  |     client::Context, | ||||||
|  |     model::{channel::Channel, id::UserId}, | ||||||
|  | }; | ||||||
|  |  | ||||||
| use crate::{ | use crate::{ | ||||||
|     check_subscription_on_message, |     check_subscription_on_message, | ||||||
| @@ -363,7 +367,7 @@ async fn delete(ctx: &Context, invoke: &mut CommandInvoke, _args: CommandOptions | |||||||
|  |  | ||||||
|     let reminders = Reminder::from_guild(ctx, invoke.guild_id(), invoke.author_id()).await; |     let reminders = Reminder::from_guild(ctx, invoke.guild_id(), invoke.author_id()).await; | ||||||
|  |  | ||||||
|     let resp = show_delete_page(&reminders, 0, timezone); |     let resp = show_delete_page(&reminders, 0, timezone, invoke.author_id()); | ||||||
|  |  | ||||||
|     let _ = invoke.respond(&ctx, resp).await; |     let _ = invoke.respond(&ctx, resp).await; | ||||||
| } | } | ||||||
| @@ -394,8 +398,9 @@ pub fn show_delete_page( | |||||||
|     reminders: &[Reminder], |     reminders: &[Reminder], | ||||||
|     page: usize, |     page: usize, | ||||||
|     timezone: Tz, |     timezone: Tz, | ||||||
|  |     author_id: UserId, | ||||||
| ) -> CreateGenericResponse { | ) -> CreateGenericResponse { | ||||||
|     let pager = Pager::new(page, DelData { timezone }); |     let pager = Pager::new(page, DelData { author_id, timezone }); | ||||||
|  |  | ||||||
|     if reminders.is_empty() { |     if reminders.is_empty() { | ||||||
|         return CreateGenericResponse::new() |         return CreateGenericResponse::new() | ||||||
| @@ -450,7 +455,7 @@ pub fn show_delete_page( | |||||||
|  |  | ||||||
|     let display = display_vec.join("\n"); |     let display = display_vec.join("\n"); | ||||||
|  |  | ||||||
|     let del_selector = ComponentDataModel::DelSelector(DelSelector { page, timezone }); |     let del_selector = ComponentDataModel::DelSelector(DelSelector { page, timezone, author_id }); | ||||||
|  |  | ||||||
|     CreateGenericResponse::new() |     CreateGenericResponse::new() | ||||||
|         .embed(|e| { |         .embed(|e| { | ||||||
|   | |||||||
| @@ -37,6 +37,7 @@ pub enum ComponentDataModel { | |||||||
|     LookPager(Pager<LookData>), |     LookPager(Pager<LookData>), | ||||||
|     DelPager(Pager<DelData>), |     DelPager(Pager<DelData>), | ||||||
|     TodoPager(Pager<TodoData>), |     TodoPager(Pager<TodoData>), | ||||||
|  |     MacroPager(Pager<GuildId>), | ||||||
| } | } | ||||||
|  |  | ||||||
| impl ComponentDataModel { | impl ComponentDataModel { | ||||||
| @@ -89,7 +90,16 @@ INSERT IGNORE INTO roles (role, name, guild_id) VALUES (?, \"Role\", (SELECT id | |||||||
|                         .await |                         .await | ||||||
|                         .unwrap(); |                         .unwrap(); | ||||||
|                 } else { |                 } else { | ||||||
|                     // tell them they cant do this |                     component | ||||||
|  |                         .create_interaction_response(&ctx, |r| { | ||||||
|  |                             r.kind(InteractionResponseType::ChannelMessageWithSource) | ||||||
|  |                                 .interaction_response_data(|response| response | ||||||
|  |                                     .flags(InteractionApplicationCommandCallbackDataFlags::EPHEMERAL) | ||||||
|  |                                     .content("Only the original command user can interact with this message") | ||||||
|  |                                 ) | ||||||
|  |                         }) | ||||||
|  |                         .await | ||||||
|  |                         .unwrap(); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             ComponentDataModel::LookPager(pager) => { |             ComponentDataModel::LookPager(pager) => { | ||||||
| @@ -168,16 +178,33 @@ INSERT IGNORE INTO roles (role, name, guild_id) VALUES (?, \"Role\", (SELECT id | |||||||
|                     .await; |                     .await; | ||||||
|             } |             } | ||||||
|             ComponentDataModel::DelPager(pager) => { |             ComponentDataModel::DelPager(pager) => { | ||||||
|                 let reminders = |                 if component.user.id == pager.data.author_id { | ||||||
|                     Reminder::from_guild(ctx, component.guild_id, component.user.id).await; |                     let reminders = | ||||||
|  |                         Reminder::from_guild(ctx, component.guild_id, component.user.id).await; | ||||||
|  |  | ||||||
|                 let max_pages = max_delete_page(&reminders, &pager.data.timezone); |                     let max_pages = max_delete_page(&reminders, &pager.data.timezone); | ||||||
|  |  | ||||||
|                 let resp = |                     let resp = show_delete_page( | ||||||
|                     show_delete_page(&reminders, pager.next_page(max_pages), pager.data.timezone); |                         &reminders, | ||||||
|  |                         pager.next_page(max_pages), | ||||||
|  |                         pager.data.timezone, | ||||||
|  |                         pager.data.author_id, | ||||||
|  |                     ); | ||||||
|  |  | ||||||
|                 let mut invoke = CommandInvoke::component(component); |                     let mut invoke = CommandInvoke::component(component); | ||||||
|                 let _ = invoke.respond(&ctx, resp).await; |                     let _ = invoke.respond(&ctx, resp).await; | ||||||
|  |                 } else { | ||||||
|  |                     component | ||||||
|  |                         .create_interaction_response(&ctx, |r| { | ||||||
|  |                             r.kind(InteractionResponseType::ChannelMessageWithSource) | ||||||
|  |                                 .interaction_response_data(|response| response | ||||||
|  |                                     .flags(InteractionApplicationCommandCallbackDataFlags::EPHEMERAL) | ||||||
|  |                                     .content("Only the original command user can interact with this message") | ||||||
|  |                                 ) | ||||||
|  |                         }) | ||||||
|  |                         .await | ||||||
|  |                         .unwrap(); | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|             ComponentDataModel::DelSelector(selector) => { |             ComponentDataModel::DelSelector(selector) => { | ||||||
|                 let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap(); |                 let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap(); | ||||||
| @@ -191,7 +218,12 @@ INSERT IGNORE INTO roles (role, name, guild_id) VALUES (?, \"Role\", (SELECT id | |||||||
|                 let reminders = |                 let reminders = | ||||||
|                     Reminder::from_guild(ctx, component.guild_id, component.user.id).await; |                     Reminder::from_guild(ctx, component.guild_id, component.user.id).await; | ||||||
|  |  | ||||||
|                 let resp = show_delete_page(&reminders, selector.page, selector.timezone); |                 let resp = show_delete_page( | ||||||
|  |                     &reminders, | ||||||
|  |                     selector.page, | ||||||
|  |                     selector.timezone, | ||||||
|  |                     selector.author_id, | ||||||
|  |                 ); | ||||||
|  |  | ||||||
|                 let mut invoke = CommandInvoke::component(component); |                 let mut invoke = CommandInvoke::component(component); | ||||||
|                 let _ = invoke.respond(&ctx, resp).await; |                 let _ = invoke.respond(&ctx, resp).await; | ||||||
| @@ -260,6 +292,7 @@ INSERT IGNORE INTO roles (role, name, guild_id) VALUES (?, \"Role\", (SELECT id | |||||||
|                 let mut invoke = CommandInvoke::component(component); |                 let mut invoke = CommandInvoke::component(component); | ||||||
|                 let _ = invoke.respond(&ctx, resp).await; |                 let _ = invoke.respond(&ctx, resp).await; | ||||||
|             } |             } | ||||||
|  |             ComponentDataModel::MacroPager(pager) => {} | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -275,6 +308,7 @@ pub struct Restrict { | |||||||
| pub struct DelSelector { | pub struct DelSelector { | ||||||
|     pub page: usize, |     pub page: usize, | ||||||
|     pub timezone: Tz, |     pub timezone: Tz, | ||||||
|  |     pub author_id: UserId, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Serialize, Deserialize)] | #[derive(Serialize, Deserialize)] | ||||||
|   | |||||||
| @@ -2,7 +2,10 @@ use chrono_tz::Tz; | |||||||
| use rmp_serde::Serializer; | use rmp_serde::Serializer; | ||||||
| use serde::{Deserialize, Serialize}; | use serde::{Deserialize, Serialize}; | ||||||
| use serde_repr::*; | use serde_repr::*; | ||||||
| use serenity::{builder::CreateComponents, model::interactions::message_component::ButtonStyle}; | use serenity::{ | ||||||
|  |     builder::CreateComponents, | ||||||
|  |     model::{id::UserId, interactions::message_component::ButtonStyle}, | ||||||
|  | }; | ||||||
|  |  | ||||||
| use crate::{component_models::ComponentDataModel, models::reminder::look_flags::LookFlags}; | use crate::{component_models::ComponentDataModel, models::reminder::look_flags::LookFlags}; | ||||||
|  |  | ||||||
| @@ -102,6 +105,7 @@ pub struct LookData { | |||||||
|  |  | ||||||
| #[derive(Deserialize, Serialize, Clone)] | #[derive(Deserialize, Serialize, Clone)] | ||||||
| pub struct DelData { | pub struct DelData { | ||||||
|  |     pub author_id: UserId, | ||||||
|     pub timezone: Tz, |     pub timezone: Tz, | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -305,9 +305,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> { | |||||||
|         .add_command(&reminder_cmds::TIMER_COMMAND) |         .add_command(&reminder_cmds::TIMER_COMMAND) | ||||||
|         .add_command(&reminder_cmds::REMIND_COMMAND) |         .add_command(&reminder_cmds::REMIND_COMMAND) | ||||||
|         /* |         /* | ||||||
|         .add_command("r", &reminder_cmds::REMIND_COMMAND) |  | ||||||
|         .add_command("interval", &reminder_cmds::INTERVAL_COMMAND) |  | ||||||
|         .add_command("i", &reminder_cmds::INTERVAL_COMMAND) |  | ||||||
|         .add_command("natural", &reminder_cmds::NATURAL_COMMAND) |         .add_command("natural", &reminder_cmds::NATURAL_COMMAND) | ||||||
|         .add_command("n", &reminder_cmds::NATURAL_COMMAND) |         .add_command("n", &reminder_cmds::NATURAL_COMMAND) | ||||||
|         .add_command("", &reminder_cmds::NATURAL_COMMAND) |         .add_command("", &reminder_cmds::NATURAL_COMMAND) | ||||||
| @@ -326,10 +323,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> { | |||||||
|         .add_command(&moderation_cmds::TIMEZONE_COMMAND) |         .add_command(&moderation_cmds::TIMEZONE_COMMAND) | ||||||
|         .add_command(&moderation_cmds::PREFIX_COMMAND) |         .add_command(&moderation_cmds::PREFIX_COMMAND) | ||||||
|         .add_command(&moderation_cmds::MACRO_CMD_COMMAND) |         .add_command(&moderation_cmds::MACRO_CMD_COMMAND) | ||||||
|         /* |  | ||||||
|         .add_command("alias", &moderation_cmds::ALIAS_COMMAND) |  | ||||||
|         .add_command("a", &moderation_cmds::ALIAS_COMMAND) |  | ||||||
|         */ |  | ||||||
|         .add_hook(&hooks::CHECK_SELF_PERMISSIONS_HOOK) |         .add_hook(&hooks::CHECK_SELF_PERMISSIONS_HOOK) | ||||||
|         .add_hook(&hooks::MACRO_CHECK_HOOK) |         .add_hook(&hooks::MACRO_CHECK_HOOK) | ||||||
|         .build(); |         .build(); | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| use serenity::model::id::GuildId; | use serenity::{client::Context, model::id::GuildId}; | ||||||
|  |  | ||||||
| use crate::framework::CommandOptions; | use crate::{framework::CommandOptions, SQLPool}; | ||||||
|  |  | ||||||
| pub struct CommandMacro { | pub struct CommandMacro { | ||||||
|     pub guild_id: GuildId, |     pub guild_id: GuildId, | ||||||
| @@ -8,3 +8,23 @@ pub struct CommandMacro { | |||||||
|     pub description: Option<String>, |     pub description: Option<String>, | ||||||
|     pub commands: Vec<CommandOptions>, |     pub commands: Vec<CommandOptions>, | ||||||
| } | } | ||||||
|  |  | ||||||
|  | impl CommandMacro { | ||||||
|  |     pub async fn from_guild(ctx: &Context, guild_id: impl Into<GuildId>) -> Vec<Self> { | ||||||
|  |         let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap(); | ||||||
|  |         let guild_id = guild_id.into(); | ||||||
|  |  | ||||||
|  |         sqlx::query!("SELECT * FROM macro WHERE guild_id = ?", guild_id.0) | ||||||
|  |             .fetch_all(&pool) | ||||||
|  |             .await | ||||||
|  |             .unwrap() | ||||||
|  |             .iter() | ||||||
|  |             .map(|row| Self { | ||||||
|  |                 guild_id: GuildId(row.guild_id), | ||||||
|  |                 name: row.name.clone(), | ||||||
|  |                 description: row.description.clone(), | ||||||
|  |                 commands: serde_json::from_str(&row.commands).unwrap(), | ||||||
|  |             }) | ||||||
|  |             .collect::<Vec<Self>>() | ||||||
|  |     } | ||||||
|  | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user