Skip to content

Commit 6525781

Browse files
authored
Merge pull request #6421 from NMDSdevopsServiceAdm/fix/delete-certificates-when-deleting-training-record
Fix/delete certificates when deleting training record
2 parents fa8e46c + e95d9f7 commit 6525781

File tree

2 files changed

+101
-74
lines changed
  • backend/server

2 files changed

+101
-74
lines changed

backend/server/routes/establishments/training/index.js

+26-31
Original file line numberDiff line numberDiff line change
@@ -154,44 +154,39 @@ const updateTrainingRecord = async (req, res) => {
154154
}
155155
};
156156

157-
// deletes requested training record using the training uid
158-
const deleteTrainingRecord = async (req, res) => {
159-
const establishmentId = req.establishmentId;
160-
const trainingUid = req.params.trainingUid;
161-
const workerUid = req.params.workerId;
162-
const establishmentUid = req.params.id;
157+
const deleteTrainingRecordEndpoint = async (req, res) => {
158+
const trainingRecord = new Training(req.establishmentId, req.params.workerId);
159+
const trainingCertificateService = WorkerCertificateService.initialiseTraining();
163160

164-
const thisTrainingRecord = new Training(establishmentId, workerUid);
161+
return await deleteTrainingRecord(req, res, trainingRecord, trainingCertificateService);
162+
};
165163

164+
const deleteTrainingRecord = async (req, res, trainingRecord, trainingCertificateService) => {
166165
try {
167-
// before updating a Worker, we need to be sure the Worker is
168-
// available to the given establishment. The best way of doing that
169-
// is to restore from given UID
170-
if (await thisTrainingRecord.restore(trainingUid)) {
171-
// TODO: JSON validation
166+
const trainingUid = req.params.trainingUid;
167+
const workerUid = req.params.workerId;
168+
const establishmentUid = req.params.id;
172169

173-
const trainingCertificates = thisTrainingRecord?._trainingCertificates;
170+
const trainingRecordFound = await trainingRecord.restore(trainingUid);
171+
if (!trainingRecordFound) {
172+
return res.status(404).send('Not Found');
173+
}
174174

175-
const trainingCertificateService = WorkerCertificateService.initialiseTraining();
175+
const trainingCertificates = trainingRecord?._trainingCertificates;
176176

177-
if (this.trainingCertificates?.length) {
178-
await trainingCertificateService.deleteCertificates(
179-
trainingCertificates,
180-
establishmentUid,
181-
workerUid,
182-
trainingUid,
183-
);
184-
}
177+
if (trainingCertificates?.length) {
178+
await trainingCertificateService.deleteCertificates(
179+
trainingCertificates,
180+
establishmentUid,
181+
workerUid,
182+
trainingUid,
183+
);
184+
}
185185

186-
// by deleting after the restore we can be sure this training record belongs to the given worker
187-
const deleteSuccess = await thisTrainingRecord.delete();
188-
if (deleteSuccess) {
189-
return res.status(204).json();
190-
} else {
191-
return res.status(404).send('Not Found');
192-
}
186+
const deleteSuccess = await trainingRecord.delete();
187+
if (deleteSuccess) {
188+
return res.status(204).json();
193189
} else {
194-
// not found worker
195190
return res.status(404).send('Not Found');
196191
}
197192
} catch (err) {
@@ -204,7 +199,7 @@ router.route('/').get(hasPermission('canViewWorker'), getTrainingListWithMissing
204199
router.route('/').post(hasPermission('canEditWorker'), createTrainingRecord);
205200
router.route('/:trainingUid').get(hasPermission('canViewWorker'), viewTrainingRecord);
206201
router.route('/:trainingUid').put(hasPermission('canEditWorker'), updateTrainingRecord);
207-
router.route('/:trainingUid').delete(hasPermission('canEditWorker'), deleteTrainingRecord);
202+
router.route('/:trainingUid').delete(hasPermission('canEditWorker'), deleteTrainingRecordEndpoint);
208203
router.use('/:trainingUid/certificate', TrainingCertificateRoute);
209204

210205
module.exports = router;

backend/server/test/unit/routes/establishments/training/index.spec.js

+75-43
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@ const expect = require('chai').expect;
22
const sinon = require('sinon');
33
const httpMocks = require('node-mocks-http');
44
const buildUser = require('../../../../factories/user');
5-
const models = require('../../../../../models');
65
const Training = require('../../../../../models/classes/training').Training;
76
const { deleteTrainingRecord } = require('../../../../../routes/establishments/training/index');
87
const {
98
mockTrainingRecordWithCertificates,
109
mockTrainingRecordWithoutCertificates,
1110
} = require('../../../mockdata/training');
12-
const WorkerCertificateService = require('../../../../../routes/establishments/workerCertificate/workerCertificateService');
1311
const HttpError = require('../../../../../utils/errors/httpError');
1412

1513
describe('server/routes/establishments/training/index.js', () => {
@@ -25,8 +23,8 @@ describe('server/routes/establishments/training/index.js', () => {
2523
let workerUid = mockTrainingRecordWithCertificates.workerUid;
2624
let trainingUid = mockTrainingRecordWithCertificates.uid;
2725
let establishmentUid = user.establishment.uid;
28-
29-
let stubs = {};
26+
let trainingRecord;
27+
let trainingCertificateService;
3028

3129
beforeEach(() => {
3230
req = httpMocks.createRequest({
@@ -37,76 +35,110 @@ describe('server/routes/establishments/training/index.js', () => {
3735
});
3836
res = httpMocks.createResponse();
3937

40-
stubs = {
41-
trainingRecord: sinon.createStubInstance(Training),
42-
restoreTrainingRecord: sinon.stub(Training.prototype, 'restore'),
43-
getWorkerCertificateServiceInstance: sinon.stub(WorkerCertificateService, 'initialiseTraining').returns(new WorkerCertificateService()),
44-
deleteCertificates: sinon.stub(WorkerCertificateService.prototype, 'deleteCertificates'),
45-
destroyTrainingRecord: sinon.stub(models.workerTraining, 'destroy'),
46-
}
38+
trainingRecord = sinon.createStubInstance(Training);
39+
trainingRecord.restore.resolves(true);
40+
41+
trainingCertificateService = {
42+
deleteCertificates: sinon.stub(),
43+
};
4744
});
4845

49-
it('should return with a status of 204 when the training record is deleted with training certificates', async () => {
50-
stubs.restoreTrainingRecord.returns(mockTrainingRecordWithCertificates);
51-
stubs.destroyTrainingRecord.returns(1);
46+
describe('With training certificates', () => {
47+
beforeEach(() => {
48+
trainingRecord.trainingCertificates = mockTrainingRecordWithCertificates.trainingCertificates;
49+
trainingRecord.delete.resolves(1);
50+
});
5251

53-
await deleteTrainingRecord(req, res);
52+
it('should return with a status of 204', async () => {
53+
await deleteTrainingRecord(req, res, trainingRecord, trainingCertificateService);
54+
55+
expect(res.statusCode).to.equal(204);
56+
});
5457

55-
expect(res.statusCode).to.equal(204);
58+
it('should call delete on training instance', async () => {
59+
await deleteTrainingRecord(req, res, trainingRecord, trainingCertificateService);
60+
61+
expect(trainingRecord.delete).to.have.been.calledOnce;
62+
});
63+
64+
it('should call deleteCertificates', async () => {
65+
await deleteTrainingRecord(req, res, trainingRecord, trainingCertificateService);
66+
67+
expect(trainingCertificateService.deleteCertificates.calledOnce).to.be.true;
68+
expect(
69+
trainingCertificateService.deleteCertificates.calledWith(
70+
mockTrainingRecordWithCertificates.trainingCertificates,
71+
establishmentUid,
72+
workerUid,
73+
trainingUid,
74+
),
75+
).to.be.true;
76+
});
5677
});
5778

58-
it('should return with a status of 204 when the training record is deleted with no training certificates', async () => {
59-
stubs.restoreTrainingRecord.returns(mockTrainingRecordWithoutCertificates);
60-
stubs.destroyTrainingRecord.returns(1);
79+
describe('Without training certificates', () => {
80+
beforeEach(() => {
81+
trainingRecord.trainingCertificates = null;
82+
trainingRecord.delete.resolves(1);
83+
});
84+
85+
it('should return with a status of 204 when successful', async () => {
86+
await deleteTrainingRecord(req, res, trainingRecord, trainingCertificateService);
87+
88+
expect(res.statusCode).to.equal(204);
89+
});
6190

62-
await deleteTrainingRecord(req, res);
91+
it('should call delete on training instance', async () => {
92+
await deleteTrainingRecord(req, res, trainingRecord, trainingCertificateService);
6393

64-
expect(res.statusCode).to.equal(204);
94+
expect(trainingRecord.delete).to.have.been.calledOnce;
95+
});
96+
97+
it('should not call deleteCertificates when no training certificates', async () => {
98+
await deleteTrainingRecord(req, res, trainingRecord, trainingCertificateService);
99+
100+
expect(trainingCertificateService.deleteCertificates.called).to.be.false;
101+
});
65102
});
66103

67104
describe('errors', () => {
68105
it('should pass through status code if one is provided', async () => {
69-
stubs.restoreTrainingRecord.throws(new HttpError('Test error message', 123));
70-
req.params.trainingUid = 'mockTrainingUid';
106+
trainingRecord.restore.throws(new HttpError('Test error message', 123));
71107

72-
await deleteTrainingRecord(req, res);
108+
await deleteTrainingRecord(req, res, trainingRecord, trainingCertificateService);
73109

74110
expect(res.statusCode).to.equal(123);
75111
});
76112

77113
it('should default to status code 500 if no error code is provided', async () => {
78-
stubs.restoreTrainingRecord.throws(new Error());
79-
req.params.trainingUid = 'mockTrainingUid';
114+
trainingRecord.restore.throws(new Error());
80115

81-
await deleteTrainingRecord(req, res);
116+
await deleteTrainingRecord(req, res, trainingRecord, trainingCertificateService);
82117

83118
expect(res.statusCode).to.equal(500);
84119
});
85120

86-
describe('restoring training record', () => {
87-
it('should return a 404 status code if there is an unknown worker uid', async () => {
88-
trainingRecord_workerUid = 'mockWorkerUid';
121+
it('should return a 404 status code when failed to restore training (e.g. unknown worker uid)', async () => {
122+
trainingRecord.restore.resolves(false);
89123

90-
await deleteTrainingRecord(req, res);
124+
await deleteTrainingRecord(req, res, trainingRecord, trainingCertificateService);
91125

92-
const response = res._getData();
126+
const response = res._getData();
93127

94-
expect(res.statusCode).to.equal(404);
95-
expect(response).to.equal('Not Found');
96-
});
128+
expect(res.statusCode).to.equal(404);
129+
expect(response).to.equal('Not Found');
97130
});
98131

99-
describe('deleting training record', () => {
100-
it('should return with a status of 404 when there is an error deleting the training record from the database', async () => {
101-
stubs.destroyTrainingRecord.returns(0);
132+
it('should return with a status of 404 when there is an error deleting the training record from the database', async () => {
133+
trainingRecord.restore.resolves(true);
134+
trainingRecord.delete.resolves(0);
102135

103-
await deleteTrainingRecord(req, res);
136+
await deleteTrainingRecord(req, res, trainingRecord, trainingCertificateService);
104137

105-
const response = res._getData();
138+
const response = res._getData();
106139

107-
expect(res.statusCode).to.equal(404);
108-
expect(response).to.equal('Not Found');
109-
});
140+
expect(res.statusCode).to.equal(404);
141+
expect(response).to.equal('Not Found');
110142
});
111143
});
112144
});

0 commit comments

Comments
 (0)