mirror of
https://github.com/Cog-Creators/Red-DiscordBot.git
synced 2025-12-09 02:42:30 -05:00
[Mod] Added optional role hierarchy check
Toggleable with [p]modset hierarchy This enables a role hierarchy check before all moderation actions. If the mod doesn't have a role superior to the user's top role the action will be denied. Server owner and bot owner are exempt from the check.
This commit is contained in:
86
cogs/mod.py
86
cogs/mod.py
@@ -31,9 +31,10 @@ ACTIONS_CASES = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
default_settings = {
|
default_settings = {
|
||||||
"ban_mention_spam" : False,
|
"ban_mention_spam" : False,
|
||||||
"delete_repeats" : False,
|
"delete_repeats" : False,
|
||||||
"mod-log" : None
|
"mod-log" : None,
|
||||||
|
"respect_hierarchy" : False
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -111,14 +112,18 @@ class Mod:
|
|||||||
await send_cmd_help(ctx)
|
await send_cmd_help(ctx)
|
||||||
roles = settings.get_server(server).copy()
|
roles = settings.get_server(server).copy()
|
||||||
_settings = {**self.settings[server.id], **roles}
|
_settings = {**self.settings[server.id], **roles}
|
||||||
|
if "respect_hierarchy" not in _settings:
|
||||||
|
_settings["respect_hierarchy"] = default_settings["respect_hierarchy"]
|
||||||
if "delete_delay" not in _settings:
|
if "delete_delay" not in _settings:
|
||||||
_settings["delete_delay"] = -1
|
_settings["delete_delay"] = "Disabled"
|
||||||
|
|
||||||
msg = ("Admin role: {ADMIN_ROLE}\n"
|
msg = ("Admin role: {ADMIN_ROLE}\n"
|
||||||
"Mod role: {MOD_ROLE}\n"
|
"Mod role: {MOD_ROLE}\n"
|
||||||
"Mod-log: {mod-log}\n"
|
"Mod-log: {mod-log}\n"
|
||||||
"Delete repeats: {delete_repeats}\n"
|
"Delete repeats: {delete_repeats}\n"
|
||||||
"Ban mention spam: {ban_mention_spam}\n"
|
"Ban mention spam: {ban_mention_spam}\n"
|
||||||
"Delete delay: {delete_delay}\n"
|
"Delete delay: {delete_delay}\n"
|
||||||
|
"Respects hierarchy: {respect_hierarchy}"
|
||||||
"".format(**_settings))
|
"".format(**_settings))
|
||||||
await self.bot.say(box(msg))
|
await self.bot.say(box(msg))
|
||||||
|
|
||||||
@@ -278,6 +283,23 @@ class Mod:
|
|||||||
)
|
)
|
||||||
await self.bot.say(msg)
|
await self.bot.say(msg)
|
||||||
|
|
||||||
|
@modset.command(pass_context=True, no_pm=True)
|
||||||
|
@checks.serverowner_or_permissions()
|
||||||
|
async def hierarchy(self, ctx):
|
||||||
|
"""Toggles role hierarchy check for mods / admins"""
|
||||||
|
server = ctx.message.server
|
||||||
|
toggled = self.settings[server.id].get("respect_hierarchy",
|
||||||
|
default_settings["respect_hierarchy"])
|
||||||
|
if not toggled:
|
||||||
|
self.settings[server.id]["respect_hierarchy"] = True
|
||||||
|
await self.bot.say("Role hierarchy will be checked when "
|
||||||
|
"moderation commands are issued.")
|
||||||
|
else:
|
||||||
|
self.settings[server.id]["respect_hierarchy"] = False
|
||||||
|
await self.bot.say("Role hierarchy will be ignored when "
|
||||||
|
"moderation commands are issued.")
|
||||||
|
dataIO.save_json("data/mod/settings.json", self.settings)
|
||||||
|
|
||||||
@commands.command(no_pm=True, pass_context=True)
|
@commands.command(no_pm=True, pass_context=True)
|
||||||
@checks.admin_or_permissions(kick_members=True)
|
@checks.admin_or_permissions(kick_members=True)
|
||||||
async def kick(self, ctx, user: discord.Member, *, reason: str = None):
|
async def kick(self, ctx, user: discord.Member, *, reason: str = None):
|
||||||
@@ -289,6 +311,11 @@ class Mod:
|
|||||||
await self.bot.say("I cannot let you do that. Self-harm is "
|
await self.bot.say("I cannot let you do that. Self-harm is "
|
||||||
"bad \N{PENSIVE FACE}")
|
"bad \N{PENSIVE FACE}")
|
||||||
return
|
return
|
||||||
|
elif not self.is_allowed_by_hierarchy(server, author, user):
|
||||||
|
await self.bot.say("I cannot let you do that. You are "
|
||||||
|
"not higher than the user in the role "
|
||||||
|
"hierarchy.")
|
||||||
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await self.bot.kick(user)
|
await self.bot.kick(user)
|
||||||
@@ -319,6 +346,11 @@ class Mod:
|
|||||||
await self.bot.say("I cannot let you do that. Self-harm is "
|
await self.bot.say("I cannot let you do that. Self-harm is "
|
||||||
"bad \N{PENSIVE FACE}")
|
"bad \N{PENSIVE FACE}")
|
||||||
return
|
return
|
||||||
|
elif not self.is_allowed_by_hierarchy(server, author, user):
|
||||||
|
await self.bot.say("I cannot let you do that. You are "
|
||||||
|
"not higher than the user in the role "
|
||||||
|
"hierarchy.")
|
||||||
|
return
|
||||||
|
|
||||||
if days:
|
if days:
|
||||||
if days.isdigit():
|
if days.isdigit():
|
||||||
@@ -365,6 +397,11 @@ class Mod:
|
|||||||
await self.bot.say("I cannot let you do that. Self-harm is "
|
await self.bot.say("I cannot let you do that. Self-harm is "
|
||||||
"bad \N{PENSIVE FACE}")
|
"bad \N{PENSIVE FACE}")
|
||||||
return
|
return
|
||||||
|
elif not self.is_allowed_by_hierarchy(server, author, user):
|
||||||
|
await self.bot.say("I cannot let you do that. You are "
|
||||||
|
"not higher than the user in the role "
|
||||||
|
"hierarchy.")
|
||||||
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
invite = await self.bot.create_invite(server, max_age=3600*24)
|
invite = await self.bot.create_invite(server, max_age=3600*24)
|
||||||
@@ -433,10 +470,17 @@ class Mod:
|
|||||||
channel = ctx.message.channel
|
channel = ctx.message.channel
|
||||||
server = ctx.message.server
|
server = ctx.message.server
|
||||||
overwrites = channel.overwrites_for(user)
|
overwrites = channel.overwrites_for(user)
|
||||||
|
|
||||||
if overwrites.send_messages is False:
|
if overwrites.send_messages is False:
|
||||||
await self.bot.say("That user can't send messages in this "
|
await self.bot.say("That user can't send messages in this "
|
||||||
"channel.")
|
"channel.")
|
||||||
return
|
return
|
||||||
|
elif not self.is_allowed_by_hierarchy(server, author, user):
|
||||||
|
await self.bot.say("I cannot let you do that. You are "
|
||||||
|
"not higher than the user in the role "
|
||||||
|
"hierarchy.")
|
||||||
|
return
|
||||||
|
|
||||||
self._perms_cache[user.id][channel.id] = overwrites.send_messages
|
self._perms_cache[user.id][channel.id] = overwrites.send_messages
|
||||||
overwrites.send_messages = False
|
overwrites.send_messages = False
|
||||||
try:
|
try:
|
||||||
@@ -461,6 +505,13 @@ class Mod:
|
|||||||
"""Mutes user in the server"""
|
"""Mutes user in the server"""
|
||||||
author = ctx.message.author
|
author = ctx.message.author
|
||||||
server = ctx.message.server
|
server = ctx.message.server
|
||||||
|
|
||||||
|
if not self.is_allowed_by_hierarchy(server, author, user):
|
||||||
|
await self.bot.say("I cannot let you do that. You are "
|
||||||
|
"not higher than the user in the role "
|
||||||
|
"hierarchy.")
|
||||||
|
return
|
||||||
|
|
||||||
register = {}
|
register = {}
|
||||||
for channel in server.channels:
|
for channel in server.channels:
|
||||||
if channel.type != discord.ChannelType.text:
|
if channel.type != discord.ChannelType.text:
|
||||||
@@ -506,11 +557,20 @@ class Mod:
|
|||||||
async def channel_unmute(self, ctx, user : discord.Member):
|
async def channel_unmute(self, ctx, user : discord.Member):
|
||||||
"""Unmutes user in the current channel"""
|
"""Unmutes user in the current channel"""
|
||||||
channel = ctx.message.channel
|
channel = ctx.message.channel
|
||||||
|
author = ctx.message.author
|
||||||
|
server = ctx.message.server
|
||||||
overwrites = channel.overwrites_for(user)
|
overwrites = channel.overwrites_for(user)
|
||||||
|
|
||||||
if overwrites.send_messages:
|
if overwrites.send_messages:
|
||||||
await self.bot.say("That user doesn't seem to be muted "
|
await self.bot.say("That user doesn't seem to be muted "
|
||||||
"in this channel.")
|
"in this channel.")
|
||||||
return
|
return
|
||||||
|
elif not self.is_allowed_by_hierarchy(server, author, user):
|
||||||
|
await self.bot.say("I cannot let you do that. You are "
|
||||||
|
"not higher than the user in the role "
|
||||||
|
"hierarchy.")
|
||||||
|
return
|
||||||
|
|
||||||
if user.id in self._perms_cache:
|
if user.id in self._perms_cache:
|
||||||
old_value = self._perms_cache[user.id].get(channel.id)
|
old_value = self._perms_cache[user.id].get(channel.id)
|
||||||
else:
|
else:
|
||||||
@@ -542,11 +602,19 @@ class Mod:
|
|||||||
async def server_unmute(self, ctx, user : discord.Member):
|
async def server_unmute(self, ctx, user : discord.Member):
|
||||||
"""Unmutes user in the server"""
|
"""Unmutes user in the server"""
|
||||||
server = ctx.message.server
|
server = ctx.message.server
|
||||||
|
author = ctx.message.author
|
||||||
|
|
||||||
if user.id not in self._perms_cache:
|
if user.id not in self._perms_cache:
|
||||||
await self.bot.say("That user doesn't seem to have been muted with {0}mute commands. "
|
await self.bot.say("That user doesn't seem to have been muted with {0}mute commands. "
|
||||||
"Unmute them in the channels you want with `{0}unmute <user>`"
|
"Unmute them in the channels you want with `{0}unmute <user>`"
|
||||||
"".format(ctx.prefix))
|
"".format(ctx.prefix))
|
||||||
return
|
return
|
||||||
|
elif not self.is_allowed_by_hierarchy(server, author, user):
|
||||||
|
await self.bot.say("I cannot let you do that. You are "
|
||||||
|
"not higher than the user in the role "
|
||||||
|
"hierarchy.")
|
||||||
|
return
|
||||||
|
|
||||||
for channel in server.channels:
|
for channel in server.channels:
|
||||||
if channel.type != discord.ChannelType.text:
|
if channel.type != discord.ChannelType.text:
|
||||||
continue
|
continue
|
||||||
@@ -1306,6 +1374,16 @@ class Mod:
|
|||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def is_allowed_by_hierarchy(self, server, mod, user):
|
||||||
|
toggled = self.settings[server.id].get("respect_hierarchy",
|
||||||
|
default_settings["respect_hierarchy"])
|
||||||
|
is_special = mod == server.owner or mod.id == self.bot.settings.owner
|
||||||
|
|
||||||
|
if not toggled:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return mod.top_role.position > user.top_role.position or is_special
|
||||||
|
|
||||||
async def new_case(self, server, *, action, mod=None, user, reason=None, until=None, channel=None):
|
async def new_case(self, server, *, action, mod=None, user, reason=None, until=None, channel=None):
|
||||||
action_type = action.lower() + "_cases"
|
action_type = action.lower() + "_cases"
|
||||||
if not self.settings[server.id].get(action_type, default_settings[action_type]):
|
if not self.settings[server.id].get(action_type, default_settings[action_type]):
|
||||||
|
|||||||
Reference in New Issue
Block a user