diff --git a/lib/model/migrations/20241010-01-schedule-entity-form-upgrade.js b/lib/model/migrations/20241010-01-schedule-entity-form-upgrade.js index 39d31400c..1aa35ac5f 100644 --- a/lib/model/migrations/20241010-01-schedule-entity-form-upgrade.js +++ b/lib/model/migrations/20241010-01-schedule-entity-form-upgrade.js @@ -8,13 +8,17 @@ // except according to the terms contained in the LICENSE file. const up = (db) => db.raw(` - INSERT INTO audits ("action", "acteeId") - SELECT 'upgrade.process.form.entities_version', f."acteeId" - FROM forms f - JOIN form_defs fd ON f."id" = fd."formId" + INSERT INTO audits ("action", "acteeId", "loggedAt", "details") + SELECT 'upgrade.process.form.entities_version', forms."acteeId", clock_timestamp(), + '{"upgrade": "As part of upgrading Central to v2024.3, this form is being updated to the latest entities-version spec."}' + FROM forms + JOIN form_defs fd ON forms."id" = fd."formId" JOIN dataset_form_defs dfd ON fd."id" = dfd."formDefId" + JOIN projects ON projects."id" = forms."projectId" WHERE dfd."actions" @> '["update"]' - GROUP BY f."acteeId"; + AND forms."deletedAt" IS NULL + AND projects."deletedAt" IS NULL + GROUP BY forms."acteeId"; `); const down = () => {}; diff --git a/lib/model/query/forms.js b/lib/model/query/forms.js index c609e4b7f..2e267f26c 100644 --- a/lib/model/query/forms.js +++ b/lib/model/query/forms.js @@ -201,7 +201,9 @@ const _createNewDef = (partial, form, publish, data) => ({ one }) => // =========== // partial: Partial form definition of the new version // form: Form frame of existing form -// publish: set true if you want new version to be published (only used by setManagedKey, everywhere else calls publish() explicitly) +// publish: set true if you want new version to be published (used infrequently) +// One example where publish=true is in setManagedKey, which updates the form XML. +// Most other situations call publish() explicitly. // duplicating: set true if copying form definition from previously uploaded definition, in that cases we don't check for structural change // as user has already been warned otherwise set false const createVersion = (partial, form, publish, duplicating = false) => async ({ Datasets, FormAttachments, Forms, Keys }) => { diff --git a/lib/worker/form.js b/lib/worker/form.js index bc9e2cb94..7d3a6759a 100644 --- a/lib/worker/form.js +++ b/lib/worker/form.js @@ -46,14 +46,14 @@ const updateEntitiesVersion = async ({ Forms }, event) => { const { projectId, xmlFormId } = await Forms.getByActeeIdForUpdate(event.acteeId).then(o => o.get()); const publishedVersion = await Forms.getByProjectAndXmlFormId(projectId, xmlFormId, true, Form.PublishedVersion).then(o => o.orNull()); if (publishedVersion && publishedVersion.currentDefId != null) { - const partial = await publishedVersion.withUpgradeEntityVersion('2023.1.0', '2024.1.0', '_upgrade'); + const partial = await publishedVersion.withUpgradeEntityVersion('2023.1.0', '2024.1.0', '[upgrade]'); if (partial != null) await Forms.createVersion(partial, publishedVersion, true, true); } const draftVersion = await Forms.getByProjectAndXmlFormId(projectId, xmlFormId, true, Form.DraftVersion).then(o => o.orNull()); if (draftVersion && draftVersion.draftDefId != null) { - const partial = await draftVersion.withUpgradeEntityVersion('2023.1.0', '2024.1.0', '_upgrade'); + const partial = await draftVersion.withUpgradeEntityVersion('2023.1.0', '2024.1.0', '[upgrade]'); // update xml and version in place if (partial != null) await Forms._updateDef(draftVersion.def, { xml: partial.xml, version: partial.def.version }); diff --git a/test/integration/other/form-entities-version.js b/test/integration/other/form-entities-version.js index c48eeee43..2fafa4a06 100644 --- a/test/integration/other/form-entities-version.js +++ b/test/integration/other/form-entities-version.js @@ -10,7 +10,7 @@ const upgradedUpdateEntity = ` - + @@ -48,7 +48,7 @@ describe('Update / migrate entities-version within form', () => { await asAlice.get('/v1/projects/1/forms/updateEntity/versions') .then(({ body }) => { body.length.should.equal(2); - body[0].version.should.equal('1.0_upgrade'); + body[0].version.should.equal('1.0[upgrade]'); body[1].version.should.equal('1.0'); }); @@ -76,7 +76,7 @@ describe('Update / migrate entities-version within form', () => { // The version on the draft does change even though it is updated in place await asAlice.get('/v1/projects/1/forms/updateEntity/draft') .then(({ body }) => { - body.version.should.equal('1.0_upgrade'); + body.version.should.equal('1.0[upgrade]'); }); await asAlice.get('/v1/projects/1/forms/updateEntity/versions') @@ -111,13 +111,13 @@ describe('Update / migrate entities-version within form', () => { // The version on the draft does change even though it is updated in place await asAlice.get('/v1/projects/1/forms/updateEntity/draft') .then(({ body }) => { - body.version.should.equal('1.0_upgrade'); + body.version.should.equal('1.0[upgrade]'); }); await asAlice.get('/v1/projects/1/forms/updateEntity/versions') .then(({ body }) => { body.length.should.equal(2); - body[0].version.should.equal('1.0_upgrade'); + body[0].version.should.equal('1.0[upgrade]'); body[1].version.should.equal('1.0'); }); @@ -162,7 +162,7 @@ describe('Update / migrate entities-version within form', () => { await asAlice.get('/v1/projects/1/forms/updateEntity/versions') .then(({ body }) => { - body.map(f => f.version).should.eql([ '3.0_upgrade', '3.0', '2.0', '1.0' ]); + body.map(f => f.version).should.eql([ '3.0[upgrade]', '3.0', '2.0', '1.0' ]); }); })); @@ -274,7 +274,7 @@ describe('Update / migrate entities-version within form', () => { await asAlice.get('/v1/projects/1/forms/withAttachments.xml') .then(({ text }) => { text.includes('entities:entities-version="2024.1.0"').should.equal(true); - text.includes('version="_upgrade"').should.equal(true); + text.includes('version="[upgrade]"').should.equal(true); text.includes('trunkVersion="" branchId=""').should.equal(true); }); @@ -282,7 +282,7 @@ describe('Update / migrate entities-version within form', () => { await asAlice.get('/v1/projects/1/forms/withAttachments/draft.xml') .then(({ text }) => { text.includes('entities:entities-version="2024.1.0"').should.equal(true); - text.includes('version="_upgrade"').should.equal(true); + text.includes('version="[upgrade]"').should.equal(true); text.includes('trunkVersion="" branchId=""').should.equal(true); }); diff --git a/test/integration/other/migrations.js b/test/integration/other/migrations.js index d5302e90d..fa1db847d 100644 --- a/test/integration/other/migrations.js +++ b/test/integration/other/migrations.js @@ -1094,6 +1094,29 @@ testMigration('20240914-02-remove-orphaned-client-audits.js', () => { .send(testData.forms.simpleEntity) .expect(200); + // Deleted forms and projects + // Upload another form that needs updating but will be deleted + await asAlice.post('/v1/projects/1/forms') + .send(testData.forms.updateEntity.replace('id="updateEntity"', 'id="updateEntityDeleted"')) + .expect(200); + + await asAlice.delete('/v1/projects/1/forms/updateEntityDeleted') + .expect(200); + + // Create a new project + const newProjectId = await asAlice.post('/v1/projects') + .send({ name: 'NewDeletedProject' }) + .expect(200) + .then(({ body }) => body.id); + + // Upload a form that needs updating to the new project + await asAlice.post(`/v1/projects/${newProjectId}/forms?publish=true`) + .send(testData.forms.updateEntity) + .expect(200); + + // Delete the new project + await asAlice.delete(`/v1/projects/${newProjectId}`); + // Mark forms for upgrade await up(); @@ -1111,7 +1134,7 @@ testMigration('20240914-02-remove-orphaned-client-audits.js', () => { - + diff --git a/test/unit/data/schema.js b/test/unit/data/schema.js index ea251bd5d..1ac10a285 100644 --- a/test/unit/data/schema.js +++ b/test/unit/data/schema.js @@ -2089,7 +2089,7 @@ describe('form schema', () => { describe('updateEntityForm', () => { it('should change version 2023->2024, add trunkVersion, and add branchId', (async () => { - const result = await updateEntityForm(testData.forms.updateEntity, '2023.1.0', '2024.1.0', '_upgrade'); + const result = await updateEntityForm(testData.forms.updateEntity, '2023.1.0', '2024.1.0', '[upgrade]'); // entities-version has been updated // version has suffix // trunkVersion and branchId are present @@ -2098,7 +2098,7 @@ describe('form schema', () => { - + @@ -2117,11 +2117,11 @@ describe('form schema', () => { })); it('should not alter a version 2022.1.0 form when the old version to replace is 2023.1.0', (async () => { - const result = await updateEntityForm(testData.forms.simpleEntity, '2023.1.0', '2024.1.0', '_upgrade'); + const result = await updateEntityForm(testData.forms.simpleEntity, '2023.1.0', '2024.1.0', '[upgrade]'); result.should.equal(testData.forms.simpleEntity); })); it('should not alter a version 2024.1.0 form when the old version to replace is 2023.1.0', (async () => { - const result = await updateEntityForm(testData.forms.offlineEntity, '2023.1.0', '2024.1.0', '_upgrade'); + const result = await updateEntityForm(testData.forms.offlineEntity, '2023.1.0', '2024.1.0', '[upgrade]'); result.should.equal(testData.forms.offlineEntity); })); });