From b091bd5c4908bdd99281bfe7b0239fe72c7c32d6 Mon Sep 17 00:00:00 2001 From: Luna Mendes Date: Mon, 1 Oct 2018 18:07:29 -0300 Subject: [PATCH] Add hazmat impl for OP 8 Request Guild Members - storage: add Storage.guild_exists, Storage.query_members --- litecord/gateway/websocket.py | 53 +++++++++++++++++++++++++++++++++++ litecord/storage.py | 24 ++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/litecord/gateway/websocket.py b/litecord/gateway/websocket.py index fe4f654..9ffa57f 100644 --- a/litecord/gateway/websocket.py +++ b/litecord/gateway/websocket.py @@ -496,6 +496,59 @@ class GatewayWebsocket: await self._resume(range(seq, state.seq)) await self.dispatch('RESUMED', {}) + async def _req_guild_members(self, guild_id: str, user_ids: List[int], + query: str, limit: int): + try: + guild_id = int(guild_id) + except (TypeError, ValueError): + return + + limit = limit or 1000 + exists = await self.storage.get_guild(guild_id) + + if not exists: + return + + # limit user_ids to 1000 possible members + user_ids = user_ids[:1000] + + # assumption: requesting user_ids means + # we don't do query. + if user_ids: + members = await self.storage.get_member_multi(guild_id, user_ids) + mids = [m['user']['id'] for m in members] + not_found = [uid for uid in user_ids if uid not in mids] + + await self.dispatch('GUILD_MEMBERS_CHUNK', { + 'guild_id': str(guild_id), + 'members': members, + 'not_found': not_found, + }) + + return + + # do the search + result = await self.storage.query_members(guild_id, query, limit) + await self.dispatch('GUILD_MEMBERS_CHUNK', { + 'guild_id': str(guild_id), + 'members': result + }) + + async def handle_8(self, data: Any): + """Handle OP 8 Request Guild Members.""" + gids = data['guild_id'] + uids, query, limit = data.get('user_ids', []), \ + data.get('query', ''), \ + data.get('limit', 0) + + if isinstance(gids, str): + await self._req_guild_members(gids, uids, query, limit) + return + + for gid in gids: + # ignore uids on multiple guilds + await self._req_guild_members(gid, [], query, limit) + async def _guild_sync(self, guild_id: int): members = await self.storage.get_member_data(guild_id) member_ids = [int(m['user']['id']) for m in members] diff --git a/litecord/storage.py b/litecord/storage.py index 1e77e44..648ddc1 100644 --- a/litecord/storage.py +++ b/litecord/storage.py @@ -200,6 +200,20 @@ class Storage: return members + async def query_members(self, guild_id: int, query: str, limit: int): + """Find members with usernames matching the given query.""" + mids = await self.db.fetch(f""" + SELECT user_id + FROM members + JOIN users ON members.user_id = users.id + WHERE members.guild_id = $1 + AND users.username LIKE '%'||$2 + LIMIT {limit} + """, guild_id, query) + + members = await self.get_member_multi(guild_id, mids) + return members + async def _channels_extra(self, row) -> Dict: """Fill in more information about a channel.""" channel_type = row['type'] @@ -364,6 +378,16 @@ class Storage: return {**guild, **extra} + async def guild_exists(self, guild_id: int): + """Return if a given guild ID exists.""" + owner_id = await self.db.fetch(""" + SELECT owner_id + FROM guilds + WHERE id = $1 + """, guild_id) + + return owner_id is not None + async def get_member_ids(self, guild_id: int) -> List[int]: rows = await self.db.fetch(""" SELECT user_id