Skip to content

Commit

Permalink
PAF-11: create attachments
Browse files Browse the repository at this point in the history
- Add upload model for uploading attachments functionality
- Add save, delete and disable file behaviours for uploading attachments functionality
- Add fields and translations for uploading attachments
- Add views for uploading attachments
- Add validation for number of attachments added
- Add ui and unit tests
  • Loading branch information
Rhodine-orleans-lindsay committed Apr 4, 2023
1 parent d49985a commit 84527e4
Show file tree
Hide file tree
Showing 27 changed files with 710 additions and 22 deletions.
13 changes: 13 additions & 0 deletions apps/paf/behaviours/disable-file-upload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module.exports = superclass => class extends superclass {
locals(req, res) {
const locals = super.locals(req, res);
const images = req.sessionModel.get('images');
if (images && images.length >= 3) {
// disable file upload if attachment limit reached.
req.form.options.fields['other-info-file-upload'].attributes = [{attribute: 'disabled'}];
return locals;
}
req.form.options.fields['other-info-file-upload'].attributes = [];
return locals;
}
}
16 changes: 16 additions & 0 deletions apps/paf/behaviours/limit-documents.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module.exports = superclass => class LimitDocs extends superclass {
validate(req, res, next) {
const images = req.sessionModel.get('images');
if (images && images.length >= 3 && req.form.values['other-info-file-uploads-add-another'] === 'yes') {
return next({
'other-info-file-uploads-add-another': new this.ValidationError(
'other-info-file-uploads-add-another',
{
type: 'tooMany'
}
)
});
} super.validate(req, res, next);
return next;
}
};
15 changes: 15 additions & 0 deletions apps/paf/behaviours/remove-file.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
'use strict';

module.exports = superclass => class extends superclass {
configure(req, res, next) {
if (req.query.delete) {
const images = req.sessionModel.get('images') || [];
const remaining = images.filter(i => i.id !== req.query.delete);
req.log('info', `Reference: ${req.sessionModel.get('reference')}, Removing image: ${req.query.delete}`);
req.sessionModel.set('images', remaining);
const path = req.baseUrl + req.path;
return res.redirect(path);
}
return super.configure(req, res, next);
}
};
41 changes: 41 additions & 0 deletions apps/paf/behaviours/save-file.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
'use strict';

const _ = require('lodash');
const Model = require('../models/file-upload');

