"""Garantit le rattachement RBAC explicite des utilisateurs existants. Cette migration termine la bascule depuis ``users.role`` vers les relations RBAC. Elle est idempotente et ne supprime aucune donnée historique. """ from alembic import op import sqlalchemy as sa revision = "9e39f0a1b2c3" down_revision = "9d28e9f0a1b2" branch_labels = None depends_on = None def upgrade(): bind = op.get_bind() bind.execute(sa.text( """INSERT INTO roles (slug, name, description, is_system, is_active, created_at, updated_at) SELECT 'admin', 'Administrateur système', 'Rôle système donnant toutes les permissions RBAC', 1, 1, NOW(), NOW() FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM roles WHERE slug = 'admin')""" )) bind.execute(sa.text("UPDATE roles SET is_active = 1, is_system = 1 WHERE slug = 'admin'")) bind.execute(sa.text( """INSERT INTO permissions (code, name, module, action, description, is_active) SELECT '*', 'Accès complet', 'system', 'all', 'Accès complet accordé au rôle administrateur', 1 FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM permissions WHERE code = '*')""" )) bind.execute(sa.text("UPDATE permissions SET is_active = 1 WHERE code = '*'")) bind.execute(sa.text( """INSERT INTO role_permissions (role_id, permission_id, effect) SELECT r.id, p.id, 'allow' FROM roles r CROSS JOIN permissions p WHERE r.slug = 'admin' AND p.code = '*' AND NOT EXISTS ( SELECT 1 FROM role_permissions rp WHERE rp.role_id = r.id AND rp.permission_id = p.id )""" )) # Tous les comptes existants reçoivent explicitement admin. Le champ # users.role est conservé pour compatibilité d'affichage uniquement. bind.execute(sa.text( """INSERT INTO user_roles (user_id, role_id, assigned_at) SELECT u.id, r.id, NOW() FROM users u CROSS JOIN roles r WHERE r.slug = 'admin' AND NOT EXISTS ( SELECT 1 FROM user_roles ur WHERE ur.user_id = u.id AND ur.role_id = r.id )""" )) def downgrade(): # Ne pas retirer les rattachements administrateurs : ils peuvent avoir été # modifiés après migration et leur suppression serait destructive. pass