Skip to content

Commit b69e206

Browse files
Merge pull request #63 from UKHomeOffice/PAF-11-attachments
PAF-11: Attachments
2 parents e0e6966 + 84527e4 commit b69e206

27 files changed

+710
-22
lines changed
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
module.exports = superclass => class extends superclass {
2+
locals(req, res) {
3+
const locals = super.locals(req, res);
4+
const images = req.sessionModel.get('images');
5+
if (images && images.length >= 3) {
6+
// disable file upload if attachment limit reached.
7+
req.form.options.fields['other-info-file-upload'].attributes = [{attribute: 'disabled'}];
8+
return locals;
9+
}
10+
req.form.options.fields['other-info-file-upload'].attributes = [];
11+
return locals;
12+
}
13+
}
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module.exports = superclass => class LimitDocs extends superclass {
2+
validate(req, res, next) {
3+
const images = req.sessionModel.get('images');
4+
if (images && images.length >= 3 && req.form.values['other-info-file-uploads-add-another'] === 'yes') {
5+
return next({
6+
'other-info-file-uploads-add-another': new this.ValidationError(
7+
'other-info-file-uploads-add-another',
8+
{
9+
type: 'tooMany'
10+
}
11+
)
12+
});
13+
} super.validate(req, res, next);
14+
return next;
15+
}
16+
};

apps/paf/behaviours/remove-file.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
'use strict';
2+
3+
module.exports = superclass => class extends superclass {
4+
configure(req, res, next) {
5+
if (req.query.delete) {
6+
const images = req.sessionModel.get('images') || [];
7+
const remaining = images.filter(i => i.id !== req.query.delete);
8+
req.log('info', `Reference: ${req.sessionModel.get('reference')}, Removing image: ${req.query.delete}`);
9+
req.sessionModel.set('images', remaining);
10+
const path = req.baseUrl + req.path;
11+
return res.redirect(path);
12+
}
13+
return super.configure(req, res, next);
14+
}
15+
};

apps/paf/behaviours/save-file.js

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
'use strict';
2+
3+
const _ = require('lodash');
4+
const Model = require('../models/file-upload');
5+
6+
module.exports = name => superclass => class extends superclass {
7+
process(req) {
8+
if (req.files && req.files[name]) {
9+
// set image name on values for filename extension validation
10+
// N:B validation controller gets values from
11+
// req.form.values and not on req.files
12+
req.form.values[name] = req.files[name].name;
13+
req.log('info', `Reference: ${req.sessionModel.get('reference')},
14+
Processing image: ${req.form.values[name]}`);
15+
}
16+
super.process.apply(this, arguments);
17+
}
18+
19+
locals(req, res, next) {
20+
if (!Object.keys(req.form.errors).length) {
21+
req.form.values['other-info-file-upload'] = null;
22+
}
23+
return super.locals(req, res, next);
24+
}
25+
26+
saveValues(req, res, next) {
27+
const images = req.sessionModel.get('images') || [];
28+
if (req.files && req.files[name]) {
29+
req.log('info', `Reference: ${req.sessionModel.get('reference')}, Saving image: ${req.files[name].name}`);
30+
const image = _.pick(req.files[name], ['name', 'data', 'mimetype']);
31+
const model = new Model(image);
32+
return model.save()
33+
.then(() => {
34+
req.sessionModel.set('images', [...images, model.toJSON()]);
35+
return super.saveValues(req, res, next);
36+
})
37+
.catch(next);
38+
}
39+
return super.saveValues.apply(this, arguments);
40+
}
41+
};

apps/paf/fields/index.js

