feat: complete auth/profile username migration and runtime safeguards
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
"""drop_profile_display_name_and_trigger_username
|
||||
|
||||
Revision ID: 20260224_drop_profile
|
||||
Revises: 20260224_bind_profiles_auth
|
||||
Create Date: 2026-02-24 22:10:00.000000
|
||||
|
||||
"""
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
|
||||
|
||||
revision: str = "20260224_drop_profile"
|
||||
down_revision: Union[str, Sequence[str], None] = "20260224_bind_profiles_auth"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.execute(
|
||||
"""
|
||||
ALTER TABLE public.profiles
|
||||
DROP CONSTRAINT IF EXISTS uq_profiles_username
|
||||
"""
|
||||
)
|
||||
|
||||
op.execute(
|
||||
"""
|
||||
ALTER TABLE public.profiles
|
||||
DROP COLUMN IF EXISTS display_name
|
||||
"""
|
||||
)
|
||||
|
||||
op.execute(
|
||||
"""
|
||||
CREATE OR REPLACE FUNCTION public.create_profile_for_new_user()
|
||||
RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
SECURITY DEFINER
|
||||
SET search_path = public
|
||||
AS $$
|
||||
BEGIN
|
||||
INSERT INTO public.profiles (id, username)
|
||||
VALUES (
|
||||
NEW.id,
|
||||
COALESCE(
|
||||
NULLIF(NEW.raw_user_meta_data->>'username', ''),
|
||||
'user_' || substr(replace(NEW.id::text, '-', ''), 1, 25)
|
||||
)
|
||||
)
|
||||
ON CONFLICT (id) DO NOTHING;
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.execute(
|
||||
"""
|
||||
ALTER TABLE public.profiles
|
||||
ADD COLUMN IF NOT EXISTS display_name VARCHAR(50)
|
||||
"""
|
||||
)
|
||||
|
||||
op.execute(
|
||||
"""
|
||||
WITH ranked AS (
|
||||
SELECT
|
||||
id,
|
||||
username,
|
||||
row_number() OVER (
|
||||
PARTITION BY username
|
||||
ORDER BY created_at ASC, id ASC
|
||||
) AS rn
|
||||
FROM public.profiles
|
||||
WHERE username IS NOT NULL
|
||||
)
|
||||
UPDATE public.profiles p
|
||||
SET username = LEFT(p.username, 24) || '_' || (ranked.rn - 1)::text
|
||||
FROM ranked
|
||||
WHERE p.id = ranked.id
|
||||
AND ranked.rn > 1
|
||||
"""
|
||||
)
|
||||
|
||||
op.execute(
|
||||
"""
|
||||
ALTER TABLE public.profiles
|
||||
ADD CONSTRAINT uq_profiles_username UNIQUE (username)
|
||||
"""
|
||||
)
|
||||
|
||||
op.execute(
|
||||
"""
|
||||
CREATE OR REPLACE FUNCTION public.create_profile_for_new_user()
|
||||
RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
SECURITY DEFINER
|
||||
SET search_path = public
|
||||
AS $$
|
||||
BEGIN
|
||||
INSERT INTO public.profiles (id, username, display_name)
|
||||
VALUES (
|
||||
NEW.id,
|
||||
'user_' || substr(replace(NEW.id::text, '-', ''), 1, 25),
|
||||
COALESCE(
|
||||
NULLIF(NEW.raw_user_meta_data->>'display_name', ''),
|
||||
NULLIF(NEW.raw_user_meta_data->>'full_name', '')
|
||||
)
|
||||
)
|
||||
ON CONFLICT (id) DO NOTHING;
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$
|
||||
"""
|
||||
)
|
||||
Reference in New Issue
Block a user