async def get_user_details(self, args): username, platform_id = (None,) * 2 if not args: raise InvalidCommandError("Username is required") if args[-1] == "-platform": raise InvalidCommandError( f"Platform must be specified like `-platform {list(constants.PLATFORM_EMOJI_MAP.keys())}`" ) if "-platform" in args: platform_name = args[-1].lower() username = "******".join(args[0:-2]) platform_id = constants.PLATFORM_MAP.get(platform_name) if not platform_id: raise InvalidCommandError( f"Invalid platform `{platform_name}` was specified" ) else: username = "******".join(args) if not username: raise InvalidCommandError("Username is required") return username, platform_id
async def get_bungie_details(self, username, bungie_id=None, platform_id=None): membership_id = None username_lower = username.lower() if bungie_id: try: player = await execute_pydest( self.bot.destiny.api.get_membership_data_by_id(bungie_id), self.bot.redis) except pydest.PydestException as e: log_message = f"Could not find Destiny player for {username}" log.error(f"{log_message}\n\n{e}\n\n{player}") raise InvalidCommandError(log_message) for membership in player['Response']['destinyMemberships']: if membership['membershipType'] != constants.PLATFORM_BUNGIE: membership_id = membership['membershipId'] platform_id = membership['membershipType'] break else: try: player = await execute_pydest( self.bot.destiny.api.search_destiny_player( platform_id, username), self.bot.redis) except pydest.PydestException as e: log_message = f"Could not find Destiny player for {username}" log.error(f"{log_message}\n\n{e}\n\n{player}") raise InvalidCommandError(log_message) if len(player['Response']) == 1: membership = player['Response'][0] if membership['displayName'].lower() == username_lower: membership_id = membership['membershipId'] platform_id = membership['membershipType'] else: for membership in player['Response']: display_name = membership['displayName'].lower() membership_type = membership['membershipType'] if membership_type == platform_id and display_name == username_lower: membership_id = membership['membershipId'] platform_id = membership['membershipType'] break return membership_id, platform_id
async def invite(self, ctx, *args): """Invite a member by username (Admin only, requires registration)""" manager = MessageManager(ctx) username, platform_id = await self.get_user_details(args) member_db = await self.get_member_db(ctx, username) admin_db = await self.bot.database.get_member_by_discord_id( ctx.author.id) clan_db = await self.get_admin_group(ctx) if not platform_id and clan_db.platform: platform_id = clan_db.platform else: raise InvalidCommandError( "Platform was not specified and clan default platform is not set" ) bungie_id = None if member_db: bungie_id = member_db.bungie_id membership_id, platform_id = await self.get_bungie_details( username, bungie_id, platform_id) res = None try: res = await execute_pydest( self.bot.destiny.api.group_invite_member( group_id=clan_db.clan_id, membership_type=platform_id, membership_id=membership_id, message=f"Join my clan {clan_db.name}!", access_token=admin_db.bungie_access_token), self.bot.redis) except pydest.PydestTokenException: tokens = await self.refresh_admin_tokens(manager, admin_db) res = await execute_pydest( self.bot.destiny.api.group_invite_member( group_id=clan_db.clan_id, membership_type=platform_id, membership_id=membership_id, message=f"Join my clan {clan_db.name}!", access_token=tokens['access_token']), self.bot.redis) admin_db.bungie_access_token = tokens['access_token'] admin_db.bungie_refresh_token = tokens['refresh_token'] await self.bot.database.update(admin_db) if not res: raise RuntimeError("Unexpected empty response from the Bungie API") if res['ErrorStatus'] == 'ClanTargetDisallowsInvites': message = f"User **{username}** has disabled clan invites" elif res['ErrorStatus'] != 'Success': message = f"Could not invite **{username}**" log.info(f"Could not invite '{username}': {res}") else: message = f"Invited **{username}** to clan **{clan_db.name}**" return await manager.send_message(message, mention=False, clean=False)
def predicate(ctx): try: game_mode = ctx.message.content.split()[2] except IndexError: raise InvalidCommandError( f"Missing game mode, supported are `{', '.join(SUPPORTED_GAME_MODES.keys())}`") if game_mode in SUPPORTED_GAME_MODES.keys(): return True raise InvalidGameModeError(game_mode, SUPPORTED_GAME_MODES.keys())
async def invite(self, ctx, *args): """Invite a member by username (Admin only, requires registration)""" manager = MessageManager(ctx) username, platform_id = await self.get_user_details(args) member_db = await self.get_member_db(ctx, username) admin_db = await self.bot.database.get_member_by_discord_id( ctx.author.id, include_clan=False ) clan_db = await self.get_admin_group(ctx) if not platform_id and clan_db.platform: platform_id = clan_db.platform else: raise InvalidCommandError( "Platform was not specified and clan default platform is not set" ) bungie_id = None if member_db: bungie_id = member_db.bungie_id membership_id, platform_id = await self.get_bungie_details( username, bungie_id, platform_id ) res = await execute_pydest_auth( self.bot.ext_conns, self.bot.destiny.api.group_invite_member, admin_db, manager, group_id=clan_db.clan_id, membership_type=platform_id, membership_id=membership_id, message=f"Join my clan {clan_db.name}!", access_token=admin_db.bungie_access_token, ) if res.error_status == "ClanTargetDisallowsInvites": message = f"User **{username}** has disabled clan invites" elif res.error_status == "ClanMaximumMembershipReached": message = f"Could not invite **{username}**, clan is full" elif res.error_status != "Success": message = f"Could not invite **{username}**" log.info(f"Could not invite '{username}': {res}") else: message = f"Invited **{username}** to clan **{clan_db.name}**" return await manager.send_message(message, mention=False, clean=False)
async def approve(self, ctx, *args): """Approve a pending member (Admin only, requires registration)""" manager = MessageManager(ctx) username, platform_id = await self.get_user_details(args) member_db = await self.get_member_db(ctx, username) admin_db = await self.bot.database.get_member_by_discord_id( ctx.author.id, include_clan=False ) clan_db = await self.get_admin_group(ctx) if clan_db.platform: platform_id = clan_db.platform elif not platform_id: raise InvalidCommandError( "Platform was not specified and clan default platform is not set" ) bungie_id = None if member_db: bungie_id = member_db.bungie_id membership_id, platform_id = await self.get_bungie_details( username, bungie_id, platform_id ) res = await execute_pydest_auth( self.bot.ext_conns, self.bot.destiny.api.group_approve_pending_member, admin_db, manager, group_id=clan_db.clan_id, membership_type=platform_id, membership_id=membership_id, message=f"Welcome to {clan_db.name}!", access_token=admin_db.bungie_access_token, ) if res.error_status != "Success": message = f"Could not approve **{username}**" log.info(f"Could not approve '{username}': {res}") else: message = f"Approved **{username}** as a member of clan **{clan_db.name}**" return await manager.send_message(message, mention=False, clean=False)
async def refresh_user_tokens(ctx, manager, auth_user_db): tokens = await execute_pydest(ctx['destiny'].api.refresh_oauth_token, auth_user_db.bungie_refresh_token, return_type=DestinyTokenResponse) if tokens.error: log.warning(f"{tokens.error_description} Registration is needed") user_info = await register( manager, "Your registration token has expired and re-registration is needed." ) if not user_info: raise InvalidCommandError( "I'm not sure where you went. We can try this again later.") tokens = { token: user_info.get(token) for token in [tokens.access_token, tokens.refresh_token] } return tokens
async def refresh_admin_tokens(self, manager, admin_db): tokens = await execute_pydest( self.bot.destiny.api.refresh_oauth_token( admin_db.bungie_refresh_token), self.bot.redis) if 'error' in tokens: log.warning( f"{tokens['error_description']} Registration is needed") user_info = await register( manager, "Your registration token has expired and re-registration is needed." ) if not user_info: raise InvalidCommandError( "I'm not sure where you went. We can try this again later." ) tokens = { token: user_info.get(token) for token in ['access_token', 'refresh_token'] } return tokens
async def get_bungie_details(self, username, bungie_id=None, platform_id=None): membership_id = None username_lower = username.lower() if bungie_id: try: player = await execute_pydest( self.bot.destiny.api.get_membership_data_by_id, bungie_id, return_type=DestinyMembershipResponse, ) except pydest.PydestException as e: log_message = f"Could not find Destiny player for {username}" log.error(f"{log_message}\n\n{e}\n\n{username}") raise InvalidCommandError(log_message) for membership in player.response.destiny_memberships: if membership.membership_type != constants.PLATFORM_BUNGIE: membership_id = membership.membership_id platform_id = membership.membership_type break else: player = await execute_pydest( self.bot.destiny.api.search_destiny_player, platform_id, username, return_type=DestinySearchPlayerResponse, ) if not player.response: log_message = f"Could not find Destiny player for {username}" log.error(f"{log_message}\n\n{player}") raise InvalidCommandError(log_message) if len(player.response) == 1: membership = player.response[0] if ( membership.display_name.lower() == username_lower and membership.membership_type == platform_id ): membership_id = membership.membership_id platform_id = membership.membership_type else: membership_orig = membership profile = await execute_pydest( self.bot.destiny.api.get_membership_data_by_id, membership.membership_id, return_type=DestinyMembershipResponse, ) for membership in profile.response.destiny_memberships: if membership.display_name.lower() == username_lower: user_matches = True break if user_matches: membership_id = membership_orig.membership_id platform_id = membership_orig.membership_type else: for membership in player.response: display_name = membership.display_name.lower() membership_type = membership.membership_type if ( membership_type == platform_id and display_name == username_lower ): membership_id = membership.membership_id platform_id = membership.membership_type break return membership_id, platform_id