Apr 2 2026: implement notification settings matrix
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
"""Phase 1: Add projects table, customer_assignments table, project_id on facilities, extend user role enum
|
||||
|
||||
Revision ID: phase1_projects_roles
|
||||
Revises: (set this to your current DB head before running)
|
||||
Create Date: 2026-03-04
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import mysql
|
||||
|
||||
# --- IMPORTANT: set down_revision to your live DB's current head ---
|
||||
revision = 'phase1_projects_roles'
|
||||
down_revision = '0003_add_user_active'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
bind = op.get_bind()
|
||||
inspector = sa.inspect(bind)
|
||||
existing_tables = inspector.get_table_names()
|
||||
|
||||
# ── 1. Create `projects` table ─────────────────────────────────────────
|
||||
if 'projects' not in existing_tables:
|
||||
op.create_table(
|
||||
'projects',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(255), nullable=False),
|
||||
sa.Column('description', sa.Text(), nullable=True),
|
||||
sa.Column('project_manager_id', sa.Integer(), nullable=True),
|
||||
sa.Column('active', sa.Boolean(), nullable=False, server_default='1'),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=False),
|
||||
sa.ForeignKeyConstraint(['project_manager_id'], ['users.id'], name='fk_project_manager'),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
)
|
||||
|
||||
# ── 2. Create `customer_assignments` table ─────────────────────────────
|
||||
if 'customer_assignments' not in existing_tables:
|
||||
op.create_table(
|
||||
'customer_assignments',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('user_id', sa.Integer(), nullable=False),
|
||||
sa.Column('project_id', sa.Integer(), nullable=False),
|
||||
sa.Column('facility_id', sa.Integer(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=False),
|
||||
sa.ForeignKeyConstraint(['facility_id'], ['facilities.id'],
|
||||
name='fk_ca_facility', ondelete='CASCADE'),
|
||||
sa.ForeignKeyConstraint(['project_id'], ['projects.id'],
|
||||
name='fk_ca_project', ondelete='CASCADE'),
|
||||
sa.ForeignKeyConstraint(['user_id'], ['users.id'],
|
||||
name='fk_ca_user', ondelete='CASCADE'),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('user_id', 'project_id', 'facility_id',
|
||||
name='uq_customer_assignment'),
|
||||
)
|
||||
op.create_index('ix_customer_assignments_user_id',
|
||||
'customer_assignments', ['user_id'])
|
||||
op.create_index('ix_customer_assignments_project_id',
|
||||
'customer_assignments', ['project_id'])
|
||||
op.create_index('ix_customer_assignments_facility_id',
|
||||
'customer_assignments', ['facility_id'])
|
||||
|
||||
# ── 3. Add `project_id` column to `facilities` ─────────────────────────
|
||||
existing_facility_cols = [c['name'] for c in inspector.get_columns('facilities')]
|
||||
if 'project_id' not in existing_facility_cols:
|
||||
op.add_column(
|
||||
'facilities',
|
||||
sa.Column('project_id', sa.Integer(), nullable=True)
|
||||
)
|
||||
op.create_foreign_key(
|
||||
'fk_facility_project',
|
||||
'facilities', 'projects',
|
||||
['project_id'], ['id'],
|
||||
ondelete='SET NULL'
|
||||
)
|
||||
op.create_index('ix_facilities_project_id', 'facilities', ['project_id'])
|
||||
|
||||
# ── 4. Extend `users.role` Enum with new values ────────────────────────
|
||||
# MySQL requires ALTER COLUMN to modify an ENUM.
|
||||
op.alter_column(
|
||||
'users', 'role',
|
||||
existing_type=mysql.ENUM('admin', 'supervisor', 'inspector'),
|
||||
type_=mysql.ENUM('admin', 'supervisor', 'inspector', 'project_manager', 'customer'),
|
||||
existing_nullable=False,
|
||||
nullable=False,
|
||||
)
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ── Reverse order of operations ────────────────────────────────────────
|
||||
|
||||
# 4. Revert users.role Enum
|
||||
op.alter_column(
|
||||
'users', 'role',
|
||||
existing_type=mysql.ENUM('admin', 'supervisor', 'inspector', 'project_manager', 'customer'),
|
||||
type_=mysql.ENUM('admin', 'supervisor', 'inspector'),
|
||||
existing_nullable=False,
|
||||
nullable=False,
|
||||
)
|
||||
|
||||
# 3. Remove project_id from facilities
|
||||
bind = op.get_bind()
|
||||
inspector = sa.inspect(bind)
|
||||
existing_facility_cols = [c['name'] for c in inspector.get_columns('facilities')]
|
||||
if 'project_id' in existing_facility_cols:
|
||||
op.drop_constraint('fk_facility_project', 'facilities', type_='foreignkey')
|
||||
op.drop_index('ix_facilities_project_id', table_name='facilities')
|
||||
op.drop_column('facilities', 'project_id')
|
||||
|
||||
# 2. Drop customer_assignments
|
||||
existing_tables = inspector.get_table_names()
|
||||
if 'customer_assignments' in existing_tables:
|
||||
op.drop_table('customer_assignments')
|
||||
|
||||
# 1. Drop projects
|
||||
if 'projects' in existing_tables:
|
||||
op.drop_table('projects')
|
||||
@@ -0,0 +1,37 @@
|
||||
"""Phase 8: Notification matrix — admin-controlled per-event recipient settings
|
||||
|
||||
Revision ID: phase8_notification_matrix
|
||||
Revises: phase7_mobile_api
|
||||
Create Date: 2026-04-02
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
revision = 'phase8_notification_matrix'
|
||||
down_revision = 'phase7_mobile_api'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
bind = op.get_bind()
|
||||
inspector = sa.inspect(bind)
|
||||
tables = inspector.get_table_names()
|
||||
|
||||
if 'notification_matrix' not in tables:
|
||||
op.create_table(
|
||||
'notification_matrix',
|
||||
sa.Column('id', sa.Integer, primary_key=True),
|
||||
sa.Column('event_type', sa.String(50), nullable=False),
|
||||
sa.Column('role_key', sa.String(30), nullable=False),
|
||||
# enabled: whether this role receives notifications for this event
|
||||
sa.Column('enabled', sa.Boolean, nullable=False, server_default='1'),
|
||||
# custom_emails: JSON list of extra email addresses (role_key='custom')
|
||||
sa.Column('custom_emails', sa.Text, nullable=True),
|
||||
sa.UniqueConstraint('event_type', 'role_key',
|
||||
name='uq_notif_matrix_event_role'),
|
||||
)
|
||||
|
||||
|
||||
def downgrade():
|
||||
op.drop_table('notification_matrix')
|
||||
Reference in New Issue
Block a user