Update app.py

This commit is contained in:
dev 2026-10-31 09:37:17 +00:00
parent 98997e26ca
commit 513ea3e577

133
app.py
View File

@ -597,11 +597,53 @@ MESSAGE_SELECT = """
def team_page_select() -> str: def team_page_select() -> str:
has_parent_page = False
try:
with get_db() as db:
has_parent_page = column_exists(db, "pages", "parent_page_id")
except Exception:
has_parent_page = False
if has_parent_page:
return """
SELECT
p.id,
p.team_id,
p.channel_id,
p.parent_page_id,
parent.slug AS parent_page_slug,
parent.title AS parent_page_title,
p.slug,
p.title,
p.body,
p.visibility,
p.page_type,
p.created_by_user_id,
p.updated_by_user_id,
p.created_at,
p.updated_at,
p.is_active,
t.slug AS team_slug,
t.name AS team_name,
c.slug AS channel_slug,
c.name AS channel_name
FROM pages AS p
JOIN teams AS t
ON t.id = p.team_id
LEFT JOIN channels AS c
ON c.id = p.channel_id
LEFT JOIN pages AS parent
ON parent.id = p.parent_page_id
"""
return """ return """
SELECT SELECT
p.id, p.id,
p.team_id, p.team_id,
p.channel_id, p.channel_id,
NULL AS parent_page_id,
NULL AS parent_page_slug,
NULL AS parent_page_title,
p.slug, p.slug,
p.title, p.title,
p.body, p.body,
@ -857,6 +899,7 @@ def user_payload(row: sqlite3.Row, settings_row: sqlite3.Row | None = None) -> d
"restricted_until": row["restricted_until"], "restricted_until": row["restricted_until"],
} }
def current_user() -> Optional[dict]: def current_user() -> Optional[dict]:
user_id = session.get("user_id") user_id = session.get("user_id")
if not user_id: if not user_id:
@ -950,7 +993,7 @@ def require_writable_user():
def require_moderator(): def require_moderator():
user, error = require_writable_user() user, error = require_writable_user()
if error: if error:
return None, error return error[0] if isinstance(error, tuple) and len(error) == 2 else error
if user["role"] not in {"moderator", "admin"}: if user["role"] not in {"moderator", "admin"}:
return None, (jsonify({"error": "Moderator access required.", "code": "forbidden"}), 403) return None, (jsonify({"error": "Moderator access required.", "code": "forbidden"}), 403)
return user, None return user, None
@ -1320,8 +1363,11 @@ def init_db() -> None:
bio_mode TEXT NOT NULL DEFAULT 'txt', bio_mode TEXT NOT NULL DEFAULT 'txt',
website TEXT, website TEXT,
location TEXT, location TEXT,
status_message TEXT NOT NULL DEFAULT '',
banner_attachment_id INTEGER,
updated_at TEXT NOT NULL, 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
) )
""" """
) )
@ -1334,6 +1380,13 @@ def init_db() -> None:
name_color TEXT, name_color TEXT,
custom_css TEXT NOT NULL DEFAULT '', custom_css TEXT NOT NULL DEFAULT '',
theme_mode TEXT NOT NULL DEFAULT 'dark', 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',
dm_layout_mode TEXT NOT NULL DEFAULT 'cards',
show_presence_badge INTEGER NOT NULL DEFAULT 1,
updated_at TEXT NOT NULL, 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
) )
@ -1525,12 +1578,33 @@ def init_db() -> None:
db.execute("ALTER TABLE messages ADD COLUMN channel_id INTEGER") db.execute("ALTER TABLE messages ADD COLUMN channel_id INTEGER")
if not column_exists(db, "messages", "direct_conversation_id"): if not column_exists(db, "messages", "direct_conversation_id"):
db.execute("ALTER TABLE messages ADD COLUMN direct_conversation_id INTEGER") 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, "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"): if not column_exists(db, "user_profiles", "badge_text"):
db.execute("ALTER TABLE user_profiles ADD COLUMN badge_text 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 NOT NULL DEFAULT ''")
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, "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, "user_settings", "dm_layout_mode"):
db.execute("ALTER TABLE user_settings ADD COLUMN dm_layout_mode TEXT NOT NULL DEFAULT 'cards'")
if not column_exists(db, "user_settings", "show_presence_badge"):
db.execute("ALTER TABLE user_settings ADD COLUMN show_presence_badge INTEGER NOT NULL DEFAULT 1")
if not column_exists(db, "presence_events", "direct_conversation_id"):
db.execute("ALTER TABLE presence_events ADD COLUMN direct_conversation_id INTEGER")
db.execute("CREATE INDEX IF NOT EXISTS idx_messages_room_id_id ON messages(room_id, id)") db.execute("CREATE INDEX IF NOT EXISTS idx_messages_room_id_id ON messages(room_id, id)")
db.execute("CREATE INDEX IF NOT EXISTS idx_messages_channel_id_id ON messages(channel_id, id)") db.execute("CREATE INDEX IF NOT EXISTS idx_messages_channel_id_id ON messages(channel_id, id)")
@ -1722,6 +1796,8 @@ def init_db() -> None:
bio_mode, bio_mode,
website, website,
location, location,
status_message,
banner_attachment_id,
updated_at updated_at
) )
SELECT SELECT
@ -1732,6 +1808,8 @@ def init_db() -> None:
'txt', 'txt',
'', '',
'', '',
'',
NULL,
? ?
FROM users FROM users
""", """,
@ -1746,6 +1824,13 @@ def init_db() -> None:
name_color, name_color,
custom_css, custom_css,
theme_mode, theme_mode,
profile_background_color,
profile_banner_color,
profile_visibility,
last_active_visibility,
presence_mode,
dm_layout_mode,
show_presence_badge,
updated_at updated_at
) )
SELECT SELECT
@ -1754,6 +1839,13 @@ def init_db() -> None:
NULL, NULL,
'', '',
'dark', 'dark',
NULL,
NULL,
'public',
'everyone',
'online',
'cards',
1,
? ?
FROM users FROM users
""", """,
@ -1796,7 +1888,7 @@ def bootstrap_admin() -> None:
return return
if validate_username(username) or validate_password(password, username): if validate_username(username) or validate_password(password, username):
print("WARNING: Admin bootstrap credentials failed validation.") print("warning: admin bootstrap credentials failed validation.")
return return
with get_db() as db: with get_db() as db:
@ -1846,8 +1938,10 @@ def bootstrap_admin() -> None:
bio_mode, bio_mode,
website, website,
location, location,
status_message,
banner_attachment_id,
updated_at updated_at
) VALUES (?, ?, '', '', 'txt', '', '', ?) ) VALUES (?, ?, '', '', 'txt', '', '', '', NULL, ?)
""", """,
(user_id, username, now_iso()), (user_id, username, now_iso()),
) )
@ -1860,8 +1954,15 @@ def bootstrap_admin() -> None:
name_color, name_color,
custom_css, custom_css,
theme_mode, theme_mode,
profile_background_color,
profile_banner_color,
profile_visibility,
last_active_visibility,
presence_mode,
dm_layout_mode,
show_presence_badge,
updated_at updated_at
) VALUES (?, '#f7dce8', NULL, '', 'dark', ?) ) VALUES (?, '#f7dce8', NULL, '', 'dark', NULL, NULL, 'public', 'everyone', 'online', 'cards', 1, ?)
""", """,
(user_id, now_iso()), (user_id, now_iso()),
) )
@ -1893,7 +1994,6 @@ def api_me():
@app.route("/api/register", methods=["POST"]) @app.route("/api/register", methods=["POST"])
def register(): def register():
limited = rate_limited("register") limited = rate_limited("register")
if limited: if limited:
return limited return limited
@ -1957,8 +2057,10 @@ def register():
bio_mode, bio_mode,
website, website,
location, location,
status_message,
banner_attachment_id,
updated_at updated_at
) VALUES (?, ?, '', '', 'txt', '', '', ?) ) VALUES (?, ?, '', '', 'txt', '', '', '', NULL, ?)
""", """,
(user["id"], username, now_iso()), (user["id"], username, now_iso()),
) )
@ -1971,8 +2073,15 @@ def register():
name_color, name_color,
custom_css, custom_css,
theme_mode, theme_mode,
profile_background_color,
profile_banner_color,
profile_visibility,
last_active_visibility,
presence_mode,
dm_layout_mode,
show_presence_badge,
updated_at updated_at
) VALUES (?, '#f7dce8', NULL, '', 'dark', ?) ) VALUES (?, '#f7dce8', NULL, '', 'dark', NULL, NULL, 'public', 'everyone', 'online', 'cards', 1, ?)
""", """,
(user["id"], now_iso()), (user["id"], now_iso()),
) )