1
0
Fork 1
mirror of https://github.com/TeamOctolings/Octobot.git synced 2025-01-31 09:09:00 +03:00

Use MemberData roles when checking permissions & interactions (#312)

Closes #311 

This change fixes unexpected behavior when a member's Discord roles get
desynchronized with their MemberData roles (e.g. when a member gets
role-muted). In addition this results in less API requests being made
when there are cache misses (commands should execute faster)

---------

Signed-off-by: Octol1ttle <l1ttleofficial@outlook.com>
This commit is contained in:
Octol1ttle 2024-05-23 18:21:52 +05:00 committed by GitHub
parent d03e2504fc
commit ea9302e185
Signed by: GitHub
GPG key ID: B5690EEEBB952194

View file

@ -20,18 +20,17 @@ public sealed class AccessControlService
_userApi = userApi; _userApi = userApi;
} }
private static bool CheckPermission(IEnumerable<IRole> roles, GuildData data, Snowflake memberId, private static bool CheckPermission(IEnumerable<IRole> roles, GuildData data, MemberData memberData,
IGuildMember member,
DiscordPermission permission) DiscordPermission permission)
{ {
var moderatorRole = GuildSettings.ModeratorRole.Get(data.Settings); var moderatorRole = GuildSettings.ModeratorRole.Get(data.Settings);
if (!moderatorRole.Empty() && data.GetOrCreateMemberData(memberId).Roles.Contains(moderatorRole.Value)) if (!moderatorRole.Empty() && memberData.Roles.Contains(moderatorRole.Value))
{ {
return true; return true;
} }
return roles return roles
.Where(r => member.Roles.Contains(r.ID)) .Where(r => memberData.Roles.Contains(r.ID.Value))
.Any(r => .Any(r =>
r.Permissions.HasPermission(permission) r.Permissions.HasPermission(permission)
); );
@ -80,38 +79,23 @@ public sealed class AccessControlService
return Result<string?>.FromError(botResult); return Result<string?>.FromError(botResult);
} }
var botMemberResult = await _guildApi.GetGuildMemberAsync(guildId, bot.ID, ct);
if (!botMemberResult.IsDefined(out var botMember))
{
return Result<string?>.FromError(botMemberResult);
}
var targetMemberResult = await _guildApi.GetGuildMemberAsync(guildId, targetId, ct);
if (!targetMemberResult.IsDefined(out var targetMember))
{
return Result<string?>.FromSuccess(null);
}
var rolesResult = await _guildApi.GetGuildRolesAsync(guildId, ct); var rolesResult = await _guildApi.GetGuildRolesAsync(guildId, ct);
if (!rolesResult.IsDefined(out var roles)) if (!rolesResult.IsDefined(out var roles))
{ {
return Result<string?>.FromError(rolesResult); return Result<string?>.FromError(rolesResult);
} }
var data = await _data.GetData(guildId, ct);
var targetData = data.GetOrCreateMemberData(targetId);
var botData = data.GetOrCreateMemberData(bot.ID);
if (interacterId is null) if (interacterId is null)
{ {
return CheckInteractions(action, guild, roles, targetMember, botMember, botMember); return CheckInteractions(action, guild, roles, targetData, botData, botData);
} }
var interacterResult = await _guildApi.GetGuildMemberAsync(guildId, interacterId.Value, ct); var interacterData = data.GetOrCreateMemberData(interacterId.Value);
if (!interacterResult.IsDefined(out var interacter)) var hasPermission = CheckPermission(roles, data, interacterData,
{
return Result<string?>.FromError(interacterResult);
}
var data = await _data.GetData(guildId, ct);
var hasPermission = CheckPermission(roles, data, interacterId.Value, interacter,
action switch action switch
{ {
"Ban" => DiscordPermission.BanMembers, "Ban" => DiscordPermission.BanMembers,
@ -121,31 +105,26 @@ public sealed class AccessControlService
}); });
return hasPermission return hasPermission
? CheckInteractions(action, guild, roles, targetMember, botMember, interacter) ? CheckInteractions(action, guild, roles, targetData, botData, interacterData)
: Result<string?>.FromSuccess($"UserCannot{action}Members".Localized()); : Result<string?>.FromSuccess($"UserCannot{action}Members".Localized());
} }
private static Result<string?> CheckInteractions( private static Result<string?> CheckInteractions(
string action, IGuild guild, IReadOnlyList<IRole> roles, IGuildMember targetMember, IGuildMember botMember, string action, IGuild guild, IReadOnlyList<IRole> roles, MemberData targetData, MemberData botData,
IGuildMember interacter) MemberData interacterData)
{ {
if (!targetMember.User.IsDefined(out var targetUser)) if (botData.Id == targetData.Id)
{
return new ArgumentNullError(nameof(targetMember.User));
}
if (botMember.User == targetMember.User)
{ {
return Result<string?>.FromSuccess($"UserCannot{action}Bot".Localized()); return Result<string?>.FromSuccess($"UserCannot{action}Bot".Localized());
} }
if (targetUser.ID == guild.OwnerID) if (targetData.Id == guild.OwnerID)
{ {
return Result<string?>.FromSuccess($"UserCannot{action}Owner".Localized()); return Result<string?>.FromSuccess($"UserCannot{action}Owner".Localized());
} }
var targetRoles = roles.Where(r => targetMember.Roles.Contains(r.ID)).ToList(); var targetRoles = roles.Where(r => targetData.Roles.Contains(r.ID.Value)).ToList();
var botRoles = roles.Where(r => botMember.Roles.Contains(r.ID)); var botRoles = roles.Where(r => botData.Roles.Contains(r.ID.Value));
var targetBotRoleDiff = targetRoles.MaxOrDefault(r => r.Position) - botRoles.MaxOrDefault(r => r.Position); var targetBotRoleDiff = targetRoles.MaxOrDefault(r => r.Position) - botRoles.MaxOrDefault(r => r.Position);
if (targetBotRoleDiff >= 0) if (targetBotRoleDiff >= 0)
@ -153,7 +132,7 @@ public sealed class AccessControlService
return Result<string?>.FromSuccess($"BotCannot{action}Target".Localized()); return Result<string?>.FromSuccess($"BotCannot{action}Target".Localized());
} }
var interacterRoles = roles.Where(r => interacter.Roles.Contains(r.ID)); var interacterRoles = roles.Where(r => interacterData.Roles.Contains(r.ID.Value));
var targetInteracterRoleDiff var targetInteracterRoleDiff
= targetRoles.MaxOrDefault(r => r.Position) - interacterRoles.MaxOrDefault(r => r.Position); = targetRoles.MaxOrDefault(r => r.Position) - interacterRoles.MaxOrDefault(r => r.Position);
return targetInteracterRoleDiff < 0 return targetInteracterRoleDiff < 0