61 lines
2.4 KiB
Python
61 lines
2.4 KiB
Python
"""phase37 — per-contract additional notification recipients
|
|
|
|
Creates the project_notification_recipients table. Each row subscribes one
|
|
recipient — either a staff User (in-app + email) or an external email address
|
|
(email only) — to a chosen set of notification-matrix event types, scoped to
|
|
events occurring in facilities that belong to that contract (Project).
|
|
|
|
Dispatched by notify_by_matrix() → _notify_project_recipients() in
|
|
app/utils/notifications.py, AFTER the global matrix roles and custom emails.
|
|
|
|
Idempotent: guarded by an INFORMATION_SCHEMA table-existence check so it is
|
|
safe to re-run across every tenant DB (CLAUDE.md rule 14).
|
|
|
|
NOTE: the revision id is deliberately short — alembic_version.version_num is
|
|
VARCHAR(32); ids longer than 32 chars fail the version-pointer UPDATE with
|
|
MySQL error 1406 ("Data too long for column 'version_num'").
|
|
"""
|
|
|
|
import sqlalchemy as sa
|
|
from alembic import op
|
|
|
|
revision = 'phase37_contract_recipients'
|
|
down_revision = 'phase36_issue_work_orders'
|
|
branch_labels = None
|
|
depends_on = None
|
|
|
|
|
|
def _table_exists(bind, table: str) -> bool:
|
|
result = bind.execute(sa.text(
|
|
"SELECT COUNT(*) FROM information_schema.tables "
|
|
"WHERE table_schema = DATABASE() AND table_name = :t"
|
|
), {'t': table})
|
|
return result.scalar() > 0
|
|
|
|
|
|
def upgrade():
|
|
bind = op.get_bind()
|
|
if not _table_exists(bind, 'project_notification_recipients'):
|
|
op.execute(sa.text("""
|
|
CREATE TABLE project_notification_recipients (
|
|
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
|
project_id INT NOT NULL,
|
|
user_id INT NULL,
|
|
email VARCHAR(255) NULL,
|
|
events TEXT NOT NULL,
|
|
created_at DATETIME NOT NULL,
|
|
CONSTRAINT fk_pnr_project FOREIGN KEY (project_id)
|
|
REFERENCES projects(id) ON DELETE CASCADE,
|
|
CONSTRAINT fk_pnr_user FOREIGN KEY (user_id)
|
|
REFERENCES users(id) ON DELETE CASCADE,
|
|
INDEX ix_pnr_project (project_id),
|
|
INDEX ix_pnr_user (user_id)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
|
|
"""))
|
|
|
|
|
|
def downgrade():
|
|
bind = op.get_bind()
|
|
if _table_exists(bind, 'project_notification_recipients'):
|
|
op.execute(sa.text('DROP TABLE project_notification_recipients'))
|