- 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
94 lines
3.9 KiB
Python
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
|