Skip to content

PUB-2806 Add functionality to re-submit subscription in blob explorer #1454

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Apr 11, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 22 additions & 8 deletions src/main/controllers/system-admin/BlobViewJsonController.ts
Original file line number Diff line number Diff line change
@@ -12,19 +12,14 @@ const locationService = new LocationService();
const userManagementService = new UserManagementService();
export default class BlobViewJsonController {
public async get(req: PipRequest, res: Response): Promise<void> {
const artefactId = req.query.artefactId as string;
const artefactId = req.query.artefactId;
const data = await publicationService.getIndividualPublicationJson(artefactId, req.user['userId']);
const metadata = await publicationService.getIndividualPublicationMetadata(artefactId, req.user['userId']);

if (isValidList(data, metadata)) {
const listTypes = publicationService.getListTypes();
const noMatchArtefact = metadata.locationId.toString().includes('NoMatch');
let courtName = '';
if (!noMatchArtefact) {
courtName = (await locationService.getLocationById(parseInt(metadata.locationId.toString()))).name;
} else {
courtName = 'No match artefacts';
}
const locationName = await BlobViewJsonController.getLocationName(metadata.locationId, noMatchArtefact);

await userManagementService.auditAction(
req.user,
@@ -38,7 +33,7 @@ export default class BlobViewJsonController {
res.render('system-admin/blob-view-json', {
...cloneDeep(req.i18n.getDataByLanguage(req.lng)['blob-view-json']),
data: JSON.stringify(data),
courtName,
locationName,
artefactId,
metadata,
listUrl,
@@ -50,4 +45,23 @@ export default class BlobViewJsonController {
res.render('error', req.i18n.getDataByLanguage(req.lng).error);
}
}

public async post(req: PipRequest, res: Response): Promise<void> {
const artefactId = req.query.artefactId;
if (artefactId) {
res.redirect(`blob-view-subscription-resubmit-confirmation?artefactId=${artefactId}`);
} else {
res.render('error', req.i18n.getDataByLanguage(req.lng).error);
}
}

private static async getLocationName(locationId, noMatchArtefact): Promise<string> {
let locationName = '';
if (!noMatchArtefact) {
locationName = (await locationService.getLocationById(parseInt(locationId.toString()))).name;
} else {
locationName = 'No match artefacts';
}
return locationName;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { PipRequest } from '../../models/request/PipRequest';
import { Response } from 'express';
import { cloneDeep } from 'lodash';
import { PublicationService } from '../../service/PublicationService';
import { LocationService } from '../../service/LocationService';
import { SubscriptionService } from '../../service/SubscriptionService';
import { UserManagementService } from '../../service/UserManagementService';

const publicationService = new PublicationService();
const locationService = new LocationService();
const subscriptionService = new SubscriptionService();
const userManagementService = new UserManagementService();

export default class BlobViewSubscriptionResubmitConfirmationController {
public async get(req: PipRequest, res: Response): Promise<void> {
const artefactId = req.query.artefactId;
if (artefactId) {
const metadata = await publicationService.getIndividualPublicationMetadata(artefactId, req.user['userId']);
const locationName = (await locationService.getLocationById(parseInt(metadata.locationId.toString()))).name;
res.render('system-admin/blob-view-subscription-resubmit-confirmation', {
...cloneDeep(req.i18n.getDataByLanguage(req.lng)['blob-view-subscription-resubmit-confirmation']),
locationName,
metadata,
});
} else {
res.render('error', req.i18n.getDataByLanguage(req.lng).error);
}
}

public async post(req: PipRequest, res: Response): Promise<void> {
const artefactId = req.query.artefactId;
if (artefactId) {
const response = await subscriptionService.fulfillSubscriptions(artefactId, req.user['userId']);
if (response) {
await userManagementService.auditAction(
req.user,
'RESUBMIT_SUBSCRIPTION',
`Subscriptions for publication with artefact id ${artefactId} re-submitted successfully`
);

res.redirect('blob-view-subscription-resubmit-confirmed');
} else {
res.render('error', req.i18n.getDataByLanguage(req.lng).error);
}
} else {
res.render('error', req.i18n.getDataByLanguage(req.lng).error);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { PipRequest } from '../../models/request/PipRequest';
import { Response } from 'express';

export default class BlobViewSubscriptionResubmitConfirmedController {
public async get(req: PipRequest, res: Response): Promise<void> {
res.render(
'system-admin/blob-view-subscription-resubmit-confirmed',
req.i18n.getDataByLanguage(req.lng)['blob-view-subscription-resubmit-confirmed']
);
}
}
4 changes: 4 additions & 0 deletions src/main/resources/auditActions.json
Original file line number Diff line number Diff line change
@@ -94,5 +94,9 @@
{
"key": "REJECT_MEDIA_APPLICATION",
"name": "Reject Media Application"
},
{
"key": "RESUBMIT_SUBSCRIPTION",
"name": "Re-submit subscription"
}
]
3 changes: 2 additions & 1 deletion src/main/resources/locales/cy/blob-view-json.json
Original file line number Diff line number Diff line change
@@ -3,5 +3,6 @@
"viewJson": "View Raw JSON Content",
"viewLink": "Link to rendered template",
"flatFile": "Flat file",
"jsonFile": "JSON file"
"jsonFile": "JSON file",
"resubmit": "Re-submit subscription"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"title": "Confirm subscription re-submission",
"confirmButton": "Confirm",
"cancelButton": "Cancel"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"title": "Subscription re-submitted",
"nextMessage": "What do you want to do next?",
"blobLocation": "Blob explorer - Locations"
}
3 changes: 2 additions & 1 deletion src/main/resources/locales/en/blob-view-json.json
Original file line number Diff line number Diff line change
@@ -3,5 +3,6 @@
"viewJson": "View Raw JSON Content",
"viewLink": "Link to rendered template",
"flatFile": "Flat file",
"jsonFile": "JSON file"
"jsonFile": "JSON file",
"resubmit": "Re-submit subscription"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"title": "Confirm subscription re-submission",
"confirmButton": "Confirm",
"cancelButton": "Cancel"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"title": "Subscription re-submitted",
"nextMessage": "What do you want to do next?",
"blobLocation": "Blob explorer - Locations"
}
10 changes: 10 additions & 0 deletions src/main/resources/requests/SubscriptionRequests.ts
Original file line number Diff line number Diff line change
@@ -92,4 +92,14 @@ export class SubscriptionRequests {
}
return null;
}

public async fulfillSubscriptions(artefact): Promise<string> {
try {
const response = await subscriptionManagementApi.post('/subscription/artefact-recipients', artefact);
return response.data;
} catch (error) {
logHelper.logErrorResponse(error, `fulfill subscriptions for artefact with ID ${artefact.arterfactId}`);
}
return null;
}
}
18 changes: 18 additions & 0 deletions src/main/routes/routes.ts
Original file line number Diff line number Diff line change
@@ -642,13 +642,31 @@ export default function (app: Application): void {
isPermittedSystemAdmin,
app.locals.container.cradle.systemAdminDashboardController.get
);

app.get('/blob-view-locations', isPermittedSystemAdmin, app.locals.container.cradle.blobViewLocationController.get);
app.get(
'/blob-view-publications',
isPermittedSystemAdmin,
app.locals.container.cradle.blobViewPublicationsController.get
);
app.get('/blob-view-json', isPermittedSystemAdmin, app.locals.container.cradle.blobViewJsonController.get);
app.post('/blob-view-json', isPermittedSystemAdmin, app.locals.container.cradle.blobViewJsonController.post);
app.get(
'/blob-view-subscription-resubmit-confirmation',
isPermittedSystemAdmin,
app.locals.container.cradle.blobViewSubscriptionResubmitConfirmationController.get
);
app.post(
'/blob-view-subscription-resubmit-confirmation',
isPermittedSystemAdmin,
app.locals.container.cradle.blobViewSubscriptionResubmitConfirmationController.post
);
app.get(
'/blob-view-subscription-resubmit-confirmed',
isPermittedSystemAdmin,
app.locals.container.cradle.blobViewSubscriptionResubmitConfirmedController.get
);

app.get(
'/bulk-create-media-accounts',
isPermittedSystemAdmin,
5 changes: 5 additions & 0 deletions src/main/service/SubscriptionService.ts
Original file line number Diff line number Diff line change
@@ -639,4 +639,9 @@ export class SubscriptionService {
});
pendingSubscriptionsFromCache.setListTypeSubscription(userId, [...new Set(selectedListTypes)]);
}

public async fulfillSubscriptions(artefactId, userId): Promise<string> {
const artefact = await publicationService.getIndividualPublicationMetadata(artefactId, userId);
return await subscriptionRequests.fulfillSubscriptions(artefact);
}
}
45 changes: 23 additions & 22 deletions src/main/views/system-admin/blob-view-json.njk
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
{% extends "../template.njk" %}
{% from "../macros/common-components.njk" import goBack %}
{% from "../macros/common-components.njk" import goBack, submitButton %}
{% from "govuk/components/summary-list/macro.njk" import govukSummaryList %}
{% from "govuk/components/details/macro.njk" import govukDetails %}

{% block head %}
{{ super() }}
{% endblock %}
{% block pageTitle %}
{{ title }}
{% endblock %}

{% block beforeContent %}

{{ super() }}
{{ goBack(text = backButton, cspNonce = cspNonce) }}
{{ goBack(cspNonce = cspNonce) }}
{% endblock %}

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

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

{{ govukSummaryList({
rows: [
{key: {text: "Artefact Id"}, value: { text: metadata.artefactId} },
{key: {text: "Language"}, value: { text: metadata.language | titleCase} },
{key: {text: "Location Id"}, value: { text: metadata.locationId} },
{key: {text: "Location Name"}, value: { text: courtName } },
{key: {text: "List Type"}, value: { text: metadata.listType | listType} },
{key: {text: "Provenance"}, value: { text: metadata.provenance} },
{key: {text: "Publication Type"}, value: { text: metadata.type | titleCase} },
{key: {text: "Sensitivity"}, value: { text: metadata.sensitivity | titleCase} },
{key: {text: "Content Date"}, value: { text: metadata.contentDate | date('Do MMMM YYYY [at] hh:mm a')} },
{key: {text: "Display From"}, value: { text: metadata.displayFrom | date('Do MMMM YYYY [at] hh:mm a')} },
{key: {text: "Display To"}, value: { text: metadata.displayTo | date('Do MMMM YYYY [at] hh:mm a')} }
]
}) }}
<h2 class="govuk-heading-m">Metadata</h2>
{{ govukSummaryList({
rows: [
{key: {text: "Artefact ID"}, value: { text: metadata.artefactId} },
{key: {text: "Location ID"}, value: { text: metadata.locationId} },
{key: {text: "Location Name"}, value: { text: locationName } },
{key: {text: "Publication Type"}, value: { text: metadata.type | titleCase} },
{key: {text: "List Type"}, value: { text: metadata.listType | listType} },
{key: {text: "Provenance"}, value: { text: metadata.provenance} },
{key: {text: "Language"}, value: { text: metadata.language | titleCase} },
{key: {text: "Sensitivity"}, value: { text: metadata.sensitivity | titleCase} },
{key: {text: "Content Date"}, value: { text: metadata.contentDate | date('Do MMMM YYYY [at] hh:mm a')} },
{key: {text: "Display From"}, value: { text: metadata.displayFrom | date('Do MMMM YYYY [at] hh:mm a')} },
{key: {text: "Display To"}, value: { text: metadata.displayTo | date('Do MMMM YYYY [at] hh:mm a')} }
]
}) }}
</form>
</div>
</div>
{% if not noMatchArtefact %}
2 changes: 1 addition & 1 deletion src/main/views/system-admin/blob-view-locations.njk
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@

{% block beforeContent %}
{{ super() }}
{{ goBack(text = backButton, cspNonce = cspNonce) }}
{{ goBack(cspNonce = cspNonce) }}
{% endblock %}

{% block content %}
2 changes: 1 addition & 1 deletion src/main/views/system-admin/blob-view-publications.njk
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@

{% block beforeContent %}
{{ super() }}
{{ goBack(text = backButton, cspNonce = cspNonce) }}
{{ goBack(cspNonce = cspNonce) }}
{% endblock %}

{% block content %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{% extends "../template.njk" %}
{% from "../macros/common-components.njk" import goBack, submitButton %}
{% from "govuk/components/summary-list/macro.njk" import govukSummaryList %}

{% block pageTitle %}
{{ title }}
{% endblock %}

{% block beforeContent %}
{{ super() }}
{{ goBack(cspNonce = cspNonce) }}
{% endblock %}

{% block content %}
<div class="parent-box">
<h1 class="govuk-heading-l">{{ title }}</h1>
<form method="post">
{{ govukSummaryList({
rows: [
{key: {text: "Location Name"}, value: { text: locationName } },
{key: {text: "Publication Type"}, value: { text: metadata.type | titleCase} },
{key: {text: "List Type"}, value: { text: metadata.listType | listType} },
{key: {text: "Provenance"}, value: { text: metadata.provenance} },
{key: {text: "Language"}, value: { text: metadata.language | titleCase} },
{key: {text: "Sensitivity"}, value: { text: metadata.sensitivity | titleCase} },
{key: {text: "Content Date"}, value: { text: metadata.contentDate | date('Do MMMM YYYY [at] hh:mm a')} },
{key: {text: "Display From"}, value: { text: metadata.displayFrom | date('Do MMMM YYYY [at] hh:mm a')} },
{key: {text: "Display To"}, value: { text: metadata.displayTo | date('Do MMMM YYYY [at] hh:mm a')} }
]
}) }}
<div class="govuk-button-group">
{{ submitButton(label = confirmButton, id = 'confirm-resubmit-subscription') }}
<a class="govuk-link" id='cancel-resubmit-subscription' href='blob-view-locations'>{{ cancelButton }}</a>
</div>
</form>
{{ super() }}
</div>
{% endblock %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{% extends "../template.njk" %}
{% from "../macros/common-components.njk" import goBack, successPanel %}

{% block pageTitle %}
{{ title }}
{% endblock %}

{% block beforeContent %}
{{ super() }}
{{ goBack(cspNonce = cspNonce) }}
{% endblock %}

{% block content %}
{{ successPanel(title) }}
<p class="govuk-body govuk-!-font-weight-bold govuk-!-margin-top-6">{{ nextMessage }}</p>
<p class="govuk-body govuk-!-margin-0 govuk-!-font-weight-bold"><a class="govuk-link " href="blob-view-locations">{{ blobLocation }}</a></p>
{% endblock %}
4 changes: 4 additions & 0 deletions src/test/a11y/tests/system-admin-routes.test.ts
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@ import { AuditLogService } from '../../../main/service/AuditLogService';
import fs from 'fs';
import path from 'path';
import { v4 as uuidv4 } from 'uuid';
import { SubscriptionService } from '../../../main/service/SubscriptionService';

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

describe('Accessibility - System Admin Routes', () => {
app.request['cookies'] = {
2 changes: 1 addition & 1 deletion src/test/end-to-end/tests/system-admin/audit-log-test.ts
Original file line number Diff line number Diff line change
@@ -92,7 +92,7 @@ Scenario('I as a system admin should be able to view audit log for admin delete
I.fillField('#filterDate-day', padFormatted(date.getDate()) as string);
I.fillField('#filterDate-month', padFormatted(date.getMonth() + 1));
I.fillField('#filterDate-year', date.getFullYear());
I.checkOption('#actions-20');
I.checkOption('#actions-21');
I.click('Apply filters');

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