diff options
| author | 2019-01-03 20:20:53 +0100 | |
|---|---|---|
| committer | 2019-01-03 20:20:53 +0100 | |
| commit | 759766f2c20aee3c707c0de02b0c6c1a336ff2b5 (patch) | |
| tree | cf154e437be12c85cfed6eddd64a74c1d2eee787 | |
| parent | Remove obsolete `user is None` check. (diff) | |
Add documentation strings and comments.
| -rw-r--r-- | bot/cogs/sync/syncers.py | 81 | 
1 files changed, 71 insertions, 10 deletions
diff --git a/bot/cogs/sync/syncers.py b/bot/cogs/sync/syncers.py index 92c866357..66e041f49 100644 --- a/bot/cogs/sync/syncers.py +++ b/bot/cogs/sync/syncers.py @@ -1,7 +1,7 @@  import itertools  import logging  from collections import namedtuple -from typing import Dict, Set, ValuesView +from typing import Dict, Set, Tuple  from discord import Guild  from discord.ext.commands import Bot @@ -14,9 +14,11 @@ Role = namedtuple('Role', ('id', 'name', 'colour', 'permissions'))  User = namedtuple('User', ('id', 'name', 'discriminator', 'avatar_hash', 'roles', 'in_guild')) -def get_roles_for_sync(guild_roles: Set[Role], api_roles: Set[Role]) -> Set[Role]: +def get_roles_for_sync( +        guild_roles: Set[Role], api_roles: Set[Role] +) -> Tuple[Set[Role], Set[Role]]:      """ -    Determine which roles should be updated on the site. +    Determine which roles should be created or updated on the site.      Arguments:          guild_roles (Set[Role]): @@ -26,14 +28,21 @@ def get_roles_for_sync(guild_roles: Set[Role], api_roles: Set[Role]) -> Set[Role              Roles that were retrieved from the API at startup.      Returns: -        Set[Role]: -            Roles to be sent to the site for an update or insert. +        Tuple[Set[Role], Set[Role]]: +            A tuple with two elements. The first element represents +            roles to be created on the site, meaning that they were +            present on the cached guild but not on the API. The second +            element represents roles to be updated, meaning they were +            present on both the cached guild and the API but non-ID +            fields have changed inbetween.      """      guild_role_ids = {role.id for role in guild_roles}      api_role_ids = {role.id for role in api_roles}      new_role_ids = guild_role_ids - api_role_ids +    # New roles are those which are on the cached guild but not on the +    # API guild, going by the role ID. We need to send them in for creation.      roles_to_create = {role for role in guild_roles if role.id in new_role_ids}      roles_to_update = guild_roles - api_roles - roles_to_create      return roles_to_create, roles_to_update @@ -42,9 +51,21 @@ def get_roles_for_sync(guild_roles: Set[Role], api_roles: Set[Role]) -> Set[Role  async def sync_roles(bot: Bot, guild: Guild):      """      Synchronize roles found on the given `guild` with the ones on the API. + +    Arguments: +        bot (discord.ext.commands.Bot): +            The bot instance that we're running with. + +        guild (discord.Guild): +            The guild instance from the bot's cache +            to synchronize roles with.      """      roles = await bot.api_client.get('bot/roles') + +    # Pack API roles and guild roles into one common format, +    # which is also hashable. We need hashability to be able +    # to compare these easily later using sets.      api_roles = {Role(**role_dict) for role_dict in roles}      guild_roles = {          Role( @@ -54,6 +75,7 @@ async def sync_roles(bot: Bot, guild: Guild):          for role in guild.roles      }      roles_to_create, roles_to_update = get_roles_for_sync(guild_roles, api_roles) +      for role in roles_to_create:          log.info(f"Creating role `{role.name}` on the site.")          await bot.api_client.post( @@ -81,9 +103,28 @@ async def sync_roles(bot: Bot, guild: Guild):  def get_users_for_sync(          guild_users: Dict[int, User], api_users: Dict[int, User] -) -> ValuesView[User]: +) -> Tuple[Set[User], Set[User]]:      """ -    Obtain a set of users to update on the website. +    Determine which users should be created or updated on the website. + +    Arguments: +        guild_users (Dict[int, User]): +            A mapping of user IDs to user data, populated from the +            guild cached on the running bot instance. + +        api_users (Dict[int, User]): +            A mapping of user IDs to user data, populated from the API's +            current inventory of all users. + +    Returns: +        Tuple[Set[User], Set[User]]: +            Two user sets as a tuple. The first element represents users +            to be created on the website, these are users that are present +            in the cached guild data but not in the API at all, going by +            their ID. The second element represents users to update. It is +            populated by users which are present on both the API and the +            guild, but where the attribute of a user on the API is not +            equal to the attribute of the user on the guild.      """      users_to_create = set() @@ -94,14 +135,20 @@ def get_users_for_sync(          if guild_user is not None:              if api_user != guild_user:                  users_to_update.add(guild_user) -        else: -            # User left + +        elif api_user.in_guild: +            # The user is known on the API but not the guild, and the +            # API currently specifies that the user is a member of the guild. +            # This means that the user has left since the last sync. +            # Update the `in_guild` attribute of the user on the site +            # to signify that the user left.              new_api_user = api_user._replace(in_guild=False)              users_to_update.add(new_api_user)      new_user_ids = set(guild_users.keys()) - set(api_users.keys())      for user_id in new_user_ids: -        # User joined +        # The user is known on the guild but not on the API. This means +        # that the user has joined since the last sync. Create it.          new_user = guild_users[user_id]          users_to_create.add(new_user) @@ -112,9 +159,21 @@ async def sync_users(bot: Bot, guild: Guild):      """      Synchronize users found on the given      `guild` with the ones on the API. + +    Arguments: +        bot (discord.ext.commands.Bot): +            The bot instance that we're running with. + +        guild (discord.Guild): +            The guild instance from the bot's cache +            to synchronize roles with.      """      current_users = await bot.api_client.get('bot/users') + +    # Pack API users and guild users into one common format, +    # which is also hashable. We need hashability to be able +    # to compare these easily later using sets.      api_users = {          user_dict['id']: User(              roles=tuple(sorted(user_dict.pop('roles'))), @@ -130,7 +189,9 @@ async def sync_users(bot: Bot, guild: Guild):          )          for member in guild.members      } +      users_to_create, users_to_update = get_users_for_sync(guild_users, api_users) +      log.info("Creating a total of `%d` users on the site.", len(users_to_create))      for user in users_to_create:          await bot.api_client.post(  |