diff --git a/litecord/blueprints/guild/__init__.py b/litecord/blueprints/guild/__init__.py index f4f8356..36c36b6 100644 --- a/litecord/blueprints/guild/__init__.py +++ b/litecord/blueprints/guild/__init__.py @@ -1,3 +1,4 @@ from .roles import bp as guild_roles from .members import bp as guild_members from .channels import bp as guild_channels +from .mod import bp as guild_mod diff --git a/litecord/blueprints/guild/mod.py b/litecord/blueprints/guild/mod.py new file mode 100644 index 0000000..92a427f --- /dev/null +++ b/litecord/blueprints/guild/mod.py @@ -0,0 +1,112 @@ +from quart import Blueprint, request, current_app as app, jsonify + +from litecord.blueprints.auth import token_check +from litecord.blueprints.checks import guild_owner_check + +bp = Blueprint('guild_moderation', __name__) + + +async def remove_member(guild_id: int, member_id: int): + """Do common tasks related to deleting a member from the guild, + such as dispatching GUILD_DELETE and GUILD_MEMBER_REMOVE.""" + + await app.db.execute(""" + DELETE FROM members + WHERE guild_id = $1 AND user_id = $2 + """, guild_id, member_id) + + await app.dispatcher.dispatch_user(member_id, 'GUILD_DELETE', { + 'guild_id': guild_id, + 'unavailable': False, + }) + + await app.dispatcher.unsub('guild', guild_id, member_id) + + await app.dispatcher.dispatch_guild(guild_id, 'GUILD_MEMBER_REMOVE', { + 'guild_id': str(guild_id), + 'user': await app.storage.get_user(member_id), + }) + + +@bp.route('//members/', methods=['DELETE']) +async def kick_member(guild_id, member_id): + """Remove a member from a guild.""" + user_id = await token_check() + + # TODO: check KICK_MEMBERS permission + await guild_owner_check(user_id, guild_id) + await remove_member(guild_id, member_id) + return '', 204 + + +@bp.route('//bans', methods=['GET']) +async def get_bans(guild_id): + user_id = await token_check() + + # TODO: check BAN_MEMBERS permission + await guild_owner_check(user_id, guild_id) + + bans = await app.db.fetch(""" + SELECT user_id, reason + FROM bans + WHERE bans.guild_id = $1 + """, guild_id) + + res = [] + + for ban in bans: + res.append({ + 'reason': ban['reason'], + 'user': await app.storage.get_user(ban['user_id']) + }) + + return jsonify(res) + + +@bp.route('//bans/', methods=['PUT']) +async def create_ban(guild_id, member_id): + user_id = await token_check() + + # TODO: check BAN_MEMBERS permission + await guild_owner_check(user_id, guild_id) + + j = await request.get_json() + + await app.db.execute(""" + INSERT INTO bans (guild_id, user_id, reason) + VALUES ($1, $2, $3) + """, guild_id, member_id, j.get('reason', '')) + + await remove_member(guild_id, member_id) + + await app.dispatcher.dispatch_guild(guild_id, 'GUILD_BAN_ADD', { + 'guild_id': str(guild_id), + 'user': await app.storage.get_user(member_id) + }) + + return '', 204 + + +@bp.route('//bans/', methods=['DELETE']) +async def remove_ban(guild_id, banned_id): + user_id = await token_check() + + # TODO: check BAN_MEMBERS permission + await guild_owner_check(guild_id, user_id) + + res = await app.db.execute(""" + DELETE FROM bans + WHERE guild_id = $1 AND user_id = $@ + """, guild_id, banned_id) + + # we don't really need to dispatch GUILD_BAN_REMOVE + # when no bans were actually removed. + if res == 'DELETE 0': + return '', 204 + + await app.dispatcher.dispatch_guild(guild_id, 'GUILD_BAN_REMOVE', { + 'guild_id': str(guild_id), + 'user': await app.storage.get_user(banned_id) + }) + + return '', 204 diff --git a/litecord/blueprints/guilds.py b/litecord/blueprints/guilds.py index 84eb129..caaf319 100644 --- a/litecord/blueprints/guilds.py +++ b/litecord/blueprints/guilds.py @@ -11,7 +11,6 @@ from ..enums import ChannelType from ..schemas import ( validate, GUILD_CREATE, GUILD_UPDATE ) -from ..utils import dict_get from .channels import channel_ack from .checks import guild_check, guild_owner_check @@ -237,112 +236,6 @@ async def delete_guild(guild_id): return '', 204 -async def remove_member(guild_id: int, member_id: int): - """Do common tasks related to deleting a member from the guild, - such as dispatching GUILD_DELETE and GUILD_MEMBER_REMOVE.""" - - await app.db.execute(""" - DELETE FROM members - WHERE guild_id = $1 AND user_id = $2 - """, guild_id, member_id) - - await app.dispatcher.dispatch_user(member_id, 'GUILD_DELETE', { - 'guild_id': guild_id, - 'unavailable': False, - }) - - await app.dispatcher.unsub('guild', guild_id, member_id) - - await app.dispatcher.dispatch_guild(guild_id, 'GUILD_MEMBER_REMOVE', { - 'guild_id': str(guild_id), - 'user': await app.storage.get_user(member_id), - }) - - -@bp.route('//members/', methods=['DELETE']) -async def kick_member(guild_id, member_id): - """Remove a member from a guild.""" - user_id = await token_check() - - # TODO: check KICK_MEMBERS permission - await guild_owner_check(user_id, guild_id) - await remove_member(guild_id, member_id) - return '', 204 - - -@bp.route('//bans', methods=['GET']) -async def get_bans(guild_id): - user_id = await token_check() - - # TODO: check BAN_MEMBERS permission - await guild_owner_check(user_id, guild_id) - - bans = await app.db.fetch(""" - SELECT user_id, reason - FROM bans - WHERE bans.guild_id = $1 - """, guild_id) - - res = [] - - for ban in bans: - res.append({ - 'reason': ban['reason'], - 'user': await app.storage.get_user(ban['user_id']) - }) - - return jsonify(res) - - -@bp.route('//bans/', methods=['PUT']) -async def create_ban(guild_id, member_id): - user_id = await token_check() - - # TODO: check BAN_MEMBERS permission - await guild_owner_check(user_id, guild_id) - - j = await request.get_json() - - await app.db.execute(""" - INSERT INTO bans (guild_id, user_id, reason) - VALUES ($1, $2, $3) - """, guild_id, member_id, j.get('reason', '')) - - await remove_member(guild_id, member_id) - - await app.dispatcher.dispatch_guild(guild_id, 'GUILD_BAN_ADD', { - 'guild_id': str(guild_id), - 'user': await app.storage.get_user(member_id) - }) - - return '', 204 - - -@bp.route('//bans/', methods=['DELETE']) -async def remove_ban(guild_id, banned_id): - user_id = await token_check() - - # TODO: check BAN_MEMBERS permission - await guild_owner_check(guild_id, user_id) - - res = await app.db.execute(""" - DELETE FROM bans - WHERE guild_id = $1 AND user_id = $@ - """, guild_id, banned_id) - - # we don't really need to dispatch GUILD_BAN_REMOVE - # when no bans were actually removed. - if res == 'DELETE 0': - return '', 204 - - await app.dispatcher.dispatch_guild(guild_id, 'GUILD_BAN_REMOVE', { - 'guild_id': str(guild_id), - 'user': await app.storage.get_user(banned_id) - }) - - return '', 204 - - @bp.route('//messages/search') async def search_messages(guild_id): """Search messages in a guild. diff --git a/run.py b/run.py index 78ebb09..e52002b 100644 --- a/run.py +++ b/run.py @@ -19,7 +19,7 @@ from litecord.blueprints import ( # for code readability if people want to dig through # the codebase. from litecord.blueprints.guild import ( - guild_roles, guild_members, guild_channels + guild_roles, guild_members, guild_channels, mod ) from litecord.gateway import websocket_handler @@ -65,6 +65,8 @@ bps = { guild_roles: '/guilds', guild_members: '/guilds', guild_channels: '/guilds', + # mod for moderation + mod: '/guilds', channels: '/channels', webhooks: None,