diff --git a/litecord/blueprints/channels.py b/litecord/blueprints/channels.py index ed5e62e..b27d5fc 100644 --- a/litecord/blueprints/channels.py +++ b/litecord/blueprints/channels.py @@ -7,7 +7,7 @@ from litecord.auth import token_check from litecord.enums import ChannelType, GUILD_CHANS from litecord.errors import ChannelNotFound from litecord.schemas import ( - validate, CHAN_UPDATE, CHAN_OVERWRITE + validate, CHAN_UPDATE, CHAN_OVERWRITE, SEARCH_CHANNEL ) from litecord.blueprints.checks import channel_check, channel_perm_check @@ -490,3 +490,41 @@ async def delete_read_state(channel_id): """, user_id, channel_id) return '', 204 + + +@bp.route('//messages/search', methods=['GET']) +async def _search_channel(channel_id): + """Search in DMs or group DMs""" + user_id = await token_check() + await channel_check(user_id, channel_id) + await channel_perm_check(user_id, channel_id, 'read_messages') + j = validate(request.args, SEARCH_CHANNEL) + + # main message ids + rows = await app.db.fetch(f""" + SELECT message_id, + COUNT(*) OVER() as total_results + FROM messages + WHERE channel_id = $1 AND content LIKE '%'||$3||'%' + ORDER BY + LIMIT 50 + OFFSET $2 + """, channel_id, j['offset'], j['content']) + + results = 0 if not rows else rows[0]['total_results'] + main_messages = [r['message_id'] for r in rows] + + # fetch contexts for each message + # (2 messages before, 2 messages after). + + # TODO: actual contexts + res = [] + + for message_id in main_messages: + res.append([await app.storage.get_message(message_id)]) + + return jsonify({ + 'total_results': results, + 'messages': res, + 'analytics_id': '', + }) diff --git a/litecord/blueprints/guilds.py b/litecord/blueprints/guilds.py index e6dda35..f7eb245 100644 --- a/litecord/blueprints/guilds.py +++ b/litecord/blueprints/guilds.py @@ -9,7 +9,7 @@ from ..auth import token_check from ..snowflake import get_snowflake from ..enums import ChannelType from ..schemas import ( - validate, GUILD_CREATE, GUILD_UPDATE + validate, GUILD_CREATE, GUILD_UPDATE, SEARCH_CHANNEL ) from .channels import channel_ack from .checks import guild_check, guild_owner_check @@ -277,7 +277,7 @@ async def delete_guild(guild_id): return '', 204 -@bp.route('//messages/search') +@bp.route('//messages/search', methods=['GET']) async def search_messages(guild_id): """Search messages in a guild. @@ -286,12 +286,37 @@ async def search_messages(guild_id): user_id = await token_check() await guild_check(user_id, guild_id) - # TODO: implement route + j = validate(request.args, SEARCH_CHANNEL) + + # main message ids + # TODO: filter only channels where user can + # read messages to prevent leaking + rows = await app.db.fetch(f""" + SELECT message_id, + COUNT(*) OVER() as total_results + FROM messages + WHERE guild_id = $1 + ORDER BY + LIMIT 50 + OFFSET $2 + """, guild_id, j['offset']) + + results = 0 if not rows else rows[0]['total_results'] + main_messages = [r['message_id'] for r in rows] + + # fetch contexts for each message + # (2 messages before, 2 messages after). + + # TODO: actual contexts + res = [] + + for message_id in main_messages: + res.append([await app.storage.get_message(message_id)]) return jsonify({ - 'total_results': 0, - 'messages': [], - 'analytics_id': 'ass', + 'total_results': results, + 'messages': res, + 'analytics_id': '', }) diff --git a/litecord/schemas.py b/litecord/schemas.py index 8d72005..a80f4f3 100644 --- a/litecord/schemas.py +++ b/litecord/schemas.py @@ -591,3 +591,10 @@ PATCH_EMOJI = { 'type': 'string', 'minlength': 1, 'maxlength': 256, 'required': True}, 'roles': {'type': 'list', 'schema': {'coerce': int}} } + + +SEARCH_CHANNEL = { + 'content': {'type': 'string', 'minlength': 1}, + 'include_nsfw': {'type': 'boolean'}, + 'offset': {'coerce': int} +} diff --git a/manage/cmd/migration/scripts/5_add_messages_guild_id.sql b/manage/cmd/migration/scripts/5_add_messages_guild_id.sql new file mode 100644 index 0000000..07b5c5e --- /dev/null +++ b/manage/cmd/migration/scripts/5_add_messages_guild_id.sql @@ -0,0 +1 @@ +ALTER TABLE messages ADD COLUMN guild_id bigint REFERENCES guilds (id) ON DELETE CASCADE; diff --git a/schema.sql b/schema.sql index 77c6fcc..5fef6e3 100644 --- a/schema.sql +++ b/schema.sql @@ -590,6 +590,9 @@ CREATE TABLE IF NOT EXISTS messages ( id bigint PRIMARY KEY, channel_id bigint REFERENCES channels (id) ON DELETE CASCADE, + -- this is good for search. + guild_id bigint REFERENCES guilds (id) ON DELETE CASCADE, + -- those are mutually exclusive, only one of them -- can NOT be NULL at a time.