From 89ab7b820c0c176fd463e0d7b960b9e2824ac449 Mon Sep 17 00:00:00 2001 From: Luna Date: Wed, 29 Jul 2020 15:28:31 -0300 Subject: [PATCH 1/7] fix roles.permissions' datatype to bigint --- manage/cmd/migration/scripts/10_permissions.sql | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 manage/cmd/migration/scripts/10_permissions.sql diff --git a/manage/cmd/migration/scripts/10_permissions.sql b/manage/cmd/migration/scripts/10_permissions.sql new file mode 100644 index 0000000..61b8063 --- /dev/null +++ b/manage/cmd/migration/scripts/10_permissions.sql @@ -0,0 +1,3 @@ +-- channel_overwrites table already has allow and deny as bigints. +alter table roles + alter column permissions type bigint; From 154400a23e183fee992cb73544faef3d7554f7ec Mon Sep 17 00:00:00 2001 From: Luna Date: Wed, 29 Jul 2020 16:02:26 -0300 Subject: [PATCH 2/7] add "_new" fields on overwrites and roles --- litecord/permissions.py | 2 +- litecord/storage.py | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/litecord/permissions.py b/litecord/permissions.py index 6a77582..9b74d8e 100644 --- a/litecord/permissions.py +++ b/litecord/permissions.py @@ -87,7 +87,7 @@ class Permissions(ctypes.Union): return self.binary -ALL_PERMISSIONS = Permissions(0b01111111111101111111110111111111) +ALL_PERMISSIONS = Permissions(0b01111111111111111111111111111111) EMPTY_PERMISSIONS = Permissions(0) diff --git a/litecord/storage.py b/litecord/storage.py index c2790b1..819e1f1 100644 --- a/litecord/storage.py +++ b/litecord/storage.py @@ -469,6 +469,10 @@ class Storage: def _overwrite_convert(row): drow = dict(row) + drow["allow_new"] = str(drow["allow"]) + drow["deny_new"] = str(drow["deny"]) + drow["allow"] = drow["allow"] & ((2 << 31) - 1) + drow["deny"] = drow["deny"] & ((2 << 31) - 1) target_type = drow["target_type"] drow["type"] = "member" if target_type == 0 else "role" @@ -673,7 +677,12 @@ class Storage: if not row: return None - return dict(row) + drow = dict(row) + + drow["permissions_new"] = str(drow["permissions"]) + drow["permissions"] = drow["permissions"] & ((2 << 31) - 1) + + return drow async def get_role_data(self, guild_id: int) -> List[Dict[str, Any]]: """Get role list information on a guild.""" From fa4a4138f0d430aee73030aa80523b787ddc37ab Mon Sep 17 00:00:00 2001 From: Luna Date: Wed, 29 Jul 2020 16:15:15 -0300 Subject: [PATCH 3/7] assert proper overwrite target data is set --- litecord/blueprints/channels.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/litecord/blueprints/channels.py b/litecord/blueprints/channels.py index ff80c42..8b0f93a 100644 --- a/litecord/blueprints/channels.py +++ b/litecord/blueprints/channels.py @@ -397,13 +397,16 @@ async def _process_overwrites(guild_id: int, channel_id: int, overwrites: list) if target.is_user: perms = Permissions(overwrite["allow"] & ~overwrite["deny"]) + assert target.user_id is not None await _dispatch_action(guild_id, channel_id, target.user_id, perms) elif target.is_role: + assert target.role_id is not None user_ids.extend(await app.storage.get_role_members(target.role_id)) for user_id in user_ids: perms = await get_permissions(user_id, channel_id) + assert target.user_id is not None await _dispatch_action(guild_id, channel_id, target.user_id, perms) From b9655326211e0b1f15d71404aeb08225c264b4ec Mon Sep 17 00:00:00 2001 From: Luna Date: Wed, 29 Jul 2020 16:17:15 -0300 Subject: [PATCH 4/7] handle Permissions being initialized with a str --- litecord/permissions.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/litecord/permissions.py b/litecord/permissions.py index 9b74d8e..654e2be 100644 --- a/litecord/permissions.py +++ b/litecord/permissions.py @@ -18,7 +18,7 @@ along with this program. If not, see . """ import ctypes -from typing import Optional +from typing import Optional, Union from quart import current_app as app @@ -77,8 +77,10 @@ class Permissions(ctypes.Union): _fields_ = [("bits", _RawPermsBits), ("binary", ctypes.c_uint64)] - def __init__(self, val: int): - self.binary = val + def __init__(self, val: Union[str, int]): + # always coerce to int, even when the user gives us a str, because + # python ints are infinity-sized (yes, yes, the memory concerns, yes) + self.binary = int(val) def __repr__(self): return f"" From 2ad3cd6ad791f9c9c87bd7bb49f019653eb059f6 Mon Sep 17 00:00:00 2001 From: Luna Date: Wed, 29 Jul 2020 17:18:47 -0300 Subject: [PATCH 5/7] ignore unknown guilds when deleting read states --- litecord/blueprints/channels.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/litecord/blueprints/channels.py b/litecord/blueprints/channels.py index 8b0f93a..feea63e 100644 --- a/litecord/blueprints/channels.py +++ b/litecord/blueprints/channels.py @@ -46,6 +46,7 @@ from litecord.embed.messages import process_url_embed, msg_update_embeds from litecord.common.channels import channel_ack from litecord.pubsub.user import dispatch_user from litecord.permissions import get_permissions, Permissions +from litecord.errors import GuildNotFound log = Logger(__name__) bp = Blueprint("channels", __name__) @@ -678,7 +679,12 @@ async def ack_channel(channel_id, message_id): async def delete_read_state(channel_id): """Delete the read state of a channel.""" user_id = await token_check() - await channel_check(user_id, channel_id) + try: + await channel_check(user_id, channel_id) + except GuildNotFound: + # ignore when guild isn't found because we're deleting the + # read state regardless. + pass await app.db.execute( """ From de357dd524adb65d69a685be30dbc7b76febaace Mon Sep 17 00:00:00 2001 From: Luna Date: Wed, 29 Jul 2020 17:22:40 -0300 Subject: [PATCH 6/7] add guild-specific voice region list support --- litecord/blueprints/voice.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/litecord/blueprints/voice.py b/litecord/blueprints/voice.py index 7011211..dd3cad5 100644 --- a/litecord/blueprints/voice.py +++ b/litecord/blueprints/voice.py @@ -104,9 +104,7 @@ async def majority_region(user_id: int) -> Optional[str]: return _majority_region_count(regions) -@bp.route("/regions", methods=["GET"]) -async def voice_regions(): - """Return voice regions.""" +async def _all_regions(): user_id = await token_check() best_region = await majority_region(user_id) @@ -116,3 +114,16 @@ async def voice_regions(): region["optimal"] = region["id"] == best_region return jsonify(regions) + + +@bp.route("/regions", methods=["GET"]) +async def voice_regions(): + """Return voice regions.""" + return await _all_regions() + + +@bp.route("/guilds//regions", methods=["GET"]) +async def guild_voice_regions(): + """Return voice regions.""" + # we return the same list as the normal /regions route on purpose. + return await _all_regions() From ad6643421def5f7d4e0031dbe6835b41d91553bb Mon Sep 17 00:00:00 2001 From: Luna Date: Wed, 29 Jul 2020 17:37:03 -0300 Subject: [PATCH 7/7] add route to fetch notes from singular users --- litecord/blueprints/user/settings.py | 21 +++++++++++++++++++++ litecord/errors.py | 4 ++++ 2 files changed, 25 insertions(+) diff --git a/litecord/blueprints/user/settings.py b/litecord/blueprints/user/settings.py index 0d81f9d..ae05b59 100644 --- a/litecord/blueprints/user/settings.py +++ b/litecord/blueprints/user/settings.py @@ -23,6 +23,7 @@ from litecord.auth import token_check from litecord.schemas import validate, USER_SETTINGS, GUILD_SETTINGS from litecord.blueprints.checks import guild_check from litecord.pubsub.user import dispatch_user +from litecord.errors import UserNotFound bp = Blueprint("users_settings", __name__) @@ -129,6 +130,26 @@ async def patch_guild_settings(guild_id: int): return jsonify(settings) +@bp.route("/@me/notes/", methods=["GET"]) +async def get_note(target_id: int): + """Get a single note from a user.""" + user_id = await token_check() + note = await app.db.fetchval( + """ + SELECT note + FROM notes + WHERE user_id = $1 AND target_id = $2 + """, + user_id, + target_id, + ) + + if note is None: + raise UserNotFound() + + return jsonify({"user_id": user_id, "note_user_id": target_id, "note": note}) + + @bp.route("/@me/notes/", methods=["PUT"]) async def put_note(target_id: int): """Put a note to a user. diff --git a/litecord/errors.py b/litecord/errors.py index 0820f51..bef8c04 100644 --- a/litecord/errors.py +++ b/litecord/errors.py @@ -142,6 +142,10 @@ class WebhookNotFound(NotFound): error_code = 10015 +class UserNotFound(NotFound): + error_code = 10013 + + class Ratelimited(LitecordError): status_code = 429