feat(rbac): add roles and permissions
This commit is contained in:
parent
86a32a942c
commit
694b7bd09a
37 changed files with 2682 additions and 218 deletions
269
backend/hermes/alembic/versions/7b2c9f4a0d31_add_rbac.py
Normal file
269
backend/hermes/alembic/versions/7b2c9f4a0d31_add_rbac.py
Normal file
|
|
@ -0,0 +1,269 @@
|
|||
"""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")
|
||||
Loading…
Add table
Add a link
Reference in a new issue