Tweak role permissions
authorCMDR furrycat <elite@furrycat.net>
Tue, 11 May 2021 07:30:19 +0000 (09:30 +0200)
committerCMDR furrycat <elite@furrycat.net>
Tue, 11 May 2021 07:30:19 +0000 (09:30 +0200)
Only list roles to users who have permission to assign them.
Show above and below roles in list output.

plugins/role/__init__.py

index cd44f45..ddfcc8d 100644 (file)
@@ -188,7 +188,30 @@ class Role(DBConnection):
       return None
     return managed_roles[0]
 
-  async def find_role(self, role_name, message = None, member = None, server = None, command = False):
+  def complain_if_cannot_assign_role(self, member, managed_role, role, verb = None):
+    if managed_role.above_role_id:
+      above_role = self.get_role_on_server(managed_role.above_role_id, role.guild)
+      if not above_role:
+        log.warning("Can't find above role {} on server {}".format(managed_role.above_role_id, role.guild.name))
+        return (None, None, cat.yelp)
+      if member.top_role <= above_role:
+        if member.top_role < above_role or not managed_role.above_inclusive:
+          log.info('Member {} needs at least role {} to {} {} on {}'.format(member.name, above_role.name, verb, role.name, role.guild.name))
+          return (role, managed_role, cat.hiss)
+
+    if managed_role.below_role_id:
+      below_role = self.get_role_on_server(managed_role.below_role_id, role.guild)
+      if not below_role:
+        log.warning("Can't find below role {} on server {}".format(managed_role.below_role_id, role.guild.name))
+        return (None, None, cat.yelp)
+      if member.top_role >= below_role:
+        if member.top_role > below_role or not managed_role.below_inclusive:
+          log.info('Member {} needs at least role {} to {} {} on {}'.format(member.name, below_role.name, verb, role.name, role.guild.name))
+          return (role, managed_role, cat.hiss)
+
+    return (role, managed_role, None)
+
+  async def find_role(self, role_name, message = None, member = None, server = None, command = None):
     author = message.author if message is not None else member
     role = await bot.parse_role(role_name, author = author)
     if not isinstance(role, discord.role.Role):
@@ -216,32 +239,17 @@ class Role(DBConnection):
     if command is not None:
       can_manage = await self.can_manage_roles(author, message.channel if message is not None else None, command, role.guild)
 
-    if managed_role.above_role_id:
-      above_role = self.get_role_on_server(managed_role.above_role_id, role.guild)
-      if not above_role:
-        log.warning("Can't find above role {} on server {}".format(managed_role.above_role_id, role.guild.name))
-        return (None, None, cat.yelp)
-      if command is None and member.top_role <= above_role:
-        if member.top_role < above_role or not above_inclusive:
-          log.info('Member {} needs at least role {} to assign {} on {}'.format(member.name, above_role.name, role.name, role.guild.name))
-          return (role, managed_role, cat.hiss)
-
-    if managed_role.below_role_id:
-      below_role = self.get_role_on_server(managed_role.below_role_id, role.guild)
-      if not below_role:
-        log.warning("Can't find below role {} on server {}".format(managed_role.below_role_id, role.guild.name))
-        return (None, None, cat.yelp)
-      if command is None and member.top_role >= below_role:
-        if member.top_role > below_role or not below_inclusive:
-          log.info('Member {} needs at least role {} to assign {} on {}'.format(member.name, below_role.name, role.name, role.guild.name))
-          return (role, managed_role, cat.hiss)
+    complaint = self.complain_if_cannot_assign_role(member, managed_role, role, command or 'assign')
+    if complaint[2]:
+      return complaint
 
     log.debug('Managing role {} for {}'.format(role.name, member.name))
     return (role, managed_role, cat.hiss if not can_manage else None)
 
   async def list_roles(self, message, args):
-    roles = []
     hiss = False
+    server_admin = {}
+    output = []
     for managed_role in self.get_managed_roles():
       server = bot.get_server(managed_role.server_id)
       result = await self.can_manage_roles(message.author, message.channel, 'list', server, False)
@@ -260,10 +268,32 @@ class Role(DBConnection):
       if not role:
         log.warning("Can't find role {} on server {}".format(managed_role.role_id, server.name))
         continue
-      roles.append(role)
+      is_admin = server_admin.get(managed_role.server_id)
+      if is_admin is None:
+        is_admin = await self.can_manage_roles(message.author, message.channel, 'manage', server, False)
+        server_admin[managed_role.server_id] = is_admin
+      parts = ['"{}" on {}'.format(role.name, role.guild.name) if bot.is_private(message.channel) else role.name]
+      if is_admin:
+        above_role = None
+        below_role = None
+        if managed_role.above_role_id:
+          above_role = self.get_role_on_server(managed_role.above_role_id, role.guild)
+        if managed_role.below_role_id:
+          below_role = self.get_role_on_server(managed_role.below_role_id, role.guild)
+        if above_role and below_role and above_role.id == below_role.id:
+          parts.append('_only_ {}'.format(above_role.name))
+        elif above_role:
+          parts.append('_above_ {}'.format(above_role.name))
+        elif below_role:
+          parts.append('_below_ {}'.format(below_role.name))
+      else:
+        complaint = self.complain_if_cannot_assign_role(server.get_member(message.author.id), managed_role, role, 'list')
+        if complaint[2]:
+          continue
+      output.append(' '.join(parts))
 
-    if len(roles):
-      await bot.say_many(message.channel, ['"{}" on {}'.format(role.name, role.guild.name) if bot.is_private(message.channel) else role.name for role in roles])
+    if len(output):
+      await bot.say_many(message.channel, output)
     elif hiss:
       await cat.hiss(message.channel)
     else:
@@ -388,7 +418,8 @@ class Role(DBConnection):
     role, managed_role, method = await self.find_role(' '.join(args), message = message, command = 'unmanage')
     if method is not None:
       await method(message.channel)
-    if not role:
+      return
+    elif not role:
       return
 
     result = await self.can_manage_roles(message.author, message.channel, 'unmanage', role.guild)
@@ -407,7 +438,8 @@ class Role(DBConnection):
     role, managed_role, method = await self.find_role(' '.join(args), message = message)
     if method is not None:
       await method(message.channel)
-    if not role:
+      return
+    elif not role:
       return
 
     result = await self.can_manage_roles(message.author, message.channel, 'assign', role.guild)
@@ -435,6 +467,7 @@ class Role(DBConnection):
     role, managed_role, method = await self.find_role(' '.join(args), message = message)
     if method is not None:
       await method(message.channel)
+      return
     if not role:
       return