Skip to content

Commit

Permalink
make PunishmentExpiry an event
Browse files Browse the repository at this point in the history
  • Loading branch information
www committed Oct 31, 2024
1 parent 0576130 commit 4d39ba0
Show file tree
Hide file tree
Showing 10 changed files with 209 additions and 253 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 27 additions & 10 deletions core/rust.bot_modules.core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod commands;
mod help;
mod modules;
mod ping;
mod punishment_expiry_task;
mod sandwich_status_task;
mod settings;
mod stats;
Expand Down Expand Up @@ -83,16 +84,32 @@ impl silverpelt::module::Module for Module {
}

fn background_tasks(&self) -> Vec<silverpelt::BackgroundTask> {
vec![(
botox::taskman::Task {
name: "Sandwich Status Task",
description: "Checks the status of the sandwich http server",
duration: std::time::Duration::from_secs(30),
enabled: true,
run: Box::new(move |ctx| sandwich_status_task::sandwich_status_task(ctx).boxed()),
},
|_ctx| (true, "Sandwich HTTP API is enabled".to_string()),
)]
vec![
(
botox::taskman::Task {
name: "Sandwich Status Task",
description: "Checks the status of the sandwich http server",
duration: std::time::Duration::from_secs(30),
enabled: true,
run: Box::new(move |ctx| {
sandwich_status_task::sandwich_status_task(ctx).boxed()
}),
},
|_ctx| (true, "Sandwich HTTP API is enabled".to_string()),
),
((
botox::taskman::Task {
name: "Punishment Expiry Task",
description: "Check for and dispatch events for expired punishments",
duration: std::time::Duration::from_secs(30),
enabled: true,
run: Box::new(move |ctx| {
punishment_expiry_task::punishment_expiry_task(ctx).boxed()
}),
},
|_ctx| (true, "Punishment Expiry Task is enabled".to_string()),
)),
]
}

