165 lines
7.3 KiB
JavaScript
165 lines
7.3 KiB
JavaScript
import { createRequestError } from './request-client.js'
|
|
import {
|
|
normalizeOptionalNumericId,
|
|
normalizeOptionalResponseText
|
|
} from './response-normalizers.js'
|
|
import {
|
|
assertPlainPayload,
|
|
normalizeOptionalText,
|
|
normalizeResourcePathId
|
|
} from './request-normalizers.js'
|
|
import { normalizeLineagePersonIdentity } from './lineage-person-contract.js'
|
|
|
|
export const GENEALOGY_MEMBER_ROLE = Object.freeze({
|
|
OWNER: 'owner',
|
|
ADMIN: 'admin',
|
|
EDITOR: 'editor',
|
|
MEMBER: 'member',
|
|
VISITOR: 'visitor'
|
|
})
|
|
|
|
export const GENEALOGY_MEMBER_ROLE_LABELS = Object.freeze({
|
|
[GENEALOGY_MEMBER_ROLE.OWNER]: '谱主',
|
|
[GENEALOGY_MEMBER_ROLE.ADMIN]: '管理员',
|
|
[GENEALOGY_MEMBER_ROLE.EDITOR]: '可编辑成员',
|
|
[GENEALOGY_MEMBER_ROLE.MEMBER]: '普通成员',
|
|
[GENEALOGY_MEMBER_ROLE.VISITOR]: '访客'
|
|
})
|
|
|
|
const genealogyMemberRoles = new Set(Object.values(GENEALOGY_MEMBER_ROLE))
|
|
const editableGenealogyMemberRoles = new Set([
|
|
GENEALOGY_MEMBER_ROLE.ADMIN,
|
|
GENEALOGY_MEMBER_ROLE.EDITOR,
|
|
GENEALOGY_MEMBER_ROLE.MEMBER
|
|
])
|
|
|
|
const normalizeMemberOptionText = (value, field) =>
|
|
normalizeOptionalResponseText(value, field, '成员候选', 'MEMBER_OPTIONS_RESPONSE_INVALID')
|
|
|
|
const normalizeMemberText = (value, field) =>
|
|
normalizeOptionalResponseText(value, field, '家谱成员', 'MEMBER_LIST_RESPONSE_INVALID')
|
|
|
|
export const normalizeMemberUpdatePayload = (payload) => {
|
|
assertPlainPayload(payload, new Set(['memberName', 'relationName', 'roleType', 'lineagePersonId']), '成员更新请求')
|
|
const normalizedPayload = {}
|
|
const memberName = normalizeOptionalText(payload.memberName, 'memberName')
|
|
if (memberName && memberName.length > 50) throw new TypeError('memberName 超出长度限制')
|
|
if (memberName) normalizedPayload.memberName = memberName
|
|
if (Object.prototype.hasOwnProperty.call(payload, 'relationName')) {
|
|
if (typeof payload.relationName !== 'string') throw new TypeError('relationName必须是字符串')
|
|
const relationName = payload.relationName.trim()
|
|
if (relationName.length > 100) throw new TypeError('relationName 超出长度限制')
|
|
normalizedPayload.relationName = relationName
|
|
}
|
|
const roleType = normalizeOptionalText(payload.roleType, 'roleType')
|
|
if (roleType) {
|
|
if (!editableGenealogyMemberRoles.has(roleType)) {
|
|
throw new TypeError('roleType 仅允许 admin、editor 或 member')
|
|
}
|
|
normalizedPayload.roleType = roleType
|
|
}
|
|
if (payload.lineagePersonId !== undefined && payload.lineagePersonId !== null && payload.lineagePersonId !== '') {
|
|
normalizedPayload.lineagePersonId = normalizeResourcePathId(payload.lineagePersonId, '世系人物标识')
|
|
}
|
|
if (!Object.keys(normalizedPayload).length) throw new TypeError('请至少填写一项要更新的成员信息')
|
|
return normalizedPayload
|
|
}
|
|
|
|
export const normalizeGenealogyMemberOptions = (value) => {
|
|
if (!Array.isArray(value)) {
|
|
throw createRequestError('成员候选响应不是数组', 'MEMBER_OPTIONS_RESPONSE_INVALID')
|
|
}
|
|
const seenUserIds = new Set()
|
|
return value.map((item) => {
|
|
if (!item || typeof item !== 'object' || Array.isArray(item)) {
|
|
throw createRequestError('成员候选包含无效条目', 'MEMBER_OPTIONS_RESPONSE_INVALID')
|
|
}
|
|
const memberId = normalizeResourcePathId(item.memberId, '成员候选标识')
|
|
const appUserId = normalizeLineagePersonIdentity(item.appUserId, '绑定用户标识')
|
|
if (seenUserIds.has(appUserId)) {
|
|
throw createRequestError('成员候选包含重复业务用户', 'MEMBER_OPTIONS_RESPONSE_INVALID')
|
|
}
|
|
seenUserIds.add(appUserId)
|
|
const memberName = normalizeMemberOptionText(item.memberName, 'memberName')
|
|
if (!memberName) {
|
|
throw createRequestError('成员候选缺少显示名称', 'MEMBER_OPTIONS_RESPONSE_INVALID')
|
|
}
|
|
if (typeof item.eligible !== 'boolean') {
|
|
throw createRequestError('成员候选 eligible 无效', 'MEMBER_OPTIONS_RESPONSE_INVALID')
|
|
}
|
|
return {
|
|
memberId,
|
|
appUserId,
|
|
memberName,
|
|
relationName: normalizeMemberOptionText(item.relationName, 'relationName'),
|
|
roleType: normalizeMemberOptionText(item.roleType, 'roleType'),
|
|
eligible: item.eligible,
|
|
disabledReason: normalizeMemberOptionText(item.disabledReason, 'disabledReason')
|
|
}
|
|
})
|
|
}
|
|
|
|
const normalizeGenealogyMemberCapabilities = (value) => {
|
|
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
throw createRequestError('成员操作权限无效', 'MEMBER_LIST_RESPONSE_INVALID')
|
|
}
|
|
const capabilities = {}
|
|
for (const field of ['canEdit', 'canRemove', 'canLeave', 'canTransferOwner']) {
|
|
if (typeof value[field] !== 'boolean') {
|
|
throw createRequestError(`成员操作权限字段 ${field} 无效`, 'MEMBER_LIST_RESPONSE_INVALID')
|
|
}
|
|
capabilities[field] = value[field]
|
|
}
|
|
return capabilities
|
|
}
|
|
|
|
export const normalizeGenealogyMembers = (value, expectedGenealogyId) => {
|
|
if (!Array.isArray(value)) {
|
|
throw createRequestError('家谱成员响应不是数组', 'MEMBER_LIST_RESPONSE_INVALID')
|
|
}
|
|
const seenIds = new Set()
|
|
return value.map((item) => {
|
|
if (!item || typeof item !== 'object' || Array.isArray(item)) {
|
|
throw createRequestError('家谱成员包含无效条目', 'MEMBER_LIST_RESPONSE_INVALID')
|
|
}
|
|
const memberId = normalizeResourcePathId(item.memberId, '成员标识')
|
|
if (seenIds.has(memberId)) {
|
|
throw createRequestError('家谱成员包含重复标识', 'MEMBER_LIST_RESPONSE_INVALID')
|
|
}
|
|
seenIds.add(memberId)
|
|
const genealogyId = normalizeResourcePathId(item.genealogyId, '家谱标识')
|
|
if (genealogyId !== expectedGenealogyId) {
|
|
throw createRequestError('家谱成员归属与请求不匹配', 'MEMBER_LIST_RESPONSE_INVALID')
|
|
}
|
|
const roleType = normalizeMemberText(item.roleType, 'roleType')
|
|
if (!genealogyMemberRoles.has(roleType)) {
|
|
throw createRequestError('家谱成员角色无效', 'MEMBER_LIST_RESPONSE_INVALID')
|
|
}
|
|
const memberName = normalizeMemberText(item.memberName, 'memberName')
|
|
if (!memberName) {
|
|
throw createRequestError('家谱成员缺少显示名称', 'MEMBER_LIST_RESPONSE_INVALID')
|
|
}
|
|
return {
|
|
memberId,
|
|
genealogyId,
|
|
genealogyNo: normalizeMemberText(item.genealogyNo, 'genealogyNo'),
|
|
genealogyName: normalizeMemberText(item.genealogyName, 'genealogyName'),
|
|
surname: normalizeMemberText(item.surname, 'surname'),
|
|
appUserId: normalizeOptionalNumericId(item.appUserId, '成员用户标识', 'MEMBER_LIST_RESPONSE_INVALID'),
|
|
appUserNickName: normalizeMemberText(item.appUserNickName, 'appUserNickName'),
|
|
lineagePersonId: normalizeOptionalNumericId(item.lineagePersonId, '世系人物标识', 'MEMBER_LIST_RESPONSE_INVALID'),
|
|
lineagePersonNo: normalizeMemberText(item.lineagePersonNo, 'lineagePersonNo'),
|
|
lineagePersonName: normalizeMemberText(item.lineagePersonName, 'lineagePersonName'),
|
|
memberName,
|
|
roleType,
|
|
relationName: normalizeMemberText(item.relationName, 'relationName'),
|
|
joinSource: normalizeMemberText(item.joinSource, 'joinSource'),
|
|
inviterUserId: normalizeOptionalNumericId(item.inviterUserId, '邀请人用户标识', 'MEMBER_LIST_RESPONSE_INVALID'),
|
|
inviterNickName: normalizeMemberText(item.inviterNickName, 'inviterNickName'),
|
|
joinTime: normalizeMemberText(item.joinTime, 'joinTime'),
|
|
status: normalizeMemberText(item.status, 'status'),
|
|
capabilities: normalizeGenealogyMemberCapabilities(item.capabilities)
|
|
}
|
|
})
|
|
}
|