Allow server administrators to manage roles on their own server.
authorCMDR furrycat <elite@furrycat.net>
Thu, 10 Jan 2019 14:01:39 +0000 (14:01 +0000)
committerCMDR furrycat <elite@furrycat.net>
Thu, 10 Jan 2019 14:01:39 +0000 (14:01 +0000)
plugin/role/role.py

index acaa011..ab4bfb1 100644 (file)
@@ -114,12 +114,13 @@ class Role(DBConnection):
     else:
       await cat.yelp(message.channel)
 
-  async def can_manage_roles(self, author, channel, command):
+  async def can_manage_roles(self, author, channel, command, server = None, hiss = True):
     if command in ['manage', 'unmanage']:
-      if bot.is_admin(author):
+      if bot.is_admin(author, server):
         return True
       else:
-        await cat.hiss(channel)
+        if hiss:
+          await cat.hiss(channel)
         return False
     log.debug('Anyone can attempt to assign or unassign roles.')
     return True
@@ -141,75 +142,69 @@ class Role(DBConnection):
       yield ManagedRole(dict(row))
     self.close_db()
 
-  def get_managed_role(self, role):
+  def get_managed_role(self, role, as_managed = False):
     managed_roles = list(self.get_managed_roles(role))
     if managed_roles is None or not len(managed_roles):
       log.info('Role {} on {} is not managed'.format(role.name, role.server.name))
       return None
     return managed_roles[0]
 
-  async def find_role(self, message, role_name, as_managed = False):
+  async def find_role(self, message, role_name, command = False):
     role = await bot.parse_role(role_name, author = message.author)
     if not isinstance(role, discord.role.Role):
-      log.info('Failed to find server for role {} a role'.format(role_name))
+      log.info('Failed to find server for role {}'.format(role_name))
       await bot.say(message.channel, '?')
-      return None
+      return (None, None, None)
 
     if role.is_everyone:
       log.info("Can't make &everyone assignable!")
       await bot.say(message.channel, 'everyone?')
-      return None
+      return (None, None, None)
 
     if not bot.shared_with(message.author, role):
-      await cat.hiss(message.channel)
-      return None
+      return (None, None, cat.hiss)
 
     managed_role = self.get_managed_role(role)
     if managed_role is None:
-      await cat.yelp(message.channel)
-      return None
-
-    if as_managed:
-      return managed_role
+      return (None, None, cat.yelp)
 
     member = role.server.get_member(message.author.id)
+    can_manage = True
+    if command is not None:
+      can_manage = await self.can_manage_roles(message.author, message.channel, command, role.server)
 
     if managed_role.above_role_id:
       above_role = self.get_role_on_server(managed_role.above_role_id, role.server)
       if not above_role:
         log.warning("Can't find above role {} on server {}".format(managed_role.above_role_id, role.server.name))
-        await cat.yelp(message.channel)
-        return None
-      if member.top_role <= above_role:
+        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.server.name))
-          await cat.hiss(message.channel)
-          return None
+          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.server)
       if not below_role:
         log.warning("Can't find below role {} on server {}".format(managed_role.below_role_id, role.server.name))
-        await cat.yelp(message.channel)
-        return None
-      if member.top_role >= below_role:
+        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.server.name))
-          await cat.hiss(message.channel)
-          return None
+          return (role, managed_role, cat.hiss)
 
     log.debug('Managing role {} for {}'.format(role.name, member.name))
-    return role
+    return (role, managed_role, cat.hiss if not can_manage else None)
 
   async def list_roles(self, message, args):
-    result = await self.can_manage_roles(message.author, message.channel, 'manage')
-    if not result:
-      return
-
     roles = []
     hiss = False
     for managed_role in self.get_managed_roles():
       server = client.get_server(managed_role.server_id)
+      result = await self.can_manage_roles(message.author, message.channel, 'manage', server, False)
+      if not result:
+        hiss = True
+        continue
       if not bot.shared_with(message.author, server):
         log.debug('Not showing managed role {} on server {} to user {} not on that server'.format(managed_role.role_id, server.name, message.author.name))
         hiss = True
@@ -232,10 +227,6 @@ class Role(DBConnection):
       await cat.shrug(message.channel)
 
   async def manage_role(self, message, args):
-    result = await self.can_manage_roles(message.author, message.channel, 'manage')
-    if not result:
-      return
-
     if not len(args):
       await bot.say(message.channel, 'role?')
       return
@@ -246,6 +237,9 @@ class Role(DBConnection):
       log.error("Can't find role {} to manage!".format(args[0]))
       await cat.yelp(message.channel)
       return
+    result = await self.can_manage_roles(message.author, message.channel, 'manage', role.server)
+    if not result:
+      return
     if role.is_everyone:
       await bot.say(message.channel, "Can't manage everyone!")
       return
@@ -344,16 +338,18 @@ class Role(DBConnection):
       await cat.yelp(message.channel)
 
   async def unmanage_role(self, message, args):
-    result = await self.can_manage_roles(message.author, message.channel, 'unmanage')
-    if not result:
-      return
-
     if not len(args):
       await bot.say(message.channel, 'role?')
       return
 
-    managed_role = await self.find_role(message, args[0], True)
-    if not managed_role:
+    role, managed_role, method = await self.find_role(message, args[0], 'unmanage')
+    if method is not None:
+      await method(message.channel)
+    if not role:
+      return
+
+    result = await self.can_manage_roles(message.author, message.channel, 'unmanage', role.server)
+    if not result:
       return
 
     if not self.delete_from_table(client, 'roles', managed_role.id):
@@ -361,18 +357,20 @@ class Role(DBConnection):
       await cat.yelp(message.channel)
 
   async def assign_role(self, message, args):
-    result = await self.can_manage_roles(message.author, message.channel, 'assign')
-    if not result:
-      return
-
     if not len(args):
       await bot.say(message.channel, 'role?')
       return
 
-    role = await self.find_role(message, ' '.join(args))
+    role, managed_role, method = await self.find_role(message, ' '.join(args))
+    if method is not None:
+      await method(message.channel)
     if not role:
       return
 
+    result = await self.can_manage_roles(message.author, message.channel, 'assign', role.server)
+    if not result:
+      return
+
     member = role.server.get_member(message.author.id)
     if role in member.roles:
       log.info('Member {} already has role {} on {}'.format(member.name, role.name, role.server.name))
@@ -387,18 +385,20 @@ class Role(DBConnection):
       await cat.yelp(message.channel)
 
   async def unassign_role(self, message, args):
-    result = await self.can_manage_roles(message.author, message.channel, 'unassign')
-    if not result:
-      return
-
     if not len(args):
       await bot.say(message.channel, 'role?')
       return
 
-    role = await self.find_role(message, ' '.join(args))
+    role, managed_role, method = await self.find_role(message, ' '.join(args))
+    if method is not None:
+      await method(message.channel)
     if not role:
       return
 
+    result = await self.can_manage_roles(message.author, message.channel, 'unassign', role.server)
+    if not result:
+      return
+
     member = role.server.get_member(message.author.id)
     if role not in member.roles:
       log.info("Member {} doesn't have role {} on {}".format(member.name, role.name, role.server.name))