account list rework + run rustfmt

This commit is contained in:
Stachelbeere1248 2024-11-12 04:02:07 +01:00
parent 534576778d
commit 15ab265dbe
Signed by: Stachelbeere1248
SSH key fingerprint: SHA256:IozEKdw2dB8TZxkpPdMxcWSoWTIMwoLaCcZJ1AJnY2o
14 changed files with 450 additions and 305 deletions

4
.rustfmt.toml Normal file
View file

@ -0,0 +1,4 @@
max_width = 140
use_small_heuristics = "Default"
reorder_imports = true
format_strings = true

View file

@ -2,21 +2,14 @@ use poise::CreateReply;
use reqwest::{Client, Response}; use reqwest::{Client, Response};
use serde::Deserialize; use serde::Deserialize;
use serenity::{ use serenity::{
all::{ all::{ChannelId, CreateActionRow, CreateAllowedMentions, CreateButton, CreateMessage, ReactionType, User},
ChannelId,
CreateActionRow,
CreateAllowedMentions,
CreateButton,
CreateMessage,
ReactionType,
User,
},
json::JsonError, json::JsonError,
}; };
use sqlx::{Pool, query_as, Sqlite}; use sqlx::{query_as, Pool, Sqlite};
use crate::Context; use crate::commands::command_helper::cooldown;
use crate::error::Error; use crate::error::Error;
use crate::Context;
#[derive(Deserialize)] #[derive(Deserialize)]
struct Links { struct Links {
@ -40,7 +33,7 @@ struct HypixelResponse {
#[derive(Deserialize)] #[derive(Deserialize)]
struct MojangPlayer { struct MojangPlayer {
pub id: String, pub id: String,
//pub name: String, pub name: String,
} }
#[derive(PartialEq, sqlx::FromRow)] #[derive(PartialEq, sqlx::FromRow)]
@ -55,8 +48,7 @@ impl Uuid {
let url: String = format!("https://api.mojang.com/users/profiles/minecraft/{ign}"); let url: String = format!("https://api.mojang.com/users/profiles/minecraft/{ign}");
let response: Response = reqwest::get(url).await?; let response: Response = reqwest::get(url).await?;
let response_text = response.error_for_status()?.text().await.unwrap(); let response_text = response.error_for_status()?.text().await.unwrap();
let uuid = (serde_json::from_str(response_text.as_str()) let uuid = (serde_json::from_str(response_text.as_str()) as Result<MojangPlayer, JsonError>)
as Result<MojangPlayer, JsonError>)
.map(|mojang_player: MojangPlayer| Uuid { uuid: mojang_player.id })?; .map(|mojang_player: MojangPlayer| Uuid { uuid: mojang_player.id })?;
Ok(uuid) Ok(uuid)
/*match response.error_for_status() { /*match response.error_for_status() {
@ -72,6 +64,15 @@ impl Uuid {
Details: {}", why).as_str())), Details: {}", why).as_str())),
}*/ }*/
} }
async fn ign(&self) -> Result<String, Error> {
let url: String = format!("https://sessionserver.mojang.com/session/minecraft/profile/{}", self.uuid);
let response: Response = reqwest::get(url).await?;
let response_text = response.error_for_status()?.text().await.unwrap();
let ign = (serde_json::from_str(response_text.as_str()) as Result<MojangPlayer, JsonError>)
.map(|mojang_player: MojangPlayer| mojang_player.name)?;
Ok(ign)
}
} }
#[derive(PartialEq)] #[derive(PartialEq)]
struct DiscordId { struct DiscordId {
@ -82,8 +83,7 @@ impl DiscordId {
let url: String = format!("https://api.hypixel.net/v2/player?uuid={}", uuid); let url: String = format!("https://api.hypixel.net/v2/player?uuid={}", uuid);
let response: Response = client.get(url).send().await?; let response: Response = client.get(url).send().await?;
let response_text = response.error_for_status()?.text().await.unwrap(); let response_text = response.error_for_status()?.text().await.unwrap();
let matches = (serde_json::from_str(response_text.as_str()) let matches = (serde_json::from_str(response_text.as_str()) as Result<HypixelResponse, JsonError>)
as Result<HypixelResponse, JsonError>)
.map(|hypixel_response: HypixelResponse| user.name == hypixel_response.player.social_media.links.discord)?; .map(|hypixel_response: HypixelResponse| user.name == hypixel_response.player.social_media.links.discord)?;
Ok(matches) Ok(matches)
} }
@ -97,7 +97,7 @@ where
fn from_row(row: &'a R) -> sqlx::Result<Self> { fn from_row(row: &'a R) -> sqlx::Result<Self> {
let discord_id: i64 = row.try_get("discord_id")?; let discord_id: i64 = row.try_get("discord_id")?;
Ok(DiscordId { Ok(DiscordId {
id: discord_id.cast_unsigned() id: discord_id.cast_unsigned(),
}) })
} }
} }
@ -116,14 +116,17 @@ impl Link {
} }
async fn minecraft(mut self, pool: &Pool<Sqlite>) -> Result<Self, Error> { async fn minecraft(mut self, pool: &Pool<Sqlite>) -> Result<Self, Error> {
let link_id: i16 = self.link_id.cast_signed(); let link_id: i16 = self.link_id.cast_signed();
self.minecraft_accounts = query_as(format!("SELECT minecraft_uuid AS uuid FROM minecraft_links WHERE link_id = {link_id};").as_str()) self.minecraft_accounts =
.fetch_all(pool).await?; query_as(format!("SELECT minecraft_uuid AS uuid FROM minecraft_links WHERE link_id = {link_id};").as_str())
.fetch_all(pool)
.await?;
Ok(self) Ok(self)
} }
async fn discord(mut self, pool: &Pool<Sqlite>) -> Result<Self, Error> { async fn discord(mut self, pool: &Pool<Sqlite>) -> Result<Self, Error> {
let link_id: i16 = self.link_id.cast_signed(); let link_id: i16 = self.link_id.cast_signed();
self.discord_ids = query_as(format!("SELECT discord_id FROM discord_links WHERE link_id = {link_id};").as_str()) self.discord_ids = query_as(format!("SELECT discord_id FROM discord_links WHERE link_id = {link_id};").as_str())
.fetch_all(pool).await?; .fetch_all(pool)
.await?;
Ok(self) Ok(self)
} }
} }
@ -133,7 +136,6 @@ pub(crate) async fn account(_ctx: Context<'_>) -> Result<(), Error> {
unreachable!() unreachable!()
} }
#[poise::command(slash_command)] #[poise::command(slash_command)]
pub(crate) async fn add<'a>( pub(crate) async fn add<'a>(
ctx: Context<'_>, ctx: Context<'_>,
@ -141,52 +143,70 @@ pub(crate) async fn add<'a>(
#[min_length = 2] #[min_length = 2]
#[max_length = 16] #[max_length = 16]
ign: String, ign: String,
user: Option<User>, #[description = "Discord User"] user: Option<User>,
#[description = "Minecraft username"] force: Option<bool>,
) -> Result<(), Error> { ) -> Result<(), Error> {
ctx.defer_ephemeral().await?; ctx.defer_ephemeral().await?;
let user = user.unwrap_or(ctx.author().clone()); let user: User = user.unwrap_or(ctx.author().clone());
let uuid = Uuid::fetch(ign.as_str()).await?; let uuid: Uuid = Uuid::fetch(ign.as_str()).await?;
match DiscordId::matches_fetch(&user, uuid.get(), &ctx.data().hypixel_api_client).await? { let force: bool = force.unwrap_or(false) && ctx.framework().options.owners.contains(&ctx.author().id);
match DiscordId::matches_fetch(&user, uuid.get(), &ctx.data().hypixel_api_client).await? || force {
true => { true => {
let pool: Pool<Sqlite> = ctx.data().sqlite_pool.clone(); let pool: Pool<Sqlite> = ctx.data().sqlite_pool.clone();
let (status, link_id) = match link_id_from_minecraft(&pool, uuid.get()).await { let status: &str = match link_id_from_minecraft(&pool, uuid.get()).await {
None => { None => match link_id_from_discord(&pool, user.id.get()).await {
match link_id_from_discord(&pool, user.id.get()).await {
None => { None => {
let id = new_link_id(&pool).await?; let id = new_link_id(&pool).await?;
sqlx::query(format!("INSERT INTO discord_links VALUES ({}, {});", id.cast_signed(), user.id.get()).as_str()) sqlx::query(format!("INSERT INTO discord_links VALUES ({}, {});", id.cast_signed(), user.id.get()).as_str())
.execute(&pool).await?; .execute(&pool)
.await?;
sqlx::query(format!("INSERT INTO minecraft_links VALUES ({}, \"{}\");", id.cast_signed(), uuid.get()).as_str()) sqlx::query(format!("INSERT INTO minecraft_links VALUES ({}, \"{}\");", id.cast_signed(), uuid.get()).as_str())
.execute(&pool).await?; .execute(&pool)
("Linked your Discord and Minecraft account.", id) .await?;
"Linked your Discord and Minecraft account."
} }
Some(dc_id) => { Some(dc_id) => {
sqlx::query(format!("INSERT INTO minecraft_links VALUES ({}, \"{}\");", dc_id.cast_signed(), uuid.get()).as_str()) sqlx::query(format!("INSERT INTO minecraft_links VALUES ({}, \"{}\");", dc_id.cast_signed(), uuid.get()).as_str())
.execute(&pool).await?; .execute(&pool)
("Your Discord account has previously had an account linked. Added the new link.", dc_id) .await?;
"Your Discord account has previously had an account linked. Added the new link."
} }
} },
} Some(mc_id) => match link_id_from_discord(&pool, user.id.get()).await {
Some(mc_id) => {
match link_id_from_discord(&pool, user.id.get()).await {
None => { None => {
sqlx::query(format!("INSERT INTO discord_links VALUES ({}, {});", mc_id.cast_signed(), user.id.get()).as_str()) sqlx::query(format!("INSERT INTO discord_links VALUES ({}, {});", mc_id.cast_signed(), user.id.get()).as_str())
.execute(&pool).await?; .execute(&pool)
("Your Minecraft account has previously had an account linked. Added the new link.", mc_id) .await?;
"Your Minecraft account has previously had an account linked. Added the new link."
} }
Some(dc_id) => { Some(dc_id) => {
sqlx::query(format!("UPDATE minecraft_links SET link_id = {} WHERE link_id = {};", mc_id.cast_signed(), dc_id.cast_signed()).as_str()) sqlx::query(
.execute(&pool).await?; format!(
sqlx::query(format!("UPDATE discord_links SET link_id = {} WHERE link_id = {};", mc_id.cast_signed(), dc_id.cast_signed()).as_str()) "UPDATE minecraft_links SET link_id = {} WHERE link_id = {};",
.execute(&pool).await?; mc_id.cast_signed(),
("Both your Discord and Minecraft account had linked accounts. Merged all account links.", mc_id) dc_id.cast_signed()
} )
} .as_str(),
)
.execute(&pool)
.await?;
sqlx::query(
format!(
"UPDATE discord_links SET link_id = {} WHERE link_id = {};",
mc_id.cast_signed(),
dc_id.cast_signed()
)
.as_str(),
)
.execute(&pool)
.await?;
"Both your Discord and Minecraft account had linked accounts. Merged all account links."
} }
},
}; };
let link = Link::new(link_id).minecraft(&pool).await?.discord(&pool).await?; let s = format!("Verification request for {} with IGN `{}`", user.id.get(), ign);
let s = list_string(link, user.id.get()); ChannelId::new(1257776992497959075)
ChannelId::new(1257776992497959075).send_message( .send_message(
ctx, ctx,
CreateMessage::new() CreateMessage::new()
.content(s) .content(s)
@ -194,61 +214,81 @@ pub(crate) async fn add<'a>(
.components(vec![CreateActionRow::Buttons(vec![ .components(vec![CreateActionRow::Buttons(vec![
CreateButton::new("accept_verification").emoji(ReactionType::from('✅')), CreateButton::new("accept_verification").emoji(ReactionType::from('✅')),
CreateButton::new("deny_verification").emoji(ReactionType::from('❌')), CreateButton::new("deny_verification").emoji(ReactionType::from('❌')),
CreateButton::new("list_accounts").emoji(ReactionType::from('📜')),
])]), ])]),
).await?; )
.await?;
ctx.send(CreateReply::default().ephemeral(false).content(status)).await?; ctx.send(CreateReply::default().ephemeral(false).content(status)).await?;
Ok(()) Ok(())
},
false => {
Err(Error::Other(format!("The Discord account linked on Hypixel does not match the specified discord account.\n\
Please set your linked Discord account on Hypixel to `{}`.", user.name)))
} }
false => Err(Error::Other(format!(
"The Discord account linked on Hypixel does not match the specified discord account.\nPlease set your linked Discord account \
on Hypixel to `{}`.",
user.name
))),
} }
} }
#[poise::command(slash_command)] #[poise::command(slash_command)]
pub(crate) async fn list( pub(crate) async fn list(ctx: Context<'_>, user: Option<User>) -> Result<(), Error> {
ctx: Context<'_>, ctx.defer_ephemeral().await?;
user: Option<User>, cooldown(&ctx, 600, 300)?;
) -> Result<(), Error> { let user: User = user.unwrap_or(ctx.author().clone());
ctx.defer().await?; let pool: &Pool<Sqlite> = &ctx.data().sqlite_pool;
let user = user.unwrap_or(ctx.author().clone()); let s: String = list_string(pool, &user).await?;
let r = CreateReply::default().ephemeral(false); let r: CreateReply = CreateReply::default().ephemeral(false);
let pool: Pool<Sqlite> = ctx.data().sqlite_pool.clone(); ctx.send(
let link_id = link_id_from_discord(&pool, user.id.get()).await.expect("This user has no linked accounts"); r.content(s)
let link = Link::new(link_id).minecraft(&pool).await?.discord(&pool).await?; .allowed_mentions(CreateAllowedMentions::new().empty_roles().empty_users()),
let s = list_string(link, user.id.get()); )
ctx.send(r.content(s).allowed_mentions(CreateAllowedMentions::new().empty_roles().empty_users())).await?; .await?;
Ok(()) Ok(())
} }
pub(crate) async fn list_string(pool: &Pool<Sqlite>, user: &User) -> Result<String, Error> {
let link_id: u16 = link_id_from_discord(pool, user.id.get())
.await
.expect("This user has no linked accounts");
let link: Link = Link::new(link_id).minecraft(pool).await?.discord(pool).await?;
let mut discord_list = String::from("### Discord:");
for dc in link.discord_ids {
discord_list.push_str(format!("\n- <@{}>", dc.id).as_str());
}
let mut minecraft_list = String::from("### Minecraft:");
for mc in link.minecraft_accounts {
minecraft_list.push_str(format!("\n- `{}`", mc.ign().await?).as_str());
}
Ok(format!(
"## Account list for member #{}:\n{}\n{}",
link.link_id,
discord_list.as_str(),
minecraft_list.as_str()
))
}
#[poise::command(slash_command)] #[poise::command(slash_command)]
pub(crate) async fn remove(_ctx: Context<'_>) -> Result<(), Error> { pub(crate) async fn remove(_ctx: Context<'_>) -> Result<(), Error> {
unimplemented!() unimplemented!()
} }
fn list_string(link: Link, user_id: u64) -> String {
let mut discord_list = String::from("### Discord:");
for dc in link.discord_ids {
discord_list.push_str(format!("\n- <@{}>", dc.id).as_str());
}
let mut minecraft_list = String::from("### Minecraft:");
for mc in link.minecraft_accounts {
minecraft_list.push_str(format!("\n- `{}`", mc.get()).as_str());
}
format!("## Account list for <@{user_id}>:\n{}\n{}", discord_list.as_str(), minecraft_list.as_str())
}
async fn link_id_from_minecraft(pool: &Pool<Sqlite>, minecraft_uuid: &str) -> Option<u16> { async fn link_id_from_minecraft(pool: &Pool<Sqlite>, minecraft_uuid: &str) -> Option<u16> {
query_as(format!("SELECT link_id FROM minecraft_links WHERE minecraft_uuid = \"{minecraft_uuid}\" LIMIT 1;").as_str()) query_as(format!("SELECT link_id FROM minecraft_links WHERE minecraft_uuid = \"{minecraft_uuid}\" LIMIT 1;").as_str())
.fetch_optional(pool) .fetch_optional(pool)
.await.expect("Database error: fetching link id by uuid") .await
.expect("Database error: fetching link id by uuid")
.map(|link_id: LinkId| link_id.link_id.cast_unsigned()) .map(|link_id: LinkId| link_id.link_id.cast_unsigned())
} }
async fn link_id_from_discord(pool: &Pool<Sqlite>, snowflake: u64) -> Option<u16> { async fn link_id_from_discord(pool: &Pool<Sqlite>, snowflake: u64) -> Option<u16> {
query_as(format!("SELECT link_id FROM discord_links WHERE discord_id = {} LIMIT 1;", snowflake.cast_signed()).as_str()) query_as(
format!(
"SELECT link_id FROM discord_links WHERE discord_id = {} LIMIT 1;",
snowflake.cast_signed()
)
.as_str(),
)
.fetch_optional(pool) .fetch_optional(pool)
.await.expect("Database error: fetching link id by discord") .await
.expect("Database error: fetching link id by discord")
.map(|link_id: LinkId| link_id.link_id.cast_unsigned()) .map(|link_id: LinkId| link_id.link_id.cast_unsigned())
} }

