reformat LFG message with headline

This commit is contained in:
Stachelbeere1248 2024-12-19 13:19:51 +01:00
parent f44af892b4
commit 86a23a327a
Signed by: Stachelbeere1248
SSH key fingerprint: SHA256:IozEKdw2dB8TZxkpPdMxcWSoWTIMwoLaCcZJ1AJnY2o
4 changed files with 64 additions and 39 deletions

View file

@ -1,3 +1,4 @@
use std::ops::Add;
use poise::CreateReply; use poise::CreateReply;
use reqwest::{Client, Response}; use reqwest::{Client, Response};
use serde::Deserialize; use serde::Deserialize;
@ -65,9 +66,9 @@ impl Uuid {
struct DiscordId { struct DiscordId {
id: u64, id: u64,
} }
impl DiscordId { impl Uuid {
async fn matches_fetch(user: &User, uuid: &str, client: &Client) -> Result<bool, Error> { async fn has_discord_user(&self, user: &User, client: &Client) -> Result<bool, Error> {
let url: String = format!("https://api.hypixel.net/v2/player?uuid={}", uuid); let url: String = format!("https://api.hypixel.net/v2/player?uuid={}", self.uuid);
let response_400: Response = client.get(url).send().await?.error_for_status()?; let response_400: Response = client.get(url).send().await?.error_for_status()?;
let deserialized = response_400.json::<HypixelResponse>().await?; let deserialized = response_400.json::<HypixelResponse>().await?;
let matches = deserialized.player.social_media.links.discord == user.name; let matches = deserialized.player.social_media.links.discord == user.name;
@ -142,32 +143,32 @@ pub(crate) async fn add<'a>(
let user: User = user.unwrap_or(ctx.author().clone()); let user: User = user.unwrap_or(ctx.author().clone());
let uuid: Uuid = Uuid::for_ign(ign.as_str()).await?; let uuid: Uuid = Uuid::for_ign(ign.as_str()).await?;
let force: bool = force.unwrap_or(false) && ctx.framework().options.owners.contains(&ctx.author().id); 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 { match uuid.has_discord_user(&user, &ctx.data().hypixel_api_client).await? || force {
true => { true => {
let pool: Pool<Sqlite> = ctx.data().sqlite_pool.clone(); let pool = &ctx.data().sqlite_pool;
let status: &str = match link_id_from_minecraft(&pool, uuid.get()).await { let status: &str = 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.inner, user.id.get()).as_str())
.execute(&pool) .execute(pool)
.await?; .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.inner, uuid.get()).as_str())
.execute(&pool) .execute(pool)
.await?; .await?;
"Linked your Discord and Minecraft account." "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.inner, uuid.get()).as_str())
.execute(&pool) .execute(pool)
.await?; .await?;
"Your Discord account has previously had an account linked. Added the new link." "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.inner, user.id.get()).as_str())
.execute(&pool) .execute(pool)
.await?; .await?;
"Your Minecraft account has previously had an account linked. Added the new link." "Your Minecraft account has previously had an account linked. Added the new link."
} }
@ -175,22 +176,22 @@ pub(crate) async fn add<'a>(
sqlx::query( sqlx::query(
format!( format!(
"UPDATE minecraft_links SET link_id = {} WHERE link_id = {};", "UPDATE minecraft_links SET link_id = {} WHERE link_id = {};",
mc_id.cast_signed(), mc_id.inner,
dc_id.cast_signed() dc_id.inner
) )
.as_str(), .as_str(),
) )
.execute(&pool) .execute(pool)
.await?; .await?;
sqlx::query( sqlx::query(
format!( format!(
"UPDATE discord_links SET link_id = {} WHERE link_id = {};", "UPDATE discord_links SET link_id = {} WHERE link_id = {};",
mc_id.cast_signed(), mc_id.inner,
dc_id.cast_signed() dc_id.inner
) )
.as_str(), .as_str(),
) )
.execute(&pool) .execute(pool)
.await?; .await?;
"Both your Discord and Minecraft account had linked accounts. Merged all account links." "Both your Discord and Minecraft account had linked accounts. Merged all account links."
} }
@ -251,7 +252,8 @@ pub(crate) async fn list(ctx: Context<'_>, user: User) -> Result<(), Error> {
pub(crate) async fn list_string(pool: &Pool<Sqlite>, user: &User) -> Result<String, Error> { 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()) let link_id: u16 = link_id_from_discord(pool, user.id.get())
.await .await
.expect("This user has no linked accounts"); .expect("This user has no linked accounts")
.into();
let link: Link = Link::new(link_id).minecraft(pool).await?.discord(pool).await?; let link: Link = Link::new(link_id).minecraft(pool).await?.discord(pool).await?;
let mut discord_list = String::from("### Discord:"); let mut discord_list = String::from("### Discord:");
for dc in link.discord_ids { for dc in link.discord_ids {
@ -271,17 +273,16 @@ pub(crate) async fn list_string(pool: &Pool<Sqlite>, user: &User) -> Result<Stri
#[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> {
todo!() unimplemented!();
} }
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<LinkId> {
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 .await
.expect("Database error: fetching link id by uuid") .expect("Database error: fetching link id by uuid")
.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<LinkId> {
query_as( query_as(
format!( format!(
"SELECT link_id FROM discord_links WHERE discord_id = {} LIMIT 1;", "SELECT link_id FROM discord_links WHERE discord_id = {} LIMIT 1;",
@ -292,17 +293,40 @@ async fn link_id_from_discord(pool: &Pool<Sqlite>, snowflake: u64) -> Option<u16
.fetch_optional(pool) .fetch_optional(pool)
.await .await
.expect("Database error: fetching link_id for discord_id") .expect("Database error: fetching link_id for discord_id")
.map(|link_id: LinkId| link_id.link_id.cast_unsigned())
} }
#[derive(sqlx::FromRow)] #[derive(sqlx::FromRow)]
struct LinkId { struct LinkId {
link_id: i16, #[sqlx(rename = "link_id")]
inner: i16,
} }
async fn new_link_id(pool: &Pool<Sqlite>) -> Result<u16, Error> { impl From<u16> for LinkId {
fn from(unsigned: u16) -> Self {
Self {
inner: unsigned.cast_signed()
}
}
}
impl Into<u16> for LinkId {
fn into(self) -> u16 {
self.inner.cast_unsigned()
}
}
impl Add<i16> for LinkId {
type Output = LinkId;
fn add(mut self, rhs: i16) -> Self::Output {
self.inner += rhs;
self
}
}
async fn new_link_id(pool: &Pool<Sqlite>) -> Result<LinkId, Error> {
let result: LinkId = query_as("SELECT MAX(link_id) AS link_id FROM minecraft_links;") let result: LinkId = query_as("SELECT MAX(link_id) AS link_id FROM minecraft_links;")
.fetch_one(pool) .fetch_one(pool)
.await?; .await?;
Ok(result.link_id.cast_unsigned() + 1) Ok(result + 1)
} }

View file

@ -36,7 +36,7 @@ pub(crate) async fn helpstart(
} else { } else {
command_helper::cooldown(&ctx, 1200, 600)?; command_helper::cooldown(&ctx, 1200, 600)?;
reply reply
.content(format!("<@&{ping}>\nneed: {}", needed_players - bots)) .content(format!("## <@&{ping}>\nneed: {}", needed_players - bots))
.ephemeral(false) .ephemeral(false)
.allowed_mentions(CreateAllowedMentions::new().roles(vec![ping])) .allowed_mentions(CreateAllowedMentions::new().roles(vec![ping]))
}; };

View file

@ -102,7 +102,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 => {
@ -113,7 +113,7 @@ pub(crate) async fn lfg(
match note { match note {
None => {} None => {}
Some(note) => { Some(note) => {
reply_content.push_str(format!("\nNote: {note}").as_str()); reply_content.push_str(format!("\n**Note:** {note}").as_str());
} }
} }
let reply: CreateReply = CreateReply::default() let reply: CreateReply = CreateReply::default()
@ -193,7 +193,7 @@ pub(crate) async fn expert(
.roles .roles
.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 { let reply: CreateReply = match is_expert {
true => CreateReply::default() true => CreateReply::default()
.content(reply_content) .content(reply_content)
@ -240,7 +240,7 @@ pub(crate) async fn other(
let ping: u64 = match game { let ping: u64 = match game {
OtherPing::GeoGuessr => 1302249562999885824_u64, OtherPing::GeoGuessr => 1302249562999885824_u64,
}; };
let reply_content: String = format!("{current}/{desired} <@&{ping}>: {note}"); let reply_content: String = format!("## {current}/{desired} <@&{ping}>: {note}");
let reply: CreateReply = CreateReply::default() let reply: CreateReply = CreateReply::default()
.content(reply_content) .content(reply_content)

View file

@ -1,3 +1,4 @@
use std::fmt::{Display, Formatter, Result as FmtResult};
use poise::{CreateReply, FrameworkError}; use poise::{CreateReply, FrameworkError};
use crate::Data; use crate::Data;
@ -19,8 +20,8 @@ pub enum Error {
Other(String), Other(String),
} }
impl std::fmt::Display for Error { impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter) -> FmtResult {
match self { match self {
Error::SqlxError(e) => write!(f, "SQLx Error: {}", e), Error::SqlxError(e) => write!(f, "SQLx Error: {}", e),
Error::HttpsError(e) => write!(f, "HTTPS Error (Hypixel / Mojang API):\n{}", e), Error::HttpsError(e) => write!(f, "HTTPS Error (Hypixel / Mojang API):\n{}", e),