Update features.py

This commit is contained in:
dev 2026-10-31 08:41:34 +00:00
parent 80a5dc5c15
commit 6b5cd404df

View File

@ -33,6 +33,7 @@ TEAM_MEMBER_ROLES = {"owner", "admin", "member"}
PROFILE_VISIBILITIES = {"public", "members", "private"} PROFILE_VISIBILITIES = {"public", "members", "private"}
LAST_ACTIVE_VISIBILITIES = {"everyone", "members", "nobody"} LAST_ACTIVE_VISIBILITIES = {"everyone", "members", "nobody"}
PRESENCE_MODES = {"online", "silent", "focus", "dnd"} PRESENCE_MODES = {"online", "silent", "focus", "dnd"}
DM_LAYOUT_MODES = {"cards", "compact"}
REACTION_EMOJI_RE = re.compile(r"^.{1,16}$") REACTION_EMOJI_RE = re.compile(r"^.{1,16}$")
HEX_COLOR_RE = re.compile(r"^#[0-9a-fA-F]{6}$") HEX_COLOR_RE = re.compile(r"^#[0-9a-fA-F]{6}$")
PAGE_LINK_RE = re.compile(r"\]\((?:/teams/[^/]+/pages/)?([a-z0-9-]{1,48})\)", re.IGNORECASE) PAGE_LINK_RE = re.compile(r"\]\((?:/teams/[^/]+/pages/)?([a-z0-9-]{1,48})\)", re.IGNORECASE)
@ -86,6 +87,33 @@ def extract_page_reference_slugs(markdown_text: str) -> list[str]:
return slugs return slugs
def detect_website_brand(website: str) -> dict:
value = str(website or "").strip().lower()
if not value:
return {"host": "", "brand": "web", "label": "website"}
host = value
host = host.replace("https://", "").replace("http://", "")
host = host.split("/", 1)[0]
host = host.removeprefix("www.")
mappings = [
("github.com", "github", "GitHub"),
("youtube.com", "youtube", "YouTube"),
("youtu.be", "youtube", "YouTube"),
("spotify.com", "spotify", "Spotify"),
("soundcloud.com", "soundcloud", "SoundCloud"),
("twitter.com", "x", "X"),
("x.com", "x", "X"),
]
for suffix, brand, label in mappings:
if host.endswith(suffix):
return {"host": host, "brand": brand, "label": label}
return {"host": host, "brand": "web", "label": "website"}
def attachment_kind_from_name_and_mime( def attachment_kind_from_name_and_mime(
original_name: Optional[str], original_name: Optional[str],
mime_type: Optional[str], mime_type: Optional[str],
@ -104,6 +132,18 @@ def attachment_kind_from_name_and_mime(
def load_page_children(get_db, page_id: int) -> list[dict]: def load_page_children(get_db, page_id: int) -> list[dict]:
with get_db() as db: with get_db() as db:
has_parent_page = bool(
db.execute(
"""
SELECT 1
FROM pragma_table_info('pages')
WHERE name = 'parent_page_id'
"""
).fetchone()
)
if not has_parent_page:
return []
rows = db.execute( rows = db.execute(
""" """
SELECT SELECT
@ -146,6 +186,19 @@ def load_page_backlinks(get_db, page_id: int, page_slug: str, team_id: int) -> l
def load_page_comments(get_db, page_id: int) -> list[dict]: def load_page_comments(get_db, page_id: int) -> list[dict]:
with get_db() as db: with get_db() as db:
table_exists = bool(
db.execute(
"""
SELECT 1
FROM sqlite_master
WHERE type = 'table'
AND name = 'page_comments'
"""
).fetchone()
)
if not table_exists:
return []
rows = db.execute( rows = db.execute(
""" """
SELECT SELECT
@ -187,6 +240,19 @@ def load_page_comments(get_db, page_id: int) -> list[dict]:
def next_page_version_number(get_db, page_id: int) -> int: def next_page_version_number(get_db, page_id: int) -> int:
with get_db() as db: with get_db() as db:
table_exists = bool(
db.execute(
"""
SELECT 1
FROM sqlite_master
WHERE type = 'table'
AND name = 'page_versions'
"""
).fetchone()
)
if not table_exists:
return 1
row = db.execute( row = db.execute(
""" """
SELECT COALESCE(MAX(version_number), 0) AS value SELECT COALESCE(MAX(version_number), 0) AS value
@ -210,6 +276,20 @@ def snapshot_page_version(
created_by_user_id: int, created_by_user_id: int,
created_at: str, created_at: str,
) -> int: ) -> int:
with get_db() as db:
table_exists = bool(
db.execute(
"""
SELECT 1
FROM sqlite_master
WHERE type = 'table'
AND name = 'page_versions'
"""
).fetchone()
)
if not table_exists:
return 0
version_number = next_page_version_number(get_db, page_id) version_number = next_page_version_number(get_db, page_id)
with get_db() as db: with get_db() as db:
db.execute("BEGIN IMMEDIATE") db.execute("BEGIN IMMEDIATE")
@ -247,6 +327,19 @@ def snapshot_page_version(
def load_page_versions(get_db, page_id: int) -> list[dict]: def load_page_versions(get_db, page_id: int) -> list[dict]:
with get_db() as db: with get_db() as db:
table_exists = bool(
db.execute(
"""
SELECT 1
FROM sqlite_master
WHERE type = 'table'
AND name = 'page_versions'
"""
).fetchone()
)
if not table_exists:
return []
rows = db.execute( rows = db.execute(
""" """
SELECT SELECT
@ -274,6 +367,19 @@ def load_page_versions(get_db, page_id: int) -> list[dict]:
def load_page_version_detail(get_db, version_id: int): def load_page_version_detail(get_db, version_id: int):
with get_db() as db: with get_db() as db:
table_exists = bool(
db.execute(
"""
SELECT 1
FROM sqlite_master
WHERE type = 'table'
AND name = 'page_versions'
"""
).fetchone()
)
if not table_exists:
return None
row = db.execute( row = db.execute(
""" """
SELECT SELECT
@ -330,6 +436,9 @@ def page_payload(app_module, page, user: Optional[dict]) -> dict:
) )
) )
rendered_html = render_markdown_to_safe_html(page["body"] or "") rendered_html = render_markdown_to_safe_html(page["body"] or "")
parent_page_id = page["parent_page_id"] if "parent_page_id" in page.keys() else None
parent_page_slug = page["parent_page_slug"] if "parent_page_slug" in page.keys() else None
parent_page_title = page["parent_page_title"] if "parent_page_title" in page.keys() else None
return { return {
"id": page["id"], "id": page["id"],
"team_id": page["team_id"], "team_id": page["team_id"],
@ -338,9 +447,9 @@ def page_payload(app_module, page, user: Optional[dict]) -> dict:
"channel_id": page["channel_id"], "channel_id": page["channel_id"],
"channel_slug": page["channel_slug"], "channel_slug": page["channel_slug"],
"channel_name": page["channel_name"], "channel_name": page["channel_name"],
"parent_page_id": page["parent_page_id"] if "parent_page_id" in page.keys() else None, "parent_page_id": parent_page_id,
"parent_page_slug": page["parent_page_slug"] if "parent_page_slug" in page.keys() else None, "parent_page_slug": parent_page_slug,
"parent_page_title": page["parent_page_title"] if "parent_page_title" in page.keys() else None, "parent_page_title": parent_page_title,
"slug": page["slug"], "slug": page["slug"],
"title": page["title"], "title": page["title"],
"body": page["body"], "body": page["body"],
@ -740,6 +849,30 @@ def richer_message_payload(
seen_by_user = False seen_by_user = False
is_bookmarked = False is_bookmarked = False
is_pinned = False
pin_row = None
bookmark_table_exists = bool(
db.execute(
"""
SELECT 1
FROM sqlite_master
WHERE type = 'table'
AND name = 'message_bookmarks'
"""
).fetchone()
)
pin_table_exists = bool(
db.execute(
"""
SELECT 1
FROM sqlite_master
WHERE type = 'table'
AND name = 'message_pins'
"""
).fetchone()
)
if current_user_id: if current_user_id:
seen_by_user = bool( seen_by_user = bool(
db.execute( db.execute(
@ -752,26 +885,29 @@ def richer_message_payload(
(row["id"], current_user_id), (row["id"], current_user_id),
).fetchone() ).fetchone()
) )
is_bookmarked = bool( if bookmark_table_exists:
db.execute( is_bookmarked = bool(
""" db.execute(
SELECT 1 """
FROM message_bookmarks SELECT 1
WHERE message_id = ? FROM message_bookmarks
AND user_id = ? WHERE message_id = ?
""", AND user_id = ?
(row["id"], current_user_id), """,
).fetchone() (row["id"], current_user_id),
) ).fetchone()
)
pin_row = db.execute( if pin_table_exists:
""" pin_row = db.execute(
SELECT pinned_at, pinned_by_user_id """
FROM message_pins SELECT pinned_at, pinned_by_user_id
WHERE message_id = ? FROM message_pins
""", WHERE message_id = ?
(row["id"],), """,
).fetchone() (row["id"],),
).fetchone()
is_pinned = bool(pin_row)
primary_attachment = attachment_payload_legacy_from_message_select_row(row) primary_attachment = attachment_payload_legacy_from_message_select_row(row)
attachments = attachment_list_for_message(get_db, row["id"]) attachments = attachment_list_for_message(get_db, row["id"])
@ -803,7 +939,7 @@ def richer_message_payload(
"seen_by_current_user": seen_by_user, "seen_by_current_user": seen_by_user,
"reactions": reaction_summary_for_message(get_db, row["id"], user), "reactions": reaction_summary_for_message(get_db, row["id"], user),
"is_dm": bool(("direct_conversation_id" in row.keys()) and row["direct_conversation_id"]), "is_dm": bool(("direct_conversation_id" in row.keys()) and row["direct_conversation_id"]),
"is_pinned": bool(pin_row), "is_pinned": is_pinned,
"pinned_at": pin_row["pinned_at"] if pin_row else None, "pinned_at": pin_row["pinned_at"] if pin_row else None,
"pinned_by_user_id": pin_row["pinned_by_user_id"] if pin_row else None, "pinned_by_user_id": pin_row["pinned_by_user_id"] if pin_row else None,
"is_bookmarked": is_bookmarked, "is_bookmarked": is_bookmarked,
@ -856,15 +992,23 @@ def profile_payload(
profile_visibility = settings_row["profile_visibility"] if settings_row else "public" profile_visibility = settings_row["profile_visibility"] if settings_row else "public"
if profile_visibility not in PROFILE_VISIBILITIES: if profile_visibility not in PROFILE_VISIBILITIES:
profile_visibility = "public" profile_visibility = "public"
last_active_visibility = settings_row["last_active_visibility"] if settings_row else "everyone" last_active_visibility = settings_row["last_active_visibility"] if settings_row else "everyone"
if last_active_visibility not in LAST_ACTIVE_VISIBILITIES: if last_active_visibility not in LAST_ACTIVE_VISIBILITIES:
last_active_visibility = "everyone" last_active_visibility = "everyone"
presence_mode = settings_row["presence_mode"] if settings_row else "online" presence_mode = settings_row["presence_mode"] if settings_row else "online"
if presence_mode not in PRESENCE_MODES: if presence_mode not in PRESENCE_MODES:
presence_mode = "online" presence_mode = "online"
dm_layout_mode = settings_row["dm_layout_mode"] if settings_row else "cards"
if dm_layout_mode not in DM_LAYOUT_MODES:
dm_layout_mode = "cards"
show_presence_badge = bool(
settings_row["show_presence_badge"] if settings_row and "show_presence_badge" in settings_row.keys() else 1
)
last_active_at = user_row["last_login_at"] if "last_login_at" in user_row.keys() else None last_active_at = user_row["last_login_at"] if "last_login_at" in user_row.keys() else None
@ -876,6 +1020,9 @@ def profile_payload(
elif last_active_visibility == "nobody": elif last_active_visibility == "nobody":
can_show_last_active = bool(viewer and viewer["id"] == user_row["id"]) can_show_last_active = bool(viewer and viewer["id"] == user_row["id"])
website = profile_row["website"] or ""
website_meta = detect_website_brand(website) if website else {"host": "", "brand": "web", "label": "website"}
return { return {
"id": user_row["id"], "id": user_row["id"],
"username": user_row["username"], "username": user_row["username"],
@ -889,19 +1036,22 @@ def profile_payload(
"bio": bio, "bio": bio,
"bio_mode": bio_mode, "bio_mode": bio_mode,
"bio_html": safe_profile_bio_html(html_module, bio, bio_mode), "bio_html": safe_profile_bio_html(html_module, bio, bio_mode),
"website": profile_row["website"] or "", "website": website,
"website_meta": website_meta,
"location": profile_row["location"] or "", "location": profile_row["location"] or "",
"status_message": profile_row["status_message"] or "", "status_message": profile_row["status_message"] if "status_message" in profile_row.keys() else "",
"banner_attachment_id": profile_row["banner_attachment_id"], "banner_attachment_id": profile_row["banner_attachment_id"] if "banner_attachment_id" in profile_row.keys() else None,
"banner_image_url": f"/api/attachments/{profile_row['banner_attachment_id']}/download" if profile_row["banner_attachment_id"] else "", "banner_image_url": f"/api/attachments/{profile_row['banner_attachment_id']}/download" if ("banner_attachment_id" in profile_row.keys() and profile_row["banner_attachment_id"]) else "",
"updated_at": profile_row["updated_at"], "updated_at": profile_row["updated_at"],
"is_self": is_self, "is_self": is_self,
"name_color": explicit_name_color, "name_color": explicit_name_color,
"resolved_name_color": resolved, "resolved_name_color": resolved,
"profile_background_color": settings_row["profile_background_color"] if settings_row else None, "profile_background_color": settings_row["profile_background_color"] if settings_row and "profile_background_color" in settings_row.keys() else None,
"profile_banner_color": settings_row["profile_banner_color"] if settings_row else None, "profile_banner_color": settings_row["profile_banner_color"] if settings_row and "profile_banner_color" in settings_row.keys() else None,
"profile_visibility": profile_visibility, "profile_visibility": profile_visibility,
"last_active_visibility": last_active_visibility, "last_active_visibility": last_active_visibility,
"show_presence_badge": show_presence_badge,
"dm_layout_mode": dm_layout_mode,
} }
@ -977,6 +1127,7 @@ def list_dms_for_user(get_db, user_id: int) -> list[dict]:
"last_message_text": row["last_message_text"], "last_message_text": row["last_message_text"],
"last_message_created_at": row["last_message_created_at"], "last_message_created_at": row["last_message_created_at"],
"last_message_id": row["last_message_id"], "last_message_id": row["last_message_id"],
"unread_count": 0,
} }
) )
return items return items
@ -1338,8 +1489,21 @@ def call_payload(get_db, call_id: int) -> Optional[dict]:
def dispatch_scheduled_messages(get_db, now_iso_func, app_logger) -> None: def dispatch_scheduled_messages(get_db, now_iso_func, app_logger) -> None:
now_value = now_iso_func()
with get_db() as db: with get_db() as db:
table_exists = bool(
db.execute(
"""
SELECT 1
FROM sqlite_master
WHERE type = 'table'
AND name = 'scheduled_messages'
"""
).fetchone()
)
if not table_exists:
return
now_value = now_iso_func()
rows = db.execute( rows = db.execute(
""" """
SELECT SELECT