Files
orion/alembic/versions_backup/za0k1l2m3n4o5_add_admin_menu_config.py
Samir Boulahtit f20266167d
Some checks failed
CI / ruff (push) Failing after 7s
CI / pytest (push) Failing after 1s
CI / architecture (push) Failing after 9s
CI / dependency-scanning (push) Successful in 27s
CI / audit (push) Successful in 8s
CI / docs (push) Has been skipped
fix(lint): auto-fix ruff violations and tune lint rules
- Auto-fixed 4,496 lint issues (import sorting, modern syntax, etc.)
- Added ignore rules for patterns intentional in this codebase:
  E402 (late imports), E712 (SQLAlchemy filters), B904 (raise from),
  SIM108/SIM105/SIM117 (readability preferences)
- Added per-file ignores for tests and scripts
- Excluded broken scripts/rename_terminology.py (has curly quotes)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 23:10:42 +01:00

129 lines
3.9 KiB
Python

"""Add admin menu configuration table
Revision ID: za0k1l2m3n4o5
Revises: z9j0k1l2m3n4
Create Date: 2026-01-25
Adds configurable admin sidebar menus:
- Platform-level config: Controls which menu items platform admins see
- User-level config: Controls which menu items super admins see
- Opt-out model: All items visible by default
- Mandatory items enforced at application level (companies, vendors, users, settings)
"""
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = "za0k1l2m3n4o5"
down_revision = "z9j0k1l2m3n4"
branch_labels = None
depends_on = None
def upgrade() -> None:
# Create admin_menu_configs table
op.create_table(
"admin_menu_configs",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column(
"platform_id",
sa.Integer(),
nullable=True,
comment="Platform scope - applies to all platform admins of this platform",
),
sa.Column(
"user_id",
sa.Integer(),
nullable=True,
comment="User scope - applies to this specific super admin",
),
sa.Column(
"menu_item_id",
sa.String(50),
nullable=False,
comment="Menu item identifier from registry (e.g., 'products', 'inventory')",
),
sa.Column(
"is_visible",
sa.Boolean(),
nullable=False,
server_default="true",
comment="Whether this menu item is visible (False = hidden)",
),
sa.Column(
"created_at",
sa.DateTime(timezone=True),
nullable=False,
server_default=sa.func.now(),
),
sa.Column(
"updated_at",
sa.DateTime(timezone=True),
nullable=False,
server_default=sa.func.now(),
onupdate=sa.func.now(),
),
# Foreign keys
sa.ForeignKeyConstraint(
["platform_id"],
["platforms.id"],
ondelete="CASCADE",
),
sa.ForeignKeyConstraint(
["user_id"],
["users.id"],
ondelete="CASCADE",
),
sa.PrimaryKeyConstraint("id"),
# Unique constraints
sa.UniqueConstraint("platform_id", "menu_item_id", name="uq_platform_menu_config"),
sa.UniqueConstraint("user_id", "menu_item_id", name="uq_user_menu_config"),
# Check constraint: exactly one scope must be set
sa.CheckConstraint(
"(platform_id IS NOT NULL AND user_id IS NULL) OR "
"(platform_id IS NULL AND user_id IS NOT NULL)",
name="ck_admin_menu_config_scope",
),
)
# Create indexes for performance
op.create_index(
"idx_admin_menu_configs_platform_id",
"admin_menu_configs",
["platform_id"],
)
op.create_index(
"idx_admin_menu_configs_user_id",
"admin_menu_configs",
["user_id"],
)
op.create_index(
"idx_admin_menu_configs_menu_item_id",
"admin_menu_configs",
["menu_item_id"],
)
op.create_index(
"idx_admin_menu_config_platform_visible",
"admin_menu_configs",
["platform_id", "is_visible"],
)
op.create_index(
"idx_admin_menu_config_user_visible",
"admin_menu_configs",
["user_id", "is_visible"],
)
def downgrade() -> None:
# Drop indexes
op.drop_index("idx_admin_menu_config_user_visible", table_name="admin_menu_configs")
op.drop_index("idx_admin_menu_config_platform_visible", table_name="admin_menu_configs")
op.drop_index("idx_admin_menu_configs_menu_item_id", table_name="admin_menu_configs")
op.drop_index("idx_admin_menu_configs_user_id", table_name="admin_menu_configs")
op.drop_index("idx_admin_menu_configs_platform_id", table_name="admin_menu_configs")
# Drop table
op.drop_table("admin_menu_configs")