From 1efe0817b24ae07d34b9ca5bbe1cf06a745c9eac Mon Sep 17 00:00:00 2001 From: admin Date: Thu, 8 Oct 2026 00:43:17 +0000 Subject: [PATCH] Update app.py --- app.py | 98 ++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 82 insertions(+), 16 deletions(-) diff --git a/app.py b/app.py index 9939824..2eb587e 100644 --- a/app.py +++ b/app.py @@ -59,6 +59,7 @@ MAX_LOCATION_LENGTH = 120 MAX_WEBSITE_LENGTH = 300 MAX_CUSTOM_CSS_LENGTH = 20000 MAX_PROFILE_BADGE_LENGTH = 48 +MAX_STATUS_MESSAGE_LENGTH = 160 MAX_OWNED_TEAMS_PER_USER = 3 MAX_MESSAGE_EDIT_WINDOW_SECONDS = 15 * 60 MAX_SEARCH_QUERY_LENGTH = 120 @@ -850,7 +851,7 @@ def csrf_valid() -> bool: return bool(supplied and expected and hmac.compare_digest(supplied, expected)) -def user_payload(row: sqlite3.Row) -> dict: +def user_payload(row: sqlite3.Row, settings_row: Optional[sqlite3.Row] = None) -> dict: status = row["status"] restricted_until = parse_iso(row["restricted_until"]) if status == "restricted" and restricted_until and restricted_until <= utc_now(): @@ -861,6 +862,7 @@ def user_payload(row: sqlite3.Row) -> dict: "role": row["role"], "status": status, "restricted_until": row["restricted_until"], + "presence_mode": settings_row["presence_mode"] if settings_row and "presence_mode" in settings_row.keys() else "online", } @@ -882,11 +884,19 @@ def current_user() -> Optional[dict]: """, (user_id,), ).fetchone() + settings_row = db.execute( + """ + SELECT presence_mode + FROM user_settings + WHERE user_id = ? + """, + (user_id,), + ).fetchone() if not row: session.clear() return None - user = user_payload(row) + user = user_payload(row, settings_row) if user["status"] == "restricted": expires = parse_iso(user["restricted_until"]) if expires and expires <= utc_now(): @@ -922,6 +932,7 @@ def login_user(row: sqlite3.Row | dict) -> dict: "role": row["role"], "status": row["status"], "restricted_until": row.get("restricted_until") if isinstance(row, dict) else row["restricted_until"], + "presence_mode": row.get("presence_mode", "online") if isinstance(row, dict) else "online", } @@ -1376,8 +1387,11 @@ def init_db() -> None: bio_mode TEXT NOT NULL DEFAULT 'txt', website TEXT, location TEXT, + status_message TEXT, + banner_attachment_id INTEGER, updated_at TEXT NOT NULL, - FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE, + FOREIGN KEY (banner_attachment_id) REFERENCES attachments(id) ON DELETE SET NULL ) """ ) @@ -1389,6 +1403,11 @@ def init_db() -> None: name_color TEXT, custom_css TEXT NOT NULL DEFAULT '', theme_mode TEXT NOT NULL DEFAULT 'dark', + profile_background_color TEXT, + profile_banner_color TEXT, + profile_visibility TEXT NOT NULL DEFAULT 'public', + last_active_visibility TEXT NOT NULL DEFAULT 'everyone', + presence_mode TEXT NOT NULL DEFAULT 'online', updated_at TEXT NOT NULL, FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ) @@ -1610,10 +1629,24 @@ def init_db() -> None: db.execute("ALTER TABLE messages ADD COLUMN direct_conversation_id INTEGER") if not column_exists(db, "user_settings", "name_color"): db.execute("ALTER TABLE user_settings ADD COLUMN name_color TEXT") + if not column_exists(db, "user_settings", "profile_background_color"): + db.execute("ALTER TABLE user_settings ADD COLUMN profile_background_color TEXT") + if not column_exists(db, "user_settings", "profile_banner_color"): + db.execute("ALTER TABLE user_settings ADD COLUMN profile_banner_color TEXT") + if not column_exists(db, "user_settings", "profile_visibility"): + db.execute("ALTER TABLE user_settings ADD COLUMN profile_visibility TEXT NOT NULL DEFAULT 'public'") + if not column_exists(db, "user_settings", "last_active_visibility"): + db.execute("ALTER TABLE user_settings ADD COLUMN last_active_visibility TEXT NOT NULL DEFAULT 'everyone'") + if not column_exists(db, "user_settings", "presence_mode"): + db.execute("ALTER TABLE user_settings ADD COLUMN presence_mode TEXT NOT NULL DEFAULT 'online'") if not column_exists(db, "presence_events", "direct_conversation_id"): db.execute("ALTER TABLE presence_events ADD COLUMN direct_conversation_id INTEGER") if not column_exists(db, "user_profiles", "badge_text"): db.execute("ALTER TABLE user_profiles ADD COLUMN badge_text TEXT") + if not column_exists(db, "user_profiles", "status_message"): + db.execute("ALTER TABLE user_profiles ADD COLUMN status_message TEXT") + if not column_exists(db, "user_profiles", "banner_attachment_id"): + db.execute("ALTER TABLE user_profiles ADD COLUMN banner_attachment_id INTEGER") if not column_exists(db, "pages", "parent_page_id"): db.execute("ALTER TABLE pages ADD COLUMN parent_page_id INTEGER") @@ -1810,6 +1843,8 @@ def init_db() -> None: bio_mode, website, location, + status_message, + banner_attachment_id, updated_at ) SELECT @@ -1820,6 +1855,8 @@ def init_db() -> None: 'txt', '', '', + '', + NULL, ? FROM users """, @@ -1833,6 +1870,11 @@ def init_db() -> None: name_color, custom_css, theme_mode, + profile_background_color, + profile_banner_color, + profile_visibility, + last_active_visibility, + presence_mode, updated_at ) SELECT @@ -1841,6 +1883,11 @@ def init_db() -> None: NULL, '', 'dark', + NULL, + NULL, + 'public', + 'everyone', + 'online', ? FROM users """, @@ -1927,8 +1974,10 @@ def bootstrap_admin() -> None: bio_mode, website, location, + status_message, + banner_attachment_id, updated_at - ) VALUES (?, ?, '', '', 'txt', '', '', ?) + ) VALUES (?, ?, '', '', 'txt', '', '', '', NULL, ?) """, (user_id, username, now_iso()), ) @@ -1940,8 +1989,13 @@ def bootstrap_admin() -> None: name_color, custom_css, theme_mode, + profile_background_color, + profile_banner_color, + profile_visibility, + last_active_visibility, + presence_mode, updated_at - ) VALUES (?, '#f7dce8', NULL, '', 'dark', ?) + ) VALUES (?, '#f7dce8', NULL, '', 'dark', NULL, NULL, 'public', 'everyone', 'online', ?) """, (user_id, now_iso()), ) @@ -2019,6 +2073,7 @@ def register(): "role": "user", "status": "active", "restricted_until": None, + "presence_mode": "online", } db_write( """ @@ -2030,8 +2085,10 @@ def register(): bio_mode, website, location, + status_message, + banner_attachment_id, updated_at - ) VALUES (?, ?, '', '', 'txt', '', '', ?) + ) VALUES (?, ?, '', '', 'txt', '', '', '', NULL, ?) """, (user["id"], username, now_iso()), ) @@ -2043,8 +2100,13 @@ def register(): name_color, custom_css, theme_mode, + profile_background_color, + profile_banner_color, + profile_visibility, + last_active_visibility, + presence_mode, updated_at - ) VALUES (?, '#f7dce8', NULL, '', 'dark', ?) + ) VALUES (?, '#f7dce8', NULL, '', 'dark', NULL, NULL, 'public', 'everyone', 'online', ?) """, (user["id"], now_iso()), ) @@ -2084,14 +2146,17 @@ def login(): row = db.execute( """ SELECT - id, - username, - password_hash, - role, - status, - restricted_until - FROM users - WHERE username = ? + u.id, + u.username, + u.password_hash, + u.role, + u.status, + u.restricted_until, + us.presence_mode + FROM users u + LEFT JOIN user_settings us + ON us.user_id = u.id + WHERE u.username = ? """, (username,), ).fetchone() @@ -2102,7 +2167,7 @@ def login(): return jsonify({"error": "Invalid username or password."}), 401 db_write("UPDATE users SET last_login_at = ? WHERE id = ?", (now_iso(), row["id"])) - authenticated = login_user(row) + authenticated = login_user(dict(row)) audit("account_logged_in", row["id"], "user", str(row["id"])) return jsonify( { @@ -2237,6 +2302,7 @@ register_routes( "MAX_WEBSITE_LENGTH": MAX_WEBSITE_LENGTH, "MAX_CUSTOM_CSS_LENGTH": MAX_CUSTOM_CSS_LENGTH, "MAX_PROFILE_BADGE_LENGTH": MAX_PROFILE_BADGE_LENGTH, + "MAX_STATUS_MESSAGE_LENGTH": MAX_STATUS_MESSAGE_LENGTH, "MAX_OWNED_TEAMS_PER_USER": MAX_OWNED_TEAMS_PER_USER, "MAX_PAGE_COMMENT_LENGTH": MAX_PAGE_COMMENT_LENGTH, "ROOM_VISIBILITIES": ROOM_VISIBILITIES,