From 49aa6cd495d697be6cfe7be4db0e79a6dbd7fedc Mon Sep 17 00:00:00 2001 From: Luna Mendes Date: Tue, 13 Nov 2018 21:52:50 -0300 Subject: [PATCH] blueprints.users: add user avatars - images: add IconManager.update - images: delete all other converted extension variants when deleting --- litecord/blueprints/guilds.py | 15 +++-------- litecord/blueprints/icons.py | 20 +++++++++------ litecord/blueprints/users.py | 12 ++++++--- litecord/images.py | 47 ++++++++++++++++++++++++++++++----- 4 files changed, 66 insertions(+), 28 deletions(-) diff --git a/litecord/blueprints/guilds.py b/litecord/blueprints/guilds.py index 2c80f34..01b4e26 100644 --- a/litecord/blueprints/guilds.py +++ b/litecord/blueprints/guilds.py @@ -205,18 +205,9 @@ async def _update_guild(guild_id): if 'icon' in j: # delete old - old_icon_hash = await app.db.fetchval(""" - SELECT icon - FROM guilds - WHERE id = $1 - """, guild_id) - - old_icon = await app.icons.get_guild_icon( - guild_id, old_icon_hash) - - await app.icons.delete(old_icon) - - new_icon = await put_guild_icon(guild_id, j['icon']) + new_icon = await app.icons.update( + 'guild', guild_id, j['icon'] + ) await app.db.execute(""" UPDATE guilds diff --git a/litecord/blueprints/icons.py b/litecord/blueprints/icons.py index 6d83159..ac25d46 100644 --- a/litecord/blueprints/icons.py +++ b/litecord/blueprints/icons.py @@ -1,5 +1,5 @@ from os.path import splitext -from quart import Blueprint, current_app as app, send_file +from quart import Blueprint, current_app as app, send_file, request bp = Blueprint('images', __name__) @@ -20,11 +20,13 @@ def splitext_(filepath): return name, ext.strip('.') -@bp.route('/emojis/.', methods=['GET']) -async def _get_raw_emoji(emoji_id: int, ext: str): +@bp.route('/emojis/', methods=['GET']) +async def _get_raw_emoji(emoji_file): # emoji = app.icons.get_emoji(emoji_id, ext=ext) # just a test file for now - return await send_file('./LICENSE') + emoji_id, ext = splitext_(emoji_file) + return await send_icon( + 'emoji', emoji_id, emoji_id, ext=ext) @bp.route('/icons//', methods=['GET']) @@ -43,9 +45,13 @@ async def _get_default_user_avatar(discrim: int): pass -@bp.route('/avatars//.') -async def _get_user_avatar(user_id, avatar_hash, ext): - return await send_icon('user', user_id, avatar_hash, ext=ext) +@bp.route('/avatars//') +async def _get_user_avatar(user_id, avatar_file): + # size_int = int(request.args.get('size', '1024')) + # siz = (size_int, size_int) + avatar_hash, ext = splitext_(avatar_file) + return await send_icon( + 'user', user_id, avatar_hash, ext=ext) # @bp.route('/app-icons//.') diff --git a/litecord/blueprints/users.py b/litecord/blueprints/users.py index f2e418f..f5d16e5 100644 --- a/litecord/blueprints/users.py +++ b/litecord/blueprints/users.py @@ -173,9 +173,15 @@ async def patch_me(): """, j['email'], user_id) user['email'] = j['email'] - if 'avatar' in j: - # TODO: update icon - pass + if 'avatar' in j and j['avatar']: + new_icon = await app.icons.update( + 'user', user_id, j['avatar'], size=(128, 128)) + + await app.db.execute(""" + UPDATE users + SET avatar = $1 + WHERE id = $2 + """, new_icon.icon_hash, user_id) if 'new_password' in j and j['new_password']: await _check_pass(j, user) diff --git a/litecord/images.py b/litecord/images.py index e38c49e..6d8235a 100644 --- a/litecord/images.py +++ b/litecord/images.py @@ -116,6 +116,27 @@ def parse_data_uri(string) -> tuple: raise ImageError('data URI invalid syntax') +def _gen_update_sql(scope: str) -> str: + field = { + 'user': 'avatar', + 'guild': 'icon' + }[scope] + + table = { + 'user': 'users', + 'guild': 'guilds' + }[scope] + + col = { + 'user': 'id', + 'guild': 'id' + }[scope] + + return f""" + SELECT {field} FROM {table} WHERE {col} = $1 + """ + + class IconManager: """Main icon manager.""" def __init__(self, app): @@ -140,6 +161,7 @@ class IconManager: async def generic_get(self, scope, key, icon_hash, **kwargs) -> Icon: """Get any icon.""" + log.debug('GET {} {} {}', scope, key, icon_hash) key = str(key) icon_row = await self.storage.db.fetchrow(""" @@ -158,7 +180,7 @@ class IconManager: if not icon.as_pathlib.exists(): await self.delete(icon) return None - + if 'ext' in kwargs and kwargs['ext'] != icon.extension: return await self._convert_ext(icon, kwargs['ext']) @@ -252,9 +274,22 @@ class IconManager: WHERE hash = $1 """, icon.icon_hash) - icon_path = icon.as_pathlib + paths = IMAGE_FOLDER.glob(f'{icon.icon_hash}.*') - try: - icon_path.unlink() - except FileNotFoundError: - pass + for path in paths: + try: + path.unlink() + except FileNotFoundError: + pass + + async def update(self, scope: str, key: str, + new_icon_data: str, **kwargs) -> Icon: + """Update an icon on a key.""" + old_icon_hash = await self.storage.db.fetchval( + _gen_update_sql(scope), key) + + key = str(key) + old_icon = await self.generic_get(scope, key, old_icon_hash) + await self.delete(old_icon) + + return await self.put(scope, key, new_icon_data, **kwargs)