From 576f79c8b7b3a303e5848b2cf95d32effdff0ce5 Mon Sep 17 00:00:00 2001 From: Ben Date: Mon, 2 Dec 2019 23:33:38 +0000 Subject: [PATCH] Improvements to moderation handlers --- houdini.sql | 2 + houdini/data/moderator.py | 2 + houdini/handlers/play/moderation.py | 157 +++++++++++++++++----------- 3 files changed, 100 insertions(+), 61 deletions(-) diff --git a/houdini.sql b/houdini.sql index 7426347..07607ac 100644 --- a/houdini.sql +++ b/houdini.sql @@ -707,6 +707,7 @@ CREATE TABLE ban ( moderator_id INT DEFAULT NULL, reason SMALLINT NOT NULL, comment TEXT DEFAULT NULL, + message TEXT DEFAULT NULL, PRIMARY KEY (penguin_id, issued, expires), CONSTRAINT ban_ibfk_1 FOREIGN KEY (penguin_id) REFERENCES penguin (id) ON DELETE RESTRICT ON UPDATE CASCADE, CONSTRAINT ban_ibfk_2 FOREIGN KEY (moderator_id) REFERENCES penguin (id) ON DELETE RESTRICT ON UPDATE CASCADE @@ -725,6 +726,7 @@ COMMENT ON COLUMN ban.expires IS 'Expiry date'; COMMENT ON COLUMN ban.moderator_id IS 'Moderator penguin ID'; COMMENT ON COLUMN ban.reason IS 'Ban reason'; COMMENT ON COLUMN ban.comment IS 'Ban comment'; +COMMENT ON COLUMN ban.message IS 'Banned for message'; DROP TABLE IF EXISTS warning; CREATE TABLE warning ( diff --git a/houdini/data/moderator.py b/houdini/data/moderator.py index 91c7329..e5f5ade 100644 --- a/houdini/data/moderator.py +++ b/houdini/data/moderator.py @@ -11,6 +11,7 @@ class Ban(db.Model): moderator_id = db.Column(db.ForeignKey('penguin.id', ondelete='CASCADE', onupdate='CASCADE'), index=True) reason = db.Column(db.SmallInteger, nullable=False) comment = db.Column(db.Text) + message = db.Column(db.Text) class Warning(db.Model): @@ -19,6 +20,7 @@ class Warning(db.Model): penguin_id = db.Column(db.ForeignKey('penguin.id', ondelete='CASCADE', onupdate='CASCADE'), primary_key=True, nullable=False) expires = db.Column(db.DateTime, primary_key=True, nullable=False) + issued = db.Column(db.DateTime, primary_key=True, nullable=False) class Report(db.Model): diff --git a/houdini/handlers/play/moderation.py b/houdini/handlers/play/moderation.py index f07f541..87d0289 100644 --- a/houdini/handlers/play/moderation.py +++ b/houdini/handlers/play/moderation.py @@ -2,59 +2,66 @@ from houdini import handlers from houdini.data import db from houdini.handlers import XTPacket from houdini.data.moderator import Ban, Warning, Report +from houdini.data.penguin import Penguin +from houdini.constants import ClientType import datetime @handlers.handler(XTPacket('o', 'k')) async def handle_kick_player(p, penguin_id: int): - if p.data.moderator: + if p.moderator: await moderator_kick(p, penguin_id) -@handlers.handler(XTPacket('o', 'b')) +@handlers.handler(XTPacket('o', 'b'), client=ClientType.Legacy) async def handle_ban_player(p, penguin_id: int, message: str): - if p.data.moderator: + if p.moderator: await moderator_ban(p, penguin_id, comment=message) @handlers.handler(XTPacket('o', 'm')) async def handle_mute_player(p, penguin_id: int): - if p.data.moderator: + if p.moderator: if penguin_id in p.server.penguins_by_id: player = p.server.penguins_by_id[penguin_id] - if not player.data.moderator: + if not player.moderator: player.muted = True -@handlers.handler(XTPacket('o', 'initban')) +@handlers.handler(XTPacket('o', 'initban'), client=ClientType.Vanilla) +@handlers.player_attribute(moderator=True) async def handle_init_ban(p, penguin_id: int, message: str): - if penguin_id in p.server.penguins_by_id and p.data.moderator: - player = p.server.penguins_by_id[penguin_id] + player = p.server.penguins_by_id[penguin_id] if penguin_id in p.server.penguins_by_id \ + else await Penguin.get(penguin_id) + if not player.moderator: + number_bans = await db.select([db.func.count(Ban.penguin_id)]).where( + Ban.penguin_id == player.id).gino.scalar() - if not player.data.moderator: - number_bans = await db.select([db.func.count(Ban.penguin_id)]).where( - Ban.penguin_id == player.data.id).gino.scalar() - - await p.send_xt('initban', penguin_id, 0, number_bans, message, player.data.username) + await p.send_xt('initban', penguin_id, 0, number_bans, message, player.username) -@handlers.handler(XTPacket('o', 'ban')) +@handlers.handler(XTPacket('o', 'ban'), client=ClientType.Vanilla) +@handlers.player_attribute(moderator=True) async def handle_moderator_ban(p, penguin_id: int, ban_type: int, reason: int, duration: int, message: str, notes: str): - if p.data.moderator: + player = p.server.penguins_by_id[penguin_id] if penguin_id in p.server.penguins_by_id \ + else await Penguin.get(penguin_id) + if not player.moderator: + date_issued = datetime.datetime.now() + date_expires = date_issued + datetime.timedelta(hours=duration) + + if duration == 0: + await player.update(permaban=True).apply() + + await Ban.create(penguin_id=player.id, issued=date_issued, expires=date_expires, + moderator_id=p.id, reason=reason, comment=notes, message=message) + if penguin_id in p.server.penguins_by_id: - player = p.server.penguins_by_id[penguin_id] - if not player.data.moderator: - date_issued = datetime.datetime.now() - date_expires = date_issued + datetime.timedelta(hours=duration) - - if duration == 0: - await player.data.update(permaban=True).apply() - - await Ban.create(penguin_id=player.data.id, issued=date_issued, expires=date_expires, - moderator_id=p.data.id, reason=reason, comment=notes) + if player.is_vanilla_client: await player.send_xt('ban', ban_type, reason, duration, notes) - await player.close() + else: + await player.send_error(610, message) + await player.close() @handlers.handler(XTPacket('m', 'r')) @@ -64,52 +71,80 @@ async def handle_report(p, penguin_id: int, reason: int = 0): date=date_now, server_id=p.server.config.id, room_id=p.room.id) -@handlers.handler(XTPacket('o', 'moderatormessage')) -async def handle_moderator_message(p, type: int, penguin_id: int): - if p.data.moderator: +@handlers.handler(XTPacket('o', 'moderatormessage'), client=ClientType.Vanilla) +@handlers.player_attribute(moderator=True) +async def handle_moderator_message(p, warning_type: int, penguin_id: int): + player = p.server.penguins_by_id[penguin_id] if penguin_id in p.server.penguins_by_id \ + else await Penguin.get(penguin_id) + date_issued = datetime.datetime.now() + date_expires = date_issued + datetime.timedelta(hours=48) + warning_count = await db.select([db.func.count(Warning.expires)]).where( + (Warning.penguin_id == player.id) & (Warning.expires >= date_issued)).gino.scalar() + + if warning_count >= 3: + return await moderator_ban(p, player.id, message='Exceeded warning limit') + + await player.send_xt('moderatormessage', warning_type) + await Warning.create(penguin_id=player.id, issued=date_issued, expires=date_expires) + + +async def cheat_kick(p, penguin_id): + if penguin_id in p.server.penguins_by_id: + await p.server.penguins_by_id[penguin_id].send_error_and_disconnect(800) + + +async def cheat_ban(p, penguin_id, hours=24, comment=''): + if penguin_id in p.server.penguins_by_id: + player = p.server.penguins_by_id[penguin_id] + + number_bans = await db.select([db.func.count(Ban.penguin_id)]).where( + Ban.penguin_id == player.id).gino.scalar() + + date_issued = datetime.datetime.now() + date_expires = date_issued + datetime.timedelta(hours=hours) + + if number_bans >= 3: + await player.update(permaban=True).apply() + + await Ban.create(penguin_id=player.id, issued=date_issued, expires=date_expires, + moderator_id=p.id, reason=1, comment=comment, message='Cheat ban') + if penguin_id in p.server.penguins_by_id: - player = p.server.penguins_by_id[penguin_id] - date_issued = datetime.datetime.now() - date_expires = date_issued + datetime.timedelta(hours=48) - warning_count = await db.select([db.func.count(Warning.expires)]).where( - (Warning.penguin_id == player.data.id) & (Warning.expires >= date_issued)).gino.scalar() - - if warning_count >= 3: - return await moderator_ban(p, player.data.id, comment='Exceeded warning limit') - - await player.send_xt('moderatormessage', type) - await Warning.create(penguin_id=player.data.id, expires=date_expires) + await player.send_error_and_disconnect(611, comment) async def moderator_kick(p, penguin_id): - if penguin_id in p.server.penguins_by_id and p.data.moderator: + if penguin_id in p.server.penguins_by_id: player = p.server.penguins_by_id[penguin_id] - if not player.data.moderator: + if not player.moderator: for penguin in p.server.penguins_by_id.values(): - if penguin.data.moderator: - await penguin.send_xt('ma', 'k', penguin_id, player.data.username) + if penguin.moderator: + await penguin.send_xt('ma', 'k', penguin_id, player.username) await player.send_error_and_disconnect(5) -async def moderator_ban(p, penguin_id, hours=24, comment=''): - if penguin_id in p.server.penguins_by_id and p.data.moderator: - player = p.server.penguins_by_id[penguin_id] - if not player.data.moderator: - for penguin in p.server.penguins_by_id.values(): - if penguin.data.moderator: - await penguin.send_xt('ma', 'b', penguin_id, player.data.username) +async def moderator_ban(p, penguin_id, hours=24, comment='', message=''): + player = p.server.penguins_by_id[penguin_id] if penguin_id in p.server.penguins_by_id \ + else await Penguin.get(penguin_id) + if not player.moderator: + for penguin in p.server.penguins_by_id.values(): + if penguin.moderator: + await penguin.send_xt('ma', 'b', penguin_id, player.username) - number_bans = await db.select([db.func.count(Ban.penguin_id)]).where( - Ban.penguin_id == player.data.id).gino.scalar() + number_bans = await db.select([db.func.count(Ban.penguin_id)]).where( + Ban.penguin_id == player.id).gino.scalar() - date_issued = datetime.datetime.now() - date_expires = date_issued + datetime.timedelta(hours=hours) + date_issued = datetime.datetime.now() + date_expires = date_issued + datetime.timedelta(hours=hours) - if number_bans >= 3: - await player.data.update(permaban=True).apply() + if number_bans >= 3: + await player.update(permaban=True).apply() - await Ban.create(penguin_id=player.data.id, issued=date_issued, expires=date_expires, - moderator_id=p.data.id, reason=1, comment=comment) + await Ban.create(penguin_id=player.id, issued=date_issued, expires=date_expires, + moderator_id=p.id, reason=2, comment=comment, message=message) - await player.send_error_and_disconnect(610, comment) - await player.close() + if penguin_id in p.server.penguins_by_id: + if player.is_vanilla_client: + await player.send_xt('ban', 612, 2, hours, comment) + else: + await player.send_error_and_disconnect(610, comment)