feat(api): 完善家谱系统API客户端契约
- 实现家谱管理相关方法,包括创建、详情、概览、我的家谱和选项查询 - 添加家谱加入申请功能,支持申请、审核、取消和待审核列表操作 - 集成通知详情获取方法和通知ID安全验证机制 - 完善功德记录、谱文、相册、视频、祭祀活动的完整CRUD操作契约 - 实现家谱成员管理功能,包含成员列表、更新、移除和转让所有者操作 - 优化路径ID验证逻辑,拒绝不安全的数值ID并提供明确错误提示 - 更新测试用例以验证所有新增API方法的路径和请求体白名单机制
This commit is contained in:
+223
-14
@@ -163,6 +163,9 @@
|
||||
}
|
||||
|
||||
function toRequiredPathId(value, label) {
|
||||
if (typeof value === 'number' && !Number.isSafeInteger(value)) {
|
||||
throw new Error('无效' + label);
|
||||
}
|
||||
var text = String(value === undefined || value === null ? '' : value).trim();
|
||||
|
||||
if (!text) throw new Error('缺少' + label);
|
||||
@@ -238,38 +241,65 @@
|
||||
}
|
||||
|
||||
function buildMeritRecordPath(genealogyId, meritId) {
|
||||
return '/genealogy/pc/genealogies/' + toRequiredPathId(genealogyId, '家谱编号') +
|
||||
'/merit-records/' + toRequiredPathId(meritId, '功德记录编号');
|
||||
var path = '/genealogy/pc/genealogies/' + toRequiredPathId(genealogyId, '家谱编号') + '/merit-records';
|
||||
|
||||
return meritId === undefined || meritId === null || meritId === ''
|
||||
? path
|
||||
: path + '/' + toRequiredPathId(meritId, '功德记录编号');
|
||||
}
|
||||
|
||||
function buildArticleCollectionPath(genealogyId) {
|
||||
return '/genealogy/pc/genealogies/' + toRequiredPathId(genealogyId, '家谱编号') + '/articles';
|
||||
}
|
||||
|
||||
function buildArticlePath(genealogyId, articleId) {
|
||||
return '/genealogy/pc/genealogies/' + toRequiredPathId(genealogyId, '家谱编号') +
|
||||
'/articles/' + toRequiredPathId(articleId, '谱文编号');
|
||||
return buildArticleCollectionPath(genealogyId) + '/' + toRequiredPathId(articleId, '谱文编号');
|
||||
}
|
||||
|
||||
function buildAlbumCollectionPath(genealogyId) {
|
||||
return '/genealogy/pc/genealogies/' + toRequiredPathId(genealogyId, '家谱编号') + '/albums';
|
||||
}
|
||||
|
||||
function buildAlbumPath(genealogyId, albumId) {
|
||||
return '/genealogy/pc/genealogies/' + toRequiredPathId(genealogyId, '家谱编号') +
|
||||
'/albums/' + toRequiredPathId(albumId, '相册编号');
|
||||
return buildAlbumCollectionPath(genealogyId) + '/' + toRequiredPathId(albumId, '相册编号');
|
||||
}
|
||||
|
||||
function buildAlbumPhotoCollectionPath(genealogyId, albumId) {
|
||||
return buildAlbumPath(genealogyId, albumId) + '/photos';
|
||||
}
|
||||
|
||||
function buildAlbumPhotoPath(genealogyId, albumId, photoId) {
|
||||
return buildAlbumPath(genealogyId, albumId) + '/photos/' + toRequiredPathId(photoId, '相册照片编号');
|
||||
return buildAlbumPhotoCollectionPath(genealogyId, albumId) + '/' + toRequiredPathId(photoId, '相册照片编号');
|
||||
}
|
||||
|
||||
function buildVideoCollectionPath(genealogyId) {
|
||||
return '/genealogy/pc/genealogies/' + toRequiredPathId(genealogyId, '家谱编号') + '/videos';
|
||||
}
|
||||
|
||||
function buildVideoPath(genealogyId, videoId) {
|
||||
return '/genealogy/pc/genealogies/' + toRequiredPathId(genealogyId, '家谱编号') +
|
||||
'/videos/' + toRequiredPathId(videoId, '视频编号');
|
||||
return buildVideoCollectionPath(genealogyId) + '/' + toRequiredPathId(videoId, '视频编号');
|
||||
}
|
||||
|
||||
function buildCeremonyCollectionPath(genealogyId) {
|
||||
return '/genealogy/pc/genealogies/' + toRequiredPathId(genealogyId, '家谱编号') + '/ceremonies';
|
||||
}
|
||||
|
||||
function buildCeremonyPath(genealogyId, ceremonyId) {
|
||||
return '/genealogy/pc/genealogies/' + toRequiredPathId(genealogyId, '家谱编号') +
|
||||
'/ceremonies/' + toRequiredPathId(ceremonyId, '祭祀活动编号');
|
||||
return buildCeremonyCollectionPath(genealogyId) + '/' + toRequiredPathId(ceremonyId, '祭祀活动编号');
|
||||
}
|
||||
|
||||
function buildCeremonyGiftPath(genealogyId, ceremonyId, giftId) {
|
||||
return buildCeremonyPath(genealogyId, ceremonyId) + '/gifts/' + toRequiredPathId(giftId, '祭品编号');
|
||||
}
|
||||
|
||||
function buildGenealogyMemberCollectionPath(genealogyId) {
|
||||
return '/genealogy/pc/genealogies/' + toRequiredPathId(genealogyId, '家谱编号') + '/members';
|
||||
}
|
||||
|
||||
function buildGenealogyMemberPath(genealogyId, memberId) {
|
||||
return buildGenealogyMemberCollectionPath(genealogyId) + '/' + toRequiredPathId(memberId, '成员编号');
|
||||
}
|
||||
|
||||
async function login(body) {
|
||||
var data = await request('POST', '/genealogy/pc/auth/login', {
|
||||
auth: false,
|
||||
@@ -437,8 +467,57 @@
|
||||
genealogyQuota: function () {
|
||||
return request('GET', '/genealogy/pc/genealogies/quota');
|
||||
},
|
||||
genealogiesMine: function () {
|
||||
return request('GET', '/genealogy/pc/genealogies/mine');
|
||||
},
|
||||
genealogyOptions: function (query) {
|
||||
return request('GET', '/genealogy/pc/genealogies/options', { query: query });
|
||||
},
|
||||
genealogyDetail: function (genealogyId) {
|
||||
return request('GET', '/genealogy/pc/genealogies/' + toRequiredPathId(genealogyId, '家谱编号'));
|
||||
},
|
||||
genealogyOverview: function (genealogyId) {
|
||||
return request('GET', '/genealogy/pc/genealogies/' + toRequiredPathId(genealogyId, '家谱编号') + '/overview');
|
||||
},
|
||||
createGenealogy: function (body) {
|
||||
return request('POST', '/genealogy/pc/genealogies', {
|
||||
body: pickDefined(body, [
|
||||
'genealogyName', 'surname', 'regionCode', 'ancestralHall', 'originPlace',
|
||||
'addressDetail', 'coverOssId', 'intro', 'visibility', 'joinMode'
|
||||
])
|
||||
});
|
||||
},
|
||||
applyToGenealogy: function (genealogyId, body) {
|
||||
return request('POST', '/genealogy/pc/genealogies/' +
|
||||
toRequiredPathId(genealogyId, '家谱编号') + '/join-applies', {
|
||||
body: pickDefined(body, ['applicantName', 'phone', 'relationDesc', 'applyReason'])
|
||||
});
|
||||
},
|
||||
myGenealogyJoinApplies: function () {
|
||||
return request('GET', '/genealogy/pc/genealogies/join-applies/mine');
|
||||
},
|
||||
pendingGenealogyJoinApplies: function (genealogyId) {
|
||||
return request('GET', '/genealogy/pc/genealogies/' +
|
||||
toRequiredPathId(genealogyId, '家谱编号') + '/join-applies/pending');
|
||||
},
|
||||
auditGenealogyJoinApply: function (genealogyId, applyId, body) {
|
||||
return request('PUT', '/genealogy/pc/genealogies/' +
|
||||
toRequiredPathId(genealogyId, '家谱编号') + '/join-applies/' +
|
||||
toRequiredPathId(applyId, '申请编号') + '/audit', {
|
||||
body: pickDefined(body, ['status', 'auditRemark'])
|
||||
});
|
||||
},
|
||||
cancelGenealogyJoinApply: function (applyId) {
|
||||
return request('DELETE', '/genealogy/pc/genealogies/join-applies/' +
|
||||
toRequiredPathId(applyId, '申请编号'));
|
||||
},
|
||||
notifications: function (query) {
|
||||
return request('GET', '/genealogy/pc/notifications', { query: query });
|
||||
return request('GET', '/genealogy/pc/notifications', {
|
||||
query: pickDefined(query, ['readStatus'])
|
||||
});
|
||||
},
|
||||
notificationDetail: function (notificationId) {
|
||||
return request('GET', '/genealogy/pc/notifications/' + toRequiredPathId(notificationId, '通知编号'));
|
||||
},
|
||||
unreadNotificationCount: function () {
|
||||
return request('GET', '/genealogy/pc/notifications/unread-count');
|
||||
@@ -590,23 +669,131 @@
|
||||
deleteMemo: function (genealogyId, memoId) {
|
||||
return request('DELETE', buildMemoPath(genealogyId, memoId));
|
||||
},
|
||||
meritRecords: function (genealogyId) {
|
||||
return request('GET', buildMeritRecordPath(genealogyId));
|
||||
},
|
||||
createMeritRecord: function (genealogyId, body) {
|
||||
return request('POST', buildMeritRecordPath(genealogyId), {
|
||||
body: pickDefined(body, ['donorName', 'meritType', 'meritTitle', 'meritContent', 'amount', 'meritTime', 'sortOrder', 'status'])
|
||||
});
|
||||
},
|
||||
meritRecordDetail: function (genealogyId, meritId) {
|
||||
return request('GET', buildMeritRecordPath(genealogyId, meritId));
|
||||
},
|
||||
updateMeritRecord: function (genealogyId, meritId, body) {
|
||||
return request('PUT', buildMeritRecordPath(genealogyId, meritId), {
|
||||
body: pickDefined(body, ['donorName', 'meritType', 'meritTitle', 'meritContent', 'amount', 'meritTime', 'sortOrder', 'status'])
|
||||
});
|
||||
},
|
||||
deleteMeritRecord: function (genealogyId, meritId) {
|
||||
return request('DELETE', buildMeritRecordPath(genealogyId, meritId));
|
||||
},
|
||||
articles: function (genealogyId) {
|
||||
return request('GET', buildArticleCollectionPath(genealogyId));
|
||||
},
|
||||
createArticle: function (genealogyId, body) {
|
||||
return request('POST', buildArticleCollectionPath(genealogyId), {
|
||||
body: pickDefined(body, [
|
||||
'categoryId', 'articleTitle', 'articleSummary', 'coverOssId',
|
||||
'articleContent', 'authorName', 'sortOrder', 'status'
|
||||
])
|
||||
});
|
||||
},
|
||||
articleDetail: function (genealogyId, articleId) {
|
||||
return request('GET', buildArticlePath(genealogyId, articleId));
|
||||
},
|
||||
updateArticle: function (genealogyId, articleId, body) {
|
||||
return request('PUT', buildArticlePath(genealogyId, articleId), {
|
||||
body: pickDefined(body, [
|
||||
'categoryId', 'articleTitle', 'articleSummary', 'coverOssId',
|
||||
'articleContent', 'authorName', 'sortOrder', 'status'
|
||||
])
|
||||
});
|
||||
},
|
||||
deleteArticle: function (genealogyId, articleId) {
|
||||
return request('DELETE', buildArticlePath(genealogyId, articleId));
|
||||
},
|
||||
albums: function (genealogyId) {
|
||||
return request('GET', buildAlbumCollectionPath(genealogyId));
|
||||
},
|
||||
createAlbum: function (genealogyId, body) {
|
||||
return request('POST', buildAlbumCollectionPath(genealogyId), {
|
||||
body: pickDefined(body, ['albumName', 'albumDesc', 'coverOssId', 'sortOrder', 'status'])
|
||||
});
|
||||
},
|
||||
updateAlbum: function (genealogyId, albumId, body) {
|
||||
return request('PUT', buildAlbumPath(genealogyId, albumId), {
|
||||
body: pickDefined(body, ['albumName', 'albumDesc', 'coverOssId', 'sortOrder', 'status'])
|
||||
});
|
||||
},
|
||||
albumPhotos: function (genealogyId, albumId) {
|
||||
return request('GET', buildAlbumPhotoCollectionPath(genealogyId, albumId));
|
||||
},
|
||||
createAlbumPhoto: function (genealogyId, albumId, body) {
|
||||
return request('POST', buildAlbumPhotoCollectionPath(genealogyId, albumId), {
|
||||
body: pickDefined(body, [
|
||||
'ossId', 'photoTitle', 'photoDesc', 'photographer',
|
||||
'shootTime', 'sortOrder', 'status'
|
||||
])
|
||||
});
|
||||
},
|
||||
deleteAlbum: function (genealogyId, albumId) {
|
||||
return request('DELETE', buildAlbumPath(genealogyId, albumId));
|
||||
},
|
||||
deleteAlbumPhoto: function (genealogyId, albumId, photoId) {
|
||||
return request('DELETE', buildAlbumPhotoPath(genealogyId, albumId, photoId));
|
||||
},
|
||||
videos: function (genealogyId) {
|
||||
return request('GET', buildVideoCollectionPath(genealogyId));
|
||||
},
|
||||
createVideo: function (genealogyId, body) {
|
||||
return request('POST', buildVideoCollectionPath(genealogyId), { body: body });
|
||||
},
|
||||
videoDetail: function (genealogyId, videoId) {
|
||||
return request('GET', buildVideoPath(genealogyId, videoId));
|
||||
},
|
||||
updateVideo: function (genealogyId, videoId, body) {
|
||||
return request('PUT', buildVideoPath(genealogyId, videoId), { body: body });
|
||||
},
|
||||
deleteVideo: function (genealogyId, videoId) {
|
||||
return request('DELETE', buildVideoPath(genealogyId, videoId));
|
||||
},
|
||||
replaceCeremonyInvitees: function (genealogyId, ceremonyId, body) {
|
||||
return request('PUT', buildCeremonyPath(genealogyId, ceremonyId) + '/invitees', { body: body });
|
||||
ceremonies: function (genealogyId) {
|
||||
return request('GET', buildCeremonyCollectionPath(genealogyId));
|
||||
},
|
||||
createCeremony: function (genealogyId, body) {
|
||||
return request('POST', buildCeremonyCollectionPath(genealogyId), {
|
||||
body: pickDefined(body, [
|
||||
'ceremonyType', 'ceremonyTitle', 'ceremonyDesc', 'ceremonyTime',
|
||||
'location', 'locationAddress', 'longitude', 'latitude',
|
||||
'coverOssId', 'sortOrder', 'status'
|
||||
])
|
||||
});
|
||||
},
|
||||
ceremonyDetail: function (genealogyId, ceremonyId) {
|
||||
return request('GET', buildCeremonyPath(genealogyId, ceremonyId));
|
||||
},
|
||||
updateCeremony: function (genealogyId, ceremonyId, body) {
|
||||
return request('PUT', buildCeremonyPath(genealogyId, ceremonyId), {
|
||||
body: pickDefined(body, [
|
||||
'ceremonyType', 'ceremonyTitle', 'ceremonyDesc', 'ceremonyTime',
|
||||
'location', 'locationAddress', 'longitude', 'latitude',
|
||||
'coverOssId', 'sortOrder', 'status'
|
||||
])
|
||||
});
|
||||
},
|
||||
ceremonyGifts: function (genealogyId, ceremonyId) {
|
||||
return request('GET', buildCeremonyPath(genealogyId, ceremonyId) + '/gifts');
|
||||
},
|
||||
createCeremonyGift: function (genealogyId, ceremonyId, body) {
|
||||
return request('POST', buildCeremonyPath(genealogyId, ceremonyId) + '/gifts', {
|
||||
body: pickDefined(body, ['giverName', 'giftAmount', 'giftMessage'])
|
||||
});
|
||||
},
|
||||
replaceCeremonyInvitees: function (genealogyId, ceremonyId, inviteeUserIds) {
|
||||
return request('PUT', buildCeremonyPath(genealogyId, ceremonyId) + '/invitees', {
|
||||
body: { inviteeUserIds: Array.isArray(inviteeUserIds) ? inviteeUserIds : [] }
|
||||
});
|
||||
},
|
||||
ceremonyInvitations: function (genealogyId, ceremonyId) {
|
||||
return request('GET', buildCeremonyPath(genealogyId, ceremonyId) + '/invitations');
|
||||
@@ -622,6 +809,28 @@
|
||||
},
|
||||
deleteCeremonyGift: function (genealogyId, ceremonyId, giftId) {
|
||||
return request('DELETE', buildCeremonyGiftPath(genealogyId, ceremonyId, giftId));
|
||||
},
|
||||
genealogyMembers: function (genealogyId) {
|
||||
return request('GET', buildGenealogyMemberCollectionPath(genealogyId));
|
||||
},
|
||||
genealogyMemberOptions: function (genealogyId) {
|
||||
return request('GET', buildGenealogyMemberCollectionPath(genealogyId) + '/options');
|
||||
},
|
||||
updateGenealogyMember: function (genealogyId, memberId, body) {
|
||||
return request('PUT', buildGenealogyMemberPath(genealogyId, memberId), {
|
||||
body: pickDefined(body, ['memberName', 'relationName', 'roleType', 'lineagePersonId'])
|
||||
});
|
||||
},
|
||||
removeGenealogyMember: function (genealogyId, memberId) {
|
||||
return request('DELETE', buildGenealogyMemberPath(genealogyId, memberId));
|
||||
},
|
||||
leaveGenealogy: function (genealogyId) {
|
||||
return request('DELETE', buildGenealogyMemberCollectionPath(genealogyId) + '/me');
|
||||
},
|
||||
transferGenealogyOwner: function (genealogyId, body) {
|
||||
return request('PUT', buildGenealogyMemberCollectionPath(genealogyId) + '/owner-transfer', {
|
||||
body: pickDefined(body, ['targetMemberId'])
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user