glo/routes/feed.py
2026-11-03 00:22:48 +00:00

190 lines
6.4 KiB
Python

from .common import (
MAX_FEED_MESSAGES,
current_user,
jsonify,
request,
get_db,
build_feed_payload,
room_by_id,
can_access_room,
get_channel_by_id,
can_access_channel,
validate_dm_access,
)
def register_feed_routes(app):
@app.route("/api/feed")
def get_feed():
user = current_user()
after_raw = request.args.get("after_id", "").strip()
after_id = 0
if after_raw:
try:
after_id = max(0, int(after_raw))
except ValueError:
return jsonify({"error": "after_id must be a non-negative integer."}), 400
base_select = f"""
SELECT
m.id,
m.room_id,
m.channel_id,
m.direct_conversation_id,
m.user_id,
m.username,
m.text,
m.created_at,
m.attachment_id,
m.parent_message_id,
(
SELECT COUNT(*)
FROM messages AS thread_reply
WHERE thread_reply.parent_message_id = m.id
) AS thread_reply_count,
r.slug AS room_slug,
r.name AS room_name,
r.visibility AS room_visibility,
c.slug AS channel_slug,
c.name AS channel_name,
t.slug AS team_slug,
t.name AS team_name,
a.original_name AS attachment_original_name,
a.mime_type AS attachment_mime_type,
a.size_bytes AS attachment_size_bytes,
u.role AS user_role,
us.name_color AS user_name_color
FROM messages AS m
JOIN users AS u
ON u.id = m.user_id
LEFT JOIN user_settings AS us
ON us.user_id = u.id
LEFT JOIN rooms AS r
ON r.id = m.room_id
LEFT JOIN channels AS c
ON c.id = m.channel_id
AND c.is_active = 1
LEFT JOIN teams AS t
ON t.id = c.team_id
AND t.is_active = 1
LEFT JOIN attachments AS a
ON a.id = m.attachment_id
"""
params = []
if user and user["role"] in {"moderator", "admin"}:
access_clause = """
(
(m.direct_conversation_id IS NULL AND r.id IS NOT NULL AND r.is_active = 1)
OR
(m.direct_conversation_id IS NULL AND c.id IS NOT NULL AND c.is_active = 1 AND t.is_active = 1)
OR
(
m.direct_conversation_id IS NOT NULL
AND EXISTS (
SELECT 1
FROM direct_conversation_members AS dcm
WHERE dcm.direct_conversation_id = m.direct_conversation_id
AND dcm.user_id = ?
)
)
)
"""
params.append(user["id"])
elif user:
access_clause = """
(
(
m.direct_conversation_id IS NULL
AND r.id IS NOT NULL
AND r.is_active = 1
AND (
r.visibility = 'public'
OR EXISTS (
SELECT 1
FROM room_members AS rm
WHERE rm.room_id = r.id
AND rm.user_id = ?
)
)
)
OR
(
m.direct_conversation_id IS NULL
AND c.id IS NOT NULL
AND c.is_active = 1
AND t.is_active = 1
AND c.legacy_room_id IS NULL
AND EXISTS (
SELECT 1
FROM team_members AS tm
WHERE tm.team_id = c.team_id
AND tm.user_id = ?
)
)
OR
(
m.direct_conversation_id IS NOT NULL
AND EXISTS (
SELECT 1
FROM direct_conversation_members AS dcm
WHERE dcm.direct_conversation_id = m.direct_conversation_id
AND dcm.user_id = ?
)
)
)
"""
params.extend([user["id"], user["id"], user["id"]])
else:
access_clause = """
m.direct_conversation_id IS NULL
AND r.id IS NOT NULL
AND r.is_active = 1
AND r.visibility = 'public'
"""
if after_raw:
query = f"""
{base_select}
WHERE m.parent_message_id IS NULL
AND {access_clause}
AND m.id > ?
ORDER BY m.id ASC
LIMIT ?
"""
query_params = [*params, after_id, MAX_FEED_MESSAGES]
with get_db() as db:
rows = db.execute(query, tuple(query_params)).fetchall()
entries = [build_feed_payload(row, user) for row in rows]
latest_id = entries[-1]["id"] if entries else after_id
return jsonify(
{
"entries": entries,
"latest_id": latest_id,
"has_more": len(entries) == MAX_FEED_MESSAGES,
}
)
query = f"""
SELECT *
FROM (
{base_select}
WHERE m.parent_message_id IS NULL
AND {access_clause}
ORDER BY m.id DESC
LIMIT ?
)
ORDER BY id ASC
"""
query_params = [*params, MAX_FEED_MESSAGES]
with get_db() as db:
rows = db.execute(query, tuple(query_params)).fetchall()
entries = [build_feed_payload(row, user) for row in rows]
latest_id = entries[-1]["id"] if entries else 0
return jsonify({"entries": entries, "latest_id": latest_id, "has_more": False})