diff --git a/app/api/migrations/migrations/37-resync-translations/index.js b/app/api/migrations/migrations/37-resync-translations/index.js new file mode 100644 index 0000000000..619f52d0b9 --- /dev/null +++ b/app/api/migrations/migrations/37-resync-translations/index.js @@ -0,0 +1,17 @@ +export default { + delta: 37, + + name: 'resync-tranlsations', + + description: 'Moves timestamp of current translation update logs forward to force resync', + + async up(db) { + process.stdout.write('Updating updatelogs of translations...\r\n'); + + await db + .collection('updatelogs') + .updateMany({ namespace: 'translations' }, { $set: { timestamp: Date.now() } }); + + process.stdout.write('Updatelogs updated\r\n'); + }, +}; diff --git a/app/api/migrations/migrations/37-resync-translations/specs/37-resync-translations.spec.js b/app/api/migrations/migrations/37-resync-translations/specs/37-resync-translations.spec.js new file mode 100644 index 0000000000..7d647ede6a --- /dev/null +++ b/app/api/migrations/migrations/37-resync-translations/specs/37-resync-translations.spec.js @@ -0,0 +1,47 @@ +import testingDB from 'api/utils/testing_db'; +import migration from '../index.js'; +import fixtures, { translation1, translation2, translation3, entity1 } from './fixtures'; + +describe('migration resync translations', () => { + let updatelogs; + + beforeEach(async () => { + await testingDB.clearAllAndLoad(fixtures); + spyOn(process.stdout, 'write'); + spyOn(Date, 'now').and.returnValue(1000); + await migration.up(testingDB.mongodb); + }); + + afterAll(async () => { + await testingDB.disconnect(); + }); + + const getUpdatelog = mongoId => updatelogs.find(l => l.mongoId.toString() === mongoId.toString()); + + const expectLog = (logEntry, [namespace, deleted, timestamp]) => { + expect(logEntry).toEqual(expect.objectContaining({ namespace, deleted, timestamp })); + }; + + it('should have a delta number', () => { + expect(migration.delta).toBe(37); + }); + + it('should update the translation updatelogs to current timestamp and not affect others', async () => { + updatelogs = await testingDB.mongodb + .collection('updatelogs') + .find({}) + .toArray(); + + expect(updatelogs.length).toBe(4); + + const logTranslation1 = getUpdatelog(translation1); + const logTranslation2 = getUpdatelog(translation2); + const logTranslation3 = getUpdatelog(translation3); + const logEntity1 = getUpdatelog(entity1); + + expectLog(logTranslation1, ['translations', false, 1000]); + expectLog(logTranslation2, ['translations', false, 1000]); + expectLog(logTranslation3, ['translations', true, 1000]); + expectLog(logEntity1, ['entities', true, 8]); + }); +}); diff --git a/app/api/migrations/migrations/37-resync-translations/specs/fixtures.js b/app/api/migrations/migrations/37-resync-translations/specs/fixtures.js new file mode 100644 index 0000000000..b57aaa5304 --- /dev/null +++ b/app/api/migrations/migrations/37-resync-translations/specs/fixtures.js @@ -0,0 +1,37 @@ +import testingDB from 'api/utils/testing_db'; + +const translation1 = testingDB.id(); +const translation2 = testingDB.id(); +const translation3 = testingDB.id(); +const entity1 = testingDB.id(); + +export default { + updatelogs: [ + { + mongoId: translation1, + namespace: 'translations', + deleted: false, + timestamp: 6, + }, + { + mongoId: entity1, + namespace: 'entities', + deleted: true, + timestamp: 8, + }, + { + mongoId: translation2, + namespace: 'translations', + deleted: false, + timestamp: 10, + }, + { + mongoId: translation3, + namespace: 'translations', + deleted: true, + timestamp: 12, + }, + ], +}; + +export { translation1, translation2, translation3, entity1 }; diff --git a/app/api/sync/processNamespaces.ts b/app/api/sync/processNamespaces.ts index 5f3d9e62c0..d5cde138e4 100644 --- a/app/api/sync/processNamespaces.ts +++ b/app/api/sync/processNamespaces.ts @@ -317,11 +317,16 @@ class ProcessNamespaces { templatesData.find(t => t._id.toString() === context.id.toString()) ); const templateConfigProperties = this.templatesConfig[context.id.toString()].properties; - const approvedKeys = [contextTemplate.name].concat( - (contextTemplate.properties || []) - .filter(p => templateConfigProperties.includes(p._id?.toString() || '')) - .map(p => p.label) - ); + const templateTitle = contextTemplate.commonProperties?.find(p => p.name === 'title') + ?.label; + + const approvedKeys = [contextTemplate.name, templateTitle] + .concat( + (contextTemplate.properties || []) + .filter(p => templateConfigProperties.includes(p._id?.toString() || '')) + .map(p => p.label) + ) + .filter(k => Boolean(k)); context.values = (context.values || []).filter((v: any) => approvedKeys.includes(v.key)); return context; diff --git a/app/api/sync/specs/fixtures.js b/app/api/sync/specs/fixtures.js index b5b31a547a..b243c2b47c 100644 --- a/app/api/sync/specs/fixtures.js +++ b/app/api/sync/specs/fixtures.js @@ -569,6 +569,7 @@ export default { { _id: template1, name: 'template1', + commonProperties: [{ label: 'Template Title', name: 'title' }], properties: [ { _id: template1Property1, @@ -724,6 +725,7 @@ export default { { key: 't1Relationship2L', value: 't1Relationship2T' }, { key: 't1Thesauri2SelectL', value: 't1Thesauri2SelectT' }, { key: 't1Thesauri3MultiSelectL', value: 't1Thesauri3MultiSelectT' }, + { key: 'Template Title', value: 'Template Title translated' }, ], }, { diff --git a/app/api/sync/specs/syncWorker.spec.js b/app/api/sync/specs/syncWorker.spec.js index 7f31ceec2b..50e3834b19 100644 --- a/app/api/sync/specs/syncWorker.spec.js +++ b/app/api/sync/specs/syncWorker.spec.js @@ -225,7 +225,7 @@ describe('syncWorker', () => { }); describe('thesauris (dictionaries collection)', () => { - it('should sync whitelisted thesauris through template configs (deleting even non whitelisted ones)', async () => { + it('should sync whitelisted thesauris through template configs (deleting non-whitelisted ones)', async () => { await syncWorkerWithConfig({ templates: { [template1.toString()]: [ @@ -338,6 +338,7 @@ describe('syncWorker', () => { { key: 'template1', value: 'template1T' }, { key: 't1Relationship1L', value: 't1Relationship1T' }, { key: 't1Thesauri3MultiSelectL', value: 't1Thesauri3MultiSelectT' }, + { key: 'Template Title', value: 'Template Title translated' }, ]); expect(contexts.find(c => c.id.toString() === template2.toString()).values).toEqual([ { key: 'template2', value: 'template2T' },