fix(users): repair create delete and duplicate email handling
This commit is contained in:
parent
155fdbb16a
commit
0bbcaba211
22 changed files with 773 additions and 107 deletions
|
|
@ -0,0 +1,108 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
revision = "202607110006"
|
||||
down_revision = "202607110005"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
ALLOWED_ROLES = ("admin", "pruefer", "mitarbeiter", "leser")
|
||||
|
||||
|
||||
def _other_columns_use_userrole(connection) -> bool:
|
||||
result = connection.execute(
|
||||
sa.text(
|
||||
"""
|
||||
SELECT EXISTS (
|
||||
SELECT 1
|
||||
FROM pg_attribute a
|
||||
JOIN pg_class c ON c.oid = a.attrelid
|
||||
JOIN pg_type t ON t.oid = a.atttypid
|
||||
JOIN pg_namespace n ON n.oid = c.relnamespace
|
||||
WHERE t.typname = 'userrole'
|
||||
AND NOT (n.nspname = 'public' AND c.relname = 'users' AND a.attname = 'role')
|
||||
AND a.attnum > 0
|
||||
AND NOT a.attisdropped
|
||||
)
|
||||
"""
|
||||
)
|
||||
)
|
||||
return bool(result.scalar())
|
||||
|
||||
|
||||
def _normalize_roles(connection) -> None:
|
||||
connection.execute(
|
||||
sa.text(
|
||||
"""
|
||||
UPDATE users
|
||||
SET role = CASE upper(role::text)
|
||||
WHEN 'ADMIN' THEN 'admin'
|
||||
WHEN 'PRUEFER' THEN 'pruefer'
|
||||
WHEN 'EMPLOYEE' THEN 'mitarbeiter'
|
||||
WHEN 'MITARBEITER' THEN 'mitarbeiter'
|
||||
WHEN 'AUDITOR' THEN 'leser'
|
||||
WHEN 'LESER' THEN 'leser'
|
||||
ELSE role::text
|
||||
END
|
||||
"""
|
||||
)
|
||||
)
|
||||
invalid_roles = connection.execute(
|
||||
sa.text(
|
||||
"""
|
||||
SELECT DISTINCT role::text
|
||||
FROM users
|
||||
WHERE role::text NOT IN ('admin', 'pruefer', 'mitarbeiter', 'leser')
|
||||
"""
|
||||
),
|
||||
).scalars().all()
|
||||
if invalid_roles:
|
||||
raise RuntimeError(f"Unknown user roles encountered during migration: {', '.join(sorted(invalid_roles))}")
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
connection = op.get_bind()
|
||||
op.alter_column(
|
||||
"users",
|
||||
"role",
|
||||
existing_type=sa.Enum(name="userrole"),
|
||||
type_=sa.String(length=50),
|
||||
existing_nullable=False,
|
||||
existing_server_default=None,
|
||||
postgresql_using="role::text",
|
||||
nullable=False,
|
||||
)
|
||||
_normalize_roles(connection)
|
||||
op.execute(sa.text("ALTER TABLE users ALTER COLUMN role SET DEFAULT 'mitarbeiter'"))
|
||||
if not _other_columns_use_userrole(connection):
|
||||
op.execute(sa.text("DROP TYPE IF EXISTS userrole"))
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
connection = op.get_bind()
|
||||
op.execute(
|
||||
sa.text(
|
||||
"CREATE TYPE userrole AS ENUM ('admin', 'pruefer', 'mitarbeiter', 'leser')"
|
||||
)
|
||||
)
|
||||
invalid_roles = connection.execute(
|
||||
sa.text(
|
||||
"""
|
||||
SELECT DISTINCT role
|
||||
FROM users
|
||||
WHERE role NOT IN ('admin', 'pruefer', 'mitarbeiter', 'leser')
|
||||
"""
|
||||
),
|
||||
).scalars().all()
|
||||
if invalid_roles:
|
||||
raise RuntimeError(f"Cannot downgrade user roles with invalid values: {', '.join(sorted(invalid_roles))}")
|
||||
op.alter_column(
|
||||
"users",
|
||||
"role",
|
||||
existing_type=sa.String(length=50),
|
||||
type_=sa.Enum("admin", "pruefer", "mitarbeiter", "leser", name="userrole"),
|
||||
nullable=False,
|
||||
)
|
||||
op.execute(sa.text("ALTER TABLE users ALTER COLUMN role SET DEFAULT 'mitarbeiter'::userrole"))
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
"""add deleted_at to users for soft delete
|
||||
|
||||
Revision ID: 202607110007
|
||||
Revises: 202607110006
|
||||
Create Date: 2026-07-11 00:07:00.000000
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
revision = "202607110007"
|
||||
down_revision = "202607110006"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.add_column("users", sa.Column("deleted_at", sa.DateTime(timezone=True), nullable=True))
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_column("users", "deleted_at")
|
||||
Loading…
Add table
Add a link
Reference in a new issue