gbmake-payload/src/hooks/logAction.ts

108 lines
2.5 KiB
TypeScript
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.

import type { CollectionAfterChangeHook, CollectionAfterDeleteHook } from 'payload'
/**
* 记录操作日志的通用函数
*/
export async function logAction({
req,
action,
collection,
documentId,
documentTitle,
changes,
}: {
req: any
action: 'create' | 'update' | 'delete' | 'sync' | 'login' | 'logout'
collection: string
documentId?: string
documentTitle?: string
changes?: any
}) {
try {
const { payload, user } = req
if (!user) return // 无用户信息则不记录
// 获取 IP 地址
const ip =
req.headers?.['x-forwarded-for'] ||
req.headers?.['x-real-ip'] ||
req.ip ||
req.connection?.remoteAddress ||
'unknown'
// 获取 User Agent
const userAgent = req.headers?.['user-agent'] || 'unknown'
// 创建日志记录
await payload.create({
collection: 'logs',
data: {
action,
collection,
documentId: documentId?.toString(),
documentTitle,
user: user.id,
changes,
ip,
userAgent,
},
// 不触发 hooks避免递归
context: { skipHooks: true },
})
} catch (error) {
// 静默失败,避免影响主要操作
console.error('[Log Hook Error]:', error)
}
}
/**
* afterChange 钩子:记录创建和更新操作
*/
export const logAfterChange: CollectionAfterChangeHook = async ({
doc,
req,
operation,
collection,
}) => {
// 跳过日志自身的操作,避免递归
if (req.context?.skipHooks) return doc
const collectionSlug = collection?.slug as string
// 不记录 logs 和 users-sessions 自身
if (collectionSlug === 'logs' || collectionSlug === 'users-sessions') return doc
await logAction({
req,
action: operation === 'create' ? 'create' : 'update',
collection: collectionSlug,
documentId: doc.id,
documentTitle: doc.title || doc.name || doc.email || doc.alt || `ID: ${doc.id}`,
changes: operation === 'update' ? { updatedFields: Object.keys(doc) } : undefined,
})
return doc
}
/**
* afterDelete 钩子:记录删除操作
*/
export const logAfterDelete: CollectionAfterDeleteHook = async ({ doc, req, collection }) => {
if (req.context?.skipHooks) return doc
const collectionSlug = collection?.slug as string
if (collectionSlug === 'logs' || collectionSlug === 'users-sessions') return doc
await logAction({
req,
action: 'delete',
collection: collectionSlug,
documentId: doc.id,
documentTitle: doc.title || doc.name || doc.email || doc.alt || `ID: ${doc.id}`,
})
return doc
}