Files
akmon/deploy_one_click.sql
2026-01-20 08:04:15 +08:00

354 lines
12 KiB
PL/PgSQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- =====================================================
-- 一站式消息系统部署脚本
-- 自动检测环境并部署合适的权限模式
-- =====================================================
-- 部署配置检查
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;