diff --git a/Cargo.lock b/Cargo.lock index 62c7f8e..dfe48a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1437,7 +1437,7 @@ checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" [[package]] name = "payphone" -version = "4.2.6" +version = "4.2.8" dependencies = [ "async-trait", "axum", diff --git a/Cargo.toml b/Cargo.toml index 1aa1a29..ec6d7f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "payphone" -version = "4.2.6" +version = "4.2.8" edition = "2024" default-run = "payphone" diff --git a/src/database/models.rs b/src/database/models.rs index 4d10b95..b3f296a 100644 --- a/src/database/models.rs +++ b/src/database/models.rs @@ -1570,6 +1570,43 @@ impl UserIncident { && self.r#type == UserIncidentType::Ban } + pub async fn get_by_user_and_incident_id( + user_id: u64, + incident_id: u64, + session: &Session, + ) -> Result, DatabaseError> { + let user_id = u64_to_i64(user_id); + let incident_id = u64_to_i64(incident_id); + + let result = session + .query_unpaged( + r#" + SELECT + user_id, + incident_id, + report_id, + type, + message, + reason, + created_by_id, + created_at, + expires_at, + duration + FROM + payphone.user_incidents + WHERE + user_id = ? AND incident_id = ?; + "#, + (user_id, incident_id), + ) + .await + .map_err(DatabaseError::QueryError)? + .into_rows_result() + .map_err(|_| DatabaseError::ResultNotRows)?; + + get_single_row_from_result(&result).await + } + pub async fn get_for_user(user_id: u64, session: &Session) -> Result, DatabaseError> { let user_id = u64_to_i64(user_id); @@ -1655,4 +1692,20 @@ impl UserIncident { Ok(()) } + + pub async fn expire_by_user_and_incident_id( + user_id: u64, + incident_id: u64, + session: &Session, + ) -> Result<(), DatabaseError> { + let Some(mut incident) = + Self::get_by_user_and_incident_id(user_id, incident_id, session).await? + else { + return Ok(()); + }; + + incident.expires_at = Some(UtcDateTime::now()); + + incident.insert(session).await + } } diff --git a/src/framework/commands/mod.rs b/src/framework/commands/mod.rs index 414b505..eb10fc4 100644 --- a/src/framework/commands/mod.rs +++ b/src/framework/commands/mod.rs @@ -63,7 +63,7 @@ pub trait Command: Send + Sync + Debug { vec![] } - fn show_in_help(&self, rt: &Runtime, extras: &E) -> bool { + fn show_in_help(&self, _rt: &Runtime, _extras: &E) -> bool { true } diff --git a/src/groups/calls/events.rs b/src/groups/calls/events.rs index 2975da6..8b17406 100644 --- a/src/groups/calls/events.rs +++ b/src/groups/calls/events.rs @@ -90,7 +90,7 @@ impl OnMessageHandler for CallMessageHandler { &self, event: &MessageCreate, rt: Arc>, - extras: Arc>, + _extras: Arc>, ) -> EventResult { if event.author.bot || event.author.system.unwrap_or(false) { return Ok(()); diff --git a/src/groups/leveling/events.rs b/src/groups/leveling/events.rs index 5c40171..897abf9 100644 --- a/src/groups/leveling/events.rs +++ b/src/groups/leveling/events.rs @@ -46,7 +46,7 @@ impl OnMessageHandler for MessageLevelingHandler { &self, event: &MessageCreate, rt: Arc>, - extras: Arc>, + _extras: Arc>, ) -> EventResult { if event.author.bot || event.author.system.unwrap_or(false) { return Ok(()); diff --git a/src/groups/moderation/components.rs b/src/groups/moderation/components.rs index 2a8bddc..0a2f523 100644 --- a/src/groups/moderation/components.rs +++ b/src/groups/moderation/components.rs @@ -78,6 +78,60 @@ impl Button for CounterButton { } } +#[derive(Debug)] +pub struct ExpireIncidentButton { + pub user_id: u64, + pub incident_id: u64, + pub incident_index: usize, +} + +#[async_trait] +impl Button for ExpireIncidentButton { + fn id(&self) -> Option { + Some(format!("incidents:expire:{}", get_random_u64())) + } + + fn label(&self) -> Option { + Some("Expire Incident".into()) + } + + fn style(&self) -> ButtonStyle { + ButtonStyle::Danger + } + + fn disabled(&self) -> bool { + false + } + + async fn on_press( + &self, + ctx: InteractionContext, + ) -> Result<(), InteractionError> { + if !ctx.extras.user.is_moderator { + ctx.defer().await?; + return Ok(()); + } + + UserIncident::expire_by_user_and_incident_id( + self.user_id, + self.incident_id, + &ctx.rt.state.db, + ) + .await?; + + ctx.edit_original_message( + get_incident_page(self.user_id, &ctx.rt.state.db, self.incident_index) + .await + .inspect_err(|e| log::error!("Failed to get incident page: {e:?}"))? + .into(), + ) + .await + .inspect_err(|e| log::error!("Failed to edit original message: {e:?}"))?; + + Ok(()) + } +} + #[derive(Debug)] pub struct DeleteIncidentButton { pub user_id: u64, diff --git a/src/groups/moderation/embeds.rs b/src/groups/moderation/embeds.rs index 3986e55..11efe7d 100644 --- a/src/groups/moderation/embeds.rs +++ b/src/groups/moderation/embeds.rs @@ -48,7 +48,7 @@ pub fn incident_embed(incident: &UserIncident) -> Embed { incident .created_by_id .map(|id| format!("<@{id}>")) - .unwrap_or("Automod".into()), + .unwrap_or("Automatic Moderator".into()), )); if incident.r#type == UserIncidentType::Ban { @@ -81,7 +81,7 @@ pub fn incident_embed(incident: &UserIncident) -> Embed { incident .created_by_id .map(|id| format!("<@{id}>")) - .unwrap_or("Automod".into()), + .unwrap_or("Automatic Moderator".into()), )); if incident.r#type == UserIncidentType::Ban { diff --git a/src/groups/moderation/mod.rs b/src/groups/moderation/mod.rs index 4fc56be..dad38a0 100644 --- a/src/groups/moderation/mod.rs +++ b/src/groups/moderation/mod.rs @@ -1,11 +1,13 @@ use scylla::client::session::Session; use crate::{ - database::models::{DatabaseError, UserIncident}, + database::models::{DatabaseError, UserIncident, UserIncidentType}, extras::Extras, framework::messages::MessageBuilder, groups::moderation::{ - components::{ArrowIncidentButton, CounterButton, DeleteIncidentButton}, + components::{ + ArrowIncidentButton, CounterButton, DeleteIncidentButton, ExpireIncidentButton, + }, embeds::incident_embed, }, state::State, @@ -27,7 +29,7 @@ pub(super) async fn get_incident_page( incidents.sort_by(|a, b| b.created_at.cmp(&a.created_at)); if let Some(incident) = incidents.get(page_index) { - Ok(MessageBuilder::new() + let mut builder = MessageBuilder::new() .embed(incident_embed(incident)) .component( ArrowIncidentButton { @@ -55,15 +57,29 @@ pub(super) async fn get_incident_page( go_to: incidents.get(page_index + 1).map(|_| page_index + 1), }, 1, - ) - .component( - DeleteIncidentButton { + ); + + if incident.r#type == UserIncidentType::Ban { + builder = builder.component( + ExpireIncidentButton { incident_id: incident.incident_id, incident_index: page_index, user_id, }, - 1, - )) + 2, + ); + } + + builder = builder.component( + DeleteIncidentButton { + incident_id: incident.incident_id, + incident_index: page_index, + user_id, + }, + 2, + ); + + Ok(builder) } else { Ok(MessageBuilder::new().content("No incidents found for this user.")) }