+21-11
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ module.exports = {
221221
dependent: {
222222
field: 'vehicle-type',
223223
value: 'cars'
224-
},
224+
}
225225
},
226226
'crime-hgv-group': {
227227
mixin: 'radio-group',
@@ -238,7 +238,7 @@ module.exports = {
238238
dependent: {
239239
field: 'vehicle-type',
240240
value: 'hgvs'
241-
},
241+
}
242242
},
243243
'crime-lorry-group': {
244244
mixin: 'radio-group',
@@ -252,7 +252,7 @@ module.exports = {
252252
dependent: {
253253
field: 'vehicle-type',
254254
value: 'lorries'
255-
},
255+
}
256256
},
257257
'crime-van-group': {
258258
mixin: 'radio-group',
@@ -268,7 +268,7 @@ module.exports = {
268268
dependent: {
269269
field: 'vehicle-type',
270270
value: 'vans'
271-
},
271+
}
272272
},
273273
'boat-type': {
274274
isPageHeading: true,
@@ -320,7 +320,7 @@ module.exports = {
320320
dependent: {
321321
field: 'boat-type',
322322
value: 'carriers'
323-
},
323+
}
324324
},
325325
'crime-general-cargo-group': {
326326
mixin: 'radio-group',
@@ -334,7 +334,7 @@ module.exports = {
334334
dependent: {
335335
field: 'boat-type',
336336
value: 'general-cargos'
337-
},
337+
}
338338
},
339339
'crime-vessel-group': {
340340
mixin: 'radio-group',
@@ -349,7 +349,7 @@ module.exports = {
349349
dependent: {
350350
field: 'boat-type',
351351
value: 'vessels'
352-
},
352+
}
353353
},
354354
'boat-name': {
355355
mixin: 'input-text'
@@ -913,7 +913,7 @@ module.exports = {
913913
dependent: {
914914
field: 'report-person-transport-type',
915915
value: 'cars'
916-
},
916+
}
917917
},
918918
'report-person-transport-hgv-group': {
919919
mixin: 'radio-group',
@@ -930,7 +930,7 @@ module.exports = {
930930
dependent: {
931931
field: 'report-person-transport-type',
932932
value: 'hgv'
933-
},
933+
}
934934
},
935935
'report-person-transport-lorry-group': {
936936
mixin: 'radio-group',
@@ -944,7 +944,7 @@ module.exports = {
944944
dependent: {
945945
field: 'report-person-transport-type',
946946
value: 'lorries'
947-
},
947+
}
948948
},
949949
'report-person-transport-van-group': {
950950
mixin: 'radio-group',
@@ -960,7 +960,7 @@ module.exports = {
960960
dependent: {
961961
field: 'report-person-transport-type',
962962
value: 'vans'
963-
},
963+
}
964964
},
965965
'report-person-transport-make': {
966966
mixin: 'input-text'
@@ -1167,6 +1167,16 @@ module.exports = {
11671167
value: 'yes'
11681168
}
11691169
},
1170+
'other-info-file-upload': {
1171+
mixin: 'input-file',
1172+
className: 'govuk-file-upload',
1173+
attributes: []
1174+
},
1175+
'add-other-info-file-upload': {
1176+
isPageHeading: true,
1177+
mixin: 'radio-group',
1178+
options: ['yes', 'no']
1179+
},
11701180
'about-you-first-name': {
11711181
mixin: 'input-text'
11721182
},

apps/paf/index.js

