90 lines
3.3 KiB
Python
90 lines
3.3 KiB
Python
"""Репозиторий шаблонов сообщений (Блок 4.1: редактирование в админке).
|
||
|
||
Каждое изменение текста пишет запись в ``message_template_history`` — это аудит
|
||
и материал для отката. Бот подключится к этим данным в Блоке 4.5.
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from typing import Any
|
||
|
||
from common.db.pool import get_pool
|
||
|
||
|
||
async def list_templates() -> list[dict[str, Any]]:
|
||
"""Вернуть список шаблонов без текста (для таблицы в админке)."""
|
||
async with get_pool().connection() as conn:
|
||
cur = await conn.execute(
|
||
"""
|
||
SELECT key, description, enabled, updated_at, updated_by,
|
||
length(text) AS text_length
|
||
FROM bot.message_templates
|
||
ORDER BY key
|
||
"""
|
||
)
|
||
return await cur.fetchall()
|
||
|
||
|
||
async def get_template(key: str) -> dict[str, Any] | None:
|
||
"""Вернуть шаблон целиком (с текстом) или ``None``."""
|
||
async with get_pool().connection() as conn:
|
||
cur = await conn.execute(
|
||
"""
|
||
SELECT key, text, description, enabled, updated_at, updated_by
|
||
FROM bot.message_templates
|
||
WHERE key = %s
|
||
""",
|
||
(key,),
|
||
)
|
||
return await cur.fetchone()
|
||
|
||
|
||
async def update_template(key: str, text: str, *, editor_id: int | None = None) -> dict[str, Any] | None:
|
||
"""Обновить текст шаблона и записать историю.
|
||
|
||
Возвращает ``None``, если шаблона нет. Старое значение читается под
|
||
``FOR UPDATE``, поэтому параллельные правки не потеряют историю.
|
||
"""
|
||
async with get_pool().connection() as conn:
|
||
cur = await conn.execute("SELECT text FROM bot.message_templates WHERE key = %s FOR UPDATE", (key,))
|
||
row = await cur.fetchone()
|
||
if row is None:
|
||
return None
|
||
|
||
old_text = row["text"]
|
||
if old_text == text:
|
||
return {"key": key, "old_text": old_text, "text": text, "changed": False}
|
||
|
||
await conn.execute(
|
||
"""
|
||
UPDATE bot.message_templates
|
||
SET text = %s, updated_at = now(), updated_by = %s
|
||
WHERE key = %s
|
||
""",
|
||
(text, editor_id, key),
|
||
)
|
||
await conn.execute(
|
||
"""
|
||
INSERT INTO bot.message_template_history (key, old_text, new_text, editor_id)
|
||
VALUES (%s, %s, %s, %s)
|
||
""",
|
||
(key, old_text, text, editor_id),
|
||
)
|
||
return {"key": key, "old_text": old_text, "text": text, "changed": True}
|
||
|
||
|
||
async def template_history(key: str, *, limit: int = 10) -> list[dict[str, Any]]:
|
||
"""Последние изменения шаблона (для блока истории в редакторе)."""
|
||
async with get_pool().connection() as conn:
|
||
cur = await conn.execute(
|
||
"""
|
||
SELECT id, old_text, new_text, editor_id, changed_at
|
||
FROM bot.message_template_history
|
||
WHERE key = %s
|
||
ORDER BY changed_at DESC
|
||
LIMIT %s
|
||
""",
|
||
(key, limit),
|
||
)
|
||
return await cur.fetchall()
|