Files
jiapuapp/services/api/genealogy-membership-contract.js

118 lines
4.7 KiB
JavaScript

import { createRequestError } from './request-client.js'
import { normalizeResponseText } from './response-normalizers.js'
import {
assertPlainPayload,
normalizeOptionalText,
normalizeResourcePathId
} from './request-normalizers.js'
import { normalizeGenealogyPathId } from './genealogy-contract.js'
export const JOIN_APPLICATION_STATUS = Object.freeze({
PENDING: '0',
APPROVED: '1',
REJECTED: '2',
CANCELLED: '3'
})
export const JOIN_APPLICATION_STATUS_LABELS = Object.freeze({
[JOIN_APPLICATION_STATUS.PENDING]: '审核中',
[JOIN_APPLICATION_STATUS.APPROVED]: '已通过',
[JOIN_APPLICATION_STATUS.REJECTED]: '未通过',
[JOIN_APPLICATION_STATUS.CANCELLED]: '已撤回'
})
const joinApplicationAuditStatuses = new Set([
JOIN_APPLICATION_STATUS.APPROVED,
JOIN_APPLICATION_STATUS.REJECTED
])
export const normalizeJoinApplicationPayload = (payload) => {
assertPlainPayload(payload, new Set(['applicantName', 'phone', 'relationDesc', 'applyReason']), '加入申请请求')
const normalizedPayload = {}
for (const field of ['applicantName', 'phone', 'relationDesc', 'applyReason']) {
const normalizedText = normalizeOptionalText(payload[field], field)
if (normalizedText) normalizedPayload[field] = normalizedText
}
return normalizedPayload
}
export const normalizeGenealogyInvitationToken = (value) => {
if (typeof value !== 'string') throw new TypeError('邀请码必须是文本')
const token = value.trim()
if (!token) throw new TypeError('请输入邀请码')
if (token.length > 128) throw new TypeError('邀请码长度不能超过128个字符')
return token
}
export const normalizeGenealogyInvitationRedeemPayload = (payload) => {
assertPlainPayload(payload, new Set(['token']), '家谱邀请码兑换请求')
return { token: normalizeGenealogyInvitationToken(payload.token) }
}
export const normalizeGenealogyInvitation = (value, expectedStatus = '') => {
if (!value || typeof value !== 'object' || Array.isArray(value)) {
throw createRequestError('家谱邀请码响应无效', 'GENEALOGY_INVITATION_RESPONSE_INVALID')
}
const genealogyId = normalizeGenealogyPathId(value.genealogyId)
const genealogyName = normalizeResponseText(value.genealogyName, 'genealogyName')
const status = normalizeResponseText(value.status, 'status')
const expiresAt = normalizeResponseText(value.expiresAt, 'expiresAt')
if (!genealogyName || !status || !expiresAt) {
throw createRequestError('家谱邀请码响应缺少可展示信息', 'GENEALOGY_INVITATION_RESPONSE_INVALID')
}
if (expectedStatus && status !== expectedStatus) {
throw createRequestError('家谱邀请码状态与当前操作不匹配', 'GENEALOGY_INVITATION_RESPONSE_INVALID')
}
const redemptionResult = normalizeResponseText(value.redemptionResult, 'redemptionResult')
if (expectedStatus === 'REDEEMED' && !['DIRECT_MEMBER', 'PENDING_APPLY'].includes(redemptionResult)) {
throw createRequestError('家谱邀请码兑换结果无效', 'GENEALOGY_INVITATION_RESPONSE_INVALID')
}
return {
genealogyId,
genealogyName,
status,
expiresAt,
redemptionResult
}
}
export const normalizeIssuedGenealogyInvitation = (value) => {
const invitation = normalizeGenealogyInvitation(value, 'ACTIVE')
return {
...invitation,
token: normalizeGenealogyInvitationToken(value.token)
}
}
const genealogyInvitationStatuses = new Set(['ACTIVE', 'REDEEMED', 'REVOKED', 'EXPIRED'])
export const normalizeMyGenealogyInvitations = (value) => {
if (!Array.isArray(value)) {
throw createRequestError('我的家谱邀请响应不是列表', 'GENEALOGY_INVITATION_RESPONSE_INVALID')
}
const invitations = value.map((item) => {
const invitation = normalizeGenealogyInvitation(item)
const id = normalizeResourcePathId(item.inviteId, '家谱邀请标识')
if (!genealogyInvitationStatuses.has(invitation.status)) {
throw createRequestError('家谱邀请状态无效', 'GENEALOGY_INVITATION_RESPONSE_INVALID')
}
return { id, ...invitation }
})
if (new Set(invitations.map((item) => item.id)).size !== invitations.length) {
throw createRequestError('我的家谱邀请响应包含重复标识', 'GENEALOGY_INVITATION_RESPONSE_INVALID')
}
return invitations
}
export const normalizeJoinAuditPayload = (payload) => {
assertPlainPayload(payload, new Set(['status', 'auditRemark']), '加入申请审核请求')
const status = normalizeOptionalText(payload.status, '审核状态')
if (!joinApplicationAuditStatuses.has(status)) {
throw new TypeError('加入申请审核状态只能是通过或拒绝')
}
const normalizedPayload = { status }
const auditRemark = normalizeOptionalText(payload.auditRemark, '审核备注')
if (auditRemark) normalizedPayload.auditRemark = auditRemark
return normalizedPayload
}