Fix #10: Persist bans and mutes to database
- Add Ban and Mute models to models.py - Load persisted bans/mutes from DB on app startup in create_app() - Persist ban to DB on mod_ban and mod_kickban - Persist/delete mute to DB on mod_mute toggle - Bans and mutes now survive server restarts
This commit is contained in:
parent
496701c713
commit
9570283ad8
34
app.py
34
app.py
|
|
@ -53,7 +53,7 @@ from flask import Flask, request, send_from_directory
|
||||||
from flask_socketio import SocketIO, emit, join_room, disconnect
|
from flask_socketio import SocketIO, emit, join_room, disconnect
|
||||||
|
|
||||||
from database import db, init_db
|
from database import db, init_db
|
||||||
from models import User, Message, UserIgnore
|
from models import User, Message, UserIgnore, Ban, Mute
|
||||||
from config import (
|
from config import (
|
||||||
SECRET_KEY, ADMIN_PASSWORD, DATABASE_URL, CORS_ORIGINS,
|
SECRET_KEY, ADMIN_PASSWORD, DATABASE_URL, CORS_ORIGINS,
|
||||||
MAX_MSG_LEN, LOBBY, AI_FREE_LIMIT, AI_BOT_NAME,
|
MAX_MSG_LEN, LOBBY, AI_FREE_LIMIT, AI_BOT_NAME,
|
||||||
|
|
@ -304,6 +304,15 @@ def create_app() -> Flask:
|
||||||
init_db(app)
|
init_db(app)
|
||||||
_app_ref = app
|
_app_ref = app
|
||||||
|
|
||||||
|
# Load persisted bans and mutes from the database
|
||||||
|
with app.app_context():
|
||||||
|
for ban in Ban.query.all():
|
||||||
|
banned_usernames.add(ban.username.lower())
|
||||||
|
if ban.ip:
|
||||||
|
banned_ips.add(ban.ip)
|
||||||
|
for mute in Mute.query.all():
|
||||||
|
muted_users.add(mute.username.lower())
|
||||||
|
|
||||||
msg_queue = (
|
msg_queue = (
|
||||||
os.environ.get("SOCKETIO_MESSAGE_QUEUE")
|
os.environ.get("SOCKETIO_MESSAGE_QUEUE")
|
||||||
or os.environ.get("REDIS_URL")
|
or os.environ.get("REDIS_URL")
|
||||||
|
|
@ -659,13 +668,19 @@ def on_ban(data):
|
||||||
target = str(data.get("target", "")).strip()
|
target = str(data.get("target", "")).strip()
|
||||||
lower = target.lower()
|
lower = target.lower()
|
||||||
banned_usernames.add(lower)
|
banned_usernames.add(lower)
|
||||||
|
ip = None
|
||||||
target_sid = username_to_sid.get(lower)
|
target_sid = username_to_sid.get(lower)
|
||||||
if target_sid:
|
if target_sid:
|
||||||
info = connected_users.get(target_sid, {})
|
info = connected_users.get(target_sid, {})
|
||||||
if info.get("ip"):
|
if info.get("ip"):
|
||||||
banned_ips.add(info["ip"])
|
banned_ips.add(info["ip"])
|
||||||
|
ip = info["ip"]
|
||||||
socketio.emit("kicked", {"msg": "You have been banned."}, to=target_sid)
|
socketio.emit("kicked", {"msg": "You have been banned."}, to=target_sid)
|
||||||
eventlet.spawn_after(0.5, _do_disconnect, target_sid)
|
eventlet.spawn_after(0.5, _do_disconnect, target_sid)
|
||||||
|
# Persist to DB
|
||||||
|
if not Ban.query.filter_by(username=lower).first():
|
||||||
|
db.session.add(Ban(username=lower, ip=ip))
|
||||||
|
db.session.commit()
|
||||||
socketio.emit("system", {"msg": f"🔨 **{target}** was banned.", "ts": _ts()}, to=LOBBY)
|
socketio.emit("system", {"msg": f"🔨 **{target}** was banned.", "ts": _ts()}, to=LOBBY)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -675,9 +690,16 @@ def on_mute(data):
|
||||||
target = str(data.get("target", "")).strip()
|
target = str(data.get("target", "")).strip()
|
||||||
lower = target.lower()
|
lower = target.lower()
|
||||||
if lower in muted_users:
|
if lower in muted_users:
|
||||||
muted_users.discard(lower); action = "unmuted"
|
muted_users.discard(lower)
|
||||||
|
Mute.query.filter_by(username=lower).delete()
|
||||||
|
db.session.commit()
|
||||||
|
action = "unmuted"
|
||||||
else:
|
else:
|
||||||
muted_users.add(lower); action = "muted"
|
muted_users.add(lower)
|
||||||
|
if not Mute.query.filter_by(username=lower).first():
|
||||||
|
db.session.add(Mute(username=lower))
|
||||||
|
db.session.commit()
|
||||||
|
action = "muted"
|
||||||
emit("system", {"msg": f"🔇 **{target}** was {action}.", "ts": _ts()}, to=LOBBY)
|
emit("system", {"msg": f"🔇 **{target}** was {action}.", "ts": _ts()}, to=LOBBY)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -688,13 +710,19 @@ def on_kickban(data):
|
||||||
lower = target.lower()
|
lower = target.lower()
|
||||||
# Ban
|
# Ban
|
||||||
banned_usernames.add(lower)
|
banned_usernames.add(lower)
|
||||||
|
ip = None
|
||||||
target_sid = username_to_sid.get(lower)
|
target_sid = username_to_sid.get(lower)
|
||||||
if target_sid:
|
if target_sid:
|
||||||
info = connected_users.get(target_sid, {})
|
info = connected_users.get(target_sid, {})
|
||||||
if info.get("ip"):
|
if info.get("ip"):
|
||||||
banned_ips.add(info["ip"])
|
banned_ips.add(info["ip"])
|
||||||
|
ip = info["ip"]
|
||||||
socketio.emit("kicked", {"msg": "You have been banned."}, to=target_sid)
|
socketio.emit("kicked", {"msg": "You have been banned."}, to=target_sid)
|
||||||
eventlet.spawn_after(0.5, _do_disconnect, target_sid)
|
eventlet.spawn_after(0.5, _do_disconnect, target_sid)
|
||||||
|
# Persist to DB
|
||||||
|
if not Ban.query.filter_by(username=lower).first():
|
||||||
|
db.session.add(Ban(username=lower, ip=ip))
|
||||||
|
db.session.commit()
|
||||||
# Announce
|
# Announce
|
||||||
socketio.emit("system", {"msg": f"💀 **{target}** was kickbanned.", "ts": _ts()}, to=LOBBY)
|
socketio.emit("system", {"msg": f"💀 **{target}** was kickbanned.", "ts": _ts()}, to=LOBBY)
|
||||||
|
|
||||||
|
|
|
||||||
20
models.py
20
models.py
|
|
@ -80,3 +80,23 @@ class Message(db.Model):
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<Message {self.sender_id}→{self.recipient_id} @ {self.timestamp}>"
|
return f"<Message {self.sender_id}→{self.recipient_id} @ {self.timestamp}>"
|
||||||
|
|
||||||
|
|
||||||
|
class Ban(db.Model):
|
||||||
|
"""Persisted ban entry – survives server restarts."""
|
||||||
|
__tablename__ = "bans"
|
||||||
|
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
username = db.Column(db.String(20), nullable=False, index=True)
|
||||||
|
ip = db.Column(db.String(45), nullable=True, index=True)
|
||||||
|
reason = db.Column(db.String(255), nullable=True)
|
||||||
|
created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
|
||||||
|
|
||||||
|
|
||||||
|
class Mute(db.Model):
|
||||||
|
"""Persisted mute entry – survives server restarts."""
|
||||||
|
__tablename__ = "mutes"
|
||||||
|
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
username = db.Column(db.String(20), unique=True, nullable=False, index=True)
|
||||||
|
created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue