chore: sync current workspace to dev
This commit is contained in:
@@ -8,6 +8,7 @@ COPY pyproject.toml uv.lock ./
|
||||
RUN uv sync --frozen --no-dev
|
||||
|
||||
COPY backend/src ./backend/src
|
||||
COPY backend/alembic ./backend/alembic
|
||||
|
||||
ENV PYTHONPATH=/app/backend/src
|
||||
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
"""bind_profiles_to_auth_users
|
||||
|
||||
Revision ID: 20260224_bind_profiles_auth
|
||||
Revises: 85d25a191d06
|
||||
Create Date: 2026-02-24 17:55:00.000000
|
||||
|
||||
"""
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = "20260224_bind_profiles_auth"
|
||||
down_revision: Union[str, Sequence[str], None] = "85d25a191d06"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# Remove orphan profiles that are not backed by auth.users.
|
||||
# This guarantees FK creation will not fail on historical inconsistent data.
|
||||
op.execute(
|
||||
"""
|
||||
DELETE FROM public.profiles p
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM auth.users u
|
||||
WHERE u.id = p.id
|
||||
)
|
||||
"""
|
||||
)
|
||||
|
||||
# Backfill profile rows for existing auth users.
|
||||
op.execute(
|
||||
"""
|
||||
INSERT INTO public.profiles (id, username, display_name)
|
||||
SELECT
|
||||
u.id,
|
||||
'user_' || substr(replace(u.id::text, '-', ''), 1, 25),
|
||||
COALESCE(
|
||||
NULLIF(u.raw_user_meta_data->>'display_name', ''),
|
||||
NULLIF(u.raw_user_meta_data->>'full_name', '')
|
||||
)
|
||||
FROM auth.users u
|
||||
LEFT JOIN public.profiles p ON p.id = u.id
|
||||
WHERE p.id IS NULL
|
||||
"""
|
||||
)
|
||||
|
||||
# Enforce one-to-one binding between profiles.id and auth.users.id.
|
||||
op.execute(
|
||||
"""
|
||||
ALTER TABLE public.profiles
|
||||
ADD CONSTRAINT fk_profiles_id_auth_users
|
||||
FOREIGN KEY (id) REFERENCES auth.users(id)
|
||||
ON DELETE CASCADE
|
||||
"""
|
||||
)
|
||||
|
||||
# Auto-create profile rows when new auth users are registered.
|
||||
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;
|
||||
$$
|
||||
"""
|
||||
)
|
||||
|
||||
op.execute(
|
||||
"""
|
||||
DROP TRIGGER IF EXISTS on_auth_user_created ON auth.users
|
||||
"""
|
||||
)
|
||||
op.execute(
|
||||
"""
|
||||
CREATE TRIGGER on_auth_user_created
|
||||
AFTER INSERT ON auth.users
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.create_profile_for_new_user()
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.execute("DROP TRIGGER IF EXISTS on_auth_user_created ON auth.users")
|
||||
op.execute("DROP FUNCTION IF EXISTS public.create_profile_for_new_user()")
|
||||
op.execute(
|
||||
"""
|
||||
ALTER TABLE public.profiles
|
||||
DROP CONSTRAINT IF EXISTS fk_profiles_id_auth_users
|
||||
"""
|
||||
)
|
||||
@@ -2,7 +2,7 @@ from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
|
||||
from sqlalchemy import String, Text
|
||||
from sqlalchemy import ForeignKey, String, Text
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
@@ -21,6 +21,7 @@ class Profile(TimestampMixin, SoftDeleteMixin, Base):
|
||||
|
||||
id: Mapped[uuid.UUID] = mapped_column(
|
||||
UUID(as_uuid=True),
|
||||
ForeignKey("auth.users.id", ondelete="CASCADE"),
|
||||
primary_key=True,
|
||||
)
|
||||
username: Mapped[str] = mapped_column(
|
||||
|
||||
Reference in New Issue
Block a user