import { createRequestError } from './request-client.js' const permissionResponseError = (message) => createRequestError(message, 'GENEALOGY_PERMISSION_RESPONSE_INVALID') const normalizePermissionCode = (value, subject = '权限编码') => { if (typeof value !== 'string' || !/^[A-Z][A-Z0-9_]{2,63}$/.test(value.trim())) { throw permissionResponseError(`${subject}无效`) } return value.trim() } const normalizePermissionIdentity = (value, subject) => { if (typeof value === 'string' && /^[1-9]\d*$/.test(value)) return value if (typeof value === 'number' && Number.isSafeInteger(value) && value > 0) return String(value) throw permissionResponseError(`${subject}无效`) } const normalizePermissionText = (value, field, { required = false } = {}) => { if (value === undefined || value === null) { if (required) throw permissionResponseError(`权限响应缺少${field}`) return '' } if (typeof value !== 'string') throw permissionResponseError(`权限响应${field}无效`) const normalized = value.trim() if (required && !normalized) throw permissionResponseError(`权限响应缺少${field}`) return normalized } export const normalizePermissionCatalog = (value) => { if (!Array.isArray(value)) throw permissionResponseError('权限目录不是列表') const options = value.map((item) => { if (!item || typeof item !== 'object' || Array.isArray(item) || typeof item.enabled !== 'boolean') { throw permissionResponseError('权限目录包含无效条目') } return { code: normalizePermissionCode(item.code), label: normalizePermissionText(item.name, 'name', { required: true }), groupCode: normalizePermissionText(item.groupCode, 'groupCode', { required: true }), groupName: normalizePermissionText(item.groupName, 'groupName', { required: true }), description: normalizePermissionText(item.description, 'description'), sensitive: item.sensitive === true, enabled: item.enabled, disabledReason: normalizePermissionText(item.disabledReason, 'disabledReason') } }) if (new Set(options.map((item) => item.code)).size !== options.length) { throw permissionResponseError('权限目录包含重复编码') } return options } export const normalizeMemberPermissionAssignment = ( value, enabledCodes, { expectedGenealogyId = '', expectedMemberId = '' } = {} ) => { if (!value || typeof value !== 'object' || Array.isArray(value) || !Array.isArray(value.permissionCodes)) { throw permissionResponseError('成员权限响应无效') } const permissionCodes = value.permissionCodes.map((code) => normalizePermissionCode(code)) if (new Set(permissionCodes).size !== permissionCodes.length) { throw permissionResponseError('成员权限响应包含重复编码') } const allowedCodes = new Set(enabledCodes) if (permissionCodes.some((code) => !allowedCodes.has(code))) { throw permissionResponseError('成员权限响应包含目录外或已停用权限') } const genealogyId = normalizePermissionIdentity(value.genealogyId, '权限响应家谱标识') const memberId = normalizePermissionIdentity(value.memberId, '权限响应成员标识') if ( (expectedGenealogyId && genealogyId !== expectedGenealogyId) || (expectedMemberId && memberId !== expectedMemberId) ) { throw permissionResponseError('成员权限响应归属与请求不匹配') } return { genealogyId, memberId, permissionCodes } } export const normalizeMemberPermissionPayload = (permissionCodes, reason, enabledCodes) => { if (!Array.isArray(permissionCodes)) throw new TypeError('权限项必须是数组') const allowedCodes = new Set(enabledCodes) const normalizedCodes = permissionCodes.map((code) => normalizePermissionCode(code, '提交权限编码')) if (new Set(normalizedCodes).size !== normalizedCodes.length || normalizedCodes.some((code) => !allowedCodes.has(code))) { throw new TypeError('提交权限包含重复、目录外或已停用权限') } if (typeof reason !== 'string') throw new TypeError('授权原因必须是字符串') const normalizedReason = reason.trim() if (normalizedReason.length > 200) throw new TypeError('授权原因不能超过200个字符') return { permissionCodes: normalizedCodes, ...(normalizedReason ? { reason: normalizedReason } : {}) } }