-- ===================================================================================== -- Trigger Function: handle_new_user -- Version: v3 -- Purpose: auth.users 新用户创建后,同步写入 public.ak_users(权威)和 public.user_roles(兼容)。 -- 此版本修复了向 user_roles 写入时可能因 role 为 NULL 导致的 NOT NULL 约束失败问题。 -- Security: SECURITY DEFINER + 固定 search_path -- Depends: -- - public.ak_users(auth_id,email,username,role) -- - public.user_roles(user_id,role) -- ===================================================================================== CREATE OR REPLACE FUNCTION public.handle_new_user() RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path = public AS $$ DECLARE user_role TEXT; user_email TEXT := NEW.email; user_name TEXT; has_user_roles BOOLEAN := FALSE; BEGIN -- 1) 基于邮箱规则分配默认角色(可按需调整) -- 确保 user_role 总有一个非 NULL 的值 user_role := CASE WHEN user_email ILIKE '%@admin.%' THEN 'admin' WHEN user_email ILIKE '%@teacher.%' OR user_email ILIKE '%@edu.%' THEN 'teacher' ELSE 'consumer' -- 默认角色 END; -- 2) 默认 username:取邮箱 @ 前缀 IF user_email IS NOT NULL AND POSITION('@' IN user_email) > 1 THEN user_name := SPLIT_PART(user_email, '@', 1); ELSE user_name := 'user_' || SUBSTRING(NEW.id::text, 1, 8); -- 使用 user_ + uid前8位作为备用名 END IF; -- 3) 写入 ak_users(权威) -- 使用 ON CONFLICT 确保幂等:同一 auth_id 只会有一条记录 INSERT INTO public.ak_users (auth_id, email, username, role) VALUES (NEW.id, user_email, user_name, user_role) ON CONFLICT (auth_id) DO UPDATE SET email = COALESCE(EXCLUDED.email, public.ak_users.email), username = COALESCE(EXCLUDED.username, public.ak_users.username), -- 只有当现有 role 为空时才更新,避免覆盖手动设置的 admin 角色 role = COALESCE(public.ak_users.role, EXCLUDED.role), updated_at = now(); -- 4) 兼容写入 user_roles(如果表存在) SELECT EXISTS ( SELECT 1 FROM information_schema.tables WHERE table_schema='public' AND table_name='user_roles' ) INTO has_user_roles; IF has_user_roles THEN BEGIN -- 确保插入的 role 不为 NULL,即使上面的逻辑有误 INSERT INTO public.user_roles (user_id, role, created_by) VALUES (NEW.id, COALESCE(user_role, 'customer'), NEW.id); EXCEPTION WHEN unique_violation THEN -- 忽略重复插入的错误 NULL; WHEN not_null_violation THEN -- 记录非空约束错误,但不中断整个触发器 RAISE NOTICE '[handle_new_user] WARNING: Failed to INSERT into user_roles due to NOT NULL violation. user_id: %, role: %', NEW.id, user_role; END; END IF; -- 5) 更新 auth.users 元数据(可选保留) UPDATE auth.users SET raw_user_meta_data = COALESCE(raw_user_meta_data, '{}'::jsonb) || jsonb_build_object('user_role', user_role) WHERE id = NEW.id; RETURN NEW; END; $$;