This commit is contained in:
2026-02-04 17:35:46 +08:00
parent 7344aaae77
commit 0ee4577b31
82 changed files with 20458 additions and 0 deletions

View File

@@ -0,0 +1,145 @@
-- ============================================
-- 用户登录 / 注册 - 核心用户资料表结构(创建版 / Create-only
-- ============================================
-- 用途创建核心业务用户资料表ak_users及其相关函数和 RLS 策略。
-- 特点:
-- 1. 不做 DROP/DELETE/TRUNCATE不清空数据
-- 2. 通过 IF NOT EXISTS + 系统表判断,实现可重复执行
-- 3. 职责单一:只负责 ak_users不涉及其他基础表
-- 4. 依赖应在基础表01_create_tables.sql之后执行
-- ============================================
-- ============================================
-- 1. 业务用户资料表 ak_users
-- ============================================
CREATE TABLE IF NOT EXISTS public.ak_users (
id uuid primary key,
username text,
email text,
gender text,
birthday date,
height_cm numeric,
weight_kg numeric,
bio text,
avatar_url text,
preferred_language text,
role text,
school_id text,
grade_id text,
class_id text,
created_at timestamptz default now(),
updated_at timestamptz default now()
);
-- 中文注释
COMMENT ON TABLE public.ak_users IS '业务用户资料表(与 auth.users 一一对应)';
COMMENT ON COLUMN public.ak_users.id IS '用户ID等于 auth.users.id';
COMMENT ON COLUMN public.ak_users.username IS '用户名/昵称';
COMMENT ON COLUMN public.ak_users.email IS '邮箱';
COMMENT ON COLUMN public.ak_users.gender IS '性别';
COMMENT ON COLUMN public.ak_users.birthday IS '生日';
COMMENT ON COLUMN public.ak_users.height_cm IS '身高(厘米)';
COMMENT ON COLUMN public.ak_users.weight_kg IS '体重(公斤)';
COMMENT ON COLUMN public.ak_users.bio IS '个人简介';
COMMENT ON COLUMN public.ak_users.avatar_url IS '头像地址';
COMMENT ON COLUMN public.ak_users.preferred_language IS '偏好语言';
COMMENT ON COLUMN public.ak_users.role IS '角色(如 customer/merchant/admin 等)';
COMMENT ON COLUMN public.ak_users.school_id IS '学校ID可选';
COMMENT ON COLUMN public.ak_users.grade_id IS '年级ID可选';
COMMENT ON COLUMN public.ak_users.class_id IS '班级ID可选';
COMMENT ON COLUMN public.ak_users.created_at IS '创建时间';
COMMENT ON COLUMN public.ak_users.updated_at IS '更新时间';
-- 为 ak_users 添加 updated_at 触发器
-- 注意:通用函数 update_updated_at_column() 在 01_create_tables.sql 中创建
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_trigger WHERE tgname = 'update_ak_users_updated_at') THEN
EXECUTE 'CREATE TRIGGER update_ak_users_updated_at BEFORE UPDATE ON public.ak_users FOR EACH ROW EXECUTE FUNCTION public.update_updated_at_column()';
END IF;
END $$;
-- ============================================
-- 2. 行级安全策略RLS
-- ============================================
-- 启用 RLS
ALTER TABLE public.ak_users ENABLE ROW LEVEL SECURITY;
-- 仅允许本人读写自己的资料
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename='ak_users' AND policyname='ak_users_self_select') THEN
EXECUTE 'CREATE POLICY "ak_users_self_select" ON public.ak_users FOR SELECT USING (auth.uid() = id)';
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename='ak_users' AND policyname='ak_users_self_insert') THEN
EXECUTE 'CREATE POLICY "ak_users_self_insert" ON public.ak_users FOR INSERT WITH CHECK (auth.uid() = id)';
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename='ak_users' AND policyname='ak_users_self_update') THEN
EXECUTE 'CREATE POLICY "ak_users_self_update" ON public.ak_users FOR UPDATE USING (auth.uid() = id)';
END IF;
END $$;
-- ============================================
-- 3. 相关函数
-- ============================================
-- 函数1手动初始化/更新用户资料(可选,供前端调用)
CREATE OR REPLACE FUNCTION public.upsert_user_profile(
p_user_id uuid,
p_email text,
p_username text default null
)
RETURNS public.ak_users
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
DECLARE
v_username text := coalesce(p_username, split_part(p_email, '@', 1), 'user');
v_result public.ak_users;
BEGIN
-- 插入或更新用户资料
INSERT INTO public.ak_users (id, email, username)
VALUES (p_user_id, p_email, v_username)
ON CONFLICT (id) DO UPDATE
SET
email = excluded.email,
username = coalesce(excluded.username, ak_users.username)
RETURNING * INTO v_result;
RETURN v_result;
END;
$$;
-- 函数2供 auth.users 触发器使用,自动创建用户资料
CREATE OR REPLACE FUNCTION public.handle_new_user()
RETURNS trigger
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
BEGIN
BEGIN
INSERT INTO public.ak_users (id, email, username)
VALUES (NEW.id, NEW.email, COALESCE(SPLIT_PART(NEW.email, '@', 1), 'user'))
ON CONFLICT (id) DO NOTHING;
EXCEPTION WHEN OTHERS THEN
-- 重要:不要因为业务表写入失败而阻断 auth.users 的注册事务
RAISE WARNING 'handle_new_user failed: %', SQLERRM;
END;
RETURN NEW;
END;
$$;
-- ============================================
-- 4. 函数授权
-- ============================================
-- upsert_user_profile 只允许已登录用户调用
REVOKE ALL ON FUNCTION public.upsert_user_profile(uuid, text, text) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION public.upsert_user_profile(uuid, text, text) TO authenticated;
-- handle_new_user 是触发器函数,由系统内部调用,无需对任何角色授权