View file

@ -1,7 +1,9 @@
use std::string::String; use std::string::String;
use poise::CreateReply; use poise::CreateReply;
use crate::Context;
use crate::error::Error; use crate::error::Error;
use crate::Context;
#[poise::command(slash_command, guild_only, owners_only)] #[poise::command(slash_command, guild_only, owners_only)]
pub(crate) async fn bots( pub(crate) async fn bots(

View file

@ -1,7 +1,7 @@
use std::time::Duration; use std::time::Duration;
use crate::Context;
use crate::error::Error; use crate::error::Error;
use crate::Context;
pub(crate) fn cooldown(ctx: &Context, user: u64, guild: u64) -> Result<(), Error> { pub(crate) fn cooldown(ctx: &Context, user: u64, guild: u64) -> Result<(), Error> {
let mut cooldown_tracker = ctx.command().cooldowns.lock().unwrap(); let mut cooldown_tracker = ctx.command().cooldowns.lock().unwrap();

View file

@ -1,9 +1,9 @@
use poise::CreateReply; use poise::CreateReply;
use serenity::all::CreateAllowedMentions; use serenity::all::CreateAllowedMentions;
use crate::Context;
use crate::commands::command_helper; use crate::commands::command_helper;
use crate::error::Error; use crate::error::Error;
use crate::Context;
#[poise::command(slash_command, guild_only)] #[poise::command(slash_command, guild_only)]
pub(crate) async fn helpstart( pub(crate) async fn helpstart(
@ -20,23 +20,19 @@ pub(crate) async fn helpstart(
let mut reply = CreateReply::default(); let mut reply = CreateReply::default();
let ping = match g { let ping = match g {
1256217633959841853_u64 => 1257411572092113017_u64, 1256217633959841853_u64 => 1257411572092113017_u64,
_ => 0_u64 _ => 0_u64,
}; };
reply = if bots >= needed_players { reply = if bots >= needed_players {
reply.content("Bots available. Please use <@424767825001971715> in the bot-commands channel instead.") reply
.content("Bots available. Please use <@424767825001971715> in the bot-commands channel instead.")
.ephemeral(true) .ephemeral(true)
} else { } else {
match command_helper::cooldown(&ctx, 1200, 600) { command_helper::cooldown(&ctx, 1200, 600)?;
Ok(_) => reply reply
.content(format!( .content(format!("<@&{ping}>\nneed: {}", needed_players - bots))
"<@&{ping}>\nneed: {}",
needed_players - bots
))
.ephemeral(false) .ephemeral(false)
.allowed_mentions(CreateAllowedMentions::new().roles(vec![ping])), .allowed_mentions(CreateAllowedMentions::new().roles(vec![ping]))
Err(why) => reply.content(why.to_string()).ephemeral(true),
}
}; };
if let Err(why) = ctx.send(reply).await { if let Err(why) = ctx.send(reply).await {
println!("Error sending message: {why}") println!("Error sending message: {why}")

View file

@ -1,7 +1,6 @@
use poise::{ChoiceParameter, CreateReply}; use poise::{ChoiceParameter, CreateReply};
use serenity::all::{CreateAllowedMentions, RoleId}; use serenity::all::{CreateAllowedMentions, RoleId};
use crate::Context;
//from main.rs //from main.rs
use crate::commands::command_helper::cooldown; use crate::commands::command_helper::cooldown;
// //
@ -9,6 +8,7 @@ use crate::commands::lfg::Difficulty::Normal;
use crate::commands::lfg::Map::*; use crate::commands::lfg::Map::*;
use crate::commands::lfg::Mode::*; use crate::commands::lfg::Mode::*;
use crate::error::Error; use crate::error::Error;
use crate::Context;
#[derive(Debug, poise::ChoiceParameter, PartialEq)] #[derive(Debug, poise::ChoiceParameter, PartialEq)]
pub enum Map { pub enum Map {
@ -68,9 +68,7 @@ pub(crate) async fn lfg(
note: Option<String>, note: Option<String>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let guild_id = ctx.guild_id().unwrap().get(); let guild_id = ctx.guild_id().unwrap().get();
let mut reply: CreateReply = CreateReply::default(); cooldown(&ctx, 600, 300)?;
reply = match cooldown(&ctx, 600, 300) {
Ok(_) => {
let current: u8 = current_players.unwrap_or(1); let current: u8 = current_players.unwrap_or(1);
let mut desired: u8 = desired_players.unwrap_or(4); let mut desired: u8 = desired_players.unwrap_or(4);
if current >= desired { if current >= desired {
@ -112,13 +110,10 @@ pub(crate) async fn lfg(
reply_content.push_str(format!("\nNote: {note}").as_str()); reply_content.push_str(format!("\nNote: {note}").as_str());
} }
} }
reply let reply: CreateReply = CreateReply::default()
.content(reply_content) .content(reply_content)
.ephemeral(false) .ephemeral(false)
.allowed_mentions(CreateAllowedMentions::new().roles(vec![ping])) .allowed_mentions(CreateAllowedMentions::new().roles(vec![ping]));
}
Err(why) => reply.content(why.to_string()).ephemeral(true),
};
if let Err(why) = ctx.send(reply).await { if let Err(why) = ctx.send(reply).await {
println!("Error sending message: {why}"); println!("Error sending message: {why}");
@ -156,8 +151,7 @@ pub(crate) async fn expert(
#[rename = "message"] #[rename = "message"]
note: String, note: String,
) -> Result<(), Error> { ) -> Result<(), Error> {
let reply: CreateReply = match cooldown(&ctx, 600, 300) { cooldown(&ctx, 600, 300)?;
Ok(_) => {
let current: u8 = current_players.unwrap_or(1); let current: u8 = current_players.unwrap_or(1);
let mut desired: u8 = desired_players.unwrap_or(4); let mut desired: u8 = desired_players.unwrap_or(4);
if current >= desired { if current >= desired {
@ -166,19 +160,19 @@ pub(crate) async fn expert(
let (ping, allowed_roles): (u64, Vec<u64>) = match mode { let (ping, allowed_roles): (u64, Vec<u64>) = match mode {
ExpertMap::Speedrun => ( ExpertMap::Speedrun => (
1295322375637958716, 1295322375637958716,
ROLE_LIST.iter().skip(2).map(|tier| [tier[4], tier[5]]).flatten().collect() ROLE_LIST.iter().skip(2).map(|tier| [tier[4], tier[5]]).flatten().collect(),
), ),
ExpertMap::DeadEnd => ( ExpertMap::DeadEnd => (
1295321319344177172, 1295321319344177172,
ROLE_LIST.iter().skip(2).map(|tier| [tier[1], tier[5]]).flatten().collect() ROLE_LIST.iter().skip(2).map(|tier| [tier[1], tier[5]]).flatten().collect(),
), ),
ExpertMap::BadBlood => ( ExpertMap::BadBlood => (
1295322259631640607, 1295322259631640607,
ROLE_LIST.iter().skip(2).map(|tier| [tier[2], tier[5]]).flatten().collect() ROLE_LIST.iter().skip(2).map(|tier| [tier[2], tier[5]]).flatten().collect(),
), ),
ExpertMap::AlienArcadium => ( ExpertMap::AlienArcadium => (
1295322327910842441, 1295322327910842441,
ROLE_LIST.iter().skip(2).map(|tier| [tier[3], tier[5]]).flatten().collect() ROLE_LIST.iter().skip(2).map(|tier| [tier[3], tier[5]]).flatten().collect(),
), ),
}; };
let is_expert: bool = ctx let is_expert: bool = ctx
@ -189,8 +183,7 @@ pub(crate) async fn expert(
.iter() .iter()
.any(|user_role: &RoleId| allowed_roles.contains(&user_role.get())); .any(|user_role: &RoleId| allowed_roles.contains(&user_role.get()));
let reply_content: String = format!("{current}/{desired} <@&{ping}>: {note}"); let reply_content: String = format!("{current}/{desired} <@&{ping}>: {note}");
let reply: CreateReply = match is_expert {
match is_expert {
true => CreateReply::default() true => CreateReply::default()
.content(reply_content) .content(reply_content)
.ephemeral(false) .ephemeral(false)
@ -198,13 +191,7 @@ pub(crate) async fn expert(
false => CreateReply::default() false => CreateReply::default()
.content("You do not have any of the required expert ranks.") .content("You do not have any of the required expert ranks.")
.ephemeral(true), .ephemeral(true),
}
}
Err(why) => {
CreateReply::default().content(why.to_string()).ephemeral(true)
}
}; };
if let Err(why) = ctx.send(reply).await { if let Err(why) = ctx.send(reply).await {
println!("Error sending message: {why}"); println!("Error sending message: {why}");
} }
@ -219,8 +206,7 @@ enum OtherPing {
#[poise::command(slash_command, guild_only, rename = "lfg-other")] #[poise::command(slash_command, guild_only, rename = "lfg-other")]
pub(crate) async fn other( pub(crate) async fn other(
ctx: Context<'_>, ctx: Context<'_>,
#[rename = "game"] #[rename = "game"] game: OtherPing,
game: OtherPing,
#[min = 1_u8] #[min = 1_u8]
#[max = 3_u8] #[max = 3_u8]
#[description = "default: 1"] #[description = "default: 1"]
@ -230,8 +216,7 @@ pub(crate) async fn other(
#[rename = "message"] #[rename = "message"]
note: String, note: String,
) -> Result<(), Error> { ) -> Result<(), Error> {
let reply: CreateReply = match cooldown(&ctx, 0, 7200) { cooldown(&ctx, 0, 7200)?;
Ok(_) => {
let current: u8 = current_players.unwrap_or(1); let current: u8 = current_players.unwrap_or(1);
let desired: u8 = match game { let desired: u8 = match game {
OtherPing::GeoGuessr => 20_u8, OtherPing::GeoGuessr => 20_u8,
@ -241,15 +226,10 @@ pub(crate) async fn other(
}; };
let reply_content: String = format!("{current}/{desired} <@&{ping}>: {note}"); let reply_content: String = format!("{current}/{desired} <@&{ping}>: {note}");
CreateReply::default() let reply: CreateReply = CreateReply::default()
.content(reply_content) .content(reply_content)
.ephemeral(false) .ephemeral(false)
.allowed_mentions(CreateAllowedMentions::new().roles(vec![ping])) .allowed_mentions(CreateAllowedMentions::new().roles(vec![ping]));
}
Err(why) => {
CreateReply::default().content(why.to_string()).ephemeral(true)
}
};
if let Err(why) = ctx.send(reply).await { if let Err(why) = ctx.send(reply).await {
println!("Error sending message: {why}"); println!("Error sending message: {why}");
@ -257,15 +237,78 @@ pub(crate) async fn other(
Ok(()) Ok(())
} }
const ROLE_LIST: [[u64; 6]; 9] = [
const ROLE_LIST: [[u64; 6]; 9] = [ // [[basic, de, bb, aa, sr, star]; 9] // [[basic, de, bb, aa, sr, star]; 9]
[1256229103678259311, 1256229192744304670, 1256229223450935377, 1256229498899271754, 1256229540900900996, 1256229575269154866], //novice [
[1256230831131983932, 1256230750827577447, 1256230776828334143, 1256230793630715975, 1256230818444214333, 1256230734642024468], //seasoned 1256229103678259311,
[1256230723455553556, 1256230653083521045, 1256230666786443310, 1256230686214324255, 1256230704061353995, 1256230636721537097], //expert 1256229192744304670,
[1256230625635995718, 1256230573203128370, 1256230582908747776, 1256230600025706506, 1256230610998005872, 1256230557897986068], //pro 1256229223450935377,
[1256230543532626002, 1256230480823582861, 1256230502273126421, 1256230515355160597, 1256230531478065243, 1256230463241191494], //master 1256229498899271754,
[1256230442907074703, 1256230359419588700, 1256230396719403141, 1256230416516649012, 1256230429212545025, 1256230346848997396], //grandmaster 1256229540900900996,
[1256230332169060362, 1256230266889044020, 1256230288888168458, 1256230416516649012, 1256230316528631870, 1256230242943766651], //legend 1256229575269154866,
[1256230231732387950, 1256230157967163495, 1256230181199151254, 1256230194499420223, 1256230207099244646, 1256230102627258449], //divine ], //novice
[1256230002597302322, 1256229873064869939, 1256229929247440906, 1256229963166646314, 1256229982569627792, 1256229672598110218], //goat [
1256230831131983932,
1256230750827577447,
1256230776828334143,
1256230793630715975,
1256230818444214333,
1256230734642024468,
], //seasoned
[
1256230723455553556,
1256230653083521045,
1256230666786443310,
1256230686214324255,
1256230704061353995,
1256230636721537097,
], //expert
[
1256230625635995718,
1256230573203128370,
1256230582908747776,
1256230600025706506,
1256230610998005872,
1256230557897986068,
], //pro
[
1256230543532626002,
1256230480823582861,
1256230502273126421,
1256230515355160597,
1256230531478065243,
1256230463241191494,
], //master
[
1256230442907074703,
1256230359419588700,
1256230396719403141,
1256230416516649012,
1256230429212545025,
1256230346848997396,
], //grandmaster
[
1256230332169060362,
1256230266889044020,
1256230288888168458,
1256230416516649012,
1256230316528631870,
1256230242943766651,
], //legend
[
1256230231732387950,
1256230157967163495,
1256230181199151254,
1256230194499420223,
1256230207099244646,
1256230102627258449,
], //divine
[
1256230002597302322,
1256229873064869939,
1256229929247440906,
1256229963166646314,
1256229982569627792,
1256229672598110218,
], //goat
]; ];

View file

@ -1,6 +1,6 @@
pub(crate) mod accountv2;
pub(crate) mod bots; pub(crate) mod bots;
pub(crate) mod command_helper; pub(crate) mod command_helper;
pub(crate) mod helpstart; pub(crate) mod helpstart;
pub(crate) mod lfg; pub(crate) mod lfg;
pub(crate) mod xd; pub(crate) mod xd;
pub(crate) mod accountv2;

View file

@ -1,7 +1,14 @@
use crate::Context;
use crate::error::Error; use crate::error::Error;
use crate::Context;
const XD: &str = "⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n⣿⣿⣿⡿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣿⡿⠿⠿⠿⠿⠿⠿⠿⢿⡿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n⣿⣿⣿⣧⣄⡀⠀⠀⠀⢀⣠⣼⣿⣿⣿⣿⣧⣄⡀⠀⠀⠀⣀⣤⣼⣷⣦⣤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⢿⣿⣿⣿⣿⣿⣿\n⣿⣿⣿⣿⣿⣿⣦⠀⠀⠀⠻⣿⣿⣿⣿⣿⣿⠟⠀⠀⢀⣼⣿⣿⣿⣿⣿⣿⡇⠀⠀⢸⣿⣿⣿⣿⣿⣿⣶⣦⣄⡀⠀⠀⠙⢿⣿⣿⣿⣿\n⣿⣿⣿⣿⣿⣿⣿⣷⡀⠀⠀⠙⣿⣿⣿⣿⠋⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠈⢿⣿⣿⣿\n⣿⣿⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠈⢿⡿⠁⠀⠀⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⢸⣿⣿⣿\n⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⡀⠀⠀⠀⠀⢠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⣿⣿⣿\n⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡗⠀⠀⠀⠐⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡏⠀⠀⠀⣿⣿⣿\n⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠏⠀⠀⣠⡀⠀⠀⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⢸⣿⣿⣿\n⣿⣿⣿⣿⣿⣿⣿⣿⡿⠃⠀⠀⣰⣿⣷⡄⠀⠀⠘⢿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⣾⣿⣿⣿\n⣿⣿⣿⣿⣿⣿⣿⡟⠁⠀⢀⣼⣿⣿⣿⣿⣆⠀⠀⠈⠻⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠁⠀⢀⣼⣿⣿⣿⣿\n⣿⣿⣿⣿⣿⣿⠋⠀⠀⢠⣾⣿⣿⣿⣿⣿⣿⣷⡀⠀⠀⠙⣿⣿⣿⣿⣿⣿⡇⠀⠀⢸⣿⣿⣿⣿⣿⣿⠿⠛⠁⠀⠀⣠⣾⣿⣿⣿⣿⣿\n⣿⣿⣿⠿⠛⠁⠀⠀⠀⠙⠻⣿⣿⣿⣿⣿⡿⠟⠋⠀⠀⠀⠈⠛⠻⡿⠟⠛⠁⠀⠀⠈⠉⠉⠉⠉⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⣿⣿⣿\n⣿⣿⣿⣶⣶⣶⣶⣶⣶⣶⣶⣿⣿⣿⣿⣿⣷⣶⣶⣶⣶⣶⣶⣶⣶⣷⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n"; const XD: &str = "⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n⣿⣿⣿⡿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣿⡿⠿⠿⠿⠿⠿⠿⠿⢿⡿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\\
n\n\\
n\n\\
n\n\\
n\n\\
n\n\\
n\n\\
n\n";
#[poise::command(slash_command)] #[poise::command(slash_command)]
pub(crate) async fn xd(ctx: Context<'_>) -> Result<(), Error> { pub(crate) async fn xd(ctx: Context<'_>) -> Result<(), Error> {

View file

@ -5,7 +5,7 @@ pub enum Error {
ParsingError(serde_json::Error), ParsingError(serde_json::Error),
SerenityError(serenity::Error), SerenityError(serenity::Error),
OnCooldown(std::time::Duration), OnCooldown(std::time::Duration),
Other(String) Other(String),
} }
impl std::fmt::Display for Error { impl std::fmt::Display for Error {
@ -15,7 +15,9 @@ impl std::fmt::Display for Error {
Error::HttpsError(e) => write!(f, "HTTPS Error (Hypixel / Mojang API):\n{}", e), Error::HttpsError(e) => write!(f, "HTTPS Error (Hypixel / Mojang API):\n{}", e),
Error::ParsingError(e) => write!(f, "Parsing Error:\n {}", e), Error::ParsingError(e) => write!(f, "Parsing Error:\n {}", e),
Error::SerenityError(e) => write!(f, "Serenity Error:\n {}", e), Error::SerenityError(e) => write!(f, "Serenity Error:\n {}", e),
Error::OnCooldown(d) => write!(f, "This command is on cooldown. {}s remaining.", d.as_secs()), Error::OnCooldown(d) => {
write!(f, "This command is on cooldown. {}s remaining.", d.as_secs())
}
Error::Other(s) => write!(f, "{}", s), Error::Other(s) => write!(f, "{}", s),
} }
} }

View file

@ -1,34 +1,93 @@
use serenity::all::{ComponentInteraction, ComponentInteractionDataKind, Context, CreateMessage, EditMessage, GuildId, Interaction, RoleId}; use serenity::all::ButtonStyle::Success;
use serenity::all::ComponentInteractionDataKind;
use serenity::all::Context;
use serenity::all::CreateActionRow;
use serenity::all::CreateButton;
use serenity::all::CreateInteractionResponse::Message;
use serenity::all::CreateInteractionResponseMessage;
use serenity::all::CreateMessage;
use serenity::all::EditMessage;
use serenity::all::GuildId;
use serenity::all::Interaction;
use serenity::all::ReactionType;
use serenity::all::RoleId;
use serenity::all::{ButtonStyle, ComponentInteraction};
use crate::error::Error; use crate::error::Error;
use crate::Data;
pub(crate) async fn component(ctx: &Context, interaction: &Interaction) -> Result<(), Error> { pub(crate) async fn component(ctx: &Context, interaction: &Interaction, data: &Data) -> Result<(), Error> {
let component = interaction.clone().message_component().unwrap(); let component = interaction.clone().message_component().unwrap();
match component.data.kind { match component.data.kind {
ComponentInteractionDataKind::Button => button(ctx, component).await, ComponentInteractionDataKind::Button => button(ctx, component, data).await,
_ => Ok(()) _ => Ok(()),
} }
} }
async fn button(ctx: &Context, mut component: ComponentInteraction) -> Result<(), Error> { async fn button(ctx: &Context, mut interaction: ComponentInteraction, data: &Data) -> Result<(), Error> {
let m = component.message.clone(); let m = &interaction.message;
let u = m.mentions.first().expect("Message did not mention a user."); let u = m.mentions.first().expect("Message did not mention a user.");
match component.data.custom_id.as_str() { match interaction.data.custom_id.as_str() {
"accept_verification" => { "accept_verification" => {
let _dm = u.direct_message(ctx, CreateMessage::new() let _dm = u
.content("Your verified minecraft account was approved.")).await?; .direct_message(ctx, CreateMessage::new().content("Your verified minecraft account was approved."))
let member = m.guild_id.unwrap_or(GuildId::new(1256217633959841853_u64)).member(ctx, u.id).await?; .await?;
let member = m
.guild_id
.unwrap_or(GuildId::new(1256217633959841853_u64))
.member(ctx, u.id)
.await?;
member.add_role(ctx, RoleId::new(1256218805911425066_u64)).await?; member.add_role(ctx, RoleId::new(1256218805911425066_u64)).await?;
member.remove_role(ctx, RoleId::new(1256253358701023232_u64)).await?; member.remove_role(ctx, RoleId::new(1256253358701023232_u64)).await?;
component.message.edit(ctx, EditMessage::new().components(vec![])).await?; interaction
.message
.edit(
ctx,
EditMessage::new().components(vec![CreateActionRow::Buttons(vec![
CreateButton::new("accept_verification")
.emoji(ReactionType::from('✅'))
.style(Success)
.disabled(true),
CreateButton::new("deny_verification")
.emoji(ReactionType::from('❌'))
.disabled(true),
CreateButton::new("list_accounts").emoji(ReactionType::from('📜')),
])]),
)
.await?;
Ok(()) Ok(())
} }
"deny_verification" => { "deny_verification" => {
let _dm = u.direct_message(ctx, CreateMessage::new() let _dm = u
.content("Your verified minecraft account was denied.")).await?; .direct_message(ctx, CreateMessage::new().content("Your verified minecraft account was denied."))
component.message.edit(ctx, EditMessage::new().components(vec![])).await?; .await?;
interaction
.message
.edit(
ctx,
EditMessage::new().components(vec![CreateActionRow::Buttons(vec![
CreateButton::new("accept_verification")
.emoji(ReactionType::from('✅'))
.disabled(true),
CreateButton::new("deny_verification")
.emoji(ReactionType::from('❌'))
.style(ButtonStyle::Danger)
.disabled(true),
CreateButton::new("list_accounts").emoji(ReactionType::from('📜')),
])]),
)
.await?;
Ok(()) Ok(())
} }
_ => Ok(()) "list_accounts" => {
let user = interaction.message.mentions.first().unwrap();
let s: String = crate::commands::accountv2::list_string(&data.sqlite_pool, user).await?;
interaction
.create_response(ctx, Message(CreateInteractionResponseMessage::new().content(s).ephemeral(true)))
.await?;
Ok(())
}
_ => Ok(()),
} }
} }

View file

@ -5,10 +5,8 @@ use crate::error::Error;
pub(crate) async fn on_create(ctx: &Context, msg: &Message) -> Result<(), Error> { pub(crate) async fn on_create(ctx: &Context, msg: &Message) -> Result<(), Error> {
match msg.guild_id.map(|g| g.get()) { match msg.guild_id.map(|g| g.get()) {
None => Ok(()), None => Ok(()),
Some(1256217633959841853_u64) => { Some(1256217633959841853_u64) => zmp_create(ctx, msg).await,
zmp_create(ctx, msg).await _ => Ok(()),
}
_ => Ok(())
} }
} }
@ -19,7 +17,6 @@ async fn zmp_create(ctx: &Context, msg: &Message) -> Result<(), Error> {
msg.react(ctx, '🇱').await?; msg.react(ctx, '🇱').await?;
Ok(()) Ok(())
} }
_ => Ok(()) _ => Ok(()),
} }
} }

View file

@ -6,10 +6,10 @@ use crate::error::Error;
pub(crate) async fn on_create(ctx: &Context, thread: &GuildChannel) -> Result<(), Error> { pub(crate) async fn on_create(ctx: &Context, thread: &GuildChannel) -> Result<(), Error> {
match thread.parent_id.map(|parent| parent.get()) { match thread.parent_id.map(|parent| parent.get()) {
Some(1295108216388325386) => { Some(1295108216388325386) => {
thread.id.edit_thread(ctx, EditThread::new().rate_limit_per_user(7200_u16)).await?; thread.id.edit_thread(ctx, EditThread::new().rate_limit_per_user(60_u16)).await?;
Ok(()) Ok(())
} }
Some(_) => Ok(()), Some(_) => Ok(()),
None => Ok(()) None => Ok(()),
} }
} }

View file

@ -5,17 +5,18 @@ use std::convert::Into;
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use poise::{CreateReply, FrameworkError, serenity_prelude as serenity}; use poise::{serenity_prelude as serenity, CreateReply, FrameworkError};
use serenity::{FullEvent, model::id::UserId};
use serenity::all::{ActivityData, InteractionType, RoleId}; use serenity::all::{ActivityData, InteractionType, RoleId};
use serenity::prelude::GatewayIntents; use serenity::prelude::GatewayIntents;
use serenity::{model::id::UserId, FullEvent};
use sqlx::Sqlite; use sqlx::Sqlite;
use tokio::sync::RwLock; use tokio::sync::RwLock;
use error::Error; use error::Error;
mod commands; mod commands;
mod handlers;
mod error; mod error;
mod handlers;
struct Data { struct Data {
bots: Arc<RwLock<u8>>, bots: Arc<RwLock<u8>>,
@ -23,7 +24,6 @@ struct Data {
hypixel_api_client: reqwest::Client, hypixel_api_client: reqwest::Client,
} // User data, which is stored and accessible in all command invocations } // User data, which is stored and accessible in all command invocations
type Context<'a> = poise::Context<'a, Data, Error>; type Context<'a> = poise::Context<'a, Data, Error>;
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
@ -35,14 +35,8 @@ async fn main() {
let hypixel_api: String = std::env::var("HYPIXEL_API_KEY").unwrap(); let hypixel_api: String = std::env::var("HYPIXEL_API_KEY").unwrap();
let hypixel_api_client = { let hypixel_api_client = {
let mut headers = reqwest::header::HeaderMap::new(); let mut headers = reqwest::header::HeaderMap::new();
headers.insert( headers.insert("API-Key", reqwest::header::HeaderValue::try_from(hypixel_api).unwrap());
"API-Key", reqwest::ClientBuilder::new().default_headers(headers).build().unwrap()
reqwest::header::HeaderValue::try_from(hypixel_api).unwrap(),
);
reqwest::ClientBuilder::new()
.default_headers(headers)
.build()
.unwrap()
}; };
let options = poise::FrameworkOptions { let options = poise::FrameworkOptions {
@ -64,9 +58,14 @@ async fn main() {
Box::pin(async move { Box::pin(async move {
match error { match error {
FrameworkError::CommandStructureMismatch { description, ctx, .. } => { FrameworkError::CommandStructureMismatch { description, ctx, .. } => {
if let Err(e) = ctx.send(CreateReply::default() if let Err(e) = ctx
.content(format!("# Command arguments did not match. The command probably has been updated recently. Try reloading Discord. Description:\n{}", description))) .send(CreateReply::default().content(format!(
.await { "# Command arguments did not match. The command probably has been updated recently. Try reloading \
Discord. Description:\n{}",
description
)))
.await
{
tracing::error!("Fatal error while sending error message: {}", e); tracing::error!("Fatal error while sending error message: {}", e);
} }
} }
@ -79,9 +78,7 @@ async fn main() {
}) })
}, },
owners: { HashSet::from([UserId::new(449579075531440128_u64), UserId::new(659112817508745216_u64)]) }, owners: { HashSet::from([UserId::new(449579075531440128_u64), UserId::new(659112817508745216_u64)]) },
event_handler: |_ctx, event, _framework, _data| { event_handler: |ctx, event, framework, data| Box::pin(event_handler(ctx, event, framework, data)),
Box::pin(event_handler(_ctx, event, _framework, _data))
},
..Default::default() ..Default::default()
}; };
@ -100,8 +97,7 @@ async fn main() {
.build(); .build();
let token = std::env::var("DISCORD_TOKEN").unwrap(); let token = std::env::var("DISCORD_TOKEN").unwrap();
let intents = let intents = GatewayIntents::non_privileged() | GatewayIntents::MESSAGE_CONTENT | GatewayIntents::GUILD_MEMBERS;
GatewayIntents::non_privileged() | GatewayIntents::MESSAGE_CONTENT | GatewayIntents::GUILD_MEMBERS;
let client = serenity::ClientBuilder::new(token, intents) let client = serenity::ClientBuilder::new(token, intents)
.framework(framework) .framework(framework)
.activity(ActivityData::custom("NPC moment...")) .activity(ActivityData::custom("NPC moment..."))
@ -112,7 +108,7 @@ async fn event_handler(
ctx: &serenity::Context, ctx: &serenity::Context,
event: &FullEvent, event: &FullEvent,
_framework: poise::FrameworkContext<'_, Data, Error>, _framework: poise::FrameworkContext<'_, Data, Error>,
_data: &Data, data: &Data,
) -> Result<(), Error> { ) -> Result<(), Error> {
match event { match event {
FullEvent::Ready { data_about_bot, .. } => { FullEvent::Ready { data_about_bot, .. } => {
@ -126,9 +122,8 @@ async fn event_handler(
} }
} }
FullEvent::InteractionCreate { interaction } => { FullEvent::InteractionCreate { interaction } => {
if interaction.application_id().get() == 1165594074473037824 if interaction.application_id().get() == 1165594074473037824 && interaction.kind() == InteractionType::Component {
&& interaction.kind() == InteractionType::Component { handlers::bot_interaction::component(ctx, interaction, data).await?;
handlers::bot_interaction::component(ctx, interaction).await?;
} }
} }
FullEvent::Message { new_message } => { FullEvent::Message { new_message } => {