fn config_options(&self) -> Vec<module_settings::types::ConfigOption> {
Expand Down
54 changes: 54 additions & 0 deletions core/rust.bot_modules.core/src/punishment_expiry_task.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
pub async fn punishment_expiry_task(
ctx: &serenity::all::client::Context,
) -> Result<(), silverpelt::Error> {
let data = ctx.data::<silverpelt::data::Data>();
let pool = &data.pool;

let punishments = silverpelt::punishments::GuildPunishment::get_expired(pool).await?;

let mut set = tokio::task::JoinSet::new();

let shard_count = data.props.shard_count().await?.try_into()?;
let shards = data.props.shards().await?;

for punishment in punishments {
let guild_id = punishment.guild_id;

// Ensure shard id
let shard_id = serenity::utils::shard_id(guild_id, shard_count);

if !shards.contains(&shard_id) {
continue;
}

// Dispatch event
let event = silverpelt::ar_event::AntiraidEvent::PunishmentExpire(punishment);

let event_handler_context =
std::sync::Arc::new(silverpelt::ar_event::EventHandlerContext {
event,
guild_id,
data: data.clone(),
serenity_context: ctx.clone(),
});

// Spawn task to dispatch event
set.spawn(silverpelt::ar_event::dispatch_event_to_modules(
event_handler_context,
));
}

while let Some(res) = set.join_next().await {
match res {
Ok(Ok(())) => {}
Ok(Err(e)) => {
log::error!("Error in temporary_punishment_task: {:?}", e);
}
Err(e) => {
log::error!("Error in temporary_punishment_task: {}", e);
}
}
}

Ok(())
}
22 changes: 8 additions & 14 deletions core/rust.bot_modules.hooks/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ pub(crate) async fn event_listener(ectx: &EventHandlerContext) -> Result<(), sil

Ok(())
}
AntiraidEvent::PunishmentCreate(ref punishments) => {
let punishment = serde_json::to_value(punishments)?;
AntiraidEvent::PunishmentCreate(ref punishment) => {
let punishment = serde_json::to_value(punishment)?;

dispatch_audit_log(
ctx,
Expand All @@ -126,21 +126,15 @@ pub(crate) async fn event_listener(ectx: &EventHandlerContext) -> Result<(), sil

Ok(())
}
AntiraidEvent::MemberVerify((user_id, ref data)) => {
AntiraidEvent::PunishmentExpire(ref punishment) => {
let punishment = serde_json::to_value(punishment)?;

dispatch_audit_log(
ctx,
&ectx.data,
"AR/MemberVerify",
"(Anti Raid) Member Verify",
{
let mut m = serde_json::Map::new();
m.insert(
"user_id".to_string(),
serde_json::Value::String(user_id.to_string()),
);
m.insert("data".to_string(), data.clone());
serde_json::Value::Object(m)
},
"AR/PunishmentExpire",
"(Anti Raid) Punishment Expired",
serde_json::to_value(punishment)?,
ectx.guild_id,
)
.await?;
Expand Down
4 changes: 2 additions & 2 deletions core/rust.bot_modules.hooks/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ impl silverpelt::module::ModuleEventListeners for EventHandler {

fn event_handler_filter(&self, event: &silverpelt::ar_event::AntiraidEvent) -> bool {
match event {
silverpelt::ar_event::AntiraidEvent::TrustedWebEvent((_event_name, _)) => true, // We need trusted web events
silverpelt::ar_event::AntiraidEvent::TrustedWebEvent(_) => true, // We need trusted web events
silverpelt::ar_event::AntiraidEvent::Discord(_) => true,
silverpelt::ar_event::AntiraidEvent::Custom(_) => true,
silverpelt::ar_event::AntiraidEvent::StingCreate(_) => true,
silverpelt::ar_event::AntiraidEvent::PunishmentCreate(_) => true,
silverpelt::ar_event::AntiraidEvent::MemberVerify(_) => true,
silverpelt::ar_event::AntiraidEvent::PunishmentExpire(_) => true,
}
}
}
1 change: 1 addition & 0 deletions core/rust.bot_modules.temporary_punishments/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ sandwich_driver = { path = "../rust.sandwich_driver" }
serde_json = "1.0"
sqlx = { version = "0.8", features = [ "runtime-tokio-rustls", "postgres", "chrono", "uuid", "json"] }
modules_ext = { path = "../rust.modules_ext" }
async-trait = "0.1.80"

[dependencies.serenity]
git = "https://github.com/Anti-Raid/serenity"
Expand Down
91 changes: 91 additions & 0 deletions core/rust.bot_modules.temporary_punishments/src/events.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
use silverpelt::ar_event::{AntiraidEvent, EventHandlerContext};

/// Temporary Punishments event listener
pub(crate) async fn event_listener(ectx: &EventHandlerContext) -> Result<(), silverpelt::Error> {
match ectx.event {
AntiraidEvent::PunishmentExpire(ref punishment) => {
let target_user_id = match punishment.target {
silverpelt::punishments::PunishmentTarget::User(user_id) => user_id,
_ => return Ok(()),
};

let cache_http = botox::cache::CacheHttpImpl::from_ctx(&ectx.serenity_context);

let bot_id = ectx.serenity_context.cache.current_user().id;

let mut current_user = match sandwich_driver::member_in_guild(
&cache_http,
&ectx.data.reqwest,
punishment.guild_id,
bot_id,
)
.await?
{
Some(user) => user,
None => {
sqlx::query!(
"UPDATE punishments SET duration = NULL, handle_log = $1 WHERE id = $2",
serde_json::json!({
"error": "Bot not in guild",
}),
punishment.id
)
.execute(&ectx.data.pool)
.await?;

return Ok(());
}
};

let permissions = current_user.permissions(&ectx.serenity_context.cache)?;

// Bot doesn't have permissions to unban
if !permissions.ban_members() {
sqlx::query!(
"UPDATE punishments SET duration = NULL, handle_log = $1 WHERE id = $2",
serde_json::json!({
"error": "Bot doesn't have permissions to unban",
}),
punishment.id
)
.execute(&ectx.data.pool)
.await?;
}

let reason = format!(
"Revert expired ban with reason={}, duration={:#?}",
punishment.reason, punishment.duration
);

let punishment_actions = silverpelt::punishments::get_punishment_actions_for_guild(
punishment.guild_id,
&ectx.data,
)
.await?;

let cpa_revert = silverpelt::punishments::from_punishment_action_string(
&punishment_actions,
&punishment.punishment,
)?;

cpa_revert
.revert(
&silverpelt::punishments::PunishmentActionData {
cache_http,
pool: ectx.data.pool.clone(),
reqwest: ectx.data.reqwest.clone(),
object_store: ectx.data.object_store.clone(),
},
target_user_id,
&mut current_user,
reason,
)
.await?;

Ok(())
}
_ => {
Ok(()) // Ignore non-discord events
}
}
}
38 changes: 23 additions & 15 deletions core/rust.bot_modules.temporary_punishments/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
pub mod tasks;

use futures_util::future::FutureExt;
pub mod events;

pub struct Module;

Expand All @@ -14,7 +12,7 @@ impl silverpelt::module::Module for Module {
}

fn description(&self) -> &'static str {
"Customizable setting and management of temporary punishments (tempbans/temp role removals). Most servers will not need to customize this"
"Simple default temporary punishment handling. Can be disabled for servers that want custom handling through e.g. hooks."
}

fn is_default_enabled(&self) -> bool {
Expand All @@ -25,20 +23,30 @@ impl silverpelt::module::Module for Module {
vec![]
}

fn background_tasks(&self) -> Vec<silverpelt::BackgroundTask> {
vec![(
botox::taskman::Task {
name: "Temporary Punishment Task",
description: "Handle expired punishments",
duration: std::time::Duration::from_secs(60),
enabled: true,
run: Box::new(move |ctx| tasks::temporary_punishment_task(ctx).boxed()),
},
|_ctx| (true, "Temporary Punishment Task is enabled".to_string()),
)]
fn event_listeners(&self) -> Option<Box<dyn silverpelt::module::ModuleEventListeners>> {
Some(Box::new(EventListener))
}

fn full_command_list(&self) -> Vec<silverpelt::module::CommandObj> {
modules_ext::create_full_command_list(self)
}
}

struct EventListener;

#[async_trait::async_trait]
impl silverpelt::module::ModuleEventListeners for EventListener {
async fn event_handler(
&self,
ctx: &silverpelt::ar_event::EventHandlerContext,
) -> Result<(), silverpelt::Error> {
events::event_listener(ctx).await
}

fn event_handler_filter(&self, event: &silverpelt::ar_event::AntiraidEvent) -> bool {
matches!(
event,
silverpelt::ar_event::AntiraidEvent::PunishmentExpire(_)
) // We only care about punishment expires
}
}
Loading

0 comments on commit 4d39ba0

Please sign in to comment.