237 lines
8.3 KiB
JavaScript
237 lines
8.3 KiB
JavaScript
import {
|
|
createPreviewMyJoinApplications,
|
|
createPreviewPendingJoinApplications,
|
|
previewCurrentUser
|
|
} from '@/data/preview/genealogy-membership.js'
|
|
import { hasRemoteConfig } from '@/utils/runtime-config.js'
|
|
import { normalizeGenealogyPathId } from './genealogy-contract.js'
|
|
import {
|
|
JOIN_APPLICATION_STATUS,
|
|
normalizeGenealogyInvitation,
|
|
normalizeGenealogyInvitationRedeemPayload,
|
|
normalizeGenealogyInvitationToken,
|
|
normalizeIssuedGenealogyInvitation,
|
|
normalizeJoinApplicationPayload,
|
|
normalizeJoinAuditPayload,
|
|
normalizeMyGenealogyInvitations
|
|
} from './genealogy-membership-contract.js'
|
|
import { normalizeResourcePathId } from './request-normalizers.js'
|
|
import { createRequestError, requestStrict } from './request-client.js'
|
|
|
|
const requireRemoteMembership = (label, operation) => {
|
|
if (hasRemoteConfig()) return
|
|
throw createRequestError(
|
|
`${label}${operation}需要真实服务,当前本地预览不会伪造结果`,
|
|
operation === '读取' ? 'REMOTE_READ_REQUIRED' : 'REMOTE_WRITE_REQUIRED'
|
|
)
|
|
}
|
|
|
|
const previewMyJoinApplications = createPreviewMyJoinApplications()
|
|
const previewPendingJoinApplications = createPreviewPendingJoinApplications()
|
|
let nextPreviewApplicationId = Date.now()
|
|
const snapshotPreviewJoinApplications = (applications) =>
|
|
applications.map((application) => ({ ...application }))
|
|
const createPreviewApplicationId = () => String(nextPreviewApplicationId++)
|
|
|
|
const readMembershipList = async (url, label, requestOptions) => {
|
|
requireRemoteMembership(label, '读取')
|
|
const rows = await requestStrict({ url, method: 'GET' }, {
|
|
requestController: requestOptions.requestController ?? null
|
|
})
|
|
if (!Array.isArray(rows)) {
|
|
throw createRequestError(`${label}响应不是列表`, 'LIST_RESPONSE_INVALID')
|
|
}
|
|
return rows
|
|
}
|
|
|
|
const writeMembership = (url, method, data, label, requestOptions) => {
|
|
requireRemoteMembership(label, '写入')
|
|
return requestStrict({
|
|
url,
|
|
method,
|
|
...(data === undefined ? {} : { data })
|
|
}, {
|
|
requestController: requestOptions.requestController ?? null
|
|
})
|
|
}
|
|
|
|
export const genealogyMembershipApi = {
|
|
async previewGenealogyInvitation(token, requestOptions = {}) {
|
|
const normalizedToken = normalizeGenealogyInvitationToken(token)
|
|
requireRemoteMembership('家谱邀请码', '读取')
|
|
const invitation = await requestStrict({
|
|
url: `/genealogy/app/genealogies/invitations/preview?token=${encodeURIComponent(normalizedToken)}`,
|
|
method: 'GET'
|
|
}, {
|
|
requestController: requestOptions.requestController ?? null
|
|
})
|
|
return normalizeGenealogyInvitation(invitation, 'ACTIVE')
|
|
},
|
|
|
|
async issueGenealogyInvitation(genealogyId, requestOptions = {}) {
|
|
const normalizedGenealogyId = normalizeGenealogyPathId(genealogyId)
|
|
const invitationResponse = await writeMembership(
|
|
`/genealogy/app/genealogies/${normalizedGenealogyId}/invitations`,
|
|
'POST',
|
|
undefined,
|
|
'家谱邀请码签发',
|
|
requestOptions
|
|
)
|
|
const invitation = normalizeIssuedGenealogyInvitation(invitationResponse)
|
|
if (invitation.genealogyId !== normalizedGenealogyId) {
|
|
throw createRequestError(
|
|
'家谱邀请码归属与当前家谱不匹配',
|
|
'GENEALOGY_INVITATION_RESPONSE_INVALID'
|
|
)
|
|
}
|
|
return invitation
|
|
},
|
|
|
|
async getMyGenealogyInvitations(requestOptions = {}) {
|
|
requireRemoteMembership('我的家谱邀请', '读取')
|
|
const invitations = await requestStrict({
|
|
url: '/genealogy/app/genealogies/invitations/mine',
|
|
method: 'GET'
|
|
}, {
|
|
requestController: requestOptions.requestController ?? null
|
|
})
|
|
return normalizeMyGenealogyInvitations(invitations)
|
|
},
|
|
|
|
async revokeGenealogyInvitation(inviteId, requestOptions = {}) {
|
|
const normalizedInviteId = normalizeResourcePathId(inviteId, '家谱邀请标识')
|
|
requireRemoteMembership('家谱邀请码撤销', '写入')
|
|
await requestStrict({
|
|
url: `/genealogy/app/genealogies/invitations/${normalizedInviteId}`,
|
|
method: 'DELETE'
|
|
}, {
|
|
requireData: false,
|
|
requestController: requestOptions.requestController ?? null
|
|
})
|
|
return null
|
|
},
|
|
|
|
async redeemGenealogyInvitation(payload, requestOptions = {}) {
|
|
const invitation = await writeMembership(
|
|
'/genealogy/app/genealogies/invitations/redeem',
|
|
'POST',
|
|
normalizeGenealogyInvitationRedeemPayload(payload),
|
|
'家谱邀请码兑换',
|
|
requestOptions
|
|
)
|
|
return normalizeGenealogyInvitation(invitation, 'REDEEMED')
|
|
},
|
|
|
|
async applyToJoin(genealogyId, payload, requestOptions = {}) {
|
|
const normalizedGenealogyId = normalizeGenealogyPathId(genealogyId)
|
|
const applicationDraft = normalizeJoinApplicationPayload(payload)
|
|
if (hasRemoteConfig()) {
|
|
return requestStrict({
|
|
url: `/genealogy/app/genealogies/${normalizedGenealogyId}/join-applies`,
|
|
method: 'POST',
|
|
data: applicationDraft
|
|
}, {
|
|
requestController: requestOptions.requestController ?? null
|
|
})
|
|
}
|
|
previewMyJoinApplications.unshift({
|
|
id: createPreviewApplicationId(),
|
|
genealogyId: normalizedGenealogyId,
|
|
name: applicationDraft.applicantName || previewCurrentUser.name,
|
|
phone: applicationDraft.phone || previewCurrentUser.phone,
|
|
relation: applicationDraft.relationDesc || '关系待补充',
|
|
reason: applicationDraft.applyReason || '',
|
|
appliedAt: '刚刚',
|
|
status: JOIN_APPLICATION_STATUS.PENDING
|
|
})
|
|
return null
|
|
},
|
|
|
|
async getMyJoinApplications(requestOptions = {}) {
|
|
if (!hasRemoteConfig()) {
|
|
return snapshotPreviewJoinApplications(previewMyJoinApplications)
|
|
}
|
|
return readMembershipList(
|
|
'/genealogy/app/genealogies/join-applies/mine',
|
|
'我的加入申请',
|
|
requestOptions
|
|
)
|
|
},
|
|
|
|
async withdrawJoinApplication(applicationId, requestOptions = {}) {
|
|
const normalizedApplicationId = normalizeResourcePathId(applicationId, '加入申请标识')
|
|
if (!hasRemoteConfig()) {
|
|
const application = previewMyJoinApplications.find(
|
|
(candidate) =>
|
|
candidate.id === normalizedApplicationId &&
|
|
candidate.status === JOIN_APPLICATION_STATUS.PENDING
|
|
)
|
|
if (!application) {
|
|
throw createRequestError(
|
|
'待撤回申请不存在或已处理',
|
|
'PREVIEW_JOIN_APPLICATION_NOT_FOUND'
|
|
)
|
|
}
|
|
application.status = JOIN_APPLICATION_STATUS.CANCELLED
|
|
return null
|
|
}
|
|
await requestStrict({
|
|
url: `/genealogy/app/genealogies/join-applies/${normalizedApplicationId}`,
|
|
method: 'DELETE'
|
|
}, {
|
|
requireData: false,
|
|
requestController: requestOptions.requestController ?? null
|
|
})
|
|
return null
|
|
},
|
|
|
|
async getPendingApplications(genealogyId, requestOptions = {}) {
|
|
const normalizedGenealogyId = normalizeGenealogyPathId(genealogyId)
|
|
if (!hasRemoteConfig()) {
|
|
return snapshotPreviewJoinApplications(
|
|
previewPendingJoinApplications.filter(
|
|
(application) =>
|
|
application.genealogyId === normalizedGenealogyId &&
|
|
application.status === JOIN_APPLICATION_STATUS.PENDING
|
|
)
|
|
)
|
|
}
|
|
return readMembershipList(
|
|
`/genealogy/app/genealogies/${normalizedGenealogyId}/join-applies/pending`,
|
|
'待审核申请',
|
|
requestOptions
|
|
)
|
|
},
|
|
|
|
async auditApplication(genealogyId, applicationId, payload, requestOptions = {}) {
|
|
const normalizedGenealogyId = normalizeGenealogyPathId(genealogyId)
|
|
const normalizedApplicationId = normalizeResourcePathId(applicationId, '加入申请标识')
|
|
const auditDecision = normalizeJoinAuditPayload(payload)
|
|
if (hasRemoteConfig()) {
|
|
await requestStrict({
|
|
url: `/genealogy/app/genealogies/${normalizedGenealogyId}/join-applies/${normalizedApplicationId}/audit`,
|
|
method: 'PUT',
|
|
data: auditDecision
|
|
}, {
|
|
requireData: false,
|
|
requestController: requestOptions.requestController ?? null
|
|
})
|
|
return null
|
|
}
|
|
const application = previewPendingJoinApplications.find(
|
|
(candidate) =>
|
|
candidate.id === normalizedApplicationId &&
|
|
candidate.genealogyId === normalizedGenealogyId &&
|
|
candidate.status === JOIN_APPLICATION_STATUS.PENDING
|
|
)
|
|
if (!application) {
|
|
throw createRequestError(
|
|
'待审核申请不存在、已处理或不属于当前家谱',
|
|
'PREVIEW_JOIN_APPLICATION_NOT_FOUND'
|
|
)
|
|
}
|
|
Object.assign(application, auditDecision)
|
|
return null
|
|
}
|
|
}
|