feat: add api and mcp
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
import asyncpg
|
||||
|
||||
from utils.read.models import ChatListItem, MessageVersionView, MessageView, Page
|
||||
|
||||
_MESSAGE_COLS = (
|
||||
"chat_id, message_id, date, sender_id, text, "
|
||||
"has_media, is_self_destruct, edited_at, deleted_at"
|
||||
)
|
||||
|
||||
|
||||
def _peer_title(
|
||||
first: str | None, last: str | None, username: str | None
|
||||
) -> str | None:
|
||||
name = " ".join(part for part in (first, last) if part)
|
||||
return name or username
|
||||
|
||||
|
||||
async def list_chats(
|
||||
pool: asyncpg.Pool, account_id: int, page: Page
|
||||
) -> list[ChatListItem]:
|
||||
rows = await pool.fetch(
|
||||
"SELECT m.chat_id, count(*) AS message_count, max(m.date) AS last_date, "
|
||||
"(SELECT p.first_name FROM peers p "
|
||||
"WHERE p.account_id = $1 AND p.peer_id = m.chat_id) AS first_name, "
|
||||
"(SELECT p.last_name FROM peers p "
|
||||
"WHERE p.account_id = $1 AND p.peer_id = m.chat_id) AS last_name, "
|
||||
"(SELECT p.username FROM peers p "
|
||||
"WHERE p.account_id = $1 AND p.peer_id = m.chat_id) AS username, "
|
||||
"(SELECT ch.title FROM chat_history ch "
|
||||
"WHERE ch.account_id = $1 AND ch.chat_id = m.chat_id "
|
||||
"AND ch.title IS NOT NULL ORDER BY ch.ts DESC LIMIT 1) AS group_title "
|
||||
"FROM messages m WHERE m.account_id = $1 "
|
||||
"GROUP BY m.chat_id ORDER BY last_date DESC LIMIT $2 OFFSET $3",
|
||||
account_id,
|
||||
page.capped_limit,
|
||||
page.offset,
|
||||
)
|
||||
items = []
|
||||
for row in rows:
|
||||
title = row["group_title"] or _peer_title(
|
||||
row["first_name"], row["last_name"], row["username"]
|
||||
)
|
||||
items.append(
|
||||
ChatListItem(
|
||||
chat_id=row["chat_id"],
|
||||
title=title,
|
||||
message_count=row["message_count"],
|
||||
last_date=row["last_date"],
|
||||
)
|
||||
)
|
||||
return items
|
||||
|
||||
|
||||
async def get_chat_history(
|
||||
pool: asyncpg.Pool,
|
||||
account_id: int,
|
||||
chat_id: int,
|
||||
page: Page,
|
||||
*,
|
||||
include_deleted: bool = True,
|
||||
) -> list[MessageView]:
|
||||
where = "account_id = $1 AND chat_id = $2"
|
||||
if not include_deleted:
|
||||
where += " AND deleted_at IS NULL"
|
||||
rows = await pool.fetch(
|
||||
f"SELECT {_MESSAGE_COLS} FROM messages WHERE {where} " # noqa: S608
|
||||
"ORDER BY date DESC, message_id DESC LIMIT $3 OFFSET $4",
|
||||
account_id,
|
||||
chat_id,
|
||||
page.capped_limit,
|
||||
page.offset,
|
||||
)
|
||||
return [MessageView(**dict(row)) for row in rows]
|
||||
|
||||
|
||||
async def get_deleted_messages(
|
||||
pool: asyncpg.Pool, account_id: int, page: Page, *, chat_id: int | None = None
|
||||
) -> list[MessageView]:
|
||||
params: list[object] = [account_id]
|
||||
where = "account_id = $1 AND deleted_at IS NOT NULL"
|
||||
if chat_id is not None:
|
||||
params.append(chat_id)
|
||||
where += f" AND chat_id = ${len(params)}"
|
||||
params.append(page.capped_limit)
|
||||
params.append(page.offset)
|
||||
rows = await pool.fetch(
|
||||
f"SELECT {_MESSAGE_COLS} FROM messages WHERE {where} " # noqa: S608
|
||||
f"ORDER BY deleted_at DESC LIMIT ${len(params) - 1} OFFSET ${len(params)}",
|
||||
*params,
|
||||
)
|
||||
return [MessageView(**dict(row)) for row in rows]
|
||||
|
||||
|
||||
async def get_message_versions(
|
||||
pool: asyncpg.Pool, account_id: int, chat_id: int, message_id: int
|
||||
) -> list[MessageVersionView]:
|
||||
rows = await pool.fetch(
|
||||
"SELECT observed_at, edit_date, text FROM message_versions "
|
||||
"WHERE account_id = $1 AND chat_id = $2 AND message_id = $3 "
|
||||
"ORDER BY observed_at",
|
||||
account_id,
|
||||
chat_id,
|
||||
message_id,
|
||||
)
|
||||
return [MessageVersionView(**dict(row)) for row in rows]
|
||||
Reference in New Issue
Block a user