Files
ss-tools/backend/alembic/versions/s3t4u5v6w7x8_maintenance_default_message.py
busya 585a00c537 semantic-curation: fix anchors, metadata, and relations across backend + specs
- Replace legacy @PURPOSE with @BRIEF across 241 files
- Add missing [C:N] complexity tiers to function contracts in core modules
- Fix tombstone contracts: add @STATUS DEPRECATED to 5 deprecated anchors
- Resolve 7 unresolved @RELATION edges in executor.py (DictionaryManager, TranslationPreview, etc.)
- Fix flat hierarchical IDs in 4 test files (22 test functions)
- Fix invalid tags/relations in logger.py (@ADR, @CONSEQUENCES, DISABLED_BY)
- Rebuild semantic index: 9,576 contracts, 4,742 edges, 0 parse warnings
2026-08-20 11:45:15 +03:00

94 lines
3.9 KiB
Python

# #region Alembic.MaintenanceDefaultMessage [C:2] [TYPE Module] [SEMANTICS alembic,maintenance,settings,message]
# @ingroup Alembic
# @BRIEF Add the default message used to prefill new maintenance notices.
# @LAYER Database
# @RELATION DEPENDS_ON -> [Models.Maintenance.MaintenanceSettings]
# @INVARIANT default_message is non-nullable and does not alter existing event messages.
# @INVARIANT Only the exact legacy built-in template is migrated; user-edited templates stay intact.
"""add maintenance settings default message
Revision ID: s3t4u5v6w7x8
Revises: r2s3t4u5v6w7
Create Date: 2026-08-10 13:15:00.000000
"""
from collections.abc import Sequence
import sqlalchemy as sa
from sqlalchemy import inspect
from alembic import op
revision: str = "s3t4u5v6w7x8"
down_revision: str | Sequence[str] | None = "r2s3t4u5v6w7"
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None
DEFAULT_MESSAGE = "Выполняется плановое обновление данных. Показатели могут быть временно недоступны."
OLD_DEFAULT_TEMPLATE = (
'<div style="background:#FFF3E0;padding:16px;border-left:4px solid #FF9800;border-radius:4px">\n\n'
"## ⚠️ Технические работы\n\n"
"{message}\n\n"
"**Начало:** {start_time}\n"
"**Конец:** {end_time}\n\n"
"*Данные могут быть неполными или временно недоступны.*\n\n"
"</div>"
)
RUSAL_DEFAULT_TEMPLATE = (
'<div style="background:#F2F7FA;border:1px solid #005B96;border-left:5px solid #005B96;'
'border-radius:8px;padding:14px 16px;margin-bottom:12px;font-family:Arial,sans-serif;color:#1F3344">\n'
'<div style="color:#005B96;font-size:16px;font-weight:700">РУСАЛ · Технические работы</div>\n'
'<p style="margin:8px 0;color:#1F3344">{message}</p>\n'
'<table style="font-size:13px;color:#40586B"><tr><td style="padding-right:12px">Начало:</td>'
'<td><strong>{start_time}</strong></td></tr><tr><td style="padding-right:12px">Окончание:</td>'
'<td><strong>{end_time}</strong></td></tr></table>\n'
'<p style="margin:10px 0 0;font-size:12px;color:#61788A">Данные на дашборде могут быть временно неполными.</p>\n'
"</div>"
)
def _column_exists(table: str, column: str) -> bool:
"""Return whether a column exists on a pre-existing installation."""
inspector = inspect(op.get_bind())
return inspector.has_table(table) and any(
item["name"] == column for item in inspector.get_columns(table)
)
def _table_exists(table: str) -> bool:
"""Return whether a legacy installation already has the table."""
return inspect(op.get_bind()).has_table(table)
def upgrade() -> None:
"""Persist the default message without modifying historical events."""
if _table_exists("maintenance_settings") and not _column_exists(
"maintenance_settings", "default_message"
):
op.add_column(
"maintenance_settings",
sa.Column(
"default_message",
sa.Text(),
nullable=False,
server_default=DEFAULT_MESSAGE,
),
)
if _table_exists("maintenance_settings"):
op.get_bind().execute(
sa.text(
"UPDATE maintenance_settings "
"SET banner_template = :new_template "
"WHERE id = 'default' AND banner_template = :old_template"
),
{"new_template": RUSAL_DEFAULT_TEMPLATE, "old_template": OLD_DEFAULT_TEMPLATE},
)
def downgrade() -> None:
"""Remove the setting; existing event messages remain intact."""
if _column_exists("maintenance_settings", "default_message"):
op.drop_column("maintenance_settings", "default_message")
# #endregion Alembic.MaintenanceDefaultMessage