changed stuff according to merge request !2

This commit is contained in:
Anish Nayak
2025-08-12 23:13:03 +01:00
parent 540db21c45
commit bacdc8ea0f
12 changed files with 262 additions and 134 deletions
+29 -10
View File
@@ -5,25 +5,29 @@ CREATE KEYSPACE IF NOT EXISTS payphone
} AND TABLETS = { } AND TABLETS = {
'enabled': false 'enabled': false
}; };
CREATE TYPE IF NOT EXISTS payphone.message (
id BIGINT,
CREATE TYPE IF NOT EXISTS payphone.message_metadata (
call_id BIGINT,
author_id BIGINT, author_id BIGINT,
author_name TEXT, author_name TEXT,
author_avatar_url TEXT, author_avatar_url TEXT,
author_mask ASCII, author_mask ASCII,
content TEXT, content TEXT,
attachments LIST<TEXT>, attachments LIST<TEXT>,
sticker BIGINT, sticker BIGINT,
propagation_message_id BIGINT, propagation_message_id BIGINT,
propagation_channel_id BIGINT, propagation_channel_id BIGINT,
replying_to_id BIGINT,
message_replied_to_metadata FROZEN<payphone.message_metadata>, replying_to_id,
is_deleted BOOLEAN, is_deleted BOOLEAN,
is_edited BOOLEAN, is_edited BOOLEAN,
is_censored BOOLEAN is_censored BOOLEAN,
); );
CREATE TABLE IF NOT EXISTS payphone.users ( CREATE TABLE IF NOT EXISTS payphone.users (
user_id BIGINT PRIMARY KEY, user_id BIGINT PRIMARY KEY,
@@ -82,7 +86,9 @@ CREATE TABLE IF NOT EXISTS payphone.participants (
CREATE TABLE IF NOT EXISTS payphone.messages ( CREATE TABLE IF NOT EXISTS payphone.messages (
call_id BIGINT, call_id BIGINT,
message_id BIGINT, message_id BIGINT,
message_metadata FROZEN<payphone.message_metadata>,
data FROZEN<payphone.message>,
PRIMARY KEY (call_id, message_id) PRIMARY KEY (call_id, message_id)
); );
@@ -92,31 +98,44 @@ CREATE TABLE IF NOT EXISTS payphone.servers (
name TEXT, name TEXT,
prefix TEXT, prefix TEXT,
); );
CREATE TABLE IF NOT EXISTS payphone.reports ( CREATE TABLE IF NOT EXISTS payphone.reports (
report_id BIGINT, report_id BIGINT,
message FROZEN<payphone.message_metadata>,
message FROZEN<payphone.message>,
replying_to FROZEN<payphone.message>,
created_at TIMESTAMP, created_at TIMESTAMP,
reviewed_at TIMESTAMP, reviewed_at TIMESTAMP,
created_by_ids SET<BIGINT>, created_by_ids SET<BIGINT>,
reviewed_by_id BIGINT, reviewed_by_id BIGINT,
resolution ASCII, resolution ASCII,
PRIMARY KEY (report_id)
PRIMARY KEY (message_author_id, report_id)
); );
CREATE TABLE IF NOT EXISTS payphone.user_incidents ( CREATE TABLE IF NOT EXISTS payphone.user_incidents (
user_id BIGINT, user_id BIGINT,
incident_id BIGINT, incident_id BIGINT,
-- ban, warning -- ban, warning
type ASCII, type ASCII,
call_id BIGINT, call_id BIGINT,
report_id BIGINT, report_id BIGINT,
message FROZEN<payphone.message_metadata>,
message FROZEN<payphone.message>,
replying_to FROZEN<payphone.message>,
reason TEXT, reason TEXT,
created_by_id BIGINT, created_by_id BIGINT,
created_at TIMESTAMP, created_at TIMESTAMP,
expires_at TIMESTAMP, expires_at TIMESTAMP,
duration ASCII, duration ASCII,
PRIMARY KEY (user_id) PRIMARY KEY (user_id)
); );
+83 -41
View File
@@ -1,5 +1,5 @@
use scylla::{DeserializeValue, SerializeValue};
use scylla::{ use scylla::{
DeserializeValue, SerializeValue,
client::session::Session, client::session::Session,
deserialize::row::DeserializeRow, deserialize::row::DeserializeRow,
errors::{ExecutionError, SingleRowError}, errors::{ExecutionError, SingleRowError},
@@ -192,8 +192,8 @@ impl From<TwilightUser> for User {
} }
#[derive(Debug, Clone, SerializeValue, DeserializeValue)] #[derive(Debug, Clone, SerializeValue, DeserializeValue)]
pub struct MessageMetadata { pub struct Message {
pub call_id: i64, pub id: i64,
pub author_id: i64, pub author_id: i64,
pub author_name: Option<String>, pub author_name: Option<String>,
pub author_avatar_url: Option<String>, pub author_avatar_url: Option<String>,
@@ -204,13 +204,12 @@ pub struct MessageMetadata {
pub propagation_message_id: Option<i64>, pub propagation_message_id: Option<i64>,
pub propagation_channel_id: Option<i64>, pub propagation_channel_id: Option<i64>,
pub replying_to_id: Option<i64>, pub replying_to_id: Option<i64>,
pub message_replied_to_metadata: Option<Box<MessageMetadata>>,
pub is_deleted: Option<bool>, pub is_deleted: Option<bool>,
pub is_edited: Option<bool>, pub is_edited: Option<bool>,
pub is_censored: Option<bool>, pub is_censored: Option<bool>,
} }
impl<'a> Object<'a> for MessageMetadata { impl<'a> Object<'a> for Message {
type Row = ( type Row = (
i64, i64,
i64, i64,
@@ -223,14 +222,13 @@ impl<'a> Object<'a> for MessageMetadata {
Option<i64>, Option<i64>,
Option<i64>, Option<i64>,
Option<i64>, Option<i64>,
Option<Box<MessageMetadata>>,
Option<bool>, Option<bool>,
Option<bool>, Option<bool>,
Option<bool>, Option<bool>,
); );
fn from_row(row: Self::Row) -> Self { fn from_row(row: Self::Row) -> Self {
Self { Self {
call_id: row.0, id: row.0,
author_id: row.1, author_id: row.1,
author_name: row.2, author_name: row.2,
author_avatar_url: row.3, author_avatar_url: row.3,
@@ -241,15 +239,14 @@ impl<'a> Object<'a> for MessageMetadata {
propagation_message_id: row.8, propagation_message_id: row.8,
propagation_channel_id: row.9, propagation_channel_id: row.9,
replying_to_id: row.10, replying_to_id: row.10,
message_replied_to_metadata: row.11, is_deleted: row.11,
is_deleted: row.12, is_edited: row.12,
is_edited: row.13, is_censored: row.13,
is_censored: row.14,
} }
} }
fn to_row(value: Self) -> Self::Row { fn to_row(value: Self) -> Self::Row {
( (
value.call_id, value.id,
value.author_id, value.author_id,
value.author_name, value.author_name,
value.author_avatar_url, value.author_avatar_url,
@@ -260,7 +257,6 @@ impl<'a> Object<'a> for MessageMetadata {
value.propagation_message_id, value.propagation_message_id,
value.propagation_channel_id, value.propagation_channel_id,
value.replying_to_id, value.replying_to_id,
value.message_replied_to_metadata,
value.is_deleted, value.is_deleted,
value.is_edited, value.is_edited,
value.is_censored, value.is_censored,
@@ -268,17 +264,14 @@ impl<'a> Object<'a> for MessageMetadata {
} }
} }
// --- BEGIN: Payphone Message and Report Models --- pub struct MessageRow {
#[derive(Debug, Clone)]
pub struct Message {
pub call_id: u64, pub call_id: u64,
pub message_id: u64, pub message_id: u64,
pub message_metadata: MessageMetadata, pub data: Message,
} }
impl Message { impl MessageRow {
pub async fn get_by_id( pub async fn get_by_call_and_message_id(
call_id: u64, call_id: u64,
message_id: u64, message_id: u64,
session: &Session, session: &Session,
@@ -288,7 +281,7 @@ impl Message {
let result = session let result = session
.query_unpaged( .query_unpaged(
r#" r#"
SELECT call_id, message_id, message_metadata SELECT call_id, message_id, data
FROM payphone.messages FROM payphone.messages
WHERE call_id = ? AND message_id = ? WHERE call_id = ? AND message_id = ?
LIMIT 1; LIMIT 1;
@@ -299,12 +292,8 @@ impl Message {
.map_err(DatabaseError::QueryError)? .map_err(DatabaseError::QueryError)?
.into_rows_result() .into_rows_result()
.map_err(|_| DatabaseError::ResultNotRows)?; .map_err(|_| DatabaseError::ResultNotRows)?;
match result.single_row::<(i64, i64, MessageMetadata)>() { match result.single_row::<<MessageRow as Object>::Row>() {
Ok(row) => Ok(Some(Self { Ok(row) => Ok(Some(<MessageRow as Object>::from_row(row))),
call_id: i64_to_u64(row.0),
message_id: i64_to_u64(row.1),
message_metadata: row.2,
})),
Err(error) => match error { Err(error) => match error {
SingleRowError::DeserializationFailed(_) | SingleRowError::TypeCheckFailed(_) => { SingleRowError::DeserializationFailed(_) | SingleRowError::TypeCheckFailed(_) => {
Err(DatabaseError::DeserializationFailed) Err(DatabaseError::DeserializationFailed)
@@ -315,10 +304,54 @@ impl Message {
} }
} }
impl<'a> Object<'a> for Report {
type Row = (
i64, // report_id
Message,
Option<Message>,
OffsetDateTime,
Option<OffsetDateTime>,
Vec<i64>,
Option<i64>,
Option<String>,
);
fn from_row(row: Self::Row) -> Self {
Self {
report_id: i64_to_u64(row.0),
message: row.1,
replying_to: row.2,
created_at: row.3,
reviewed_at: row.4,
created_by_ids: row.5.iter().map(|&id| i64_to_u64(id)).collect(),
reviewed_by_id: row.6.map(i64_to_u64),
resolution: row.7,
}
}
fn to_row(value: Self) -> Self::Row {
(
u64_to_i64(value.report_id),
value.message,
value.replying_to,
value.created_at,
value.reviewed_at,
value
.created_by_ids
.iter()
.map(|&id| u64_to_i64(id))
.collect(),
value.reviewed_by_id.map(u64_to_i64),
value.resolution,
)
}
}
// --- BEGIN: Payphone Message and Report Models ---
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Report { pub struct Report {
pub report_id: u64, pub report_id: u64,
pub message: MessageMetadata, pub message: Message,
pub replying_to: Option<Message>,
pub created_at: OffsetDateTime, pub created_at: OffsetDateTime,
pub reviewed_at: Option<OffsetDateTime>, pub reviewed_at: Option<OffsetDateTime>,
pub created_by_ids: Vec<u64>, pub created_by_ids: Vec<u64>,
@@ -326,33 +359,42 @@ pub struct Report {
pub resolution: Option<String>, pub resolution: Option<String>,
} }
impl<'a> Object<'a> for MessageRow {
type Row = (i64, i64, <Message as Object<'a>>::Row);
fn from_row(row: Self::Row) -> Self {
Self {
call_id: i64_to_u64(row.0),
message_id: i64_to_u64(row.1),
data: <Message as Object>::from_row(row.2),
}
}
fn to_row(value: Self) -> Self::Row {
(
u64_to_i64(value.call_id),
u64_to_i64(value.message_id),
<Message as Object>::to_row(value.data),
)
}
}
impl Report { impl Report {
pub async fn insert(&self, session: &Session) -> Result<(), DatabaseError> { pub async fn insert(&self, session: &Session) -> Result<(), DatabaseError> {
let row = Self::to_row(self.clone());
session session
.query_unpaged( .query_unpaged(
r#" r#"
INSERT INTO payphone.reports ( INSERT INTO payphone.reports (
report_id, report_id,
message, message,
replying_to,
created_at, created_at,
reviewed_at, reviewed_at,
created_by_ids, created_by_ids,
reviewed_by_id, reviewed_by_id,
resolution resolution
) VALUES (?, ?, ?, ?, ?, ?, ?); ) VALUES (?, ?, ?, ?, ?, ?, ?, ?);
"#, "#,
( row,
u64_to_i64(self.report_id),
&self.message,
self.created_at,
self.reviewed_at,
self.created_by_ids
.iter()
.map(|&id| u64_to_i64(id))
.collect::<Vec<i64>>(),
self.reviewed_by_id.map(u64_to_i64),
self.resolution.as_ref(),
),
) )
.await .await
.map_err(DatabaseError::QueryError)?; .map_err(DatabaseError::QueryError)?;
+35 -43
View File
@@ -1,24 +1,24 @@
use std::{fmt::Debug, sync::Arc}; use crate::framework::{
commands::{Command, runner::CommandRunner},
events::traits::{
OnInteractionHandler, OnMessageDeleteHandler, OnMessageEditHandler, OnMessageHandler,
OnReadyHandler, OnReconnectHandler, OnServerCreateHandler, OnServerDeleteHandler,
OnServerUpdateHandler,
},
interactions::{
components::Component, message_command::MessageCommand,
message_command_registry::MessageCommandRegistry,
message_command_runner::MessageCommandRunner, registry::ComponentRegistry,
},
runtime::Runtime,
};
use crate::utils::Bye;
use async_trait::async_trait; use async_trait::async_trait;
use std::{fmt::Debug, sync::Arc};
use thiserror::Error; use thiserror::Error;
use twilight_gateway::{Event, EventTypeFlags, Intents, Shard, ShardId, StreamExt}; use twilight_gateway::{Event, EventTypeFlags, Intents, Shard, ShardId, StreamExt};
use twilight_http::Client; use twilight_http::Client;
use crate::{
framework::{
commands::{Command, runner::CommandRunner},
events::traits::{
OnInteractionHandler, OnMessageDeleteHandler, OnMessageEditHandler, OnMessageHandler,
OnReadyHandler, OnReconnectHandler, OnServerCreateHandler, OnServerDeleteHandler,
OnServerUpdateHandler,
},
interactions::{components::Component, registry::ComponentRegistry},
runtime::Runtime,
},
utils::Bye,
};
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum RuntimeError { pub enum RuntimeError {
#[error("The application's details could not be fetched")] #[error("The application's details could not be fetched")]
@@ -70,10 +70,7 @@ where
} }
} }
use crate::framework::interactions::message_command::MessageCommand; pub struct Bot<T: Send + Sync + Debug = ()> {
use crate::framework::interactions::message_command_registry::MessageCommandRegistry;
pub struct Bot<T: Send + Sync = ()> {
state: Arc<T>, state: Arc<T>,
prefixes: Arc<dyn IntoPrefixes<T> + Send + Sync>, prefixes: Arc<dyn IntoPrefixes<T> + Send + Sync>,
intents: Intents, intents: Intents,
@@ -91,7 +88,7 @@ pub struct Bot<T: Send + Sync = ()> {
on_server_delete_handlers: Vec<Arc<dyn OnServerDeleteHandler<T>>>, on_server_delete_handlers: Vec<Arc<dyn OnServerDeleteHandler<T>>>,
} }
impl<T: 'static + Send + Sync> Bot<T> { impl<T: 'static + Send + Sync + Debug> Bot<T> {
pub fn new(state: T, prefixes: impl IntoPrefixes<T> + Send + Sync + 'static) -> Self { pub fn new(state: T, prefixes: impl IntoPrefixes<T> + Send + Sync + 'static) -> Self {
Self { Self {
state: Arc::new(state), state: Arc::new(state),
@@ -102,7 +99,7 @@ impl<T: 'static + Send + Sync> Bot<T> {
message_commands: Vec::new(), message_commands: Vec::new(),
on_ready_handlers: Vec::new(), on_ready_handlers: Vec::new(),
on_reconnect_handlers: Vec::new(), on_reconnect_handlers: Vec::new(),
on_interaction_handlers: Vec::new(), on_interaction_handlers: Vec::new(), // Will push MessageCommandRunner in run()
on_message_handlers: vec![Arc::new(CommandRunner)], on_message_handlers: vec![Arc::new(CommandRunner)],
on_message_edit_handlers: Vec::new(), on_message_edit_handlers: Vec::new(),
on_message_delete_handlers: Vec::new(), on_message_delete_handlers: Vec::new(),
@@ -202,7 +199,14 @@ impl<T: 'static + Send + Sync> Bot<T> {
message_command_registry.register(command.name(), command.clone()); message_command_registry.register(command.name(), command.clone());
} }
let bot = Arc::new(self); let mut bot = self;
bot.on_interaction_handlers.insert(
0,
Arc::new(MessageCommandRunner {
registry: message_command_registry.clone(),
}),
);
let bot = Arc::new(bot);
let runtime = Arc::new(Runtime { let runtime = Arc::new(Runtime {
http, http,
@@ -219,8 +223,6 @@ impl<T: 'static + Send + Sync> Bot<T> {
if let Some(Ok(event)) = gateway.next_event(EventTypeFlags::all()).await { if let Some(Ok(event)) = gateway.next_event(EventTypeFlags::all()).await {
let task_rt = runtime.clone(); let task_rt = runtime.clone();
let task_bot = bot.clone(); let task_bot = bot.clone();
let message_command_registry = message_command_registry.clone();
tokio::spawn(async move { tokio::spawn(async move {
match event { match event {
Event::Ready(event) => { Event::Ready(event) => {
@@ -246,24 +248,14 @@ impl<T: 'static + Send + Sync> Bot<T> {
} }
} }
Event::InteractionCreate(interaction) => { Event::InteractionCreate(interaction) => {
// First, try message command registry for handler in &task_bot.on_interaction_handlers {
if let Err(e) = message_command_registry handler
.execute(&interaction, task_rt.clone()) .on_interaction(&interaction, task_rt.clone())
.await .await
{ .inspect_err(
// If not a message command, fall back to interaction handlers |e| log::error!("An error occurred while handling on interaction for {handler:?}! {e:?}")
for handler in &task_bot.on_interaction_handlers { )
handler .bye();
.on_interaction(&interaction, task_rt.clone())
.await
.inspect_err(
|e| log::error!("An error occurred while handling on interaction for {handler:?}! {e:?}")
)
.bye();
}
if !matches!(e, crate::framework::interactions::InteractionError::InteractionTypeUnsent) {
log::error!("Message command dispatch error: {e:?}");
}
} }
} }
Event::MessageCreate(message) => { Event::MessageCreate(message) => {
+5 -1
View File
@@ -1,5 +1,4 @@
use std::sync::Arc; use std::sync::Arc;
use twilight_model::{ use twilight_model::{
gateway::payload::incoming::InteractionCreate, gateway::payload::incoming::InteractionCreate,
http::interaction::{InteractionResponse, InteractionResponseType}, http::interaction::{InteractionResponse, InteractionResponseType},
@@ -17,6 +16,11 @@ pub struct InteractionContext<T> {
} }
impl<T> InteractionContext<T> { impl<T> InteractionContext<T> {
pub fn send(
self: &Arc<Self>,
) -> crate::framework::interactions::messages::InteractionResponder<T> {
crate::framework::interactions::messages::InteractionResponder::new(self.clone())
}
pub fn new(event: InteractionCreate, rt: Arc<Runtime<T>>, prefix: String) -> Self { pub fn new(event: InteractionCreate, rt: Arc<Runtime<T>>, prefix: String) -> Self {
Self { event, rt, prefix } Self { event, rt, prefix }
} }
@@ -7,7 +7,7 @@ use twilight_model::gateway::payload::incoming::InteractionCreate;
pub trait MessageCommand<T>: Send + Sync + Debug { pub trait MessageCommand<T>: Send + Sync + Debug {
fn name(&self) -> &'static str; fn name(&self) -> &'static str;
fn description(&self) -> &'static str { fn description(&self) -> &'static str {
"A message context menu command duh." "A Payphone context menu command."
} }
async fn execute( async fn execute(
&self, &self,
@@ -1,3 +1,4 @@
// to be later integrated into interaction registry...currently component registry
use crate::framework::{ use crate::framework::{
interactions::{ interactions::{
InteractionError, context::InteractionContext, message_command::MessageCommand, InteractionError, context::InteractionContext, message_command::MessageCommand,
@@ -11,7 +12,7 @@ use twilight_model::{
gateway::payload::incoming::InteractionCreate, gateway::payload::incoming::InteractionCreate,
}; };
#[derive(Default)] #[derive(Default, Debug)]
pub struct MessageCommandRegistry<T> { pub struct MessageCommandRegistry<T> {
inner: HashMap<String, Arc<dyn MessageCommand<T>>>, inner: HashMap<String, Arc<dyn MessageCommand<T>>>,
} }
@@ -0,0 +1,32 @@
use async_trait::async_trait;
use std::sync::Arc;
use twilight_model::gateway::payload::incoming::InteractionCreate;
use crate::framework::{
events::traits::{EventResult, OnInteractionHandler},
interactions::message_command_registry::MessageCommandRegistry,
runtime::Runtime,
};
#[derive(Debug)]
pub struct MessageCommandRunner<T> {
pub registry: Arc<MessageCommandRegistry<T>>,
}
#[async_trait]
impl<T: Send + Sync + std::fmt::Debug + 'static> OnInteractionHandler<T>
for MessageCommandRunner<T>
{
async fn on_interaction(&self, event: &InteractionCreate, rt: Arc<Runtime<T>>) -> EventResult {
if let Err(e) = self.registry.execute(event, rt).await {
// Only log errors that aren't "not a message command"
if !matches!(
e,
crate::framework::interactions::InteractionError::InteractionTypeUnsent
) {
log::error!("Message command dispatch error: {e:?}");
}
}
Ok(())
}
}
+40
View File
@@ -0,0 +1,40 @@
use std::sync::Arc;
use twilight_model::http::interaction::{
InteractionResponse, InteractionResponseData, InteractionResponseType,
};
use crate::framework::{
interactions::{InteractionError, context::InteractionContext},
runtime::Runtime,
};
pub struct InteractionResponder<T> {
ctx: Arc<InteractionContext<T>>,
}
impl<T> InteractionResponder<T> {
pub fn new(ctx: Arc<InteractionContext<T>>) -> Self {
Self { ctx }
}
pub async fn content(&self, content: impl Into<String>) -> Result<(), InteractionError> {
self.ctx
.rt
.http
.interaction(self.ctx.rt.app.id)
.create_response(
self.ctx.event.id,
&self.ctx.event.token,
&InteractionResponse {
kind: InteractionResponseType::ChannelMessageWithSource,
data: Some(InteractionResponseData {
content: Some(content.into()),
..Default::default()
}),
},
)
.await
.map_err(|_| InteractionError::DeferringFailed)?;
Ok(())
}
}
+5 -1
View File
@@ -1,5 +1,6 @@
pub mod message_command_runner;
pub mod messages;
use thiserror::Error; use thiserror::Error;
pub mod components; pub mod components;
pub mod context; pub mod context;
pub mod message_command; pub mod message_command;
@@ -25,4 +26,7 @@ pub enum InteractionError {
#[error("No prefixes were returned for the event")] #[error("No prefixes were returned for the event")]
PrefixesVectorEmpty, PrefixesVectorEmpty,
#[error(transparent)]
DatabaseError(#[from] crate::database::models::DatabaseError),
} }
+21 -28
View File
@@ -1,9 +1,10 @@
use async_trait::async_trait; use async_trait::async_trait;
use scc::HashSet; use scc::HashSet;
use std::sync::Arc;
use twilight_model::id::Id; use twilight_model::id::Id;
use crate::{ use crate::{
database::models::{Call, Channel, Message, Report}, database::models::{Call, Channel, Message, MessageRow, Report},
framework::commands::{Command, CommandError, context::CommandContext}, framework::commands::{Command, CommandError, context::CommandContext},
framework::interactions::{ framework::interactions::{
InteractionError, context::InteractionContext, message_command::MessageCommand, InteractionError, context::InteractionContext, message_command::MessageCommand,
@@ -46,26 +47,29 @@ impl MessageCommand<State> for ReportMessageCommand {
.ok_or(InteractionError::InteractionNotFound)?; .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_row = MessageRow::get_by_call_and_message_id(call_id, target_message_id, db)
.await .await
.map_err(|_| InteractionError::InteractionNotFound)? .map_err(|_| InteractionError::InteractionNotFound)?
.ok_or(InteractionError::InteractionNotFound)?; .ok_or(InteractionError::InteractionNotFound)?;
// 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 store in replying_to
let mut message_metadata = message.message_metadata.clone(); let replying_to = if let Some(replying_to_id) = message_row.data.replying_to_id {
if let Some(replying_to_id) = message_metadata.replying_to_id { if let Ok(Some(reply_msg_row)) =
if let Ok(Some(reply_msg)) = MessageRow::get_by_call_and_message_id(call_id, replying_to_id as u64, db).await
Message::get_by_id(call_id, replying_to_id as u64, db).await
{ {
message_metadata.message_replied_to_metadata = Some(reply_msg_row.data)
Some(Box::new(reply_msg.message_metadata)); } else {
None
} }
} } else {
None
};
// Build the report using the new UDT-based message metadata // Build the report using the new flat message and replying_to
let report = Report { let report = Report {
report_id: get_random_u64(), report_id: get_random_u64(),
message: message_metadata, message: message_row.data,
replying_to,
created_at: time::OffsetDateTime::now_utc(), created_at: time::OffsetDateTime::now_utc(),
reviewed_at: None, reviewed_at: None,
created_by_ids: vec![ctx.event.author_id().map(|id| id.get()).unwrap_or(0)], created_by_ids: vec![ctx.event.author_id().map(|id| id.get()).unwrap_or(0)],
@@ -77,24 +81,13 @@ impl MessageCommand<State> for ReportMessageCommand {
report report
.insert(db) .insert(db)
.await .await
.map_err(|_| InteractionError::DeferringFailed)?; .map_err(InteractionError::DatabaseError)?;
// Respond to the user // Respond to the user
ctx.rt.http Arc::new(ctx)
.interaction(ctx.rt.app.id) .send()
.create_response( .content("Message has been reported to the moderators.")
ctx.event.id, .await?;
&ctx.event.token,
&twilight_model::http::interaction::InteractionResponse {
kind: twilight_model::http::interaction::InteractionResponseType::ChannelMessageWithSource,
data: Some(twilight_model::http::interaction::InteractionResponseData {
content: Some("Message has been reported to the moderators.".to_string()),
..Default::default()
}),
},
)
.await
.map_err(|_| InteractionError::DeferringFailed)?;
Ok(()) Ok(())
} }
} }
+8 -8
View File
@@ -107,13 +107,7 @@ use std::{
sync::mpsc, sync::mpsc,
}; };
use axum::{Router, response::Redirect, routing}; use crate::groups::calls::commands::ReportMessageCommand;
use clap::Parser;
use notify::{Event, EventKind, Watcher};
use tokio::net::TcpListener;
use tower_http::services::ServeDir;
use twilight_gateway::Intents;
use crate::{ use crate::{
cli::{Args, Commands}, cli::{Args, Commands},
framework::bot::Bot, framework::bot::Bot,
@@ -128,6 +122,12 @@ use crate::{
}, },
state::State, state::State,
}; };
use axum::{Router, response::Redirect, routing};
use clap::Parser;
use notify::{Event, EventKind, Watcher};
use tokio::net::TcpListener;
use tower_http::services::ServeDir;
use twilight_gateway::Intents;
mod cli; mod cli;
mod constants; mod constants;
@@ -185,7 +185,7 @@ async fn start(token: String, database_addr: String) {
.command(CallCommand::new()) .command(CallCommand::new())
.command(HangupCommand) .command(HangupCommand)
.component(HelpGoBackButton) .component(HelpGoBackButton)
.message_command(crate::groups::calls::commands::ReportMessageCommand) .message_command(ReportMessageCommand)
.on_ready(ReadyHandler) .on_ready(ReadyHandler)
.on_reconnect(ReconnectHandler) .on_reconnect(ReconnectHandler)
.on_message(MessageRedirector) .on_message(MessageRedirector)
+1
View File
@@ -19,6 +19,7 @@
//! ``` //! ```
use scylla::client::session::Session; use scylla::client::session::Session;
#[derive(Debug)]
pub struct State { pub struct State {
pub db: Session, pub db: Session,