Add friend request command
This commit is contained in:
@@ -18,9 +18,7 @@ use twilight_model::{
|
|||||||
user::User as TwilightUser,
|
user::User as TwilightUser,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{constants::DEFAULT_PREFIX, groups::calls::DisplayProfile, utils::get_random_u64};
|
||||||
constants::DEFAULT_PREFIX, groups::calls::events::DisplayProfile, utils::get_random_u64,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum DatabaseOrDiscordError {
|
pub enum DatabaseOrDiscordError {
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ use twilight_model::id::Id;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
database::models::{Call, Channel},
|
database::models::{Call, Channel},
|
||||||
|
discord::sanitizing::SanitizeDiscordMarkdown,
|
||||||
framework::commands::{Command, CommandError, context::CommandContext},
|
framework::commands::{Command, CommandError, context::CommandContext},
|
||||||
|
groups::calls::get_display_profile,
|
||||||
state::State,
|
state::State,
|
||||||
utils::Bye,
|
utils::Bye,
|
||||||
};
|
};
|
||||||
@@ -304,3 +306,97 @@ impl Command<State> for HangupCommand {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct FriendRequestCommand;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl Command<State> for FriendRequestCommand {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"friendreq"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn aliases(&self) -> &'static [&'static str] {
|
||||||
|
&["f", "fr", "friendrequest"]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn description(&self) -> &'static str {
|
||||||
|
"Shows your username to the other party and asks them to send you a friend request on Discord."
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn execute(
|
||||||
|
&self,
|
||||||
|
ctx: CommandContext<'_, State>,
|
||||||
|
_args: &str,
|
||||||
|
) -> Result<(), CommandError> {
|
||||||
|
let channel = Channel::get_by_id(ctx.event.channel_id.get(), &ctx.rt.state.db)
|
||||||
|
.await
|
||||||
|
.inspect_err(|e| log::error!("Failed to get channel: {e:?}"))
|
||||||
|
.map_err(|_| CommandError::DatabaseQueryFailed)?;
|
||||||
|
|
||||||
|
let Some(channel) = channel else {
|
||||||
|
ctx.send()
|
||||||
|
.content(format!(
|
||||||
|
"❌ You're not on a call! Use `{}call` to start one.",
|
||||||
|
ctx.prefix
|
||||||
|
))
|
||||||
|
.await
|
||||||
|
.map_err(|_| CommandError::MessageSendingFailed)?;
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
|
||||||
|
let call = if let Some(call_id) = channel.call_id {
|
||||||
|
Call::get_by_id(call_id, &ctx.rt.state.db)
|
||||||
|
.await
|
||||||
|
.inspect_err(|e| log::error!("Failed to get call: {e:?}"))
|
||||||
|
.map_err(|_| CommandError::DatabaseQueryFailed)?
|
||||||
|
} else {
|
||||||
|
ctx.send()
|
||||||
|
.content(format!(
|
||||||
|
"❌ You're not on a call! Use `{}call` to start one.",
|
||||||
|
ctx.prefix
|
||||||
|
))
|
||||||
|
.await
|
||||||
|
.map_err(|_| CommandError::MessageSendingFailed)?;
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(call) = call else {
|
||||||
|
ctx.send()
|
||||||
|
.content("❌ Oops! We could not find that call.")
|
||||||
|
.await
|
||||||
|
.map_err(|_| CommandError::MessageSendingFailed)?;
|
||||||
|
|
||||||
|
return Err(CommandError::DatabaseInconsistentState);
|
||||||
|
};
|
||||||
|
|
||||||
|
let other_channel_id = call.other_party_channel_id(channel.id);
|
||||||
|
|
||||||
|
let profile = get_display_profile(ctx.event);
|
||||||
|
|
||||||
|
ctx
|
||||||
|
.rt
|
||||||
|
.http
|
||||||
|
.create_message(
|
||||||
|
Id::new(other_channel_id)
|
||||||
|
)
|
||||||
|
.content(
|
||||||
|
&format!(
|
||||||
|
"📬 **{}** wants you to send them a friend request on Discord! Their username is `{}`.",
|
||||||
|
profile.name.sanitize(false),
|
||||||
|
ctx.event.author.name.sanitize(false)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|_| CommandError::MessageSendingFailed)?;
|
||||||
|
|
||||||
|
ctx.send()
|
||||||
|
.content("📬 Asked the other party to send you a friend request!")
|
||||||
|
.await
|
||||||
|
.map_err(|_| CommandError::MessageSendingFailed)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,16 +2,14 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use twilight_model::{gateway::payload::incoming::MessageCreate, id::Id};
|
use twilight_model::{gateway::payload::incoming::MessageCreate, id::Id};
|
||||||
use twilight_validate::request::webhook_username;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
database::models::{Call, Channel, Message},
|
database::models::{Call, Channel, Message},
|
||||||
discord::images,
|
|
||||||
framework::{
|
framework::{
|
||||||
events::traits::{EventResult, OnMessageHandler},
|
events::traits::{EventResult, OnMessageHandler},
|
||||||
runtime::Runtime,
|
runtime::Runtime,
|
||||||
},
|
},
|
||||||
groups::calls::moderation::escape_message,
|
groups::calls::{get_display_profile, moderation::escape_message},
|
||||||
state::State,
|
state::State,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -128,49 +126,3 @@ impl OnMessageHandler<State> for MessageRedirector {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct DisplayProfile {
|
|
||||||
pub id: u64,
|
|
||||||
pub name: String,
|
|
||||||
pub avatar_url: String,
|
|
||||||
pub mask: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_display_profile(event: &MessageCreate) -> DisplayProfile {
|
|
||||||
let member = event.member.clone();
|
|
||||||
|
|
||||||
let name = if let Some(nick) = &member.clone().and_then(|member| member.nick) {
|
|
||||||
if webhook_username(nick).is_err() {
|
|
||||||
"Invalid Nickname".to_string()
|
|
||||||
} else {
|
|
||||||
nick.clone()
|
|
||||||
}
|
|
||||||
} else if let Some(name) = &event.author.global_name {
|
|
||||||
if webhook_username(name).is_err() {
|
|
||||||
"Invalid Global Name".to_string()
|
|
||||||
} else {
|
|
||||||
name.clone()
|
|
||||||
}
|
|
||||||
} else if webhook_username(&event.author.name).is_err() {
|
|
||||||
"Invalid Username".to_string()
|
|
||||||
} else {
|
|
||||||
event.author.name.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
let avatar_hash = member
|
|
||||||
.and_then(|inner| inner.avatar)
|
|
||||||
.or(event.author.avatar);
|
|
||||||
let avatar_url = images::get_avatar_url(
|
|
||||||
avatar_hash,
|
|
||||||
event.author.id.get(),
|
|
||||||
event.author.discriminator as u64,
|
|
||||||
);
|
|
||||||
|
|
||||||
DisplayProfile {
|
|
||||||
id: event.author.id.get(),
|
|
||||||
name,
|
|
||||||
avatar_url,
|
|
||||||
mask: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,5 +1,56 @@
|
|||||||
//! Call commands and events.
|
//! Call commands and events.
|
||||||
|
|
||||||
|
use twilight_model::gateway::payload::incoming::MessageCreate;
|
||||||
|
use twilight_validate::request::webhook_username;
|
||||||
|
|
||||||
|
use crate::discord::images;
|
||||||
|
|
||||||
pub mod commands;
|
pub mod commands;
|
||||||
pub mod events;
|
pub mod events;
|
||||||
pub(super) mod moderation;
|
pub(super) mod moderation;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct DisplayProfile {
|
||||||
|
pub id: u64,
|
||||||
|
pub name: String,
|
||||||
|
pub avatar_url: String,
|
||||||
|
pub mask: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_display_profile(event: &MessageCreate) -> DisplayProfile {
|
||||||
|
let member = event.member.clone();
|
||||||
|
|
||||||
|
let name = if let Some(nick) = &member.clone().and_then(|member| member.nick) {
|
||||||
|
if webhook_username(nick).is_err() {
|
||||||
|
"Invalid Nickname".to_string()
|
||||||
|
} else {
|
||||||
|
nick.clone()
|
||||||
|
}
|
||||||
|
} else if let Some(name) = &event.author.global_name {
|
||||||
|
if webhook_username(name).is_err() {
|
||||||
|
"Invalid Global Name".to_string()
|
||||||
|
} else {
|
||||||
|
name.clone()
|
||||||
|
}
|
||||||
|
} else if webhook_username(&event.author.name).is_err() {
|
||||||
|
"Invalid Username".to_string()
|
||||||
|
} else {
|
||||||
|
event.author.name.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
let avatar_hash = member
|
||||||
|
.and_then(|inner| inner.avatar)
|
||||||
|
.or(event.author.avatar);
|
||||||
|
let avatar_url = images::get_avatar_url(
|
||||||
|
avatar_hash,
|
||||||
|
event.author.id.get(),
|
||||||
|
event.author.discriminator as u64,
|
||||||
|
);
|
||||||
|
|
||||||
|
DisplayProfile {
|
||||||
|
id: event.author.id.get(),
|
||||||
|
name,
|
||||||
|
avatar_url,
|
||||||
|
mask: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+2
-1
@@ -126,7 +126,7 @@ use crate::{
|
|||||||
groups::{
|
groups::{
|
||||||
about::{commands::HelpCommand, components::HelpGoBackButton},
|
about::{commands::HelpCommand, components::HelpGoBackButton},
|
||||||
calls::{
|
calls::{
|
||||||
commands::{CallCommand, HangupCommand, SkipCommand},
|
commands::{CallCommand, FriendRequestCommand, HangupCommand, SkipCommand},
|
||||||
events::MessageRedirector,
|
events::MessageRedirector,
|
||||||
},
|
},
|
||||||
gateway::events::{ReadyHandler, ReconnectHandler},
|
gateway::events::{ReadyHandler, ReconnectHandler},
|
||||||
@@ -227,6 +227,7 @@ async fn start(token: String, database_addr: String, shard: ShardId) {
|
|||||||
.command(CallCommand::new())
|
.command(CallCommand::new())
|
||||||
.command(SkipCommand)
|
.command(SkipCommand)
|
||||||
.command(HangupCommand)
|
.command(HangupCommand)
|
||||||
|
.command(FriendRequestCommand)
|
||||||
.command(PrefixCommand)
|
.command(PrefixCommand)
|
||||||
.component(HelpGoBackButton)
|
.component(HelpGoBackButton)
|
||||||
.on_ready(ReadyHandler)
|
.on_ready(ReadyHandler)
|
||||||
|
|||||||
Reference in New Issue
Block a user