Fix Discord username generation

This commit is contained in:
gpt-engineer-app[bot]
2025-10-12 00:48:48 +00:00
parent cf94eef683
commit c129fb1a9e

View File

@@ -0,0 +1,118 @@
-- Fix Discord username generation by reading from auth.identities
CREATE OR REPLACE FUNCTION public.handle_new_user()
RETURNS trigger
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path TO 'public', 'auth'
AS $$
DECLARE
v_username TEXT;
v_display_name TEXT;
v_email TEXT;
v_provider TEXT;
v_username_attempt INTEGER := 0;
v_max_attempts INTEGER := 10;
v_unique_username TEXT;
v_identity_data JSONB;
BEGIN
-- Extract email and provider
v_email := NEW.email;
v_provider := NEW.raw_app_meta_data->>'provider';
-- Smart username generation based on provider
IF v_provider = 'google' THEN
-- For Google: try email prefix, then name-based, then UUID fallback
v_username := COALESCE(
-- Email prefix (before @), sanitized
LOWER(REGEXP_REPLACE(split_part(v_email, '@', 1), '[^a-z0-9_]', '_', 'g')),
-- Name-based, sanitized
LOWER(REGEXP_REPLACE(NEW.raw_user_meta_data->>'name', '[^a-z0-9_]', '_', 'g')),
-- UUID fallback
'user_' || substring(NEW.id::text, 1, 8)
);
v_display_name := NEW.raw_user_meta_data->>'name';
ELSIF v_provider = 'discord' THEN
-- For Discord: Extract data from auth.identities table
SELECT identity_data INTO v_identity_data
FROM auth.identities
WHERE user_id = NEW.id AND provider = 'discord'
LIMIT 1;
IF v_identity_data IS NOT NULL THEN
-- Extract username from full_name (preferred) or name without discriminator
v_username := COALESCE(
LOWER(REGEXP_REPLACE(v_identity_data->>'full_name', '[^a-z0-9_]', '_', 'g')),
LOWER(REGEXP_REPLACE(split_part(v_identity_data->>'name', '#', 1), '[^a-z0-9_]', '_', 'g')),
'user_' || substring(NEW.id::text, 1, 8)
);
-- Extract display name from custom_claims.global_name (preferred) or full_name
v_display_name := COALESCE(
v_identity_data->'custom_claims'->>'global_name',
v_identity_data->>'full_name',
v_identity_data->>'name'
);
RAISE NOTICE 'Discord user data extracted: username=%, display_name=%', v_username, v_display_name;
ELSE
-- Fallback if identity data not found
v_username := 'user_' || substring(NEW.id::text, 1, 8);
v_display_name := NULL;
RAISE WARNING 'Discord identity data not found for user %, using fallback', NEW.id;
END IF;
ELSE
-- Manual signup or other providers
v_username := COALESCE(
NEW.raw_user_meta_data->>'username',
'user_' || substring(NEW.id::text, 1, 8)
);
v_display_name := COALESCE(
NEW.raw_user_meta_data->>'display_name',
NEW.raw_user_meta_data->>'name'
);
END IF;
-- Ensure username uniqueness by appending counter if needed
v_unique_username := v_username;
WHILE v_username_attempt < v_max_attempts LOOP
BEGIN
-- Try to insert with current username
INSERT INTO public.profiles (
user_id,
username,
display_name,
oauth_provider
)
VALUES (
NEW.id,
v_unique_username,
v_display_name,
v_provider
);
-- If successful, exit loop
EXIT;
EXCEPTION WHEN unique_violation THEN
-- Username taken, try next variant
v_username_attempt := v_username_attempt + 1;
IF v_username_attempt < v_max_attempts THEN
v_unique_username := v_username || '_' || v_username_attempt;
ELSE
-- Final fallback to UUID if all attempts fail
v_unique_username := 'user_' || substring(NEW.id::text, 1, 8);
END IF;
END;
END LOOP;
-- Log the final username for debugging
RAISE NOTICE 'Created profile for user % with username %', NEW.id, v_unique_username;
RETURN NEW;
END;
$$;
COMMENT ON FUNCTION public.handle_new_user IS 'Creates user profile on signup with smart username generation. For Discord, reads from auth.identities table.';