geoguessr pings, run rustfmt on project

This commit is contained in:
Stachelbeere1248 2024-11-02 13:49:20 +01:00
parent 020de4d0b8
commit 741cd17c62
Signed by: Stachelbeere1248
SSH key fingerprint: SHA256:IozEKdw2dB8TZxkpPdMxcWSoWTIMwoLaCcZJ1AJnY2o
11 changed files with 118 additions and 315 deletions

View file

@ -1,258 +0,0 @@
use poise::CreateReply;
use serde::{Deserialize, Serialize};
use serenity::all::{ChannelId, CreateActionRow, CreateButton, CreateMessage, ReactionType, User};
use serenity::builder::CreateAllowedMentions;
use sqlx::{Pool, query_as, Sqlite};
use crate::{Context, Error};
#[poise::command(slash_command, subcommands("add", "list"))]
pub(crate) async fn account(_ctx: Context<'_>) -> Result<(), Error> {
Ok(())
}
#[poise::command(slash_command)]
pub(crate) async fn add(ctx: Context<'_>, ign: String) -> Result<(), Error> {
ctx.defer_ephemeral().await?;
let pool = ctx.data().sqlite_pool.clone();
let minecraft_uuid = minecraft_uuid_for_username(ign.clone()).await?;
let hypixel_linked_discord = linked_discord_for_uuid(
ctx.data().hypixel_api_client.clone(),
minecraft_uuid.as_str(),
)
.await?;
if hypixel_linked_discord.eq(ctx.author().name.as_str()) {
link(
ctx.author().id.get(),
minecraft_uuid.as_str(),
&pool,
)
.await;
let s = format!("## User <@{}> added an account:\n### added:\n- name: {}\n- uuid: {}",
ctx.author().id.get(),
ign.clone(),
minecraft_uuid
);
ChannelId::new(1257776992497959075).send_message(ctx,
CreateMessage::new()
.content(s)
.allowed_mentions(CreateAllowedMentions::new().empty_roles().all_users(true))
.components(vec![CreateActionRow::Buttons(vec![
CreateButton::new("accept_verification").emoji(ReactionType::from('✅')),
CreateButton::new("deny_verification").emoji(ReactionType::from('❌')),
])])
).await?;
ctx.send(CreateReply::default().content("Linked accounts.")).await?;
} else {
ctx.send(CreateReply::default().content("This Minecraft account's link doesn't seem to match your discord username. Be sure to not link using the display name and remove the @.")).await?;
}
Ok(())
}
#[poise::command(slash_command)]
pub(crate) async fn remove(ctx: Context<'_>) -> Result<(), Error> {
ctx.say("hi").await?;
Ok(())
}
#[poise::command(slash_command)]
pub(crate) async fn list(ctx: Context<'_>, user: Option<User>) -> Result<(), Error> {
ctx.defer_ephemeral().await?;
let user_id = user.clone().map(|user| user.id.get());
let user_name = user.clone().map(|user| user.name);
let author_name = ctx.author().name.clone();
let pool = ctx.data().sqlite_pool.clone();
let link_id = link_id_from_discord(&pool, user_id.unwrap_or(ctx.author().id.get())).await;
let t = match link_id {
Some(id) => minecraft_uuids(&pool, id).await,
None => Vec::new(),
};
let mut content = format!(
"## {}'s linked accounts: ",
user_name.unwrap_or(author_name)
);
for l in t {
content.push_str(format!("\nuuid: {}", l).as_str())
}
let reply = CreateReply::default().ephemeral(true).content(content);
if let Err(why) = ctx.send(reply).await {
println!("Error sending message: {why}");
}
Ok(())
}
async fn link(discord_id: u64, uuid: &str, pool: &Pool<Sqlite>) {
let link_id = match link_id_from_minecraft(pool, uuid.to_string()).await {
None => new_link_id(pool).await,
Some(link_id_mc_old) => {
// merge sets
let new_link_id_discord = link_id_from_discord(pool, discord_id)
.await
.unwrap_or(u16::MAX)
.cast_signed();
sqlx::query(format!("UPDATE minecraft_links SET link_id = {} WHERE link_id = {new_link_id_discord};", link_id_mc_old.cast_signed()).as_str()).execute(pool).await.expect("Database Error: linking previously linked accounts by another user");
sqlx::query(
format!(
"UPDATE discord_links SET link_id = {} WHERE link_id = {new_link_id_discord};",
link_id_mc_old.cast_signed()
)
.as_str(),
)
.execute(pool)
.await.expect("Database Error: linking previously linked accounts by another user");
link_id_mc_old
}
};
let link_id = link_id.cast_signed();
let discord_id = discord_id.cast_signed();
sqlx::query(
format!("INSERT INTO minecraft_links VALUES ({link_id}, \"{uuid}\");").as_str(),
)
.execute(pool)
.await.expect("Database Error: inserting new minecraft value");
sqlx::query(
format!("INSERT INTO discord_links VALUES ({link_id}, \"{discord_id}\");").as_str(),
)
.execute(pool)
.await.expect("Database Error: inserting new discord value");
}
#[derive(Serialize, Deserialize)]
struct Links {
#[serde(rename = "DISCORD")]
pub discord: String,
}
#[derive(Serialize, Deserialize)]
struct SocialMedia {
pub links: Links,
pub prompt: bool,
}
#[derive(Serialize, Deserialize)]
struct HypixelPlayer {
#[serde(rename = "socialMedia")]
pub social_media: SocialMedia,
}
#[derive(Serialize, Deserialize)]
struct HypixelResponse {
#[serde(rename = "player")]
pub player: HypixelPlayer,
}
#[derive(Serialize, Deserialize)]
struct MojangPlayer {
pub id: String,
pub name: String,
}
async fn minecraft_uuid_for_username(name: String) -> Result<String, serde_json::Error> {
let url = format!("https://api.mojang.com/users/profiles/minecraft/{name}");
let response = reqwest::get(url).await.expect(format!("Failed retrieving hypixel response for {name}").as_str());
let response_text = response.text().await.unwrap();
return (serde_json::from_str(response_text.as_str())
as Result<MojangPlayer, serde_json::Error>)
.map(|mojang_player: MojangPlayer| mojang_player.id);
}
async fn linked_discord_for_uuid(
hypixel_client: reqwest::Client,
uuid: &str,
) -> Result<String, Error> {
let hypixel_url = format!("https://api.hypixel.net/v2/player?uuid={uuid}");
return match hypixel_client.get(hypixel_url).send().await {
Ok(response) => {
let response_text = response.text().await.unwrap();
match (serde_json::from_str(response_text.as_str())
as Result<HypixelResponse, serde_json::Error>)
.map(|hypixel_response: HypixelResponse| {
hypixel_response.player.social_media.links.discord
}) {
Ok(discord) => Ok(discord),
Err(why) => Err(Error::try_from(why).unwrap()),
}
}
Err(why) => Err(Error::try_from(why).unwrap()),
};
}
#[derive(sqlx::FromRow)]
struct DiscordLink {
link_id: i16,
discord_id: i64,
}
#[derive(sqlx::FromRow)]
struct MinecraftLink {
link_id: i16,
minecraft_uuid: String,
}
#[derive(sqlx::FromRow)]
struct LinkId {
link_id: i16,
}
async fn link_id_from_discord(pool: &Pool<Sqlite>, snowflake: u64) -> Option<u16> {
let discord_id: i64 = snowflake.cast_signed();
return query_as(
format!("SELECT * FROM discord_links WHERE discord_id = {discord_id} LIMIT 1;").as_str(),
)
.fetch_optional(pool)
.await
.expect("Database error: fetching link id by discord")
.map(|discord_link: DiscordLink| discord_link.link_id.cast_unsigned());
}
async fn link_id_from_minecraft(pool: &Pool<Sqlite>, minecraft_uuid: String) -> Option<u16> {
return query_as(
format!(
"SELECT * FROM minecraft_links WHERE minecraft_uuid = \"{minecraft_uuid}\" LIMIT 1;"
)
.as_str(),
)
.fetch_optional(pool)
.await
.expect("Database error: fetching link id by uuid")
.map(|minecraft_link: MinecraftLink| minecraft_link.link_id.cast_unsigned());
}
async fn new_link_id(pool: &Pool<Sqlite>) -> u16 {
let result: Result<LinkId, sqlx::Error> = query_as("SELECT link_id FROM minecraft_links WHERE link_id = (SELECT MAX(link_id) FROM minecraft_links) LIMIT 1;")
.fetch_one(pool)
.await;
result
.expect("Database error: fetching new id")
.link_id.cast_unsigned() + 1
}
async fn minecraft_uuids(pool: &Pool<Sqlite>, link_id: u16) -> Vec<String> {
let link_id: i16 = link_id.cast_signed();
let link_result: Result<Vec<MinecraftLink>, sqlx::Error> =
query_as(format!("SELECT * FROM minecraft_links WHERE link_id = {link_id};").as_str())
.fetch_all(pool)
.await;
return match link_result {
Ok(links) => links
.into_iter()
.map(|minecraft_link: MinecraftLink| minecraft_link.minecraft_uuid)
.collect(),
Err(why) => {
println!("Error: {}", why);
Vec::new()
}
};
}
/*
async fn discord_ids(pool: &Pool<Sqlite>, link_id: u16) -> Vec<u64> {
let link_id: i16 = link_id.cast_signed();
let link_result: Result<Vec<DiscordLink>, sqlx::Error> = query_as(format!("SELECT * FROM discord_links WHERE link_id = {link_id}").as_str())
.fetch_all(pool)
.await;
return match link_result {
Ok(links) => links.into_iter().map(|discord_link: DiscordLink| discord_link.discord_id.cast_unsigned()).collect(),
Err(why) => {
println!("Error: {}", why);
Vec::new()
}
}
}*/

