Aug 7 - Update: add external inspector
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
"""phase51 — add 'external_inspector' role to users.role ENUM
|
||||
|
||||
Introduces the External Inspector role: an inspector employed by the customer
|
||||
or a third party rather than by the tenant. It has exactly the same
|
||||
capabilities as the internal 'inspector' role and is scoped the same way —
|
||||
through InspectorAssignment rows, resolved by get_inspector_scope().
|
||||
|
||||
Every capability/scoping check that used to test `role == 'inspector'` now
|
||||
tests membership of User.INSPECTOR_ROLES (exposed as the `is_inspector`
|
||||
property), so the new role picks up inspector behaviour everywhere without a
|
||||
per-route allowlist.
|
||||
|
||||
This is a pure ENUM expansion (adds a value, removes and migrates nothing), so
|
||||
the 3-step ENUM protocol does not apply and re-running the same MODIFY is a
|
||||
no-op — safe to re-run.
|
||||
|
||||
MULTI-TENANT NOTE
|
||||
-----------------
|
||||
This runs once per tenant database via control/tenant_migrate.py, like every
|
||||
other script in migrations/versions. It is a metadata-only ALTER on a small
|
||||
table, but MySQL still takes an exclusive metadata lock for the duration, so
|
||||
run it during the normal migration window rather than under load.
|
||||
|
||||
Notification matrix rows for the new 'external_inspector' column are NOT seeded
|
||||
here: MATRIX_DEFAULTS mirrors the Inspector column at runtime and is_enabled()
|
||||
falls back to that default when a row is absent, so an unseeded tenant behaves
|
||||
exactly like the Inspector column until an admin saves the matrix page.
|
||||
"""
|
||||
|
||||
revision = 'phase51_external_inspector'
|
||||
down_revision = 'phase50_sched_acknowledged'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
_ENUM_WITH_EXTERNAL = (
|
||||
"ENUM('admin','director','inspector','project_manager','customer',"
|
||||
"'auditor','external_inspector')"
|
||||
)
|
||||
_ENUM_WITHOUT_EXTERNAL = (
|
||||
"ENUM('admin','director','inspector','project_manager','customer','auditor')"
|
||||
)
|
||||
|
||||
|
||||
def upgrade():
|
||||
# Idempotent: MODIFY to the expanded set is harmless if already applied.
|
||||
op.execute(sa.text(
|
||||
f"ALTER TABLE users MODIFY COLUMN role {_ENUM_WITH_EXTERNAL} NOT NULL"
|
||||
))
|
||||
|
||||
|
||||
def downgrade():
|
||||
# Reassign any external_inspector rows before contracting the ENUM so no
|
||||
# account is orphaned. They become internal inspectors, which keeps their
|
||||
# InspectorAssignment scoping intact — the same contracts still apply.
|
||||
op.execute(sa.text(
|
||||
"UPDATE users SET role = 'inspector' WHERE role = 'external_inspector'"
|
||||
))
|
||||
op.execute(sa.text(
|
||||
f"ALTER TABLE users MODIFY COLUMN role {_ENUM_WITHOUT_EXTERNAL} NOT NULL"
|
||||
))
|
||||
Reference in New Issue
Block a user