Skip to content

Commit 5a90099

Browse files
committed
feat(handlers): add maintenance mode checks for commands and DMs
1 parent d7dfaba commit 5a90099

2 files changed

Lines changed: 149 additions & 2 deletions

File tree

rustmail/src/handlers/guild_interaction_handler.rs

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ use crate::prelude::config::*;
33
use crate::prelude::features::*;
44
use crate::prelude::modules::*;
55
use crate::prelude::types::*;
6-
use serenity::all::{Context, EventHandler, Interaction};
6+
use crate::utils::{MessageBuilder, defer_response};
7+
use serenity::all::{Context, EventHandler, Interaction, Permissions};
78
use std::sync::Arc;
9+
use std::sync::atomic::{AtomicBool, Ordering};
810
use tokio::sync::watch::Receiver;
911

1012
#[derive(Clone)]
@@ -13,6 +15,7 @@ pub struct InteractionHandler {
1315
pub registry: Arc<CommandRegistry>,
1416
pub shutdown: Arc<Receiver<bool>>,
1517
pub pagination: PaginationStore,
18+
pub maintenance_mode: Arc<AtomicBool>,
1619
}
1720

1821
impl InteractionHandler {
@@ -21,16 +24,59 @@ impl InteractionHandler {
2124
registry: Arc<CommandRegistry>,
2225
shutdown: Receiver<bool>,
2326
pagination: PaginationStore,
27+
maintenance_mode: Arc<AtomicBool>,
2428
) -> Self {
2529
Self {
2630
config: Arc::new(config.clone()),
2731
registry,
2832
shutdown: Arc::new(shutdown),
2933
pagination,
34+
maintenance_mode,
3035
}
3136
}
3237
}
3338

