Files
akmon/supabase_message_client_complete.js
2026-01-20 08:04:15 +08:00

610 lines
17 KiB
JavaScript
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.
/**
* Supabase 消息系统客户端 - 完整角色管理版本
* 包含角色管理、权限检查、消息操作等功能
*/
import { createClient } from '@supabase/supabase-js'
// Supabase 配置
const supabaseUrl = 'YOUR_SUPABASE_URL'
const supabaseKey = 'YOUR_SUPABASE_ANON_KEY'
const supabase = createClient(supabaseUrl, supabaseKey)
/**
* 用户角色管理类
*/
class UserRoleManager {
constructor(supabaseClient) {
this.supabase = supabaseClient
this.currentUser = null
this.currentRole = null
this.permissions = {}
}
/**
* 初始化用户角色信息
*/
async initialize() {
try {
const { data: { user } } = await this.supabase.auth.getUser()
if (user) {
this.currentUser = user
this.currentRole = await this.getUserRole(user.id)
this.permissions = await this.getUserPermissions(user.id)
console.log('✅ 用户角色初始化完成:', {
userId: user.id,
email: user.email,
role: this.currentRole,
permissions: this.permissions
})
}
return {
user: this.currentUser,
role: this.currentRole,
permissions: this.permissions
}
} catch (error) {
console.error('❌ 用户角色初始化失败:', error)
throw error
}
}
/**
* 获取用户角色
* @param {string} userId - 用户ID
* @returns {Promise<string>} 用户角色
*/
async getUserRole(userId = null) {
try {
const { data, error } = await this.supabase
.rpc('get_user_role', { target_user_id: userId })
if (error) throw error
return data || 'student'
} catch (error) {
console.error('获取用户角色失败:', error)
return 'student'
}
}
/**
* 获取用户权限
* @param {string} userId - 用户ID
* @returns {Promise<Object>} 用户权限对象
*/
async getUserPermissions(userId = null) {
try {
const { data, error } = await this.supabase
.from('user_roles')
.select('permissions')
.eq('user_id', userId || this.currentUser?.id)
.eq('is_active', true)
.single()
if (error && error.code !== 'PGRST116') throw error
return data?.permissions || {}
} catch (error) {
console.error('获取用户权限失败:', error)
return {}
}
}
/**
* 检查用户是否有特定权限
* @param {string} permission - 权限名称
* @param {string} userId - 用户ID可选
* @returns {Promise<boolean>} 是否有权限
*/
async hasPermission(permission, userId = null) {
try {
const { data, error } = await this.supabase
.rpc('user_has_permission', {
permission_name: permission,
target_user_id: userId
})
if (error) throw error
return data === true
} catch (error) {
console.error('权限检查失败:', error)
return false
}
}
/**
* 检查是否可以访问资源
* @param {string} resourceType - 资源类型
* @param {string} resourceId - 资源ID
* @param {string} accessType - 访问类型
* @returns {Promise<boolean>} 是否可以访问
*/
async canAccessResource(resourceType, resourceId, accessType = 'read') {
try {
const { data, error } = await this.supabase
.rpc('can_access_resource', {
resource_type: resourceType,
resource_id: resourceId,
access_type: accessType
})
if (error) throw error
return data === true
} catch (error) {
console.error('资源访问检查失败:', error)
return false
}
}
/**
* 更新用户角色(仅管理员)
* @param {string} targetUserId - 目标用户ID
* @param {string} newRole - 新角色
* @param {Object} additionalData - 额外数据
* @returns {Promise<boolean>} 是否更新成功
*/
async updateUserRole(targetUserId, newRole, additionalData = {}) {
try {
const { data, error } = await this.supabase
.rpc('update_user_role', {
target_user_id: targetUserId,
new_role: newRole,
additional_data: additionalData
})
if (error) throw error
console.log('✅ 用户角色更新成功:', { targetUserId, newRole })
return data === true
} catch (error) {
console.error('❌ 用户角色更新失败:', error)
throw error
}
}
/**
* 批量更新用户角色
* @param {Array} roleUpdates - 角色更新数组
* @returns {Promise<Array>} 更新结果
*/
async batchUpdateUserRoles(roleUpdates) {
try {
const { data, error } = await this.supabase
.rpc('batch_update_user_roles', {
role_updates: roleUpdates
})
if (error) throw error
console.log('✅ 批量角色更新完成:', data)
return data
} catch (error) {
console.error('❌ 批量角色更新失败:', error)
throw error
}
}
/**
* 获取用户详细信息(管理员视图)
*/
async getUsersWithRoles() {
try {
const { data, error } = await this.supabase
.from('user_roles_detailed')
.select('*')
.order('created_at', { ascending: false })
if (error) throw error
return data
} catch (error) {
console.error('获取用户角色列表失败:', error)
throw error
}
}
/**
* 测试权限系统
* @param {string} testUserId - 测试用户ID
*/
async testPermissions(testUserId = null) {
try {
const { data, error } = await this.supabase
.rpc('test_message_permissions', {
test_user_id: testUserId || this.currentUser?.id
})
if (error) throw error
console.log('🧪 权限测试结果:', data)
return data
} catch (error) {
console.error('权限测试失败:', error)
throw error
}
}
}
/**
* 消息系统管理类
*/
class MessageManager {
constructor(supabaseClient, roleManager) {
this.supabase = supabaseClient
this.roleManager = roleManager
}
/**
* 发送安全消息
* @param {Object} messageData - 消息数据
* @returns {Promise<string>} 消息ID
*/
async sendSecureMessage(messageData) {
try {
const {
messageTypeId,
receiverType,
receiverId,
title,
content,
metadata = {}
} = messageData
const { data, error } = await this.supabase
.rpc('send_secure_message', {
message_type_id: messageTypeId,
receiver_type: receiverType,
receiver_id: receiverId,
title,
content,
metadata_json: metadata
})
if (error) throw error
console.log('✅ 消息发送成功:', data)
return data
} catch (error) {
console.error('❌ 消息发送失败:', error)
throw error
}
}
/**
* 获取用户可访问的消息列表
* @param {Object} options - 查询选项
* @returns {Promise<Array>} 消息列表
*/
async getAccessibleMessages(options = {}) {
try {
const {
limit = 50,
offset = 0,
messageType = null,
unreadOnly = false
} = options
let query = this.supabase
.from('ak_messages')
.select(`
*,
ak_message_types(type_name, display_name),
ak_message_recipients(
read_at,
replied_at,
status
)
`)
.order('created_at', { ascending: false })
.range(offset, offset + limit - 1)
if (messageType) {
query = query.eq('ak_message_types.type_name', messageType)
}
if (unreadOnly) {
query = query.is('ak_message_recipients.read_at', null)
}
const { data, error } = await query
if (error) throw error
return data
} catch (error) {
console.error('获取消息列表失败:', error)
throw error
}
}
/**
* 标记消息为已读
* @param {string} messageId - 消息ID
*/
async markMessageAsRead(messageId) {
try {
const { error } = await this.supabase
.from('ak_message_recipients')
.update({
read_at: new Date().toISOString(),
status: 'read'
})
.eq('message_id', messageId)
.eq('user_id', this.roleManager.currentUser?.id)
if (error) throw error
console.log('✅ 消息已标记为已读:', messageId)
} catch (error) {
console.error('标记消息已读失败:', error)
throw error
}
}
/**
* 获取消息统计
*/
async getMessageStats() {
try {
const { data, error } = await this.supabase
.from('ak_message_stats')
.select('*')
.eq('entity_type', 'user')
.eq('entity_id', this.roleManager.currentUser?.id)
if (error) throw error
return data
} catch (error) {
console.error('获取消息统计失败:', error)
throw error
}
}
/**
* 加入消息群组
* @param {string} groupId - 群组ID
* @param {string} joinMessage - 加入消息
*/
async joinMessageGroup(groupId, joinMessage = '') {
try {
const { data, error } = await this.supabase
.rpc('join_message_group', {
target_group_id: groupId,
join_message: joinMessage
})
if (error) throw error
if (data === true) {
console.log('✅ 成功加入群组:', groupId)
} else {
console.log('⏳ 申请已提交,等待审批:', groupId)
}
return data
} catch (error) {
console.error('加入群组失败:', error)
throw error
}
}
/**
* 获取用户可访问的群组列表
*/
async getAccessibleGroups() {
try {
const { data, error } = await this.supabase
.from('ak_message_groups')
.select(`
*,
ak_message_group_members!inner(
status,
joined_at,
role
)
`)
.eq('ak_message_group_members.user_id', this.roleManager.currentUser?.id)
.eq('ak_message_group_members.status', 'active')
.order('created_at', { ascending: false })
if (error) throw error
return data
} catch (error) {
console.error('获取群组列表失败:', error)
throw error
}
}
}
/**
* 主应用类
*/
class MessageApp {
constructor() {
this.supabase = supabase
this.roleManager = new UserRoleManager(this.supabase)
this.messageManager = new MessageManager(this.supabase, this.roleManager)
this.initialized = false
}
/**
* 初始化应用
*/
async initialize() {
try {
await this.roleManager.initialize()
this.initialized = true
// 监听认证状态变化
this.supabase.auth.onAuthStateChange(async (event, session) => {
console.log('🔄 认证状态变化:', event)
if (event === 'SIGNED_IN' || event === 'TOKEN_REFRESHED') {
await this.roleManager.initialize()
} else if (event === 'SIGNED_OUT') {
this.roleManager.currentUser = null
this.roleManager.currentRole = null
this.roleManager.permissions = {}
}
})
console.log('✅ 消息应用初始化完成')
return true
} catch (error) {
console.error('❌ 消息应用初始化失败:', error)
throw error
}
}
/**
* 用户登录
* @param {string} email - 邮箱
* @param {string} password - 密码
*/
async signIn(email, password) {
try {
const { data, error } = await this.supabase.auth.signInWithPassword({
email,
password
})
if (error) throw error
await this.roleManager.initialize()
console.log('✅ 登录成功')
return data
} catch (error) {
console.error('❌ 登录失败:', error)
throw error
}
}
/**
* 用户注册
* @param {string} email - 邮箱
* @param {string} password - 密码
* @param {Object} metadata - 额外元数据
*/
async signUp(email, password, metadata = {}) {
try {
const { data, error } = await this.supabase.auth.signUp({
email,
password,
options: {
data: metadata
}
})
if (error) throw error
console.log('✅ 注册成功,请检查邮箱验证')
return data
} catch (error) {
console.error('❌ 注册失败:', error)
throw error
}
}
/**
* 用户退出
*/
async signOut() {
try {
const { error } = await this.supabase.auth.signOut()
if (error) throw error
console.log('✅ 退出成功')
} catch (error) {
console.error('❌ 退出失败:', error)
throw error
}
}
/**
* 获取当前用户信息
*/
getCurrentUserInfo() {
return {
user: this.roleManager.currentUser,
role: this.roleManager.currentRole,
permissions: this.roleManager.permissions,
initialized: this.initialized
}
}
/**
* 角色管理器
*/
get roles() {
return this.roleManager
}
/**
* 消息管理器
*/
get messages() {
return this.messageManager
}
}
// 创建全局实例
const messageApp = new MessageApp()
// 导出
export { MessageApp, UserRoleManager, MessageManager, messageApp }
// 使用示例
/*
// 1. 初始化应用
await messageApp.initialize()
// 2. 用户登录
await messageApp.signIn('teacher@example.com', 'password123')
// 3. 检查用户角色和权限
const userInfo = messageApp.getCurrentUserInfo()
console.log('当前用户:', userInfo)
// 4. 检查特定权限
const canSendBroadcast = await messageApp.roles.hasPermission('can_send_broadcasts')
console.log('可以发送广播:', canSendBroadcast)
// 5. 发送消息
const messageId = await messageApp.messages.sendSecureMessage({
messageTypeId: 'some-type-id',
receiverType: 'user',
receiverId: 'student-user-id',
title: '作业通知',
content: '请完成本周的作业',
metadata: { priority: 'high' }
})
// 6. 获取消息列表
const messages = await messageApp.messages.getAccessibleMessages({
limit: 20,
unreadOnly: true
})
// 7. 加入群组
const joinResult = await messageApp.messages.joinMessageGroup('group-id')
// 8. 管理员操作:更新用户角色
if (userInfo.role === 'admin') {
await messageApp.roles.updateUserRole('user-id', 'teacher', {
department: 'Mathematics',
class_id: 'class-123'
})
}
// 9. 测试权限系统
await messageApp.roles.testPermissions()
*/