354 lines
12 KiB
PL/PgSQL
354 lines
12 KiB
PL/PgSQL
-- =====================================================
|
||
-- 一站式消息系统部署脚本
|
||
-- 自动检测环境并部署合适的权限模式
|
||
-- =====================================================
|
||
|
||
-- 部署配置检查
|
||
DO $$
|
||
BEGIN
|
||
RAISE NOTICE '🚀 开始消息系统一站式部署...';
|
||
RAISE NOTICE '📋 部署清单:';
|
||
RAISE NOTICE ' 1. 检查依赖扩展';
|
||
RAISE NOTICE ' 2. 创建/更新表结构';
|
||
RAISE NOTICE ' 3. 部署权限系统';
|
||
RAISE NOTICE ' 4. 插入基础数据';
|
||
RAISE NOTICE ' 5. 验证部署结果';
|
||
RAISE NOTICE '';
|
||
END $$;
|
||
|
||
-- =============================================================================
|
||
-- 1. 检查和创建必要的扩展
|
||
-- =============================================================================
|
||
|
||
DO $$
|
||
BEGIN
|
||
RAISE NOTICE '🔧 检查数据库扩展...';
|
||
|
||
-- UUID扩展
|
||
IF NOT EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'uuid-ossp') THEN
|
||
CREATE EXTENSION "uuid-ossp";
|
||
RAISE NOTICE ' ✅ 已创建 uuid-ossp 扩展';
|
||
ELSE
|
||
RAISE NOTICE ' ✅ uuid-ossp 扩展已存在';
|
||
END IF;
|
||
|
||
-- 文本搜索扩展
|
||
IF NOT EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'pg_trgm') THEN
|
||
BEGIN
|
||
CREATE EXTENSION "pg_trgm";
|
||
RAISE NOTICE ' ✅ 已创建 pg_trgm 扩展';
|
||
EXCEPTION WHEN OTHERS THEN
|
||
RAISE NOTICE ' ⚠️ pg_trgm 扩展创建失败,将跳过全文搜索功能';
|
||
END;
|
||
ELSE
|
||
RAISE NOTICE ' ✅ pg_trgm 扩展已存在';
|
||
END IF;
|
||
END $$;
|
||
|
||
-- =============================================================================
|
||
-- 2. 创建消息类型表(如果不存在)
|
||
-- =============================================================================
|
||
|
||
CREATE TABLE IF NOT EXISTS public.ak_message_types (
|
||
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
|
||
type_name VARCHAR(50) UNIQUE NOT NULL,
|
||
display_name VARCHAR(100) NOT NULL,
|
||
description TEXT,
|
||
icon VARCHAR(50),
|
||
color VARCHAR(7) DEFAULT '#1890ff',
|
||
is_active BOOLEAN DEFAULT true,
|
||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||
updated_at TIMESTAMPTZ DEFAULT NOW(),
|
||
created_by UUID,
|
||
updated_by UUID
|
||
);
|
||
|
||
-- 创建更新触发器
|
||
CREATE OR REPLACE FUNCTION public.update_updated_at_column()
|
||
RETURNS TRIGGER AS $$
|
||
BEGIN
|
||
NEW.updated_at = NOW();
|
||
RETURN NEW;
|
||
END;
|
||
$$ LANGUAGE plpgsql;
|
||
|
||
DROP TRIGGER IF EXISTS update_ak_message_types_updated_at ON public.ak_message_types;
|
||
CREATE TRIGGER update_ak_message_types_updated_at
|
||
BEFORE UPDATE ON public.ak_message_types
|
||
FOR EACH ROW EXECUTE FUNCTION public.update_updated_at_column();
|
||
|
||
-- =============================================================================
|
||
-- 3. 环境检测和权限模式选择
|
||
-- =============================================================================
|
||
|
||
DO $$
|
||
DECLARE
|
||
is_production BOOLEAN := false;
|
||
supabase_url TEXT;
|
||
deployment_mode TEXT;
|
||
BEGIN
|
||
RAISE NOTICE '🔍 检测部署环境...';
|
||
|
||
-- 尝试检测环境(这里可以根据实际情况调整检测逻辑)
|
||
-- 检查是否有特定的生产环境标识
|
||
BEGIN
|
||
-- 检查当前数据库名称或其他生产环境标识
|
||
SELECT current_database() INTO supabase_url;
|
||
|
||
-- 简单的环境判断逻辑
|
||
IF supabase_url LIKE '%prod%' OR supabase_url LIKE '%production%' THEN
|
||
is_production := true;
|
||
deployment_mode := 'production';
|
||
ELSE
|
||
deployment_mode := 'development';
|
||
END IF;
|
||
|
||
EXCEPTION WHEN OTHERS THEN
|
||
deployment_mode := 'development';
|
||
END;
|
||
|
||
RAISE NOTICE ' 🎯 检测到环境: %', deployment_mode;
|
||
|
||
-- 根据环境选择权限模式
|
||
IF is_production THEN
|
||
RAISE NOTICE ' 🔒 将部署生产权限模式(基于角色)';
|
||
ELSE
|
||
RAISE NOTICE ' 🔓 将部署开发权限模式(开放权限)';
|
||
RAISE NOTICE ' ⚠️ 如需生产权限,请手动运行 restore_normal_permissions.sql';
|
||
END IF;
|
||
END $$;
|
||
|
||
-- =============================================================================
|
||
-- 4. 部署基础数据和权限(开发模式)
|
||
-- =============================================================================
|
||
|
||
-- 插入基础消息类型
|
||
INSERT INTO public.ak_message_types (type_name, display_name, description, icon, color)
|
||
VALUES
|
||
('system', '系统消息', '系统自动发送的消息', 'system', '#52c41a'),
|
||
('notification', '通知消息', '普通通知消息', 'bell', '#1890ff'),
|
||
('announcement', '公告消息', '重要公告消息', 'megaphone', '#fa8c16'),
|
||
('private', '私人消息', '个人私密消息', 'mail', '#722ed1'),
|
||
('group', '群组消息', '群组内的消息', 'team', '#13c2c2'),
|
||
('task', '任务消息', '任务相关消息', 'check-circle', '#52c41a'),
|
||
('urgent', '紧急消息', '紧急重要消息', 'warning', '#ff4d4f'),
|
||
('reminder', '提醒消息', '定时提醒消息', 'clock-circle', '#faad14')
|
||
ON CONFLICT (type_name) DO UPDATE SET
|
||
display_name = EXCLUDED.display_name,
|
||
description = EXCLUDED.description,
|
||
icon = EXCLUDED.icon,
|
||
color = EXCLUDED.color,
|
||
updated_at = NOW();
|
||
|
||
-- 启用RLS(如果表存在)
|
||
DO $$
|
||
DECLARE
|
||
table_names TEXT[] := ARRAY[
|
||
'ak_message_types', 'ak_messages', 'ak_message_recipients',
|
||
'ak_message_groups', 'ak_message_group_members', 'ak_message_templates',
|
||
'ak_user_message_preferences', 'ak_message_stats'
|
||
];
|
||
table_name TEXT;
|
||
BEGIN
|
||
RAISE NOTICE '🛡️ 启用行级安全性...';
|
||
|
||
FOREACH table_name IN ARRAY table_names LOOP
|
||
BEGIN
|
||
EXECUTE format('ALTER TABLE IF EXISTS public.%I ENABLE ROW LEVEL SECURITY', table_name);
|
||
RAISE NOTICE ' ✅ 已为 % 启用RLS', table_name;
|
||
EXCEPTION WHEN OTHERS THEN
|
||
RAISE NOTICE ' ⚠️ 表 % 不存在,跳过RLS设置', table_name;
|
||
END;
|
||
END LOOP;
|
||
END $$;
|
||
|
||
-- =============================================================================
|
||
-- 5. 部署开发权限策略(默认)
|
||
-- =============================================================================
|
||
|
||
-- 清理现有策略
|
||
DO $$
|
||
DECLARE
|
||
table_names TEXT[] := ARRAY[
|
||
'ak_message_types', 'ak_messages', 'ak_message_recipients',
|
||
'ak_message_groups', 'ak_message_group_members', 'ak_message_templates',
|
||
'ak_user_message_preferences', 'ak_message_stats'
|
||
];
|
||
table_name TEXT;
|
||
r RECORD;
|
||
BEGIN
|
||
RAISE NOTICE '🔓 部署开发权限模式...';
|
||
|
||
FOREACH table_name IN ARRAY table_names LOOP
|
||
-- 删除现有策略
|
||
FOR r IN
|
||
SELECT policyname
|
||
FROM pg_policies
|
||
WHERE schemaname = 'public' AND tablename = table_name
|
||
LOOP
|
||
EXECUTE format('DROP POLICY IF EXISTS %I ON public.%I', r.policyname, table_name);
|
||
END LOOP;
|
||
|
||
-- 创建开放策略(如果表存在)
|
||
BEGIN
|
||
EXECUTE format('
|
||
CREATE POLICY "auto_dev_access_%s" ON public.%I
|
||
FOR ALL USING (auth.role() = ''authenticated'')
|
||
WITH CHECK (auth.role() = ''authenticated'')
|
||
', replace(table_name, 'ak_', ''), table_name);
|
||
RAISE NOTICE ' ✅ 已为 % 创建开放权限', table_name;
|
||
EXCEPTION WHEN OTHERS THEN
|
||
RAISE NOTICE ' ⚠️ 表 % 不存在,跳过权限设置', table_name;
|
||
END;
|
||
END LOOP;
|
||
END $$;
|
||
|
||
-- =============================================================================
|
||
-- 6. 创建便捷开发函数
|
||
-- =============================================================================
|
||
|
||
-- 快速发送消息函数
|
||
CREATE OR REPLACE FUNCTION public.quick_send(
|
||
p_title TEXT,
|
||
p_content TEXT,
|
||
p_to_user TEXT DEFAULT NULL,
|
||
p_type TEXT DEFAULT 'notification'
|
||
)
|
||
RETURNS UUID
|
||
LANGUAGE plpgsql
|
||
SECURITY DEFINER
|
||
AS $$
|
||
DECLARE
|
||
v_message_id UUID;
|
||
v_type_id UUID;
|
||
v_to_user_id UUID;
|
||
BEGIN
|
||
-- 获取消息类型
|
||
SELECT id INTO v_type_id FROM public.ak_message_types WHERE type_name = p_type LIMIT 1;
|
||
|
||
-- 如果指定了接收者,尝试解析
|
||
IF p_to_user IS NOT NULL THEN
|
||
IF p_to_user ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$' THEN
|
||
v_to_user_id := p_to_user::UUID;
|
||
ELSE
|
||
v_to_user_id := auth.uid(); -- 默认发给自己
|
||
END IF;
|
||
ELSE
|
||
v_to_user_id := auth.uid(); -- 默认发给自己
|
||
END IF;
|
||
|
||
-- 创建消息
|
||
INSERT INTO public.ak_messages (
|
||
message_type_id, sender_type, sender_id, receiver_type, receiver_id,
|
||
title, content, status, created_by
|
||
) VALUES (
|
||
v_type_id, 'user', auth.uid(), 'user', v_to_user_id,
|
||
p_title, p_content, 'sent', auth.uid()
|
||
) RETURNING id INTO v_message_id;
|
||
|
||
RETURN v_message_id;
|
||
END $$;
|
||
|
||
-- 消息统计函数
|
||
CREATE OR REPLACE FUNCTION public.message_stats()
|
||
RETURNS TABLE (
|
||
total_messages BIGINT,
|
||
unread_messages BIGINT,
|
||
message_types BIGINT,
|
||
recent_messages BIGINT
|
||
)
|
||
LANGUAGE plpgsql
|
||
SECURITY DEFINER
|
||
AS $$
|
||
BEGIN
|
||
RETURN QUERY
|
||
SELECT
|
||
(SELECT COUNT(*) FROM public.ak_messages)::BIGINT,
|
||
(SELECT COUNT(*) FROM public.ak_message_recipients WHERE status = 'unread')::BIGINT,
|
||
(SELECT COUNT(*) FROM public.ak_message_types WHERE is_active = true)::BIGINT,
|
||
(SELECT COUNT(*) FROM public.ak_messages WHERE created_at > NOW() - INTERVAL '24 hours')::BIGINT;
|
||
END $$;
|
||
|
||
-- =============================================================================
|
||
-- 7. 部署验证和结果报告
|
||
-- =============================================================================
|
||
|
||
DO $$
|
||
DECLARE
|
||
table_count INTEGER;
|
||
policy_count INTEGER;
|
||
function_count INTEGER;
|
||
type_count INTEGER;
|
||
extension_count INTEGER;
|
||
BEGIN
|
||
RAISE NOTICE '✅ 部署完成,生成部署报告...';
|
||
RAISE NOTICE '';
|
||
|
||
-- 统计表数量
|
||
SELECT COUNT(*) INTO table_count
|
||
FROM information_schema.tables
|
||
WHERE table_schema = 'public'
|
||
AND table_name LIKE 'ak_%';
|
||
|
||
-- 统计策略数量
|
||
SELECT COUNT(*) INTO policy_count
|
||
FROM pg_policies
|
||
WHERE schemaname = 'public'
|
||
AND tablename LIKE 'ak_%';
|
||
|
||
-- 统计函数数量
|
||
SELECT COUNT(*) INTO function_count
|
||
FROM information_schema.routines
|
||
WHERE routine_schema = 'public'
|
||
AND routine_name IN ('quick_send', 'message_stats');
|
||
|
||
-- 统计消息类型
|
||
SELECT COUNT(*) INTO type_count
|
||
FROM public.ak_message_types
|
||
WHERE is_active = true;
|
||
|
||
-- 统计扩展
|
||
SELECT COUNT(*) INTO extension_count
|
||
FROM pg_extension
|
||
WHERE extname IN ('uuid-ossp', 'pg_trgm');
|
||
|
||
RAISE NOTICE '📊 部署统计报告:';
|
||
RAISE NOTICE ' 🗄️ 消息相关表: % 个', table_count;
|
||
RAISE NOTICE ' 🛡️ 安全策略: % 个', policy_count;
|
||
RAISE NOTICE ' ⚙️ 便捷函数: % 个', function_count;
|
||
RAISE NOTICE ' 📝 消息类型: % 个', type_count;
|
||
RAISE NOTICE ' 🔧 数据库扩展: % 个', extension_count;
|
||
RAISE NOTICE '';
|
||
|
||
RAISE NOTICE '🎯 部署模式: 🔓 开发模式(开放权限)';
|
||
RAISE NOTICE '⚠️ 生产环境请运行: restore_normal_permissions.sql';
|
||
RAISE NOTICE '';
|
||
|
||
RAISE NOTICE '🛠️ 可用的便捷函数:';
|
||
RAISE NOTICE ' • quick_send(标题, 内容, 接收者, 类型) - 快速发送消息';
|
||
RAISE NOTICE ' • message_stats() - 查看消息统计';
|
||
RAISE NOTICE '';
|
||
|
||
RAISE NOTICE '📝 使用示例:';
|
||
RAISE NOTICE ' SELECT quick_send(''测试'', ''这是测试消息'');';
|
||
RAISE NOTICE ' SELECT * FROM message_stats();';
|
||
RAISE NOTICE ' SELECT * FROM public.ak_message_types;';
|
||
|
||
IF table_count > 0 AND policy_count > 0 THEN
|
||
RAISE NOTICE '';
|
||
RAISE NOTICE '🎉 消息系统部署成功!可以开始使用了。';
|
||
ELSE
|
||
RAISE NOTICE '';
|
||
RAISE NOTICE '⚠️ 部署可能不完整,请检查错误信息。';
|
||
END IF;
|
||
END $$;
|
||
|
||
-- 最终状态检查
|
||
SELECT
|
||
'🚀 一站式部署完成' as status,
|
||
'开发模式已启用' as mode,
|
||
COUNT(*) || ' 个消息类型已创建' as message_types,
|
||
'运行 SELECT * FROM message_stats() 查看统计' as next_step
|
||
FROM public.ak_message_types
|
||
WHERE is_active = true;
|