+36-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
'use strict';
2+
const saveImage = require('./behaviours/save-file');
3+
const removeImage = require('./behaviours/remove-file');
4+
const CombineAndLoopFields = require('hof').components.combineAndLoopFields;
5+
const limitDocs = require('./behaviours/limit-documents');
6+
const disableUpload = require('./behaviours/disable-file-upload');
27
const SummaryPageBehaviour = require('hof').components.summary;
38
const transportBehaviour = require('./behaviours/transport-behaviour');
49
const Aggregate = require('./behaviours/aggregator');
@@ -356,7 +361,7 @@ module.exports = {
356361
field: 'report-person-occupation',
357362
value: 'yes'
358363
}
359-
},
364+
}
360365
]
361366
},
362367
'/report-person-occupation-type': {
@@ -662,6 +667,36 @@ module.exports = {
662667
next: '/other-info-file-upload'
663668
},
664669
'/other-info-file-upload': {
670+
behaviours: [saveImage('other-info-file-upload'), disableUpload],
671+
fields: ['other-info-file-upload'],
672+
continueOnEdit: true,
673+
forks: [{
674+
target: '/add-other-info-file-upload',
675+
condition: req => {
676+
if (req.form.values['other-info-file-upload']) {
677+
return true
678+
}
679+
return false;
680+
}
681+
}],
682+
next: '/about-you'
683+
},
684+
'/add-other-info-file-upload': {
685+
template: 'list-add-looped-files',
686+
behaviours: [CombineAndLoopFields({
687+
groupName: 'other-info-file-uploads',
688+
fieldsToGroup: [
689+
'other-info-file-upload'
690+
],
691+
groupOptional: true,
692+
removePrefix: 'other-',
693+
combineValuesToSingleField: 'record',
694+
returnTo: '/other-info-file-upload'
695+
}), removeImage, limitDocs],
696+
next: '/about-you',
697+
locals: {
698+
section: 'other-info-file-upload'
699+
}
665700
},
666701
'/about-you': {
667702
fields: ['how-did-you-find-out-about-the-crime'],

apps/paf/models/file-upload.js

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
'use strict';
2+
3+
const url = require('url');
4+
const Model = require('hof').model;
5+
const uuid = require('uuid').v4;
6+
const config = require('../../../config');
7+
8+
module.exports = class UploadModel extends Model {
9+
constructor(...args) {
10+
super(...args);
11+
this.set('id', uuid());
12+
}
13+
14+
async save() {
15+
const result = await new Promise((resolve, reject) => {
16+
const attributes = {
17+
url: config.upload.hostname
18+
};
19+
const reqConf = url.parse(this.url(attributes));
20+
reqConf.formData = {
21+
document: {
22+
value: this.get('data'),
23+
options: {
24+
filename: this.get('name'),
25+
contentType: this.get('mimetype')
26+
}
27+
}
28+
};
29+
reqConf.method = 'POST';
30+
this.request(reqConf, (err, data) => {
31+
if (err) {
32+
return reject(err);
33+
}
34+
resolve(data);
35+
});
36+
});
37+
this.set({ url: result.url });
38+
return this.unset('data');
39+
}
40+
41+
auth() {
42+
if (!config.keycloak.token) {
43+
// eslint-disable-next-line no-console
44+
console.error('keycloak token url is not defined');
45+
return Promise.resolve({
46+
bearer: 'abc123'
47+
});
48+
}
49+
const tokenReq = {
50+
url: config.keycloak.token,
51+
form: {
52+
username: config.keycloak.username,
53+
password: config.keycloak.password,
54+
grant_type: 'password',
55+
client_id: config.keycloak.clientId,
56+
client_secret: config.keycloak.secret
57+
},
58+
method: 'POST'
59+
};
60+
61+
return new Promise((resolve, reject) => {
62+
this._request(tokenReq, (err, response) => {
63+
const body = JSON.parse(response.body);
64+
65+
if (err || body.error) {
66+
return reject(err || new Error(`${body.error} - ${body.error_description}`));
67+
}
68+
69+
resolve({
70+
bearer: JSON.parse(response.body).access_token
71+
});
72+
});
73+
});
74+
}
75+
};

apps/paf/sections/summary-data-sections.js

+11-1
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,17 @@ module.exports = {
221221
'other-info': [
222222
'other-info-description',
223223
'other-info-another-crime',
224-
'other-info-another-crime-description'
224+
'other-info-another-crime-description',
225+
{
226+
step: '/add-other-info-file-upload',
227+
field: 'images',
228+
parse: (list, req) => {
229+
if (!req.sessionModel.get('images') ) {
230+
return null;
231+
}
232+
return list && list.map(a => a.name).join('\n————————————————\n') || 'None';
233+
}
234+
}
225235
],
226236
'about-you': [
227237
'how-did-you-find-out-about-the-crime',

apps/paf/translations/src/en/fields.json

+18
Original file line numberDiff line numberDiff line change
@@ -1087,6 +1087,21 @@
10871087
},
10881088
"legendClassName": "govuk-fieldset__legend"
10891089
},
1090+
"other-info-file-upload": {
1091+
"hint": "You can add up to 3 documents",
1092+
"label": "Attachment"
1093+
},
1094+
"other-info-file-uploads-add-another": {
1095+
"options": {
1096+
"yes": {
1097+
"label": "Yes"
1098+
},
1099+
"no": {
1100+
"label": "No"
1101+
}
1102+
},
1103+
"legendClassName": "govuk-fieldset__legend"
1104+
},
10901105
"persons": {
10911106
"label": "Additional People",
10921107
"changeLinkDescription": "Additional People"
@@ -1356,5 +1371,8 @@
13561371
},
13571372
"when-to-contact": {
13581373
"label": "When would you like us to contact you?"
1374+
},
1375+
"images": {
1376+
"label": "Attachments"
13591377
}
13601378
}

0 commit comments

Comments
 (0)