module.exports = name => superclass => class extends superclass {
process(req) {
if (req.files && req.files[name]) {
// set image name on values for filename extension validation
// N:B validation controller gets values from
// req.form.values and not on req.files
req.form.values[name] = req.files[name].name;
req.log('info', `Reference: ${req.sessionModel.get('reference')},
Processing image: ${req.form.values[name]}`);
}
super.process.apply(this, arguments);
}

locals(req, res, next) {
if (!Object.keys(req.form.errors).length) {
req.form.values['other-info-file-upload'] = null;
}
return super.locals(req, res, next);
}

saveValues(req, res, next) {
const images = req.sessionModel.get('images') || [];
if (req.files && req.files[name]) {
req.log('info', `Reference: ${req.sessionModel.get('reference')}, Saving image: ${req.files[name].name}`);
const image = _.pick(req.files[name], ['name', 'data', 'mimetype']);
const model = new Model(image);
return model.save()
.then(() => {
req.sessionModel.set('images', [...images, model.toJSON()]);
return super.saveValues(req, res, next);
})
.catch(next);
}
return super.saveValues.apply(this, arguments);
}
};
32 changes: 21 additions & 11 deletions apps/paf/fields/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ module.exports = {
dependent: {
field: 'vehicle-type',
value: 'cars'
},
}
},
'crime-hgv-group': {
mixin: 'radio-group',
Expand All @@ -238,7 +238,7 @@ module.exports = {
dependent: {
field: 'vehicle-type',
value: 'hgvs'
},
}
},
'crime-lorry-group': {
mixin: 'radio-group',
Expand All @@ -252,7 +252,7 @@ module.exports = {
dependent: {
field: 'vehicle-type',
value: 'lorries'
},
}
},
'crime-van-group': {
mixin: 'radio-group',
Expand All @@ -268,7 +268,7 @@ module.exports = {
dependent: {
field: 'vehicle-type',
value: 'vans'
},
}
},
'boat-type': {
isPageHeading: true,
Expand Down Expand Up @@ -320,7 +320,7 @@ module.exports = {
dependent: {
field: 'boat-type',
value: 'carriers'
},
}
},
'crime-general-cargo-group': {
mixin: 'radio-group',
Expand All @@ -334,7 +334,7 @@ module.exports = {
dependent: {
field: 'boat-type',
value: 'general-cargos'
},
}
},
'crime-vessel-group': {
mixin: 'radio-group',
Expand All @@ -349,7 +349,7 @@ module.exports = {
dependent: {
field: 'boat-type',
value: 'vessels'
},
}
},
'boat-name': {
mixin: 'input-text'
Expand Down Expand Up @@ -913,7 +913,7 @@ module.exports = {
dependent: {
field: 'report-person-transport-type',
value: 'cars'
},
}
},
'report-person-transport-hgv-group': {
mixin: 'radio-group',
Expand All @@ -930,7 +930,7 @@ module.exports = {
dependent: {
field: 'report-person-transport-type',
value: 'hgv'
},
}
},
'report-person-transport-lorry-group': {
mixin: 'radio-group',
Expand All @@ -944,7 +944,7 @@ module.exports = {
dependent: {
field: 'report-person-transport-type',
value: 'lorries'
},
}
},
'report-person-transport-van-group': {
mixin: 'radio-group',
Expand All @@ -960,7 +960,7 @@ module.exports = {
dependent: {
field: 'report-person-transport-type',
value: 'vans'
},
}
},
'report-person-transport-make': {
mixin: 'input-text'
Expand Down Expand Up @@ -1167,6 +1167,16 @@ module.exports = {
value: 'yes'
}
},
'other-info-file-upload': {
mixin: 'input-file',
className: 'govuk-file-upload',
attributes: []
},
'add-other-info-file-upload': {
isPageHeading: true,
mixin: 'radio-group',
options: ['yes', 'no']
},
'about-you-first-name': {
mixin: 'input-text'
},
Expand Down
37 changes: 36 additions & 1 deletion apps/paf/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
'use strict';
const saveImage = require('./behaviours/save-file');
const removeImage = require('./behaviours/remove-file');
const CombineAndLoopFields = require('hof').components.combineAndLoopFields;
const limitDocs = require('./behaviours/limit-documents');
const disableUpload = require('./behaviours/disable-file-upload');
const SummaryPageBehaviour = require('hof').components.summary;
const transportBehaviour = require('./behaviours/transport-behaviour');
const Aggregate = require('./behaviours/aggregator');
Expand Down Expand Up @@ -356,7 +361,7 @@ module.exports = {
field: 'report-person-occupation',
value: 'yes'
}
},
}
]
},
'/report-person-occupation-type': {
Expand Down Expand Up @@ -662,6 +667,36 @@ module.exports = {
next: '/other-info-file-upload'
},
'/other-info-file-upload': {
behaviours: [saveImage('other-info-file-upload'), disableUpload],
fields: ['other-info-file-upload'],
continueOnEdit: true,
forks: [{
target: '/add-other-info-file-upload',
condition: req => {
if (req.form.values['other-info-file-upload']) {
return true
}
return false;
}
}],
next: '/about-you'
},
'/add-other-info-file-upload': {
template: 'list-add-looped-files',
behaviours: [CombineAndLoopFields({
groupName: 'other-info-file-uploads',
fieldsToGroup: [
'other-info-file-upload'
],
groupOptional: true,
removePrefix: 'other-',
combineValuesToSingleField: 'record',
returnTo: '/other-info-file-upload'
}), removeImage, limitDocs],
next: '/about-you',
locals: {
section: 'other-info-file-upload'
}
},
'/about-you': {
fields: ['how-did-you-find-out-about-the-crime'],
Expand Down
75 changes: 75 additions & 0 deletions apps/paf/models/file-upload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
'use strict';

const url = require('url');
const Model = require('hof').model;
const uuid = require('uuid').v4;
const config = require('../../../config');

module.exports = class UploadModel extends Model {
constructor(...args) {
super(...args);
this.set('id', uuid());
}

async save() {
const result = await new Promise((resolve, reject) => {
const attributes = {
url: config.upload.hostname
};
const reqConf = url.parse(this.url(attributes));
reqConf.formData = {
document: {
value: this.get('data'),
options: {
filename: this.get('name'),
contentType: this.get('mimetype')
}
}
};
reqConf.method = 'POST';
this.request(reqConf, (err, data) => {
if (err) {
return reject(err);
}
resolve(data);
});
});
this.set({ url: result.url });
return this.unset('data');
}

auth() {
if (!config.keycloak.token) {
// eslint-disable-next-line no-console
console.error('keycloak token url is not defined');
return Promise.resolve({
bearer: 'abc123'
});
}
const tokenReq = {
url: config.keycloak.token,
form: {
username: config.keycloak.username,
password: config.keycloak.password,
grant_type: 'password',
client_id: config.keycloak.clientId,
client_secret: config.keycloak.secret
},
method: 'POST'
};

return new Promise((resolve, reject) => {
this._request(tokenReq, (err, response) => {
const body = JSON.parse(response.body);

if (err || body.error) {
return reject(err || new Error(`${body.error} - ${body.error_description}`));
}

resolve({
bearer: JSON.parse(response.body).access_token
});
});
});
}
};
12 changes: 11 additions & 1 deletion apps/paf/sections/summary-data-sections.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,17 @@ module.exports = {
'other-info': [
'other-info-description',
'other-info-another-crime',
'other-info-another-crime-description'
'other-info-another-crime-description',
{
step: '/add-other-info-file-upload',
field: 'images',
parse: (list, req) => {
if (!req.sessionModel.get('images') ) {
return null;
}
return list && list.map(a => a.name).join('\n————————————————\n') || 'None';
}
}
],
'about-you': [
'how-did-you-find-out-about-the-crime',
Expand Down
18 changes: 18 additions & 0 deletions apps/paf/translations/src/en/fields.json
Original file line number Diff line number Diff line change
Expand Up @@ -1087,6 +1087,21 @@
},
"legendClassName": "govuk-fieldset__legend"
},
"other-info-file-upload": {
"hint": "You can add up to 3 documents",
"label": "Attachment"
},
"other-info-file-uploads-add-another": {
"options": {
"yes": {
"label": "Yes"
},
"no": {
"label": "No"
}
},
"legendClassName": "govuk-fieldset__legend"
},
"persons": {
"label": "Additional People",
"changeLinkDescription": "Additional People"
Expand Down Expand Up @@ -1356,5 +1371,8 @@
},
"when-to-contact": {
"label": "When would you like us to contact you?"
},
"images": {
"label": "Attachments"
}
}
Loading

0 comments on commit 84527e4

Please sign in to comment.