Use propagation message ID to query instead of materialized view
This commit is contained in:
Generated
+1
-1
@@ -2013,7 +2013,7 @@ checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "payphone"
|
name = "payphone"
|
||||||
version = "4.4.24"
|
version = "4.4.31"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "payphone"
|
name = "payphone"
|
||||||
version = "4.4.24"
|
version = "4.4.31"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
default-run = "payphone"
|
default-run = "payphone"
|
||||||
|
|
||||||
|
|||||||
+22
-86
@@ -1331,38 +1331,29 @@ impl Message {
|
|||||||
propagation_message_id: u64,
|
propagation_message_id: u64,
|
||||||
session: &Session,
|
session: &Session,
|
||||||
) -> Result<Option<Self>, DatabaseError> {
|
) -> Result<Option<Self>, DatabaseError> {
|
||||||
let message_by_propagation_id =
|
let result = session
|
||||||
MessageByPropagationId::get_by_propagation_message_id(propagation_message_id, session)
|
.query_unpaged(
|
||||||
.await?;
|
r#"
|
||||||
|
SELECT
|
||||||
|
call_id,
|
||||||
|
message_id,
|
||||||
|
author_id,
|
||||||
|
propagation_message_id,
|
||||||
|
data
|
||||||
|
FROM
|
||||||
|
payphone.messages
|
||||||
|
WHERE
|
||||||
|
propagation_message_id = ?
|
||||||
|
LIMIT 1;
|
||||||
|
"#,
|
||||||
|
(
|
||||||
|
u64_to_i64(propagation_message_id),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
.into_rows_result()?;
|
||||||
|
|
||||||
if let Some(message_by_propagation_id) = message_by_propagation_id {
|
return get_single_row_from_result(&result).await;
|
||||||
let result = session
|
|
||||||
.query_unpaged(
|
|
||||||
r#"
|
|
||||||
SELECT
|
|
||||||
call_id,
|
|
||||||
message_id,
|
|
||||||
author_id,
|
|
||||||
propagation_message_id,
|
|
||||||
data
|
|
||||||
FROM
|
|
||||||
payphone.messages
|
|
||||||
WHERE
|
|
||||||
call_id = ? AND message_id = ?
|
|
||||||
LIMIT 1;
|
|
||||||
"#,
|
|
||||||
(
|
|
||||||
u64_to_i64(message_by_propagation_id.call_id),
|
|
||||||
u64_to_i64(message_by_propagation_id.message_id),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.await?
|
|
||||||
.into_rows_result()?;
|
|
||||||
|
|
||||||
return get_single_row_from_result(&result).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(None)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_last_by_author_id(
|
pub async fn get_last_by_author_id(
|
||||||
@@ -1438,61 +1429,6 @@ impl Message {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MessageByPropagationId {
|
|
||||||
pub call_id: u64,
|
|
||||||
pub message_id: u64,
|
|
||||||
pub propagation_message_id: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Object<'a> for MessageByPropagationId {
|
|
||||||
type Row = (i64, i64, i64);
|
|
||||||
|
|
||||||
fn from_row(row: Self::Row) -> Self {
|
|
||||||
Self {
|
|
||||||
call_id: i64_to_u64(row.0),
|
|
||||||
message_id: i64_to_u64(row.1),
|
|
||||||
propagation_message_id: i64_to_u64(row.2),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_row(value: Self) -> Self::Row {
|
|
||||||
(
|
|
||||||
u64_to_i64(value.call_id),
|
|
||||||
u64_to_i64(value.message_id),
|
|
||||||
u64_to_i64(value.propagation_message_id),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MessageByPropagationId {
|
|
||||||
pub async fn get_by_propagation_message_id(
|
|
||||||
propagation_message_id: u64,
|
|
||||||
session: &Session,
|
|
||||||
) -> Result<Option<Self>, DatabaseError> {
|
|
||||||
let propagation_message_id = u64_to_i64(propagation_message_id);
|
|
||||||
|
|
||||||
let result = session
|
|
||||||
.query_unpaged(
|
|
||||||
r#"
|
|
||||||
SELECT
|
|
||||||
call_id,
|
|
||||||
message_id,
|
|
||||||
propagation_message_id
|
|
||||||
FROM
|
|
||||||
payphone.messages_by_propagation_id
|
|
||||||
WHERE
|
|
||||||
propagation_message_id = ?
|
|
||||||
LIMIT 1;
|
|
||||||
"#,
|
|
||||||
(propagation_message_id,),
|
|
||||||
)
|
|
||||||
.await?
|
|
||||||
.into_rows_result()?;
|
|
||||||
|
|
||||||
get_single_row_from_result(&result).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct MessageByAuthorId {
|
pub struct MessageByAuthorId {
|
||||||
pub call_id: u64,
|
pub call_id: u64,
|
||||||
pub message_id: u64,
|
pub message_id: u64,
|
||||||
|
|||||||
+58
-61
@@ -31,7 +31,7 @@ use crate::{
|
|||||||
components::{CodeOfConductButton, NeedHelpButton},
|
components::{CodeOfConductButton, NeedHelpButton},
|
||||||
embeds,
|
embeds,
|
||||||
masks::{get_mask_avatar_url, get_mask_display_name},
|
masks::{get_mask_avatar_url, get_mask_display_name},
|
||||||
moderation::{escape_message, moderate_message, Action, Rule},
|
moderation::{Action, Rule, escape_message, moderate_message},
|
||||||
},
|
},
|
||||||
state::State,
|
state::State,
|
||||||
utils::{ellipse, i64_to_u64},
|
utils::{ellipse, i64_to_u64},
|
||||||
@@ -226,7 +226,9 @@ impl OnMessageHandler<State, Extras> for CallMessageHandler {
|
|||||||
opposite_channel.id,
|
opposite_channel.id,
|
||||||
channel.id,
|
channel.id,
|
||||||
call.id,
|
call.id,
|
||||||
opposite_channel.call_id.map_or("None".into(), |i| i.to_string())
|
opposite_channel
|
||||||
|
.call_id
|
||||||
|
.map_or("None".into(), |i| i.to_string())
|
||||||
);
|
);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@@ -290,6 +292,7 @@ impl OnMessageHandler<State, Extras> for CallMessageHandler {
|
|||||||
|
|
||||||
if rules
|
if rules
|
||||||
.iter()
|
.iter()
|
||||||
|
.filter(|rule| !rule.ignore_for_moderators() || !user.is_moderator)
|
||||||
.any(|rule| rule.action() == &Action::BlockAndPenalty)
|
.any(|rule| rule.action() == &Action::BlockAndPenalty)
|
||||||
{
|
{
|
||||||
rt.http
|
rt.http
|
||||||
@@ -320,66 +323,63 @@ impl OnMessageHandler<State, Extras> for CallMessageHandler {
|
|||||||
} else {
|
} else {
|
||||||
let mut embeds = vec![];
|
let mut embeds = vec![];
|
||||||
|
|
||||||
if let Some(replying_to) = replying_to {
|
if let Some(replying_to) = replying_to
|
||||||
if let Some((propagation_channel_id, propagation_message_id)) = replying_to
|
&& let Some((propagation_channel_id, propagation_message_id)) = replying_to
|
||||||
.data
|
.data
|
||||||
.propagation_channel_id
|
.propagation_channel_id
|
||||||
.zip(replying_to.data.propagation_message_id)
|
.zip(replying_to.data.propagation_message_id)
|
||||||
{
|
{
|
||||||
let (display_name, avatar_url) =
|
let (display_name, avatar_url) = if let Some(mask) = &replying_to.data.author_mask {
|
||||||
if let Some(mask) = &replying_to.data.author_mask {
|
(
|
||||||
(
|
if i64_to_u64(propagation_channel_id) != event.channel_id.get() {
|
||||||
if i64_to_u64(propagation_channel_id) != event.channel_id.get() {
|
get_mask_display_name(mask)
|
||||||
get_mask_display_name(mask)
|
|
||||||
} else {
|
|
||||||
format!(
|
|
||||||
"{} ({})",
|
|
||||||
get_mask_display_name(mask),
|
|
||||||
replying_to.data.author_name
|
|
||||||
)
|
|
||||||
},
|
|
||||||
get_mask_avatar_url(mask).expect("Failed to get mask avatar URL"),
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
(
|
format!(
|
||||||
replying_to.data.author_name.clone(),
|
"{} ({})",
|
||||||
replying_to.data.author_avatar_url.clone(),
|
get_mask_display_name(mask),
|
||||||
|
replying_to.data.author_name
|
||||||
)
|
)
|
||||||
};
|
},
|
||||||
|
get_mask_avatar_url(mask).expect("Failed to get mask avatar URL"),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(
|
||||||
|
replying_to.data.author_name.clone(),
|
||||||
|
replying_to.data.author_avatar_url.clone(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
let message_link = if i64_to_u64(propagation_channel_id) == channel.id {
|
let message_link = if i64_to_u64(propagation_channel_id) == channel.id {
|
||||||
format!(
|
format!(
|
||||||
"https://discord.com/channels/{}/{}/{}",
|
"https://discord.com/channels/{}/{}/{}",
|
||||||
opposite_channel.server_id, opposite_channel.id, replying_to.message_id
|
opposite_channel.server_id, opposite_channel.id, replying_to.message_id
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
format!(
|
||||||
|
"https://discord.com/channels/{}/{}/{}",
|
||||||
|
channel.server_id, propagation_channel_id, propagation_message_id
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let replying_to_user = User::get_by_id(replying_to.author_id, &rt.state.db).await?;
|
||||||
|
|
||||||
|
embeds.push(
|
||||||
|
EmbedBuilder::new()
|
||||||
|
.author(
|
||||||
|
EmbedAuthorBuilder::new(format!("Replying to {display_name}",))
|
||||||
|
.icon_url(ImageSource::url(avatar_url).unwrap())
|
||||||
|
.url(message_link),
|
||||||
)
|
)
|
||||||
} else {
|
.color(if replying_to.data.author_mask.is_some() {
|
||||||
format!(
|
COLOR_WHITE
|
||||||
"https://discord.com/channels/{}/{}/{}",
|
} else {
|
||||||
channel.server_id, propagation_channel_id, propagation_message_id
|
replying_to_user
|
||||||
)
|
.and_then(|i| i.color.map(|c| c as u32))
|
||||||
};
|
.unwrap_or(COLOR_WHITE)
|
||||||
|
})
|
||||||
let replying_to_user =
|
.description(ellipse(moderate_message(&replying_to.data.content).0, 100))
|
||||||
User::get_by_id(replying_to.author_id, &rt.state.db).await?;
|
.build(),
|
||||||
|
);
|
||||||
embeds.push(
|
|
||||||
EmbedBuilder::new()
|
|
||||||
.author(
|
|
||||||
EmbedAuthorBuilder::new(format!("Replying to {display_name}",))
|
|
||||||
.icon_url(ImageSource::url(avatar_url).unwrap())
|
|
||||||
.url(message_link),
|
|
||||||
)
|
|
||||||
.color(if replying_to.data.author_mask.is_some() {
|
|
||||||
COLOR_WHITE
|
|
||||||
} else {
|
|
||||||
replying_to_user
|
|
||||||
.and_then(|i| i.color.map(|c| c as u32))
|
|
||||||
.unwrap_or(COLOR_WHITE)
|
|
||||||
})
|
|
||||||
.description(ellipse(moderate_message(&replying_to.data.content).0, 100))
|
|
||||||
.build(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if participant.is_masked {
|
if participant.is_masked {
|
||||||
@@ -440,14 +440,12 @@ impl OnMessageHandler<State, Extras> for CallMessageHandler {
|
|||||||
error: ApiError::General(error),
|
error: ApiError::General(error),
|
||||||
..
|
..
|
||||||
} = e.kind()
|
} = e.kind()
|
||||||
{
|
&& error.code == 10015 {
|
||||||
if error.code == 10015 {
|
|
||||||
log::debug!("Webhook not found, updating...");
|
log::debug!("Webhook not found, updating...");
|
||||||
opposite_channel
|
opposite_channel
|
||||||
.update_webhook(&rt.state.db, &rt.http)
|
.update_webhook(&rt.state.db, &rt.http)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -624,8 +622,8 @@ impl OnMessageDeleteHandler<State, Extras> for CallMessageDeleteHandler {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(propagation_message_id) = message.data.propagation_message_id {
|
if let Some(propagation_message_id) = message.data.propagation_message_id
|
||||||
if let Some((webhook_id, webhook_token)) = opposite_channel
|
&& let Some((webhook_id, webhook_token)) = opposite_channel
|
||||||
.webhook_id
|
.webhook_id
|
||||||
.zip(opposite_channel.webhook_token)
|
.zip(opposite_channel.webhook_token)
|
||||||
{
|
{
|
||||||
@@ -641,7 +639,6 @@ impl OnMessageDeleteHandler<State, Extras> for CallMessageDeleteHandler {
|
|||||||
|
|
||||||
message.insert(&rt.state.db).await?;
|
message.insert(&rt.state.db).await?;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,12 @@ qiga
|
|||||||
qigas
|
qigas
|
||||||
niqa
|
niqa
|
||||||
niqas
|
niqas
|
||||||
|
niqer
|
||||||
|
niqers
|
||||||
nqa
|
nqa
|
||||||
nqas
|
nqas
|
||||||
|
nqer
|
||||||
|
nlga
|
||||||
nlger
|
nlger
|
||||||
nlgers
|
nlgers
|
||||||
ngiga
|
ngiga
|
||||||
|
|||||||
@@ -399,6 +399,16 @@ pub trait Rule: Send + Sync + Debug {
|
|||||||
/// [`(Vec<String>, Vec<String>)`] - The list of detected rule violations in the original
|
/// [`(Vec<String>, Vec<String>)`] - The list of detected rule violations in the original
|
||||||
/// (first vector) and normalized (second vector) message.
|
/// (first vector) and normalized (second vector) message.
|
||||||
fn detect(&self, original: &str, normalized: &str) -> (Vec<String>, Vec<String>);
|
fn detect(&self, original: &str, normalized: &str) -> (Vec<String>, Vec<String>);
|
||||||
|
|
||||||
|
/// Whether this rule should be ignored for moderators. This is used to avoid censoring
|
||||||
|
/// messages from moderators, while still allowing them to be detected and logged from regular
|
||||||
|
/// users.
|
||||||
|
///
|
||||||
|
/// Returns:
|
||||||
|
/// [`bool`] - Whether this rule should be ignored for moderators.
|
||||||
|
fn ignore_for_moderators(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses a file containing phrases to be detected by rules.
|
/// Parses a file containing phrases to be detected by rules.
|
||||||
@@ -624,6 +634,10 @@ impl Rule for AdvertisingRule {
|
|||||||
|
|
||||||
(detections, vec![])
|
(detections, vec![])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ignore_for_moderators(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -760,6 +774,10 @@ impl Rule for LinksRule {
|
|||||||
|
|
||||||
(detections, vec![])
|
(detections, vec![])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ignore_for_moderators(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The list of moderation rules.
|
/// The list of moderation rules.
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
[
|
[
|
||||||
"Hey! I'm Payphone's dev, Nyeki. I know you've seen this message quite some times already, it's annoying to you and it sucks for me, yet I really want to keep Payphone going. We need to pay for hosting in two days, and we're nowhere near the amount we need. I'll have to shut down Payphone forever if we can't make it to $60 by the end of the month, $45 in two days. We're volunteering to develop and moderate Payphone daily for free, but we can't do it without your help. If you can spare a few dollars, please consider [donating to Payphone](<https://ko-fi.com/payphonedev>). Every little bit helps, and it would really mean the world to me. Thank you so much in advance for your support, I really appreciate every single cent I get of help to keep Payphone up and running."
|
"Thank you X and Anonymous Person for your support! We have covered next month's hosting costs."
|
||||||
]
|
]
|
||||||
@@ -26,10 +26,12 @@ use crate::{
|
|||||||
/// [`Result<User, ArgumentParser>`] - The user from the DB, or an [`ArgumentParsingError`] ready
|
/// [`Result<User, ArgumentParser>`] - The user from the DB, or an [`ArgumentParsingError`] ready
|
||||||
/// to be returned by the parser.
|
/// to be returned by the parser.
|
||||||
async fn get_user_by_id(id: u64, db: &Session) -> Result<User, ArgumentParsingError> {
|
async fn get_user_by_id(id: u64, db: &Session) -> Result<User, ArgumentParsingError> {
|
||||||
let Some(user) = User::get_by_id(id, db).await? else {
|
let user = User::get_by_id(id, db).await?;
|
||||||
return Err(ArgumentParsingError::InvalidArgument);
|
|
||||||
};
|
match user {
|
||||||
Ok(user)
|
Some(user) => Ok(user),
|
||||||
|
None => Err(ArgumentParsingError::InvalidArgument),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetches the user from the message's reply and falls back to the command executor.
|
/// Fetches the user from the message's reply and falls back to the command executor.
|
||||||
@@ -45,20 +47,19 @@ async fn get_user_by_id(id: u64, db: &Session) -> Result<User, ArgumentParsingEr
|
|||||||
async fn user_from_reply_or_command_executor(
|
async fn user_from_reply_or_command_executor(
|
||||||
ctx: &CommandContext<'_, State, Extras>,
|
ctx: &CommandContext<'_, State, Extras>,
|
||||||
) -> Result<User, ArgumentParsingError> {
|
) -> Result<User, ArgumentParsingError> {
|
||||||
if let Some(referenced) = &ctx.event.referenced_message {
|
if let Some(referenced) = &ctx.event.referenced_message
|
||||||
if !referenced.author.system.unwrap_or(false) {
|
&& !referenced.author.system.unwrap_or(false)
|
||||||
if referenced.author.bot {
|
{
|
||||||
if let Some(message) =
|
if referenced.author.bot
|
||||||
Message::get_by_propagation_message_id(referenced.id.get(), &ctx.rt.state.db)
|
&& let Some(message) =
|
||||||
.await?
|
Message::get_by_propagation_message_id(referenced.id.get(), &ctx.rt.state.db)
|
||||||
{
|
.await?
|
||||||
return get_user_by_id(message.author_id, &ctx.rt.state.db).await;
|
{
|
||||||
}
|
return get_user_by_id(message.author_id, &ctx.rt.state.db).await;
|
||||||
}
|
|
||||||
|
|
||||||
// If the replied message's author is not a bot or system user, use them.
|
|
||||||
return get_user_by_id(referenced.author.id.get(), &ctx.rt.state.db).await;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the replied message's author is not a bot or system user, use them.
|
||||||
|
return get_user_by_id(referenced.author.id.get(), &ctx.rt.state.db).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
// fallback to command executor
|
// fallback to command executor
|
||||||
|
|||||||
Reference in New Issue
Block a user