62 lines
2.3 KiB
Python
62 lines
2.3 KiB
Python
"""phase55 — restrict forms to specific contracts
|
|
|
|
Creates `template_contracts`: one row = "this inspection template is available
|
|
on this contract". Backs per-customer forms — a customer's bespoke form must
|
|
not be visible to, or startable against, another customer's facilities.
|
|
|
|
**No rows for a template means SHARED (available on every contract)**, not
|
|
"available nowhere". That convention is why this migration needs no backfill
|
|
and cannot change behaviour on deploy: every template that exists today has no
|
|
rows and therefore stays available everywhere, exactly as before. A form only
|
|
becomes customer-specific once an admin attaches it to at least one contract.
|
|
|
|
Inverting that default later would silently hide every shared form from every
|
|
contract, so it is enforced in one place — InspectionTemplate.available_query()
|
|
— which the pickers, their POST validation, and the mobile API all use.
|
|
|
|
Table-existence check — safe to re-run.
|
|
"""
|
|
|
|
revision = 'phase55_template_contracts'
|
|
down_revision = 'phase54_user_notif_matrix'
|
|
branch_labels = None
|
|
depends_on = None
|
|
|
|
from alembic import op
|
|
import sqlalchemy as sa
|
|
|
|
|
|
def _has_table(conn, name):
|
|
return conn.execute(sa.text(
|
|
"SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES "
|
|
"WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = :t"
|
|
), {'t': name}).scalar() > 0
|
|
|
|
|
|
def upgrade():
|
|
conn = op.get_bind()
|
|
if _has_table(conn, 'template_contracts'):
|
|
return
|
|
|
|
op.create_table(
|
|
'template_contracts',
|
|
sa.Column('id', sa.Integer, primary_key=True),
|
|
sa.Column('template_id', sa.Integer,
|
|
sa.ForeignKey('inspection_templates.id', ondelete='CASCADE'),
|
|
nullable=False, index=True),
|
|
sa.Column('project_id', sa.Integer,
|
|
sa.ForeignKey('projects.id', ondelete='CASCADE'),
|
|
nullable=False, index=True),
|
|
sa.Column('created_at', sa.DateTime, nullable=False,
|
|
server_default=sa.func.now()),
|
|
sa.UniqueConstraint('template_id', 'project_id', name='uq_template_contract'),
|
|
)
|
|
|
|
|
|
def downgrade():
|
|
conn = op.get_bind()
|
|
if _has_table(conn, 'template_contracts'):
|
|
# Dropping the table returns every form to shared — no form becomes
|
|
# unusable, they just stop being restricted.
|
|
op.drop_table('template_contracts')
|