39+
async fn is_interaction_user_maintenance_exempt(
40+
ctx: &Context,
41+
guild_id: serenity::all::GuildId,
42+
user_id: serenity::all::UserId,
43+
config: &Config,
44+
) -> bool {
45+
if config.bot.panel_super_admin_users.contains(&user_id.get()) {
46+
return true;
47+
}
48+
49+
let member = match guild_id.member(&ctx.http, user_id).await {
50+
Ok(m) => m,
51+
Err(_) => return false,
52+
};
53+
54+
if !config.bot.panel_super_admin_roles.is_empty() {
55+
for role_id in &member.roles {
56+
if config.bot.panel_super_admin_roles.contains(&role_id.get()) {
57+
return true;
58+
}
59+
}
60+
}
61+
62+
let guild = match guild_id.to_partial_guild(&ctx.http).await {
63+
Ok(g) => g,
64+
Err(_) => return false,
65+
};
66+
67+
if guild.owner_id == user_id {
68+
return true;
69+
}
70+
71+
member.roles.iter().any(|role_id| {
72+
guild
73+
.roles
74+
.get(role_id)
75+
.map(|role| role.permissions.contains(Permissions::ADMINISTRATOR))
76+
.unwrap_or(false)
77+
})
78+
}
79+
3480
#[async_trait::async_trait]
3581
impl EventHandler for InteractionHandler {
3682
async fn interaction_create(&self, ctx: Context, interaction: Interaction) {
@@ -65,6 +111,33 @@ impl EventHandler for InteractionHandler {
65111
}
66112
}
67113
Interaction::Command(command) => {
114+
if self.maintenance_mode.load(Ordering::Relaxed) {
115+
if let Some(guild_id) = command.guild_id {
116+
if !is_interaction_user_maintenance_exempt(
117+
&ctx,
118+
guild_id,
119+
command.user.id,
120+
&self.config,
121+
)
122+
.await
123+
{
124+
defer_response(&ctx, &command).await.ok();
125+
126+
let _ = MessageBuilder::system_message(&ctx, &self.config)
127+
.translated_content(
128+
"status.maintenance_mode_active",
129+
None,
130+
Some(command.user.id),
131+
command.guild_id.map(|g| g.get()),
132+
)
133+
.await
134+
.send_interaction_followup(&command, true)
135+
.await;
136+
return;
137+
}
138+
}
139+
}
140+
68141
let ctx = ctx.clone();
69142
let command = command.clone();
70143
let options = command.data.options().clone();

rustmail/src/handlers/guild_messages_handler.rs

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@ use crate::prelude::modules::*;
77
use crate::prelude::types::*;
88
use crate::prelude::utils::*;
99
use crate::wrap_command;
10-
use serenity::all::{GuildId, MessageId, UserId};
10+
use serenity::all::{GuildId, MessageId, Permissions, UserId};
1111
use serenity::{
1212
all::{ChannelId, Context, EventHandler, Message, MessageUpdateEvent},
1313
async_trait,
1414
};
1515
use std::collections::HashSet;
16+
use std::sync::atomic::{AtomicBool, Ordering};
1617
use std::sync::{LazyLock, Mutex};
1718
use std::{collections::HashMap, future::Future, pin::Pin, sync::Arc};
1819
use tokio::sync::Mutex as AsyncMutex;
@@ -39,6 +40,7 @@ pub struct GuildMessagesHandler {
3940
pub registry: Arc<CommandRegistry>,
4041
pub shutdown: Arc<Receiver<bool>>,
4142
pub pagination: PaginationStore,
43+
pub maintenance_mode: Arc<AtomicBool>,
4244
}
4345

4446
impl GuildMessagesHandler {
@@ -47,13 +49,15 @@ impl GuildMessagesHandler {
4749
registry: Arc<CommandRegistry>,
4850
shutdown: Receiver<bool>,
4951
pagination: PaginationStore,
52+
maintenance_mode: Arc<AtomicBool>,
5053
) -> Self {
5154
let h = Self {
5255
config: Arc::new(config.clone()),
5356
commands: Arc::new(AsyncMutex::new(HashMap::new())),
5457
registry,
5558
shutdown: Arc::new(shutdown),
5659
pagination,
60+
maintenance_mode,
5761
};
5862

5963
let mut lock = h.commands.lock().await;
@@ -198,10 +202,68 @@ async fn manage_incoming_message(
198202
Ok(())
199203
}
200204

205+
async fn is_user_maintenance_exempt(ctx: &Context, msg: &Message, config: &Config) -> bool {
206+
let user_id = msg.author.id.get();
207+
208+
if config.bot.panel_super_admin_users.contains(&user_id) {
209+
return true;
210+
}
211+
212+
let guild_id = match msg.guild_id {
213+
Some(id) => id,
214+
None => return false,
215+
};
216+
217+
let member = match guild_id.member(&ctx.http, msg.author.id).await {
218+
Ok(m) => m,
219+
Err(_) => return false,
220+
};
221+
222+
if !config.bot.panel_super_admin_roles.is_empty() {
223+
for role_id in &member.roles {
224+
if config.bot.panel_super_admin_roles.contains(&role_id.get()) {
225+
return true;
226+
}
227+
}
228+
}
229+
230+
let guild = match guild_id.to_partial_guild(&ctx.http).await {
231+
Ok(g) => g,
232+
Err(_) => return false,
233+
};
234+
235+
if guild.owner_id == msg.author.id {
236+
return true;
237+
}
238+
239+
member.roles.iter().any(|role_id| {
240+
guild
241+
.roles
242+
.get(role_id)
243+
.map(|role| role.permissions.contains(Permissions::ADMINISTRATOR))
244+
.unwrap_or(false)
245+
})
246+
}
247+
201248
#[async_trait]
202249
impl EventHandler for GuildMessagesHandler {
203250
async fn message(&self, ctx: Context, msg: Message) {
204251
if msg.guild_id.is_none() {
252+
if self.maintenance_mode.load(Ordering::Relaxed) {
253+
let _ = MessageBuilder::system_message(&ctx, &self.config)
254+
.translated_content(
255+
"status.maintenance_mode_active_user",
256+
None,
257+
Some(msg.author.id),
258+
None,
259+
)
260+
.await
261+
.to_user(msg.author.id)
262+
.send(true)
263+
.await;
264+
return;
265+
}
266+
205267
if let Err(error) = manage_incoming_message(&ctx, &msg, &self.config).await {
206268
if let Some(error_handler) = &self.config.error_handler {
207269
let _ = error_handler
@@ -222,6 +284,18 @@ impl EventHandler for GuildMessagesHandler {
222284
command_name = &message_content[self.config.command.prefix.len()..i];
223285
}
224286

287+
if self.maintenance_mode.load(Ordering::Relaxed) {
288+
if !is_user_maintenance_exempt(&ctx, &msg, &self.config).await {
289+
let _ = MessageBuilder::system_message(&ctx, &self.config)
290+
.translated_content("status.maintenance_mode_active", None, None, None)
291+
.await
292+
.to_channel(msg.channel_id)
293+
.send(true)
294+
.await;
295+
return;
296+
}
297+
}
298+
225299
let commands_lock = self.commands.lock().await;
226300

227301
if let Some(command_func) = commands_lock.get(command_name)

0 commit comments

Comments
 (0)