Make permissions checking not depend on the cache

This commit is contained in:
2025-08-21 19:19:02 -03:00
parent 408f0223a2
commit e28f11d9bb
3 changed files with 48 additions and 21 deletions
+47 -19
View File
@@ -1,5 +1,9 @@
use async_trait::async_trait;
use twilight_model::guild::Permissions;
use twilight_model::{
guild::Permissions,
id::{Id, marker::RoleMarker},
};
use twilight_util::permission_calculator::PermissionCalculator;
use crate::{
framework::commands::{CommandError, context::CommandContext, permissions::Permission},
@@ -31,28 +35,52 @@ pub struct ServerModeratorPermission;
impl Permission<State> for ServerModeratorPermission {
async fn check(&self, ctx: &CommandContext<State>) -> Result<bool, CommandError> {
if let Some(guild_id) = ctx.event.guild_id {
let permissions = ctx
let Some(guild) = ctx.rt.cache.guild(guild_id) else {
log::warn!("Could not get guild for ID {guild_id}!");
return Ok(false);
};
let member = ctx
.rt
.cache
.permissions()
.root(ctx.event.author.id, guild_id);
.http
.guild_member(guild_id, ctx.event.author.id)
.await
.map_err(CommandError::DiscordAPIFailed)?
.model()
.await
.map_err(CommandError::DiscordDeserializationFailed)?;
if let Ok(permissions) = permissions {
let guild = ctx
.rt
.cache
.guild(guild_id)
.ok_or(CommandError::CacheStateInconsistent)?;
let Some(everyone_role) = ctx.rt.cache.role(guild_id.cast()) else {
log::warn!("Could not get @everyone role for guild ID {guild_id}!");
Ok(permissions
.contains(Permissions::MANAGE_CHANNELS | Permissions::MANAGE_MESSAGES)
|| guild.owner_id() == ctx.event.author.id)
} else {
Err(CommandError::CacheStateInconsistent)
}
} else {
Ok(true)
return Ok(false);
};
let member_roles: Vec<(Id<RoleMarker>, Permissions)> = member
.roles
.into_iter()
.filter_map(|role_id| {
ctx.rt
.cache
.role(role_id)
.map(|role| (role.id, role.permissions))
})
.collect();
let calculator = PermissionCalculator::new(
guild_id,
ctx.event.author.id,
everyone_role.permissions,
&member_roles,
)
.owner_id(guild.owner_id());
return Ok(calculator.root().contains(Permissions::MANAGE_CHANNELS | Permissions::MANAGE_MESSAGES));
}
// DMs channel, the user has all permissions.
Ok(true)
}
async fn on_handle_denied(&self, ctx: &CommandContext<State>) -> Result<(), CommandError> {