feat(backend): feed of deleted and edited messages with bulk deletions grouped and a shared seen marker

This commit is contained in:
hh committed 2026-10-19 02:58:51 +00:00
1 parent 45c19cac20
commit 83c57ac96b
6 files changed
+657

No files matched your search

+69
View File
@@ -1,3 +1,5 @@
from datetime import datetime
import asyncpg
from utils.policy.models import FolderSpec
@@ -331,6 +333,12 @@ async def get_deleted_messages(
f"ORDER BY deleted_at DESC LIMIT ${len(params) - 1} OFFSET ${len(params)}",
*params,
)
return await _single_views(pool, account_id, rows)
async def _single_views(
pool: asyncpg.Pool, account_id: int, rows: list[asyncpg.Record]
) -> list[MessageView]:
media_by_key = await _media_map(pool, account_id, rows)
views: list[MessageView] = []
for row in rows:
@@ -341,6 +349,67 @@ async def get_deleted_messages(
return views
async def _rows_at(
pool: asyncpg.Pool, account_id: int, keys: list[tuple[int, int, datetime]]
) -> list[asyncpg.Record]:
if not keys:
return []
params: list[object] = [account_id]
clauses: list[str] = []
for key in keys:
params.extend(key)
n = len(params)
clauses.append(
f"(chat_id = ${n - 2} AND message_id = ${n - 1} AND date = ${n})"
)
return await pool.fetch(
f"SELECT {_MESSAGE_COLS} FROM messages " # noqa: S608
f"WHERE account_id = $1 AND ({' OR '.join(clauses)})",
*params,
)
async def get_messages_at(
pool: asyncpg.Pool, account_id: int, keys: list[tuple[int, int, datetime | None]]
) -> dict[tuple[int, int], MessageView]:
dated = list(
dict.fromkeys((chat, message, date) for chat, message, date in keys if date)
)
rows = await _rows_at(pool, account_id, dated)
views = {
(view.chat_id, view.message_id): view
for view in await _single_views(pool, account_id, rows)
}
for chat_id, message_id, _ in keys:
if (chat_id, message_id) not in views:
view = await get_message(pool, account_id, chat_id, message_id)
if view is not None:
views[chat_id, message_id] = view
return views
async def get_deleted_between( # noqa: PLR0913
pool: asyncpg.Pool,
account_id: int,
chat_id: int,
since: datetime,
until: datetime,
limit: int,
before: tuple[datetime, int] | None = None,
) -> list[MessageView]:
params: list[object] = [account_id, chat_id, since, until, limit]
where = "account_id = $1 AND chat_id = $2 AND deleted_at BETWEEN $3 AND $4"
if before is not None:
params.extend(before)
where += " AND (date, message_id) < ($6, $7)"
rows = await pool.fetch(
f"SELECT {_MESSAGE_COLS} FROM messages WHERE {where} " # noqa: S608
"ORDER BY date DESC, message_id DESC LIMIT $5",
*params,
)
return await _single_views(pool, account_id, rows)
async def get_message_versions(
pool: asyncpg.Pool, account_id: int, chat_id: int, message_id: int
) -> list[MessageVersionView]: