"""add rbac Revision ID: 7b2c9f4a0d31 Revises: 3f4c7b8d1e2a Create Date: 2026-07-02 13:00:00.000000 """ from typing import Sequence, Union from alembic import op import sqlalchemy as sa revision: str = "7b2c9f4a0d31" down_revision: Union[str, Sequence[str], None] = "3f4c7b8d1e2a" branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None ROLES = [ ("administrator", "Administrator", "Vollzugriff auf Olympus CRM"), ("management", "Management", "Lesender Zugriff auf operative Kernmodule"), ("sales", "Vertrieb", "Zugriff auf Kunden und Projekte"), ("technician", "Technik", "Zugriff auf Tickets und Projekte"), ("support", "Support", "Operativer Support-Zugriff"), ("warehouse", "Lager", "Zugriff auf lagernahe Prozesse"), ("guest", "Gast", "Minimaler Zugriff"), ] PERMISSIONS = [ ("users.read", "Benutzer lesen", "Benutzer anzeigen", "users"), ("users.create", "Benutzer erstellen", "Benutzer anlegen", "users"), ("users.update", "Benutzer bearbeiten", "Benutzer aktualisieren", "users"), ("users.delete", "Benutzer loeschen", "Benutzer entfernen", "users"), ("users.password.update", "Passwort aendern", "Benutzerpasswort aendern", "users"), ("roles.read", "Rollen lesen", "Rollen anzeigen", "roles"), ("roles.create", "Rollen erstellen", "Rollen anlegen", "roles"), ("roles.update", "Rollen bearbeiten", "Rollen aktualisieren", "roles"), ("roles.delete", "Rollen loeschen", "Rollen entfernen", "roles"), ("roles.assign", "Rollen zuweisen", "Berechtigungen Rollen zuweisen", "roles"), ("customers.read", "Kunden lesen", "Kunden anzeigen", "customers"), ("customers.create", "Kunden erstellen", "Kunden anlegen", "customers"), ("customers.update", "Kunden bearbeiten", "Kunden aktualisieren", "customers"), ("customers.delete", "Kunden loeschen", "Kunden entfernen", "customers"), ("projects.read", "Projekte lesen", "Projekte anzeigen", "projects"), ("projects.create", "Projekte erstellen", "Projekte anlegen", "projects"), ("projects.update", "Projekte bearbeiten", "Projekte aktualisieren", "projects"), ("projects.delete", "Projekte loeschen", "Projekte entfernen", "projects"), ("tickets.read", "Tickets lesen", "Tickets anzeigen", "tickets"), ("tickets.create", "Tickets erstellen", "Tickets anlegen", "tickets"), ("tickets.update", "Tickets bearbeiten", "Tickets aktualisieren", "tickets"), ("tickets.delete", "Tickets loeschen", "Tickets entfernen", "tickets"), ("dashboard.read", "Dashboard lesen", "Dashboard anzeigen", "dashboard"), ("system.settings.read", "Einstellungen lesen", "Systemeinstellungen anzeigen", "system"), ("system.settings.update", "Einstellungen bearbeiten", "Systemeinstellungen aktualisieren", "system"), ] def upgrade() -> None: op.create_table( "roles", sa.Column("id", sa.Integer(), nullable=False), sa.Column("name", sa.String(length=80), nullable=False), sa.Column("display_name", sa.String(length=120), nullable=False), sa.Column("description", sa.String(length=500), server_default="", nullable=False), sa.Column("is_system", sa.Boolean(), server_default=sa.true(), nullable=False), sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False), sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False), sa.PrimaryKeyConstraint("id"), ) op.create_index(op.f("ix_roles_name"), "roles", ["name"], unique=True) op.create_table( "permissions", sa.Column("id", sa.Integer(), nullable=False), sa.Column("name", sa.String(length=120), nullable=False), sa.Column("display_name", sa.String(length=160), nullable=False), sa.Column("description", sa.String(length=500), server_default="", nullable=False), sa.Column("module", sa.String(length=80), nullable=False), sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False), sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False), sa.PrimaryKeyConstraint("id"), ) op.create_index(op.f("ix_permissions_module"), "permissions", ["module"], unique=False) op.create_index(op.f("ix_permissions_name"), "permissions", ["name"], unique=True) op.create_table( "role_permissions", sa.Column("role_id", sa.Integer(), nullable=False), sa.Column("permission_id", sa.Integer(), nullable=False), sa.ForeignKeyConstraint(["permission_id"], ["permissions.id"], ondelete="CASCADE"), sa.ForeignKeyConstraint(["role_id"], ["roles.id"], ondelete="CASCADE"), sa.PrimaryKeyConstraint("role_id", "permission_id"), ) roles_table = sa.table( "roles", sa.column("name", sa.String), sa.column("display_name", sa.String), sa.column("description", sa.String), sa.column("is_system", sa.Boolean), ) permissions_table = sa.table( "permissions", sa.column("name", sa.String), sa.column("display_name", sa.String), sa.column("description", sa.String), sa.column("module", sa.String), ) op.bulk_insert( roles_table, [ { "name": name, "display_name": display_name, "description": description, "is_system": True, } for name, display_name, description in ROLES ], ) op.bulk_insert( permissions_table, [ { "name": name, "display_name": display_name, "description": description, "module": module, } for name, display_name, description, module in PERMISSIONS ], ) op.execute( """ INSERT INTO role_permissions (role_id, permission_id) SELECT roles.id, permissions.id FROM roles CROSS JOIN permissions WHERE roles.name = 'administrator' """ ) op.execute( """ INSERT INTO role_permissions (role_id, permission_id) SELECT roles.id, permissions.id FROM roles JOIN permissions ON permissions.name IN ( 'dashboard.read', 'users.read', 'customers.read', 'projects.read', 'tickets.read' ) WHERE roles.name = 'management' """ ) op.execute( """ INSERT INTO role_permissions (role_id, permission_id) SELECT roles.id, permissions.id FROM roles JOIN permissions ON permissions.name IN ( 'dashboard.read', 'customers.read', 'customers.create', 'customers.update', 'projects.read', 'tickets.read' ) WHERE roles.name = 'sales' """ ) op.execute( """ INSERT INTO role_permissions (role_id, permission_id) SELECT roles.id, permissions.id FROM roles JOIN permissions ON permissions.name IN ( 'dashboard.read', 'projects.read', 'tickets.read', 'tickets.create', 'tickets.update' ) WHERE roles.name = 'technician' """ ) op.execute( """ INSERT INTO role_permissions (role_id, permission_id) SELECT roles.id, permissions.id FROM roles JOIN permissions ON permissions.name IN ( 'dashboard.read', 'users.read', 'customers.read', 'tickets.read', 'tickets.create', 'tickets.update' ) WHERE roles.name = 'support' """ ) op.execute( """ INSERT INTO role_permissions (role_id, permission_id) SELECT roles.id, permissions.id FROM roles JOIN permissions ON permissions.name IN ( 'dashboard.read' ) WHERE roles.name IN ('warehouse', 'guest') """ ) op.add_column("users", sa.Column("role_id", sa.Integer(), nullable=True)) op.create_index(op.f("ix_users_role_id"), "users", ["role_id"], unique=False) op.create_foreign_key("fk_users_role_id_roles", "users", "roles", ["role_id"], ["id"]) op.execute( """ UPDATE users SET role_id = roles.id FROM roles WHERE roles.name = CASE WHEN users.role IN ('admin', 'administrator') THEN 'administrator' WHEN users.role IN ('manager', 'management') THEN 'management' WHEN users.role = 'sales' THEN 'sales' WHEN users.role IN ('technician', 'tech') THEN 'technician' WHEN users.role = 'warehouse' THEN 'warehouse' WHEN users.role = 'guest' THEN 'guest' ELSE 'support' END """ ) op.execute( """ UPDATE users SET role_id = (SELECT id FROM roles WHERE name = 'administrator') WHERE id = ( SELECT id FROM users ORDER BY id LIMIT 1 ) AND NOT EXISTS ( SELECT 1 FROM users JOIN roles ON users.role_id = roles.id WHERE roles.name = 'administrator' ) """ ) op.alter_column("users", "role_id", existing_type=sa.Integer(), nullable=False) def downgrade() -> None: op.drop_constraint("fk_users_role_id_roles", "users", type_="foreignkey") op.drop_index(op.f("ix_users_role_id"), table_name="users") op.drop_column("users", "role_id") op.drop_table("role_permissions") op.drop_index(op.f("ix_permissions_name"), table_name="permissions") op.drop_index(op.f("ix_permissions_module"), table_name="permissions") op.drop_table("permissions") op.drop_index(op.f("ix_roles_name"), table_name="roles") op.drop_table("roles")