diff --git a/litecord/blueprints/users.py b/litecord/blueprints/users.py index fc8fb00..e1c5719 100644 --- a/litecord/blueprints/users.py +++ b/litecord/blueprints/users.py @@ -136,38 +136,10 @@ async def put_note(target_id: int): @bp.route('/@me/settings', methods=['GET']) async def get_user_settings(): - # TODO: for now, just return hardcoded defaults, - # once we get the user_settings table working - # we can move to that. - await token_check() - - return jsonify({ - 'afk_timeout': 300, - 'animate_emoji': True, - 'convert_emoticons': False, - 'default_guilds_restricted': True, - 'detect_platform_accounts': False, - 'developer_mode': True, - 'disable_games_tab': True, - 'enable_tts_command': False, - 'explicit_content_filter': 2, - 'friend_source_flags': { - 'mutual_friends': True - }, - 'gif_auto_play': True, - 'guild_positions': [], - 'restricted_guilds': [], - 'inline_attachment_media': True, - 'inline_embed_media': True, - 'locale': 'en-US', - 'message_display_compact': False, - 'render_embeds': True, - 'render_reactions': True, - 'show_current_game': True, - 'status': 'online', - 'theme': 'dark', - 'timezone_offset': 420, - }) + """Get the current user's settings.""" + user_id = await token_check() + settings = await app.storage.get_user_settings(user_id) + return jsonify(settings) @bp.route('/@me/settings', methods=['PATCH']) diff --git a/litecord/storage.py b/litecord/storage.py index 3a3b56d..1e77e44 100644 --- a/litecord/storage.py +++ b/litecord/storage.py @@ -1,3 +1,4 @@ +import json from typing import List, Dict, Any from logbook import Logger @@ -17,12 +18,45 @@ def dict_(val): return dict(val) if val else None +async def _set_json(con): + """Set JSON and JSONB codecs for an + asyncpg connection.""" + await con.set_type_codec( + 'json', + encoder=json.dumps, + decoder=json.loads, + schema='pg_catalog' + ) + + await con.set_type_codec( + 'jsonb', + encoder=json.dumps, + decoder=json.loads, + schema='pg_catalog' + ) + + class Storage: """Class for common SQL statements.""" def __init__(self, db): self.db = db self.presence = None + async def _fetchrow_with_json(self, query: str, *args): + """Fetch a single row with JSON/JSONB support.""" + # the pool by itself doesn't have + # set_type_codec, so we must set it manually + # by acquiring the connection + async with self.db.acquire() as con: + await _set_json(con) + return await con.fetchrow(query, *args) + + async def _fetch_with_json(self, query: str, *args): + """Fetch many rows with JSON/JSONB support.""" + async with self.db.acquire() as con: + await _set_json(con) + return await con.fetch(query, *args) + async def get_user(self, user_id, secure=False) -> Dict[str, Any]: """Get a single user payload.""" user_id = int(user_id) @@ -500,3 +534,26 @@ class Storage: dinv['inviter'] = inviter return dinv + + async def get_user_settings(self, user_id: int) -> Dict[str, Any]: + row = await self._fetchrow_with_json(""" + SELECT * + FROM user_settings + WHERE id = $1 + """, user_id) + + if not row: + log.info('Generating user settings for {}', user_id) + + await self.db.execute(""" + INSERT INTO user_settings (id) + VALUES ($1) + """, user_id) + + # recalling get_user_settings + # should work after adding + return await self.get_user_settings(user_id) + + drow = dict(row) + drow.pop('id') + return drow diff --git a/run.py b/run.py index 34e9c60..3bb7036 100644 --- a/run.py +++ b/run.py @@ -83,6 +83,7 @@ async def app_after_request(resp): async def app_before_serving(): log.info('opening db') app.db = await asyncpg.create_pool(**app.config['POSTGRES']) + g.app = app app.loop = asyncio.get_event_loop()