View file

@ -3,15 +3,15 @@ use reqwest::{Client, Response};
use serde::Deserialize; use serde::Deserialize;
use serenity::{ use serenity::{
all::{ all::{
ChannelId,
CreateActionRow,
CreateAllowedMentions, CreateAllowedMentions,
CreateButton, CreateButton,
CreateActionRow, CreateMessage,
User,
ReactionType, ReactionType,
ChannelId, User,
CreateMessage
}, },
json::JsonError json::JsonError,
}; };
use sqlx::{Pool, query_as, Sqlite}; use sqlx::{Pool, query_as, Sqlite};
@ -44,7 +44,7 @@ struct MojangPlayer {
#[derive(PartialEq, sqlx::FromRow)] #[derive(PartialEq, sqlx::FromRow)]
struct Uuid { struct Uuid {
uuid: String uuid: String,
} }
impl Uuid { impl Uuid {
fn get(&self) -> &str { fn get(&self) -> &str {
@ -58,9 +58,9 @@ impl Uuid {
let response_text = res.text().await.unwrap(); let response_text = res.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)
}, }
Err(why) => Err(Error::from(format!( Err(why) => Err(Error::from(format!(
"Mojang returned an error. Please make sure to enter a valid Minecraft username.\n\n\ "Mojang returned an error. Please make sure to enter a valid Minecraft username.\n\n\
Details: {}", why).as_str())), Details: {}", why).as_str())),
@ -69,7 +69,7 @@ impl Uuid {
} }
#[derive(PartialEq)] #[derive(PartialEq)]
struct DiscordId { struct DiscordId {
id: u64 id: u64,
} }
impl DiscordId { impl DiscordId {
async fn matches_fetch(user: &User, uuid: &str, client: &Client) -> Result<bool, Error> { async fn matches_fetch(user: &User, uuid: &str, client: &Client) -> Result<bool, Error> {
@ -82,7 +82,7 @@ impl DiscordId {
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)
}, }
Err(why) => { Err(why) => {
println!("Hypixel issue: {}", why); println!("Hypixel issue: {}", why);
Err(Error::from("Hypixel returned an error.")) Err(Error::from("Hypixel returned an error."))
@ -91,9 +91,11 @@ impl DiscordId {
} }
} }
impl<'a, R: sqlx::Row> sqlx::FromRow<'a, R> for DiscordId impl<'a, R: sqlx::Row> sqlx::FromRow<'a, R> for DiscordId
where &'a ::std::primitive::str: sqlx::ColumnIndex<R>, where
&'a ::std::primitive::str: sqlx::ColumnIndex<R>,
i64: ::sqlx::decode::Decode<'a, R::Database>, i64: ::sqlx::decode::Decode<'a, R::Database>,
i64: ::sqlx::types::Type<R::Database> { i64: ::sqlx::types::Type<R::Database>,
{
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 {
@ -137,12 +139,10 @@ pub(crate) async fn account(_ctx: Context<'_>) -> Result<(), Error> {
#[poise::command(slash_command)] #[poise::command(slash_command)]
pub(crate) async fn add<'a>( pub(crate) async fn add<'a>(
ctx: Context<'_>, ctx: Context<'_>,
#[description = "Minecraft username"] #[description = "Minecraft username"]
#[min_length = 2] #[min_length = 2]
#[max_length = 16] #[max_length = 16]
ign: String, ign: String,
user: Option<User>, user: Option<User>,
) -> Result<(), Error> { ) -> Result<(), Error> {
ctx.defer_ephemeral().await?; ctx.defer_ephemeral().await?;
@ -155,7 +155,8 @@ pub(crate) async fn add<'a>(
let r = CreateReply::default().ephemeral(false); let r = CreateReply::default().ephemeral(false);
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, link_id) = match link_id_from_minecraft(&pool, uuid.get()).await {
None => { match link_id_from_discord(&pool, user.id.get()).await { None => {
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())
@ -170,13 +171,14 @@ pub(crate) async fn add<'a>(
("Your Discord account has previously had an account linked. Added the new link.", dc_id) ("Your Discord account has previously had an account linked. Added the new link.", dc_id)
} }
} }
}, Some(mc_id) => { }
Some(mc_id) => {
match link_id_from_discord(&pool, user.id.get()).await { 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.expect("Database Error: inserting new minecraft value"); .execute(&pool).await.expect("Database Error: inserting new minecraft value");
("Your Minecraft account has previously had an account linked. Added the new link.", mc_id) ("Your Minecraft account has previously had an account linked. Added the new link.", mc_id)
}, }
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(format!("UPDATE minecraft_links SET link_id = {} WHERE link_id = {};", mc_id.cast_signed(), dc_id.cast_signed()).as_str())
.execute(&pool).await.expect("Database Error: Merging Minecraft Accounts."); .execute(&pool).await.expect("Database Error: Merging Minecraft Accounts.");
@ -198,7 +200,7 @@ 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('❌')),
])]) ])]),
).await?; ).await?;
} }
false => { false => {
@ -214,7 +216,7 @@ pub(crate) async fn add<'a>(
#[poise::command(slash_command)] #[poise::command(slash_command)]
pub(crate) async fn list( pub(crate) async fn list(
ctx: Context<'_>, ctx: Context<'_>,
user: Option<User> user: Option<User>,
) -> Result<(), Error> { ) -> Result<(), Error> {
ctx.defer().await?; ctx.defer().await?;
let user = user.unwrap_or(ctx.author().clone()); let user = user.unwrap_or(ctx.author().clone());

View file

@ -1,7 +1,7 @@
use std::string::String; use std::string::String;
use crate::commands::command_helper;
use crate::{Context, Error}; use crate::{Context, Error};
use crate::commands::command_helper;
#[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,8 +1,8 @@
use poise::CreateReply; use poise::CreateReply;
use serenity::all::CreateAllowedMentions; use serenity::all::CreateAllowedMentions;
use crate::commands::command_helper;
use crate::{Context, Error}; use crate::{Context, Error};
use crate::commands::command_helper;
#[poise::command(slash_command, guild_only)] #[poise::command(slash_command, guild_only)]
pub(crate) async fn helpstart( pub(crate) async fn helpstart(

View file

@ -1,8 +1,9 @@
use poise::{ChoiceParameter, CreateReply}; use poise::{ChoiceParameter, CreateReply};
use serenity::all::{CreateAllowedMentions, RoleId}; use serenity::all::{CreateAllowedMentions, RoleId};
use crate::{Context, Error};
//from main.rs //from main.rs
use crate::commands::command_helper::cooldown; use crate::commands::command_helper::cooldown;
use crate::{Context, Error};
// //
use crate::commands::lfg::Difficulty::Normal; use crate::commands::lfg::Difficulty::Normal;
use crate::commands::lfg::Map::*; use crate::commands::lfg::Map::*;
@ -44,29 +45,23 @@ pub enum Difficulty {
#[poise::command(slash_command, guild_only)] #[poise::command(slash_command, guild_only)]
pub(crate) async fn lfg( pub(crate) async fn lfg(
ctx: Context<'_>, ctx: Context<'_>,
#[rename = "map"] map: Map, #[rename = "map"] map: Map,
#[description = "Normal"] #[description = "Normal"]
#[rename = "difficulty"] #[rename = "difficulty"]
difficulty: Option<Difficulty>, difficulty: Option<Difficulty>,
#[rename = "mode"] #[rename = "mode"]
#[description = "play-style"] #[description = "play-style"]
mode: Mode, mode: Mode,
#[min = 1_u8] #[min = 1_u8]
#[max = 3_u8] #[max = 3_u8]
#[description = "default: 1"] #[description = "default: 1"]
#[rename = "current"] #[rename = "current"]
current_players: Option<u8>, current_players: Option<u8>,
#[min = 2_u8] #[min = 2_u8]
#[max = 4_u8] #[max = 4_u8]
#[description = "default: 4"] #[description = "default: 4"]
#[rename = "desired"] #[rename = "desired"]
desired_players: Option<u8>, desired_players: Option<u8>,
#[description = "optional extra message"] #[description = "optional extra message"]
#[rename = "message"] #[rename = "message"]
note: Option<String>, note: Option<String>,
@ -102,7 +97,7 @@ pub(crate) async fn lfg(
AlienArcadium => Normal, AlienArcadium => Normal,
}; };
let mut reply_content: String = format!("<@&{ping}> {current}/{desired} {map_name}",); let mut reply_content: String = format!("<@&{ping}> {current}/{desired} {map_name}", );
match difficulty { match difficulty {
Normal => {} Normal => {}
Difficulty::Hard | Difficulty::Rip => { Difficulty::Hard | Difficulty::Rip => {
@ -142,31 +137,25 @@ enum ExpertMap {
#[name = "Speedrun"] #[name = "Speedrun"]
Speedrun, Speedrun,
} }
#[poise::command(slash_command, guild_only, rename = "expert-lfg")] #[poise::command(slash_command, guild_only, rename = "lfg-expert")]
pub(crate) async fn expert( pub(crate) async fn expert(
ctx: Context<'_>, ctx: Context<'_>,
#[rename = "map"] mode: ExpertMap, #[rename = "map"] mode: ExpertMap,
#[min = 1_u8] #[min = 1_u8]
#[max = 3_u8] #[max = 3_u8]
#[description = "default: 1"] #[description = "default: 1"]
#[rename = "current"] #[rename = "current"]
current_players: Option<u8>, current_players: Option<u8>,
#[min = 2_u8] #[min = 2_u8]
#[max = 4_u8] #[max = 4_u8]
#[description = "default: 4"] #[description = "default: 4"]
#[rename = "desired"] #[rename = "desired"]
desired_players: Option<u8>, desired_players: Option<u8>,
#[description = "extra message"] #[description = "extra message"]
#[rename = "message"] #[rename = "message"]
note: String, note: String,
) -> Result<(), Error> { ) -> Result<(), Error> {
let mut reply: CreateReply = CreateReply::default(); let reply: CreateReply = match cooldown(&ctx, 600, 300) {
reply = match cooldown(&ctx, 600, 300) {
Ok(_) => { 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);
@ -199,17 +188,20 @@ 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}");
match is_expert { match is_expert {
true => reply true => 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])),
false => reply 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) => reply.content(why.to_string()).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 {
@ -218,7 +210,54 @@ pub(crate) async fn expert(
Ok(()) Ok(())
} }
const ROLE_LIST: [[u64;6]; 9] = [ // [[basic, de, bb, aa, sr, star]; 9] #[derive(Debug, poise::ChoiceParameter)]
enum OtherPing {
#[name = "GeoGuessr"]
GeoGuessr,
}
#[poise::command(slash_command, guild_only, rename = "lfg-other")]
pub(crate) async fn other(
ctx: Context<'_>,
#[rename = "game"]
game: OtherPing,
#[min = 1_u8]
#[max = 3_u8]
#[description = "default: 1"]
#[rename = "current"]
current_players: Option<u8>,
#[description = "extra message"]
#[rename = "message"]
note: String,
) -> Result<(), Error> {
let reply: CreateReply = match cooldown(&ctx, 0, 7200) {
Ok(_) => {
let current: u8 = current_players.unwrap_or(1);
let desired: u8 = match game {
OtherPing::GeoGuessr => 20_u8,
};
let ping: u64 = match game {
OtherPing::GeoGuessr => 1302249562999885824_u64,
};
let reply_content: String = format!("{current}/{desired} <@&{ping}>: {note}");
CreateReply::default()
.content(reply_content)
.ephemeral(false)
.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 {
println!("Error sending message: {why}");
}
Ok(())
}
const ROLE_LIST: [[u64; 6]; 9] = [ // [[basic, de, bb, aa, sr, star]; 9]
[1256229103678259311, 1256229192744304670, 1256229223450935377, 1256229498899271754, 1256229540900900996, 1256229575269154866], //novice [1256229103678259311, 1256229192744304670, 1256229223450935377, 1256229498899271754, 1256229540900900996, 1256229575269154866], //novice
[1256230831131983932, 1256230750827577447, 1256230776828334143, 1256230793630715975, 1256230818444214333, 1256230734642024468], //seasoned [1256230831131983932, 1256230750827577447, 1256230776828334143, 1256230793630715975, 1256230818444214333, 1256230734642024468], //seasoned
[1256230723455553556, 1256230653083521045, 1256230666786443310, 1256230686214324255, 1256230704061353995, 1256230636721537097], //expert [1256230723455553556, 1256230653083521045, 1256230666786443310, 1256230686214324255, 1256230704061353995, 1256230636721537097], //expert

View file

@ -1,6 +1,6 @@
use crate::{Context, Error}; use crate::{Context, Error};
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

@ -1,10 +1,11 @@
use serenity::all::{ComponentInteraction, ComponentInteractionDataKind, Context, CreateMessage, EditMessage, GuildId, Interaction, RoleId}; use serenity::all::{ComponentInteraction, ComponentInteractionDataKind, Context, CreateMessage, EditMessage, GuildId, Interaction, RoleId};
use crate::Error; use crate::Error;
pub(crate) async fn component(ctx: &Context, interaction: &Interaction) -> Result<(), Error> { pub(crate) async fn component(ctx: &Context, interaction: &Interaction) -> 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).await,
_ => Ok(()) _ => Ok(())
} }
} }
@ -21,7 +22,7 @@ async fn button(ctx: &Context, mut component: ComponentInteraction) -> Result<()
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?; component.message.edit(ctx, EditMessage::new().components(vec![])).await?;
Ok(()) Ok(())
}, }
"deny_verification" => { "deny_verification" => {
let _dm = u.direct_message(ctx, CreateMessage::new() let _dm = u.direct_message(ctx, CreateMessage::new()
.content("Your verified minecraft account was denied.")).await?; .content("Your verified minecraft account was denied.")).await?;

View file

@ -1,12 +1,13 @@
use serenity::all::{Context, Message}; use serenity::all::{Context, Message};
use crate::Error; use crate::Error;
pub(crate) async fn 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(())
} }
} }
@ -17,7 +18,7 @@ async fn zmp_create(ctx: &Context, msg: &Message) -> Result<(), Error> {
msg.react(ctx, '🇼').await?; msg.react(ctx, '🇼').await?;
msg.react(ctx, '🇱').await?; msg.react(ctx, '🇱').await?;
Ok(()) Ok(())
}, }
_ => Ok(()) _ => Ok(())
} }
} }

View file

@ -1,2 +1,3 @@
pub(crate) mod bot_interaction; pub(crate) mod bot_interaction;
pub(crate) mod message; pub(crate) mod message;
pub(crate) mod thread;

15
src/handlers/thread.rs Normal file
View file

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

View file

@ -9,7 +9,7 @@ use poise::serenity_prelude as serenity;
use serenity::{FullEvent, model::id::UserId}; 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 sqlx::{Sqlite}; use sqlx::Sqlite;
use tokio::sync::RwLock; use tokio::sync::RwLock;
mod commands; mod commands;
@ -59,12 +59,11 @@ async fn main() {
on_error: |error| { on_error: |error| {
Box::pin(async move { Box::pin(async move {
match error { match error {
other => poise::builtins::on_error(other).await.unwrap(), other => poise::builtins::on_error(other).await.unwrap(),
} }
}) })
}, },
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))
}, },
@ -103,22 +102,25 @@ async fn event_handler(
match event { match event {
FullEvent::Ready { data_about_bot, .. } => { FullEvent::Ready { data_about_bot, .. } => {
println!("Logged in as {}", data_about_bot.user.name); println!("Logged in as {}", data_about_bot.user.name);
}, }
FullEvent::GuildMemberAddition { new_member } => { FullEvent::GuildMemberAddition { new_member } => {
println!("join event"); println!("join event");
if new_member.guild_id.get() == 1256217633959841853_u64 { if new_member.guild_id.get() == 1256217633959841853_u64 {
new_member.add_role(ctx, RoleId::new(1256253358701023232_u64)).await?; new_member.add_role(ctx, RoleId::new(1256253358701023232_u64)).await?;
println!("gave member role"); println!("gave member role");
} }
}, }
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).await?; handlers::bot_interaction::component(ctx, interaction).await?;
} }
}, }
FullEvent::Message { new_message } => { FullEvent::Message { new_message } => {
handlers::message::create(ctx, new_message).await?; handlers::message::on_create(ctx, new_message).await?;
}
FullEvent::ThreadCreate { thread } => {
handlers::thread::on_create(ctx, thread).await?;
} }
_ => {} _ => {}
} }