From 63ab8ea0648b57fcb5af2827e6817998e6108483 Mon Sep 17 00:00:00 2001 From: Luna Date: Sun, 1 Sep 2019 17:31:24 -0300 Subject: [PATCH 1/3] add messages.flags column --- litecord/storage.py | 5 ++++- manage/cmd/migration/scripts/3_add_message_flags.sql | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 manage/cmd/migration/scripts/3_add_message_flags.sql diff --git a/litecord/storage.py b/litecord/storage.py index 58c7bd6..31d7da2 100644 --- a/litecord/storage.py +++ b/litecord/storage.py @@ -876,7 +876,7 @@ class Storage: row = await self.fetchrow_with_json(""" SELECT id::text, channel_id::text, author_id, content, created_at AS timestamp, edited_at AS edited_timestamp, - tts, mention_everyone, nonce, message_type, embeds + tts, mention_everyone, nonce, message_type, embeds, flags FROM messages WHERE id = $1 """, message_id) @@ -961,6 +961,9 @@ class Storage: if guild_id: res['guild_id'] = str(guild_id) + if res['flags'] is None: + res.pop('flags') + return res async def get_invite(self, invite_code: str) -> Optional[Dict]: diff --git a/manage/cmd/migration/scripts/3_add_message_flags.sql b/manage/cmd/migration/scripts/3_add_message_flags.sql new file mode 100644 index 0000000..319ccde --- /dev/null +++ b/manage/cmd/migration/scripts/3_add_message_flags.sql @@ -0,0 +1,2 @@ +ALTER TABLE messages + ADD COLUMN flags bigint DEFAULT NULL; From e0d253f36f1ebead76fbead39eee479f41f527f9 Mon Sep 17 00:00:00 2001 From: Luna Date: Sun, 1 Sep 2019 18:03:29 -0300 Subject: [PATCH 2/3] add message flags updating on suppress embeds --- litecord/blueprints/channels.py | 38 ++++++++++++++++++++++++++++++++- litecord/enums.py | 9 ++++++++ manage/cmd/users.py | 1 + 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/litecord/blueprints/channels.py b/litecord/blueprints/channels.py index 11c18a5..fa3310a 100644 --- a/litecord/blueprints/channels.py +++ b/litecord/blueprints/channels.py @@ -25,7 +25,7 @@ from quart import Blueprint, request, current_app as app, jsonify from logbook import Logger from litecord.auth import token_check -from litecord.enums import ChannelType, GUILD_CHANS, MessageType +from litecord.enums import ChannelType, GUILD_CHANS, MessageType, MessageFlags from litecord.errors import ChannelNotFound, Forbidden, BadRequest from litecord.schemas import ( validate, CHAN_UPDATE, CHAN_OVERWRITE, SEARCH_CHANNEL, GROUP_DM_UPDATE, @@ -616,6 +616,40 @@ async def _search_channel(channel_id): return jsonify(await search_result_from_list(rows)) +# NOTE that those functions stay here until some other +# route or code wants it. +async def _msg_set_flags(message_id: int, new_flags: int): + flags = await app.db.fetchval(""" + SELECT flags + FROM messages + WHERE id = $1 + """, message_id) + + flags |= new_flags + + await app.db.execute(""" + UPDATE messages + SET flags = $1 + WHERE id = $1 + """, flags.value, message_id) + + +async def _msg_unset_flags(message_id: int, unset_flags: int): + flags = await app.db.fetchval(""" + SELECT flags + FROM messages + WHERE id = $1 + """, message_id) + + flags &= ~unset_flags + + await app.db.execute(""" + UPDATE messages + SET flags = $1 + WHERE id = $1 + """, flags.value, message_id) + + @bp.route('//messages//suppress-embeds', methods=['POST']) async def suppress_embeds(channel_id: int, message_id: int): @@ -656,9 +690,11 @@ async def suppress_embeds(channel_id: int, message_id: int): if suppress and url_embeds: # delete all embeds then dispatch an update + await _msg_set_flags(message_id, MessageFlags.suppress_embeds) await msg_update_embeds(message, [], app.storage, app.dispatcher) elif not suppress and not url_embeds: # spawn process_url_embed to restore the embeds, if any + await _msg_unset_flags(message_id, MessageFlags.suppress_embeds) app.sched.spawn( process_url_embed( app.config, app.storage, app.dispatcher, app.session, diff --git a/litecord/enums.py b/litecord/enums.py index 98e036c..3facc43 100644 --- a/litecord/enums.py +++ b/litecord/enums.py @@ -164,6 +164,15 @@ class UserFlags(Flags): premium_early = 512 +class MessageFlags(Flags): + """Message flags.""" + none = 0 + + crossposted = 1 << 0 + is_crosspost = 1 << 1 + suppresss_embeds = 1 << 2 + + class StatusType(EasyEnum): """All statuses there can be in a presence.""" ONLINE = 'online' diff --git a/manage/cmd/users.py b/manage/cmd/users.py index 4d37757..d835c6a 100644 --- a/manage/cmd/users.py +++ b/manage/cmd/users.py @@ -30,6 +30,7 @@ async def find_user(username, discrim, ctx) -> int: WHERE username = $1 AND discriminator = $2 """, username, discrim) + async def set_user_staff(user_id, ctx): """Give a single user staff status.""" old_flags = await ctx.db.fetchval(""" From ef6361dbdaf8eae65e91389e3ed58729b3cabf4b Mon Sep 17 00:00:00 2001 From: Luna Date: Sun, 1 Sep 2019 19:18:54 -0300 Subject: [PATCH 3/3] channels: update local message var when changing flags - embed.messages: propagate payload.flags when updating msg embeds - enums: fix typo - channels: fix flag helper functions - storage: only fill res.member when user_id is given - storage: sentinel value is 0 instead of none for flags removal --- litecord/blueprints/channels.py | 55 +++++++++++-------- litecord/embed/messages.py | 3 + litecord/enums.py | 2 +- litecord/storage.py | 15 +++-- .../migration/scripts/3_add_message_flags.sql | 2 +- 5 files changed, 49 insertions(+), 28 deletions(-) diff --git a/litecord/blueprints/channels.py b/litecord/blueprints/channels.py index fa3310a..2c9824b 100644 --- a/litecord/blueprints/channels.py +++ b/litecord/blueprints/channels.py @@ -615,46 +615,43 @@ async def _search_channel(channel_id): return jsonify(await search_result_from_list(rows)) - # NOTE that those functions stay here until some other # route or code wants it. -async def _msg_set_flags(message_id: int, new_flags: int): - flags = await app.db.fetchval(""" + + +async def _msg_update_flags(message_id: int, flags: int): + await app.db.execute(""" + UPDATE messages + SET flags = $1 + WHERE id = $2 + """, flags, message_id) + + +async def _msg_get_flags(message_id: int): + return await app.db.fetchval(""" SELECT flags FROM messages WHERE id = $1 """, message_id) - flags |= new_flags - await app.db.execute(""" - UPDATE messages - SET flags = $1 - WHERE id = $1 - """, flags.value, message_id) +async def _msg_set_flags(message_id: int, new_flags: int): + flags = await _msg_get_flags(message_id) + flags |= new_flags + await _msg_update_flags(message_id, flags) async def _msg_unset_flags(message_id: int, unset_flags: int): - flags = await app.db.fetchval(""" - SELECT flags - FROM messages - WHERE id = $1 - """, message_id) - + flags = await _msg_get_flags(message_id) flags &= ~unset_flags - - await app.db.execute(""" - UPDATE messages - SET flags = $1 - WHERE id = $1 - """, flags.value, message_id) + await _msg_update_flags(message_id, flags) @bp.route('//messages//suppress-embeds', methods=['POST']) async def suppress_embeds(channel_id: int, message_id: int): """Toggle the embeds in a message. - + Either the author of the message or a channel member with the Manage Messages permission can run this route. """ @@ -688,13 +685,27 @@ async def suppress_embeds(channel_id: int, message_id: int): url_embeds = sum( 1 for embed in message['embeds'] if embed['type'] == 'url') + # NOTE for any future self. discord doing flags an optional thing instead + # of just giving 0 is a pretty bad idea because now i have to deal with + # that behavior here, and likely in every other message update thing + if suppress and url_embeds: # delete all embeds then dispatch an update await _msg_set_flags(message_id, MessageFlags.suppress_embeds) + + message['flags'] = \ + message.get('flags', 0) | MessageFlags.suppress_embeds + await msg_update_embeds(message, [], app.storage, app.dispatcher) elif not suppress and not url_embeds: # spawn process_url_embed to restore the embeds, if any await _msg_unset_flags(message_id, MessageFlags.suppress_embeds) + + try: + message.pop('flags') + except KeyError: + pass + app.sched.spawn( process_url_embed( app.config, app.storage, app.dispatcher, app.session, diff --git a/litecord/embed/messages.py b/litecord/embed/messages.py index 1267538..4807c0f 100644 --- a/litecord/embed/messages.py +++ b/litecord/embed/messages.py @@ -82,6 +82,9 @@ async def msg_update_embeds(payload, new_embeds, storage, dispatcher): if 'guild_id' in payload: update_payload['guild_id'] = payload['guild_id'] + if 'flags' in payload: + update_payload['flags'] = payload['flags'] + await dispatcher.dispatch( 'channel', channel_id, 'MESSAGE_UPDATE', update_payload) diff --git a/litecord/enums.py b/litecord/enums.py index 3facc43..c9ecb9a 100644 --- a/litecord/enums.py +++ b/litecord/enums.py @@ -170,7 +170,7 @@ class MessageFlags(Flags): crossposted = 1 << 0 is_crosspost = 1 << 1 - suppresss_embeds = 1 << 2 + suppress_embeds = 1 << 2 class StatusType(EasyEnum): diff --git a/litecord/storage.py b/litecord/storage.py index 31d7da2..08ea0c1 100644 --- a/litecord/storage.py +++ b/litecord/storage.py @@ -942,10 +942,17 @@ class Storage: # if message is not from a dm, guild_id is None and so, _member_basic # will just return None - res['member'] = await self._member_basic_with_roles(guild_id, user_id) - if res['member'] is None: - res.pop('member') + # user id can be none, though, and we need to watch out for that + if user_id is not None: + res['member'] = await self._member_basic_with_roles( + guild_id, user_id) + + if res.get('member') is None: + try: + res.pop('member') + except KeyError: + pass pin_id = await self.db.fetchval(""" SELECT message_id @@ -961,7 +968,7 @@ class Storage: if guild_id: res['guild_id'] = str(guild_id) - if res['flags'] is None: + if res['flags'] == 0: res.pop('flags') return res diff --git a/manage/cmd/migration/scripts/3_add_message_flags.sql b/manage/cmd/migration/scripts/3_add_message_flags.sql index 319ccde..28eea36 100644 --- a/manage/cmd/migration/scripts/3_add_message_flags.sql +++ b/manage/cmd/migration/scripts/3_add_message_flags.sql @@ -1,2 +1,2 @@ ALTER TABLE messages - ADD COLUMN flags bigint DEFAULT NULL; + ADD COLUMN flags bigint DEFAULT 0;