-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(api): Add a script to delete most organizations
Co-Authored-By: EmmanuelleBonnemay <[email protected]> Co-Authored-By: Benjamin Petetot <[email protected]>
- Loading branch information
1 parent
43403db
commit afefd95
Showing
2 changed files
with
104 additions
and
0 deletions.
There are no files selected for viewing
64 changes: 64 additions & 0 deletions
64
api/src/organizational-entities/scripts/delete-organizations-script.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import Joi from 'joi'; | ||
|
||
import { csvFileParser } from '../../shared/application/scripts/parsers.js'; | ||
import { Script } from '../../shared/application/scripts/script.js'; | ||
import { ScriptRunner } from '../../shared/application/scripts/script-runner.js'; | ||
import * as dataProtectionOfficerRepository from '../infrastructure/repositories/data-protection-officer.repository.js'; | ||
import { organizationForAdminRepository } from '../infrastructure/repositories/organization-for-admin.repository.js'; | ||
import * as organizationTagRepository from '../infrastructure/repositories/organization-tag.repository.js'; | ||
|
||
const columnsSchema = [{ name: 'Organization ID', schema: Joi.number().required() }]; | ||
|
||
export class DeleteOrganizationsScript extends Script { | ||
constructor() { | ||
super({ | ||
description: 'Delete all organizations and associated tags', | ||
permanent: false, | ||
options: { | ||
file: { | ||
type: 'string', | ||
describe: 'File path to CSV file with organizations to delete', | ||
demandOption: true, | ||
requiresArg: true, | ||
coerce: csvFileParser(columnsSchema), | ||
}, | ||
dryRun: { | ||
type: 'boolean', | ||
describe: 'Run the script without actually deleting anything', | ||
default: false, | ||
}, | ||
}, | ||
}); | ||
} | ||
|
||
async handle({ | ||
options, | ||
logger, | ||
dependencies = { organizationForAdminRepository, organizationTagRepository, dataProtectionOfficerRepository }, | ||
}) { | ||
const { file, dryRun } = options; | ||
|
||
let count = 0; | ||
for (const row of file) { | ||
const organizationId = row['Organization ID']; | ||
if (!dryRun) { | ||
logger.info(organizationId); | ||
// Delete data protection officer via data-protection-officer.repository | ||
await dependencies.dataProtectionOfficerRepository.deleteDpoByOrganizationId(organizationId); | ||
// delete organization tags via organization-tags.repository | ||
await dependencies.organizationTagRepository.deleteTagsByOrganizationId(organizationId); | ||
// delete organizationvia organization-for-admin.repository | ||
await dependencies.organizationForAdminRepository.deleteById(organizationId); | ||
} | ||
count++; | ||
} | ||
|
||
if (dryRun) { | ||
logger.info(`Would delete ${count} organizations.`); | ||
} else { | ||
logger.info(`Deleted ${count} organizations.`); | ||
} | ||
} | ||
} | ||
|
||
await ScriptRunner.execute(import.meta.url, DeleteOrganizationsScript); |
40 changes: 40 additions & 0 deletions
40
api/tests/organizational-entities/unit/scripts/delete-organizations-script.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { DeleteOrganizationsScript } from '../../../../src/organizational-entities/scripts/./delete-organizations-script.js'; | ||
import { expect, sinon } from '../../../test-helper.js'; | ||
|
||
describe('DeleteOrganizationsScript', function () { | ||
describe('Handle', function () { | ||
let script; | ||
let logger; | ||
let organizationForAdminRepository; | ||
let organizationTagRepository; | ||
let dataProtectionOfficerRepository; | ||
|
||
beforeEach(function () { | ||
script = new DeleteOrganizationsScript(); | ||
logger = { info: sinon.spy() }; | ||
organizationForAdminRepository = { deleteById: sinon.stub() }; | ||
organizationTagRepository = { deleteTagsByOrganizationId: sinon.stub() }; | ||
dataProtectionOfficerRepository = { deleteDpoByOrganizationId: sinon.stub() }; | ||
}); | ||
|
||
it('handles data correctly', async function () { | ||
const file = [{ 'Organization ID': 1 }, { 'Organization ID': 2 }]; | ||
|
||
await script.handle({ | ||
options: { file }, | ||
logger, | ||
dependencies: { | ||
organizationForAdminRepository, | ||
organizationTagRepository, | ||
dataProtectionOfficerRepository, | ||
}, | ||
}); | ||
expect(organizationForAdminRepository.deleteById.calledWith(1)).to.be.true; | ||
expect(organizationForAdminRepository.deleteById.calledWith(2)).to.be.true; | ||
expect(organizationTagRepository.deleteTagsByOrganizationId.calledWith(1)).to.be.true; | ||
expect(organizationTagRepository.deleteTagsByOrganizationId.calledWith(2)).to.be.true; | ||
expect(dataProtectionOfficerRepository.deleteDpoByOrganizationId.calledWith(1)).to.be.true; | ||
expect(dataProtectionOfficerRepository.deleteDpoByOrganizationId.calledWith(2)).to.be.true; | ||
}); | ||
}); | ||
}); |