feat: complete auth/profile username migration and runtime safeguards

This commit is contained in:
qzl
2026-02-25 10:20:43 +08:00
parent 8bdcb674bb
commit 7d6dda57c1
24 changed files with 720 additions and 166 deletions
@@ -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;
$$
"""
)