forked from wangziqi/gongxue-base
feat: batch resolve public bank conflicts
This commit is contained in:
@@ -4233,6 +4233,140 @@ async function testPublicQuestionBankAdoption() {
|
||||
const keptLocalTarget = collectionAfterKeepLocal.items?.find(item => item.id === conflictTarget.id);
|
||||
assert.equal(keptLocalTarget?.content, keepLocalContent, 'keep-local resolution should preserve tenant customized content');
|
||||
|
||||
const batchTargetOne = keptLocalTarget;
|
||||
const batchTargetTwo = collectionAfterKeepLocal.items?.find(item => item.legacyId === syncedLegacyId);
|
||||
assert.ok(batchTargetOne?.id && batchTargetTwo?.id, 'batch conflict test needs two adopted tenant question copies');
|
||||
|
||||
const batchLocalOneContent = `租户批量冲突本地题一 ${Date.now()}`;
|
||||
const batchLocalTwoContent = `租户批量冲突本地题二 ${Date.now()}`;
|
||||
await request('/api/tenant-content/questions', {
|
||||
tenantId: PARTNER_TENANT_ID,
|
||||
userId: PARTNER_TENANT_ADMIN_USER_ID,
|
||||
method: 'PATCH',
|
||||
body: {
|
||||
questionId: batchTargetOne.id,
|
||||
createVersion: true,
|
||||
content: batchLocalOneContent,
|
||||
options: batchTargetOne.options || [],
|
||||
correctOptionIndex: batchTargetOne.correctOptionIndex,
|
||||
correctOptionIndices: batchTargetOne.correctOptionIndices || [],
|
||||
answerText: batchTargetOne.answerText,
|
||||
explanation: '租户批量冲突测试本地版本一。',
|
||||
sourceHash: `tenant-batch-local-one-${Date.now()}`,
|
||||
},
|
||||
});
|
||||
await request('/api/tenant-content/questions', {
|
||||
tenantId: PARTNER_TENANT_ID,
|
||||
userId: PARTNER_TENANT_ADMIN_USER_ID,
|
||||
method: 'PATCH',
|
||||
body: {
|
||||
questionId: batchTargetTwo.id,
|
||||
createVersion: true,
|
||||
content: batchLocalTwoContent,
|
||||
options: batchTargetTwo.options || [],
|
||||
correctOptionIndex: batchTargetTwo.correctOptionIndex,
|
||||
correctOptionIndices: batchTargetTwo.correctOptionIndices || [],
|
||||
answerText: batchTargetTwo.answerText,
|
||||
explanation: '租户批量冲突测试本地版本二。',
|
||||
sourceHash: `tenant-batch-local-two-${Date.now()}`,
|
||||
},
|
||||
});
|
||||
|
||||
const batchPlatformOneContent = '平台公共题库批量更新:1 + 3 = ?';
|
||||
const batchPlatformTwoContent = '平台公共题库批量更新:5 + 6 = ?';
|
||||
await request('/api/tenant-content/questions', {
|
||||
userId: TENANT_ADMIN_USER_ID,
|
||||
method: 'PATCH',
|
||||
body: {
|
||||
questionId: ids.question,
|
||||
createVersion: true,
|
||||
content: batchPlatformOneContent,
|
||||
options: [
|
||||
{ label: 'A', text: '3' },
|
||||
{ label: 'B', text: '4' },
|
||||
],
|
||||
correctOptionIndex: 1,
|
||||
correctOptionIndices: [1],
|
||||
answerText: '4',
|
||||
explanation: '平台公共题库批量冲突测试题一。',
|
||||
sourceHash: `platform-batch-conflict-one-${Date.now()}`,
|
||||
},
|
||||
});
|
||||
await request('/api/tenant-content/questions', {
|
||||
userId: TENANT_ADMIN_USER_ID,
|
||||
method: 'PATCH',
|
||||
body: {
|
||||
questionId: sourceQuestion.item.id,
|
||||
createVersion: true,
|
||||
content: batchPlatformTwoContent,
|
||||
options: [
|
||||
{ label: 'A', text: '11' },
|
||||
{ label: 'B', text: '12' },
|
||||
],
|
||||
correctOptionIndex: 0,
|
||||
correctOptionIndices: [0],
|
||||
answerText: '11',
|
||||
explanation: '平台公共题库批量冲突测试题二。',
|
||||
sourceHash: `platform-batch-conflict-two-${Date.now()}`,
|
||||
},
|
||||
});
|
||||
|
||||
const batchConflictSync = await request('/api/tenant-content/public-question-banks/sync', {
|
||||
tenantId: PARTNER_TENANT_ID,
|
||||
userId: PARTNER_TENANT_ADMIN_USER_ID,
|
||||
method: 'POST',
|
||||
body: { adoptionId: adopted.item.id, copyLimit: 20 },
|
||||
});
|
||||
assert.equal(batchConflictSync.sync?.status, 'conflict', 'batch setup should produce public bank conflicts');
|
||||
const batchConflictIds = (batchConflictSync.sync?.results || [])
|
||||
.filter(item => item.action === 'conflict' && [ids.question, sourceQuestion.item.id].includes(item.sourceQuestionId))
|
||||
.map(item => item.sourceQuestionId);
|
||||
assert.deepEqual(new Set(batchConflictIds), new Set([ids.question, sourceQuestion.item.id]), 'batch setup should produce two expected conflicts');
|
||||
|
||||
const crossTenantBatchDenied = await request('/api/tenant-content/public-question-banks/conflicts/resolve-batch', {
|
||||
userId: TENANT_ADMIN_USER_ID,
|
||||
method: 'POST',
|
||||
body: {
|
||||
adoptionId: adopted.item.id,
|
||||
sourceQuestionIds: [ids.question, sourceQuestion.item.id],
|
||||
resolution: 'accept_platform',
|
||||
},
|
||||
expectStatus: 404,
|
||||
});
|
||||
assert.equal(crossTenantBatchDenied.code, 'QUESTION_BANK_ADOPTION_NOT_FOUND', 'public bank batch conflict resolution must be tenant isolated');
|
||||
|
||||
const batchAccepted = await request('/api/tenant-content/public-question-banks/conflicts/resolve-batch', {
|
||||
tenantId: PARTNER_TENANT_ID,
|
||||
userId: PARTNER_TENANT_ADMIN_USER_ID,
|
||||
method: 'POST',
|
||||
body: {
|
||||
adoptionId: adopted.item.id,
|
||||
sourceQuestionIds: [ids.question, sourceQuestion.item.id],
|
||||
resolution: 'accept_platform',
|
||||
},
|
||||
});
|
||||
assert.equal(batchAccepted.item?.resolution, 'accept_platform', 'batch conflict resolution should expose resolution');
|
||||
assert.equal(batchAccepted.item?.processedCount, 2, 'batch conflict resolution should process both conflicts');
|
||||
assert.equal(batchAccepted.item?.remainingConflictCount, 0, 'batch conflict resolution should clear all conflicts');
|
||||
assert.equal(batchAccepted.item?.syncStatus, 'synced', 'batch conflict resolution should mark adoption synced');
|
||||
|
||||
const collectionAfterBatchAccept = await request('/api/catalog/question-collections/questions', {
|
||||
tenantId: PARTNER_TENANT_ID,
|
||||
userId: false,
|
||||
query: { collectionId: adopted.item.targetCollectionId, limit: 50 },
|
||||
});
|
||||
const batchAcceptedOne = collectionAfterBatchAccept.items?.find(item => item.id === batchTargetOne.id);
|
||||
const batchAcceptedTwo = collectionAfterBatchAccept.items?.find(item => item.id === batchTargetTwo.id);
|
||||
assert.equal(batchAcceptedOne?.content, batchPlatformOneContent, 'batch accept should update first tenant copy to platform content');
|
||||
assert.equal(batchAcceptedTwo?.content, batchPlatformTwoContent, 'batch accept should update second tenant copy to platform content');
|
||||
|
||||
const conflictListAfterBatchAccept = await request('/api/tenant-content/public-question-banks/conflicts', {
|
||||
tenantId: PARTNER_TENANT_ID,
|
||||
userId: PARTNER_TENANT_ADMIN_USER_ID,
|
||||
query: { adoptionId: adopted.item.id },
|
||||
});
|
||||
assert.equal(conflictListAfterBatchAccept.item?.conflictCount, 0, 'batch-resolved conflict list should have no remaining conflicts');
|
||||
|
||||
const mainTenantNotAdopted = await request('/api/tenant-content/public-question-banks', {
|
||||
userId: TENANT_ADMIN_USER_ID,
|
||||
query: { onlyNotAdopted: 'true' },
|
||||
|
||||
Reference in New Issue
Block a user