From d5e942d06d0302722538213bd9e904b018592998 Mon Sep 17 00:00:00 2001 From: 3nd3r Date: Sun, 12 Apr 2026 14:17:52 -0500 Subject: [PATCH] Add settings panel with Account, Chat, Violet, and Premium tabs - Gear icon in header opens settings modal - Account: view username/email, change password (server-side bcrypt) - Chat: font size slider, 12h/24h timestamps, enter-to-send toggle, sounds toggle - Violet: view AI access status, reset conversation memory - Premium: feature showcase with upgrade CTA (payment coming soon) - All chat prefs saved to localStorage - Font size applied via CSS custom property - Timestamp format conversion (24h server -> 12h client option) - Icon button styling for gear and hamburger menu --- app.py | 37 ++++++ index.html | 135 ++++++++++++++++++++++ static/chat.js | 163 +++++++++++++++++++++++++- static/style.css | 293 ++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 625 insertions(+), 3 deletions(-) diff --git a/app.py b/app.py index 57d840d..3b742f0 100644 --- a/app.py +++ b/app.py @@ -536,6 +536,7 @@ def on_join(data): "is_registered": user["is_registered"], "has_ai_access": user["has_ai_access"], "ai_messages_used": user["ai_messages_used"], + "email": db_user.email if db_user else None, "token": token, "ignored_list": [u.username for u in db_user.ignoring] if db_user else [] }) @@ -871,3 +872,39 @@ def on_verify(data): socketio.emit("system", {"msg": f"✅ **{target_user.username}** has been verified by a moderator.", "ts": _ts()}, to=LOBBY) socketio.emit("nicklist", {"users": _get_nicklist()}, to=LOBBY) + + +# --------------------------------------------------------------------------- +# Account management +# --------------------------------------------------------------------------- + +@socketio.on("change_password") +def on_change_password(data): + sid = request.sid + user = connected_users.get(sid) + if not user or not user.get("user_id"): + emit("password_changed", {"success": False, "msg": "You must be registered."}) + return + + old_pw = str(data.get("old_password", "")) + new_pw = str(data.get("new_password", "")) + + if not old_pw or not new_pw: + emit("password_changed", {"success": False, "msg": "Both fields are required."}) + return + if len(new_pw) < 6: + emit("password_changed", {"success": False, "msg": "Password must be at least 6 characters."}) + return + + db_user = db.session.get(User, user["user_id"]) + if not db_user: + emit("password_changed", {"success": False, "msg": "User not found."}) + return + + if not bcrypt.checkpw(old_pw.encode("utf-8"), db_user.password_hash.encode("utf-8")): + emit("password_changed", {"success": False, "msg": "Current password is incorrect."}) + return + + db_user.password_hash = bcrypt.hashpw(new_pw.encode("utf-8"), bcrypt.gensalt()).decode("utf-8") + db.session.commit() + emit("password_changed", {"success": True}) diff --git a/index.html b/index.html index 6188f2a..523836c 100644 --- a/index.html +++ b/index.html @@ -89,6 +89,11 @@
+
@@ -165,6 +170,136 @@ + + +