Skip to content

Commit 96cc13c

Browse files
PUB-2806 Add functionality to re-submit subscription in blob explorer (#1454)
* Add functionality to re-submit subscription in blob explorer * lint fixes * Fixed failing a11y tests * Small fixes * Added e2e test * Lint fix * Split our blob e2e test * Fix failing test * Mark test as nightly * Code review fixes * Lint fixes * Fixed failing unit tests * Add audit action * Update e2e test --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent f8b4009 commit 96cc13c

32 files changed

+1104
-307
lines changed

src/main/controllers/system-admin/BlobViewJsonController.ts

+22-8
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,14 @@ const locationService = new LocationService();
1212
const userManagementService = new UserManagementService();
1313
export default class BlobViewJsonController {
1414
public async get(req: PipRequest, res: Response): Promise<void> {
15-
const artefactId = req.query.artefactId as string;
15+
const artefactId = req.query.artefactId;
1616
const data = await publicationService.getIndividualPublicationJson(artefactId, req.user['userId']);
1717
const metadata = await publicationService.getIndividualPublicationMetadata(artefactId, req.user['userId']);
1818

1919
if (isValidList(data, metadata)) {
2020
const listTypes = publicationService.getListTypes();
2121
const noMatchArtefact = metadata.locationId.toString().includes('NoMatch');
22-
let courtName = '';
23-
if (!noMatchArtefact) {
24-
courtName = (await locationService.getLocationById(parseInt(metadata.locationId.toString()))).name;
25-
} else {
26-
courtName = 'No match artefacts';
27-
}
22+
const locationName = await BlobViewJsonController.getLocationName(metadata.locationId, noMatchArtefact);
2823

2924
await userManagementService.auditAction(
3025
req.user,
@@ -38,7 +33,7 @@ export default class BlobViewJsonController {
3833
res.render('system-admin/blob-view-json', {
3934
...cloneDeep(req.i18n.getDataByLanguage(req.lng)['blob-view-json']),
4035
data: JSON.stringify(data),
41-
courtName,
36+
locationName,
4237
artefactId,
4338
metadata,
4439
listUrl,
@@ -50,4 +45,23 @@ export default class BlobViewJsonController {
5045
res.render('error', req.i18n.getDataByLanguage(req.lng).error);
5146
}
5247
}
48+
49+
public async post(req: PipRequest, res: Response): Promise<void> {
50+
const artefactId = req.query.artefactId;
51+
if (artefactId) {
52+
res.redirect(`blob-view-subscription-resubmit-confirmation?artefactId=${artefactId}`);
53+
} else {
54+
res.render('error', req.i18n.getDataByLanguage(req.lng).error);
55+
}
56+
}
57+
58+
private static async getLocationName(locationId, noMatchArtefact): Promise<string> {
59+
let locationName = '';
60+
if (!noMatchArtefact) {
61+
locationName = (await locationService.getLocationById(parseInt(locationId.toString()))).name;
62+
} else {
63+
locationName = 'No match artefacts';
64+
}
65+
return locationName;
66+
}
5367
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { PipRequest } from '../../models/request/PipRequest';
2+
import { Response } from 'express';
3+
import { cloneDeep } from 'lodash';
4+
import { PublicationService } from '../../service/PublicationService';
5+
import { LocationService } from '../../service/LocationService';
6+
import { SubscriptionService } from '../../service/SubscriptionService';
7+
import { UserManagementService } from '../../service/UserManagementService';
8+
9+
const publicationService = new PublicationService();
10+
const locationService = new LocationService();
11+
const subscriptionService = new SubscriptionService();
12+
const userManagementService = new UserManagementService();
13+
14+
export default class BlobViewSubscriptionResubmitConfirmationController {
15+
public async get(req: PipRequest, res: Response): Promise<void> {
16+
const artefactId = req.query.artefactId;
17+
if (artefactId) {
18+
const metadata = await publicationService.getIndividualPublicationMetadata(artefactId, req.user['userId']);
19+
const locationName = (await locationService.getLocationById(parseInt(metadata.locationId.toString()))).name;
20+
res.render('system-admin/blob-view-subscription-resubmit-confirmation', {
21+
...cloneDeep(req.i18n.getDataByLanguage(req.lng)['blob-view-subscription-resubmit-confirmation']),
22+
locationName,
23+
metadata,
24+
});
25+
} else {
26+
res.render('error', req.i18n.getDataByLanguage(req.lng).error);
27+
}
28+
}
29+
30+
public async post(req: PipRequest, res: Response): Promise<void> {
31+
const artefactId = req.query.artefactId;
32+
if (artefactId) {
33+
const response = await subscriptionService.fulfillSubscriptions(artefactId, req.user['userId']);
34+
if (response) {
35+
await userManagementService.auditAction(
36+
req.user,
37+
'RESUBMIT_SUBSCRIPTION',
38+
`Subscriptions for publication with artefact id ${artefactId} re-submitted successfully`
39+
);
40+
41+
res.redirect('blob-view-subscription-resubmit-confirmed');
42+
} else {
43+
res.render('error', req.i18n.getDataByLanguage(req.lng).error);
44+
}
45+
} else {
46+
res.render('error', req.i18n.getDataByLanguage(req.lng).error);
47+
}
48+
}
49+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { PipRequest } from '../../models/request/PipRequest';
2+
import { Response } from 'express';
3+
4+
export default class BlobViewSubscriptionResubmitConfirmedController {
5+
public async get(req: PipRequest, res: Response): Promise<void> {
6+
res.render(
7+
'system-admin/blob-view-subscription-resubmit-confirmed',
8+
req.i18n.getDataByLanguage(req.lng)['blob-view-subscription-resubmit-confirmed']
9+
);
10+
}
11+
}

src/main/resources/auditActions.json

+4
Original file line numberDiff line numberDiff line change
@@ -94,5 +94,9 @@
9494
{
9595
"key": "REJECT_MEDIA_APPLICATION",
9696
"name": "Reject Media Application"
97+
},
98+
{
99+
"key": "RESUBMIT_SUBSCRIPTION",
100+
"name": "Re-submit subscription"
97101
}
98102
]

src/main/resources/locales/cy/blob-view-json.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@
33
"viewJson": "View Raw JSON Content",
44
"viewLink": "Link to rendered template",
55
"flatFile": "Flat file",
6-
"jsonFile": "JSON file"
6+
"jsonFile": "JSON file",
7+
"resubmit": "Re-submit subscription"
78
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"title": "Confirm subscription re-submission",
3+
"confirmButton": "Confirm",
4+
"cancelButton": "Cancel"
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"title": "Subscription re-submitted",
3+
"nextMessage": "What do you want to do next?",
4+
"blobLocation": "Blob explorer - Locations"
5+
}

src/main/resources/locales/en/blob-view-json.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@
33
"viewJson": "View Raw JSON Content",
44
"viewLink": "Link to rendered template",
55
"flatFile": "Flat file",
6-
"jsonFile": "JSON file"
6+
"jsonFile": "JSON file",
7+
"resubmit": "Re-submit subscription"
78
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"title": "Confirm subscription re-submission",
3+
"confirmButton": "Confirm",
4+
"cancelButton": "Cancel"
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"title": "Subscription re-submitted",
3+
"nextMessage": "What do you want to do next?",
4+
"blobLocation": "Blob explorer - Locations"
5+
}

src/main/resources/requests/SubscriptionRequests.ts

+10
Original file line numberDiff line numberDiff line change
@@ -92,4 +92,14 @@ export class SubscriptionRequests {
9292
}
9393
return null;
9494
}
95+
96+
public async fulfillSubscriptions(artefact): Promise<string> {
97+
try {
98+
const response = await subscriptionManagementApi.post('/subscription/artefact-recipients', artefact);
99+
return response.data;
100+
} catch (error) {
101+
logHelper.logErrorResponse(error, `fulfill subscriptions for artefact with ID ${artefact.arterfactId}`);
102+
}
103+
return null;
104+
}
95105
}

src/main/routes/routes.ts

+18
Original file line numberDiff line numberDiff line change
@@ -642,13 +642,31 @@ export default function (app: Application): void {
642642
isPermittedSystemAdmin,
643643
app.locals.container.cradle.systemAdminDashboardController.get
644644
);
645+
645646
app.get('/blob-view-locations', isPermittedSystemAdmin, app.locals.container.cradle.blobViewLocationController.get);
646647
app.get(
647648
'/blob-view-publications',
648649
isPermittedSystemAdmin,
649650
app.locals.container.cradle.blobViewPublicationsController.get
650651
);
651652
app.get('/blob-view-json', isPermittedSystemAdmin, app.locals.container.cradle.blobViewJsonController.get);
653+
app.post('/blob-view-json', isPermittedSystemAdmin, app.locals.container.cradle.blobViewJsonController.post);
654+
app.get(
655+
'/blob-view-subscription-resubmit-confirmation',
656+
isPermittedSystemAdmin,
657+
app.locals.container.cradle.blobViewSubscriptionResubmitConfirmationController.get
658+
);
659+
app.post(
660+
'/blob-view-subscription-resubmit-confirmation',
661+
isPermittedSystemAdmin,
662+
app.locals.container.cradle.blobViewSubscriptionResubmitConfirmationController.post
663+
);
664+
app.get(
665+
'/blob-view-subscription-resubmit-confirmed',
666+
isPermittedSystemAdmin,
667+
app.locals.container.cradle.blobViewSubscriptionResubmitConfirmedController.get
668+
);
669+
652670
app.get(
653671
'/bulk-create-media-accounts',
654672
isPermittedSystemAdmin,

src/main/service/SubscriptionService.ts

+5
Original file line numberDiff line numberDiff line change
@@ -639,4 +639,9 @@ export class SubscriptionService {
639639
});
640640
pendingSubscriptionsFromCache.setListTypeSubscription(userId, [...new Set(selectedListTypes)]);
641641
}
642+
643+
public async fulfillSubscriptions(artefactId, userId): Promise<string> {
644+
const artefact = await publicationService.getIndividualPublicationMetadata(artefactId, userId);
645+
return await subscriptionRequests.fulfillSubscriptions(artefact);
646+
}
642647
}

src/main/views/system-admin/blob-view-json.njk

+23-22
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,15 @@
11
{% extends "../template.njk" %}
2-
{% from "../macros/common-components.njk" import goBack %}
2+
{% from "../macros/common-components.njk" import goBack, submitButton %}
33
{% from "govuk/components/summary-list/macro.njk" import govukSummaryList %}
44
{% from "govuk/components/details/macro.njk" import govukDetails %}
55

6-
{% block head %}
7-
{{ super() }}
8-
{% endblock %}
96
{% block pageTitle %}
107
{{ title }}
118
{% endblock %}
129

1310
{% block beforeContent %}
14-
1511
{{ super() }}
16-
{{ goBack(text = backButton, cspNonce = cspNonce) }}
12+
{{ goBack(cspNonce = cspNonce) }}
1713
{% endblock %}
1814

1915
{% block content %}
@@ -27,23 +23,28 @@
2723
{% endif %}</h1>
2824

2925
<div id="section1">
30-
<h2 class="govuk-heading-m">Metadata</h2>
26+
<form method="post">
27+
{% if not noMatchArtefact %}
28+
{{ submitButton(label = resubmit, id = 'resubmit-subscription') }}
29+
{% endif %}
3130

32-
{{ govukSummaryList({
33-
rows: [
34-
{key: {text: "Artefact Id"}, value: { text: metadata.artefactId} },
35-
{key: {text: "Language"}, value: { text: metadata.language | titleCase} },
36-
{key: {text: "Location Id"}, value: { text: metadata.locationId} },
37-
{key: {text: "Location Name"}, value: { text: courtName } },
38-
{key: {text: "List Type"}, value: { text: metadata.listType | listType} },
39-
{key: {text: "Provenance"}, value: { text: metadata.provenance} },
40-
{key: {text: "Publication Type"}, value: { text: metadata.type | titleCase} },
41-
{key: {text: "Sensitivity"}, value: { text: metadata.sensitivity | titleCase} },
42-
{key: {text: "Content Date"}, value: { text: metadata.contentDate | date('Do MMMM YYYY [at] hh:mm a')} },
43-
{key: {text: "Display From"}, value: { text: metadata.displayFrom | date('Do MMMM YYYY [at] hh:mm a')} },
44-
{key: {text: "Display To"}, value: { text: metadata.displayTo | date('Do MMMM YYYY [at] hh:mm a')} }
45-
]
46-
}) }}
31+
<h2 class="govuk-heading-m">Metadata</h2>
32+
{{ govukSummaryList({
33+
rows: [
34+
{key: {text: "Artefact ID"}, value: { text: metadata.artefactId} },
35+
{key: {text: "Location ID"}, value: { text: metadata.locationId} },
36+
{key: {text: "Location Name"}, value: { text: locationName } },
37+
{key: {text: "Publication Type"}, value: { text: metadata.type | titleCase} },
38+
{key: {text: "List Type"}, value: { text: metadata.listType | listType} },
39+
{key: {text: "Provenance"}, value: { text: metadata.provenance} },
40+
{key: {text: "Language"}, value: { text: metadata.language | titleCase} },
41+
{key: {text: "Sensitivity"}, value: { text: metadata.sensitivity | titleCase} },
42+
{key: {text: "Content Date"}, value: { text: metadata.contentDate | date('Do MMMM YYYY [at] hh:mm a')} },
43+
{key: {text: "Display From"}, value: { text: metadata.displayFrom | date('Do MMMM YYYY [at] hh:mm a')} },
44+
{key: {text: "Display To"}, value: { text: metadata.displayTo | date('Do MMMM YYYY [at] hh:mm a')} }
45+
]
46+
}) }}
47+
</form>
4748
</div>
4849
</div>
4950
{% if not noMatchArtefact %}

src/main/views/system-admin/blob-view-locations.njk

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
{% block beforeContent %}
1010
{{ super() }}
11-
{{ goBack(text = backButton, cspNonce = cspNonce) }}
11+
{{ goBack(cspNonce = cspNonce) }}
1212
{% endblock %}
1313

1414
{% block content %}

src/main/views/system-admin/blob-view-publications.njk

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
{% block beforeContent %}
1010
{{ super() }}
11-
{{ goBack(text = backButton, cspNonce = cspNonce) }}
11+
{{ goBack(cspNonce = cspNonce) }}
1212
{% endblock %}
1313

1414
{% block content %}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{% extends "../template.njk" %}
2+
{% from "../macros/common-components.njk" import goBack, submitButton %}
3+
{% from "govuk/components/summary-list/macro.njk" import govukSummaryList %}
4+
5+
{% block pageTitle %}
6+
{{ title }}
7+
{% endblock %}
8+
9+
{% block beforeContent %}
10+
{{ super() }}
11+
{{ goBack(cspNonce = cspNonce) }}
12+
{% endblock %}
13+
14+
{% block content %}
15+
<div class="parent-box">
16+
<h1 class="govuk-heading-l">{{ title }}</h1>
17+
<form method="post">
18+
{{ govukSummaryList({
19+
rows: [
20+
{key: {text: "Location Name"}, value: { text: locationName } },
21+
{key: {text: "Publication Type"}, value: { text: metadata.type | titleCase} },
22+
{key: {text: "List Type"}, value: { text: metadata.listType | listType} },
23+
{key: {text: "Provenance"}, value: { text: metadata.provenance} },
24+
{key: {text: "Language"}, value: { text: metadata.language | titleCase} },
25+
{key: {text: "Sensitivity"}, value: { text: metadata.sensitivity | titleCase} },
26+
{key: {text: "Content Date"}, value: { text: metadata.contentDate | date('Do MMMM YYYY [at] hh:mm a')} },
27+
{key: {text: "Display From"}, value: { text: metadata.displayFrom | date('Do MMMM YYYY [at] hh:mm a')} },
28+
{key: {text: "Display To"}, value: { text: metadata.displayTo | date('Do MMMM YYYY [at] hh:mm a')} }
29+
]
30+
}) }}
31+
<div class="govuk-button-group">
32+
{{ submitButton(label = confirmButton, id = 'confirm-resubmit-subscription') }}
33+
<a class="govuk-link" id='cancel-resubmit-subscription' href='blob-view-locations'>{{ cancelButton }}</a>
34+
</div>
35+
</form>
36+
{{ super() }}
37+
</div>
38+
{% endblock %}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{% extends "../template.njk" %}
2+
{% from "../macros/common-components.njk" import goBack, successPanel %}
3+
4+
{% block pageTitle %}
5+
{{ title }}
6+
{% endblock %}
7+
8+
{% block beforeContent %}
9+
{{ super() }}
10+
{{ goBack(cspNonce = cspNonce) }}
11+
{% endblock %}
12+
13+
{% block content %}
14+
{{ successPanel(title) }}
15+
<p class="govuk-body govuk-!-font-weight-bold govuk-!-margin-top-6">{{ nextMessage }}</p>
16+
<p class="govuk-body govuk-!-margin-0 govuk-!-font-weight-bold"><a class="govuk-link " href="blob-view-locations">{{ blobLocation }}</a></p>
17+
{% endblock %}

src/test/a11y/tests/system-admin-routes.test.ts

+4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { AuditLogService } from '../../../main/service/AuditLogService';
2020
import fs from 'fs';
2121
import path from 'path';
2222
import { v4 as uuidv4 } from 'uuid';
23+
import { SubscriptionService } from '../../../main/service/SubscriptionService';
2324

2425
const userId = '1';
2526
const name = 'Test';
@@ -32,6 +33,8 @@ const systemAdminRoutes = [
3233
{ path: '/blob-view-locations' },
3334
{ path: '/blob-view-publications', parameter: '?locationId=123' },
3435
{ path: '/blob-view-json', parameter: '?artefactId=abc' },
36+
{ path: '/blob-view-subscription-resubmit-confirmation', parameter: '?artefactId=abc' },
37+
{ path: '/blob-view-subscription-resubmit-confirmed' },
3538
{ path: '/bulk-create-media-accounts', parameter: '?locationId=123' },
3639
{ path: '/bulk-create-media-accounts-confirmation', parameter: '?artefactId=abc' },
3740
{ path: '/bulk-create-media-accounts-confirmed' },
@@ -103,6 +106,7 @@ sinon.stub(FileHandlingService.prototype, 'readCsvToArray').returns([
103106
]);
104107
sinon.stub(UserManagementService.prototype, 'getFormattedData').resolves(userPageData);
105108
sinon.stub(AuditLogService.prototype, 'getFormattedAuditData').returns(auditLogPageData);
109+
sinon.stub(SubscriptionService.prototype, 'fulfillSubscriptions').resolves('success');
106110

107111
describe('Accessibility - System Admin Routes', () => {
108112
app.request['cookies'] = {

src/test/end-to-end/tests/system-admin/audit-log-test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ Scenario('I as a system admin should be able to view audit log for admin delete
9292
I.fillField('#filterDate-day', padFormatted(date.getDate()) as string);
9393
I.fillField('#filterDate-month', padFormatted(date.getMonth() + 1));
9494
I.fillField('#filterDate-year', date.getFullYear());
95-
I.checkOption('#actions-20');
95+
I.checkOption('#actions-21');
9696
I.click('Apply filters');
9797

9898
const publicationLocator = locate('//tr').withText('Upload Publication').find('a').withText('View');

0 commit comments

Comments
 (0)