moved message structs and ran cargo fmt

This commit is contained in:
Anish Nayak
2025-08-12 19:59:53 +01:00
parent 14e6d59ddd
commit 540db21c45
11 changed files with 211 additions and 171 deletions
+90 -66
View File
@@ -1,66 +1,4 @@
use scylla::{SerializeValue, DeserializeValue}; use scylla::{DeserializeValue, SerializeValue};
#[derive(Debug, Clone, SerializeValue, DeserializeValue)]
pub struct MessageMetadata {
pub call_id: i64,
pub author_id: i64,
pub author_name: Option<String>,
pub author_avatar_url: Option<String>,
pub author_mask: Option<String>,
pub content: Option<String>,
pub attachments: Option<Vec<String>>,
pub sticker: Option<i64>,
pub propagation_message_id: Option<i64>,
pub propagation_channel_id: Option<i64>,
pub replying_to_id: Option<i64>,
pub message_replied_to_metadata: Option<Box<MessageMetadata>>,
pub is_deleted: Option<bool>,
pub is_edited: Option<bool>,
pub is_censored: Option<bool>,
}
impl<'a> Object<'a> for MessageMetadata {
type Row = (
i64, i64, Option<String>, Option<String>, Option<String>, Option<String>, Option<Vec<String>>, Option<i64>, Option<i64>, Option<i64>, Option<i64>, Option<Box<MessageMetadata>>, Option<bool>, Option<bool>, Option<bool>
);
fn from_row(row: Self::Row) -> Self {
Self {
call_id: row.0,
author_id: row.1,
author_name: row.2,
author_avatar_url: row.3,
author_mask: row.4,
content: row.5,
attachments: row.6,
sticker: row.7,
propagation_message_id: row.8,
propagation_channel_id: row.9,
replying_to_id: row.10,
message_replied_to_metadata: row.11,
is_deleted: row.12,
is_edited: row.13,
is_censored: row.14,
}
}
fn to_row(value: Self) -> Self::Row {
(
value.call_id,
value.author_id,
value.author_name,
value.author_avatar_url,
value.author_mask,
value.content,
value.attachments,
value.sticker,
value.propagation_message_id,
value.propagation_channel_id,
value.replying_to_id,
value.message_replied_to_metadata,
value.is_deleted,
value.is_edited,
value.is_censored,
)
}
}
use scylla::{ use scylla::{
client::session::Session, client::session::Session,
deserialize::row::DeserializeRow, deserialize::row::DeserializeRow,
@@ -253,6 +191,83 @@ impl From<TwilightUser> for User {
} }
} }
#[derive(Debug, Clone, SerializeValue, DeserializeValue)]
pub struct MessageMetadata {
pub call_id: i64,
pub author_id: i64,
pub author_name: Option<String>,
pub author_avatar_url: Option<String>,
pub author_mask: Option<String>,
pub content: Option<String>,
pub attachments: Option<Vec<String>>,
pub sticker: Option<i64>,
pub propagation_message_id: Option<i64>,
pub propagation_channel_id: Option<i64>,
pub replying_to_id: Option<i64>,
pub message_replied_to_metadata: Option<Box<MessageMetadata>>,
pub is_deleted: Option<bool>,
pub is_edited: Option<bool>,
pub is_censored: Option<bool>,
}
impl<'a> Object<'a> for MessageMetadata {
type Row = (
i64,
i64,
Option<String>,
Option<String>,
Option<String>,
Option<String>,
Option<Vec<String>>,
Option<i64>,
Option<i64>,
Option<i64>,
Option<i64>,
Option<Box<MessageMetadata>>,
Option<bool>,
Option<bool>,
Option<bool>,
);
fn from_row(row: Self::Row) -> Self {
Self {
call_id: row.0,
author_id: row.1,
author_name: row.2,
author_avatar_url: row.3,
author_mask: row.4,
content: row.5,
attachments: row.6,
sticker: row.7,
propagation_message_id: row.8,
propagation_channel_id: row.9,
replying_to_id: row.10,
message_replied_to_metadata: row.11,
is_deleted: row.12,
is_edited: row.13,
is_censored: row.14,
}
}
fn to_row(value: Self) -> Self::Row {
(
value.call_id,
value.author_id,
value.author_name,
value.author_avatar_url,
value.author_mask,
value.content,
value.attachments,
value.sticker,
value.propagation_message_id,
value.propagation_channel_id,
value.replying_to_id,
value.message_replied_to_metadata,
value.is_deleted,
value.is_edited,
value.is_censored,
)
}
}
// --- BEGIN: Payphone Message and Report Models --- // --- BEGIN: Payphone Message and Report Models ---
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -263,7 +278,11 @@ pub struct Message {
} }
impl Message { impl Message {
pub async fn get_by_id(call_id: u64, message_id: u64, session: &Session) -> Result<Option<Self>, DatabaseError> { pub async fn get_by_id(
call_id: u64,
message_id: u64,
session: &Session,
) -> Result<Option<Self>, DatabaseError> {
let call_id = u64_to_i64(call_id); let call_id = u64_to_i64(call_id);
let message_id = u64_to_i64(message_id); let message_id = u64_to_i64(message_id);
let result = session let result = session
@@ -287,7 +306,9 @@ impl Message {
message_metadata: row.2, message_metadata: row.2,
})), })),
Err(error) => match error { Err(error) => match error {
SingleRowError::DeserializationFailed(_) | SingleRowError::TypeCheckFailed(_) => Err(DatabaseError::DeserializationFailed), SingleRowError::DeserializationFailed(_) | SingleRowError::TypeCheckFailed(_) => {
Err(DatabaseError::DeserializationFailed)
}
SingleRowError::UnexpectedRowCount(_) => Ok(None), SingleRowError::UnexpectedRowCount(_) => Ok(None),
}, },
} }
@@ -325,7 +346,10 @@ impl Report {
&self.message, &self.message,
self.created_at, self.created_at,
self.reviewed_at, self.reviewed_at,
self.created_by_ids.iter().map(|&id| u64_to_i64(id)).collect::<Vec<i64>>(), self.created_by_ids
.iter()
.map(|&id| u64_to_i64(id))
.collect::<Vec<i64>>(),
self.reviewed_by_id.map(u64_to_i64), self.reviewed_by_id.map(u64_to_i64),
self.resolution.as_ref(), self.resolution.as_ref(),
), ),
+8 -25
View File
@@ -37,24 +37,14 @@ pub trait IntoPrefixes<T> {
#[async_trait] #[async_trait]
impl<T> IntoPrefixes<T> for String { impl<T> IntoPrefixes<T> for String {
async fn get( async fn get(&self, _: &Runtime<T>, _: Option<u64>, _: Option<u64>) -> Vec<String> {
&self,
_: &Runtime<T>,
_: Option<u64>,
_: Option<u64>,
) -> Vec<String> {
vec![self.to_string()] vec![self.to_string()]
} }
} }
#[async_trait] #[async_trait]
impl<T> IntoPrefixes<T> for &str { impl<T> IntoPrefixes<T> for &str {
async fn get( async fn get(&self, _: &Runtime<T>, _: Option<u64>, _: Option<u64>) -> Vec<String> {
&self,
_: &Runtime<T>,
_: Option<u64>,
_: Option<u64>,
) -> Vec<String> {
vec![self.to_string()] vec![self.to_string()]
} }
} }
@@ -64,12 +54,7 @@ impl<T: Send + Sync + 'static, const N: usize, S: Send + Sync + 'static> IntoPre
where where
T: ToString, T: ToString,
{ {
async fn get( async fn get(&self, _: &Runtime<S>, _: Option<u64>, _: Option<u64>) -> Vec<String> {
&self,
_: &Runtime<S>,
_: Option<u64>,
_: Option<u64>,
) -> Vec<String> {
self.iter().map(|s| s.to_string()).collect() self.iter().map(|s| s.to_string()).collect()
} }
} }
@@ -80,12 +65,7 @@ where
F: Fn() -> Fut + Send + Sync + 'static, F: Fn() -> Fut + Send + Sync + 'static,
Fut: Future<Output = Vec<String>> + Send, Fut: Future<Output = Vec<String>> + Send,
{ {
async fn get( async fn get(&self, _: &Runtime<T>, _: Option<u64>, _: Option<u64>) -> Vec<String> {
&self,
_: &Runtime<T>,
_: Option<u64>,
_: Option<u64>,
) -> Vec<String> {
(self)().await (self)().await
} }
} }
@@ -267,7 +247,10 @@ impl<T: 'static + Send + Sync> Bot<T> {
} }
Event::InteractionCreate(interaction) => { Event::InteractionCreate(interaction) => {
// First, try message command registry // First, try message command registry
if let Err(e) = message_command_registry.execute(&interaction, task_rt.clone()).await { if let Err(e) = message_command_registry
.execute(&interaction, task_rt.clone())
.await
{
// If not a message command, fall back to interaction handlers // If not a message command, fall back to interaction handlers
for handler in &task_bot.on_interaction_handlers { for handler in &task_bot.on_interaction_handlers {
handler handler
@@ -1,7 +1,7 @@
use std::fmt::Debug;
use async_trait::async_trait;
use twilight_model::gateway::payload::incoming::InteractionCreate;
use crate::framework::interactions::{InteractionError, context::InteractionContext}; use crate::framework::interactions::{InteractionError, context::InteractionContext};
use async_trait::async_trait;
use std::fmt::Debug;
use twilight_model::gateway::payload::incoming::InteractionCreate;
#[async_trait] #[async_trait]
pub trait MessageCommand<T>: Send + Sync + Debug { pub trait MessageCommand<T>: Send + Sync + Debug {
@@ -9,5 +9,9 @@ pub trait MessageCommand<T>: Send + Sync + Debug {
fn description(&self) -> &'static str { fn description(&self) -> &'static str {
"A message context menu command duh." "A message context menu command duh."
} }
async fn execute(&self, ctx: InteractionContext<T>, target_message_id: u64) -> Result<(), InteractionError>; async fn execute(
&self,
ctx: InteractionContext<T>,
target_message_id: u64,
) -> Result<(), InteractionError>;
} }
@@ -1,12 +1,15 @@
use std::sync::Arc;
use scc::HashMap;
use twilight_model::{
application::interaction::InteractionData, application::command::CommandType, gateway::payload::incoming::InteractionCreate,
};
use crate::framework::{ use crate::framework::{
interactions::{InteractionError, context::InteractionContext, message_command::MessageCommand}, interactions::{
InteractionError, context::InteractionContext, message_command::MessageCommand,
},
runtime::Runtime, runtime::Runtime,
}; };
use scc::HashMap;
use std::sync::Arc;
use twilight_model::{
application::command::CommandType, application::interaction::InteractionData,
gateway::payload::incoming::InteractionCreate,
};
#[derive(Default)] #[derive(Default)]
pub struct MessageCommandRegistry<T> { pub struct MessageCommandRegistry<T> {
@@ -53,7 +56,11 @@ where
if let Some(target_id) = data.target_id { if let Some(target_id) = data.target_id {
command command
.execute( .execute(
InteractionContext::new(event.clone(), rt.clone(), prefix.to_string()), InteractionContext::new(
event.clone(),
rt.clone(),
prefix.to_string(),
),
target_id.get(), target_id.get(),
) )
.await .await
+2 -2
View File
@@ -2,10 +2,10 @@ use thiserror::Error;
pub mod components; pub mod components;
pub mod context; pub mod context;
pub mod registry;
pub mod runner;
pub mod message_command; pub mod message_command;
pub mod message_command_registry; pub mod message_command_registry;
pub mod registry;
pub mod runner;
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum InteractionError { pub enum InteractionError {
+28 -10
View File
@@ -5,7 +5,9 @@ use twilight_model::id::Id;
use crate::{ use crate::{
database::models::{Call, Channel, Message, Report}, database::models::{Call, Channel, Message, Report},
framework::commands::{Command, CommandError, context::CommandContext}, framework::commands::{Command, CommandError, context::CommandContext},
framework::interactions::{message_command::MessageCommand, InteractionError, context::InteractionContext}, framework::interactions::{
InteractionError, context::InteractionContext, message_command::MessageCommand,
},
state::State, state::State,
utils::{Bye, get_random_u64}, utils::{Bye, get_random_u64},
}; };
@@ -22,15 +24,26 @@ impl MessageCommand<State> for ReportMessageCommand {
"Report a message to the moderators." "Report a message to the moderators."
} }
async fn execute(&self, ctx: InteractionContext<State>, target_message_id: u64) -> Result<(), InteractionError> { async fn execute(
&self,
ctx: InteractionContext<State>,
target_message_id: u64,
) -> Result<(), InteractionError> {
// Extract channel_id from resolved data or fallback to event.channel (Discord API v10+) // Extract channel_id from resolved data or fallback to event.channel (Discord API v10+)
let channel_id = ctx.event.channel.as_ref().map(|c| c.id.get()) let channel_id = ctx
.event
.channel
.as_ref()
.map(|c| c.id.get())
.or_else(|| ctx.event.channel.as_ref().map(|c| c.id.get())) .or_else(|| ctx.event.channel.as_ref().map(|c| c.id.get()))
.ok_or(InteractionError::InteractionNotFound)?; .ok_or(InteractionError::InteractionNotFound)?;
let db = &ctx.rt.state.db; let db = &ctx.rt.state.db;
let channel = Channel::get_by_id(channel_id, db).await.map_err(|_| InteractionError::InteractionNotFound)?; let channel = Channel::get_by_id(channel_id, db)
let call_id = channel.and_then(|c| c.call_id).ok_or(InteractionError::InteractionNotFound)?; .await
.map_err(|_| InteractionError::InteractionNotFound)?;
let call_id = channel
.and_then(|c| c.call_id)
.ok_or(InteractionError::InteractionNotFound)?;
// Fetch the message from the database // Fetch the message from the database
let message = Message::get_by_id(call_id, target_message_id, db) let message = Message::get_by_id(call_id, target_message_id, db)
@@ -41,8 +54,11 @@ impl MessageCommand<State> for ReportMessageCommand {
// If the message is a reply, fetch the replied-to message and denormalize its metadata // If the message is a reply, fetch the replied-to message and denormalize its metadata
let mut message_metadata = message.message_metadata.clone(); let mut message_metadata = message.message_metadata.clone();
if let Some(replying_to_id) = message_metadata.replying_to_id { if let Some(replying_to_id) = message_metadata.replying_to_id {
if let Ok(Some(reply_msg)) = Message::get_by_id(call_id, replying_to_id as u64, db).await { if let Ok(Some(reply_msg)) =
message_metadata.message_replied_to_metadata = Some(Box::new(reply_msg.message_metadata)); Message::get_by_id(call_id, replying_to_id as u64, db).await
{
message_metadata.message_replied_to_metadata =
Some(Box::new(reply_msg.message_metadata));
} }
} }
@@ -57,9 +73,11 @@ impl MessageCommand<State> for ReportMessageCommand {
resolution: None, resolution: None,
}; };
// Insert the report // Insert the report
report.insert(db).await.map_err(|_| InteractionError::DeferringFailed)?; report
.insert(db)
.await
.map_err(|_| InteractionError::DeferringFailed)?;
// Respond to the user // Respond to the user
ctx.rt.http ctx.rt.http
+6 -2
View File
@@ -6,10 +6,14 @@ use twilight_model::{gateway::payload::incoming::MessageCreate, id::Id};
use twilight_validate::request::webhook_username; use twilight_validate::request::webhook_username;
use crate::{ use crate::{
database::models::{Call, Channel}, discord::{images, sanitizing::SanitizeDiscordMarkdown}, framework::{ database::models::{Call, Channel},
discord::{images, sanitizing::SanitizeDiscordMarkdown},
framework::{
events::traits::{EventResult, OnMessageHandler}, events::traits::{EventResult, OnMessageHandler},
runtime::Runtime, runtime::Runtime,
}, groups::calls::moderation::escape_message, state::State },
groups::calls::moderation::escape_message,
state::State,
}; };
#[derive(Debug)] #[derive(Debug)]