Skip to content
Open
Show file tree
Hide file tree
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
70 changes: 70 additions & 0 deletions src/main/controllers/style-guide/CrownWarnedPddaListController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { PipRequest } from '../../models/request/PipRequest';
import { Response } from 'express';
import { formatMetaDataListType, isUnexpectedListType, isValidList, isValidListType } from '../../helpers/listHelper';
import { HttpStatusCode } from 'axios';
import { cloneDeep } from 'lodash';
import { ListParseHelperService } from '../../service/ListParseHelperService';
import { LocationService } from '../../service/LocationService';
import { PublicationService } from '../../service/PublicationService';
import { formatDate } from '../../helpers/dateTimeHelper';
import { CrownPddaListService } from '../../service/listManipulation/CrownPddaListService';
import { CrownWarnedPddaListService } from '../../service/listManipulation/CrownWarnedPddaListService';
import { CrownWarnedListService } from '../../service/listManipulation/CrownWarnedListService';

const publicationService = new PublicationService();
const locationService = new LocationService();
const helperService = new ListParseHelperService();
const crownPddaListService = new CrownPddaListService();
const crownWarnedPddaListService = new CrownWarnedPddaListService();
const crownWarnedListService = new CrownWarnedListService();
const listType = 'crown-warned-pdda-list';

export default class CrownWarnedPddaListController {
public async get(req: PipRequest, res: Response): Promise<void> {
const artefactId = req.query.artefactId as string;
const payload = await publicationService.getIndividualPublicationJson(artefactId, req.user?.['userId']);
const metadata = await publicationService.getIndividualPublicationMetadata(artefactId, req.user?.['userId']);
const metadataListType = formatMetaDataListType(metadata);

if (isValidList(payload, metadata) && isValidListType(metadataListType, listType)) {
const returnedLocation = await locationService.getLocationById(metadata['locationId']);
const locationName = locationService.findCourtName(returnedLocation, req.lng, listType);

const listPayload = payload['WarnedList'];
const listHeader = listPayload.ListHeader;
const publishedDate = helperService.publicationDateInUkTime(listHeader.PublishedTime, req.lng);
const publishedTime = helperService.publicationTimeInUkTime(listHeader.PublishedTime);
const startDate = formatDate(crownPddaListService.toIsoDate(listHeader.StartDate), 'dd MMMM yyyy', req.lng);
const endDate = listHeader.EndDate
? formatDate(crownPddaListService.toIsoDate(listHeader.EndDate), 'dd MMMM yyyy', req.lng)
: '';
const version = listHeader.Version;
const venueAddress = crownPddaListService.formatAddress(listPayload.CrownCourt.CourtHouseAddress);

const listData = crownWarnedPddaListService.processPayload(payload as JSON);

res.render(`style-guide/${listType}`, {
...cloneDeep(req.i18n.getDataByLanguage(req.lng)[listType]),
...cloneDeep(req.i18n.getDataByLanguage(req.lng)['list-template']),
listData: listData,
locationName: locationName,
contentDate: crownWarnedListService.formatContentDate(metadata.contentDate, req.lng),
provenance: metadata.provenance,
publishedDate,
publishedTime,
startDate,
endDate,
version,
venueAddress,
});
} else if (
payload === HttpStatusCode.NotFound ||
metadata === HttpStatusCode.NotFound ||
isUnexpectedListType(metadataListType, listType)
) {
res.render('list-not-found', req.i18n.getDataByLanguage(req.lng)['list-not-found']);
} else {
res.render('error', req.i18n.getDataByLanguage(req.lng).error);
}
}
}
10 changes: 10 additions & 0 deletions src/main/resources/listLookup.json
Original file line number Diff line number Diff line change
Expand Up @@ -947,5 +947,15 @@
"restrictedProvenances": [],
"defaultSensitivity": "CLASSIFIED",
"isNonStrategic": false
},
"CROWN_WARNED_PDDA_LIST": {
"friendlyName": "Crown Warned PDDA List",
"welshFriendlyName": "Rhestr Rybudd PDDA Llys y Goron",
"shortenedFriendlyName": "Crown Warned PDDA List",
"url": "crown-warned-pdda-list",
"jurisdictionTypes": ["Crown Court"],
"restrictedProvenances": [],
"defaultSensitivity": "CLASSIFIED",
"isNonStrategic": false
}
}
30 changes: 30 additions & 0 deletions src/main/resources/locales/cy/crown-warned-pdda-list.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"title": "Rhestr Rybuddio Llys y Goron",
"heading": "Rhestr Rybuddio Llys y Goron ar gyfer",
"listUpdated": "Diweddarwyd diwethaf DATE am",
"to": "i",
"headingP1": "Rhoir rhybudd yng nghyswllt yr achosion isod am gyfnod gwrandawiad o'r wythnos yn dechrau",
"headingP2": "Dylid cyflwyno unrhyw sylwadau am restru achos i’r Swyddog Rhestru yn ddi-oed",
"headingP3": "Yr awdurdod erlyn yw Gwasanaeth Erlyn y Goron oni nodir yn wahanol",
"headingP4": "Mae (*) yn dynodi diffynnydd a gedwir yn y ddalfa",
"restrictionInformationHeading": "Cyfyngiadau ar gyhoeddi neu ysgrifennu am yr achosion hyn.",
"restrictionInformationP1": "Rhaid i chi wirio a oes unrhyw gyfyngiadau riportio yn berthnasol cyn cyhoeddi manylion am unrhyw un o'r achosion a restrir yma, naill ai'n ysgrifenedig, mewn darllediad neu ar y rhyngrwyd, gan gynnwys y cyfryngau cymdeithasol.",
"restrictionInformationBoldText": "Byddwch yn euog o ddirmyg llys os byddwch yn cyhoeddi unrhyw wybodaeth sydd wedi'i diogelu gan gyfyngiad riportio. Gallwch gael dirwy, eich dedfrydu i garchar, neu'r ddau.",
"restrictionInformationP2": "Bydd cyfyngiadau penodol a orchmynnir gan y llys yn cael eu crybwyll ar yr achosion a restrir yma.",
"restrictionInformationP3": "Fodd bynnag, nid yw'r cyfyngiadau bob amser yn cael eu rhestru. Mae rhai yn berthnasol yn awtomatig. Er enghraifft, anhysbysrwydd a roddir i ddioddefwyr rhai troseddau rhywiol.",
"restrictionInformationP4": "I ganfod pa gyfyngiadau riportio sy'n berthnasol ar achos penodol, cysylltwch â'r:",
"restrictionBulletPoint1": "llys yn uniongyrchol",
"restrictionBulletPoint2": "Gwasanaeth Llysoedd a Thribiwnlysoedd EM ar 0330 808 4407",
"versionText": "Fersiwn",
"tableHeaders": [
"Pennu ar gyfer",
"Cyfeirnod yr Achos",
"Enw'r Diffynnydd",
"Yr Awdurdod sy'n Erlyn",
"Achosion cysylltiedig",
"Nodiadau rhestru"
],
"toBeAllocatedText": "I'w neilltuo",
"dataSource": "Ffynhonnell Data",
"backButton": "Yn ôl"
}
30 changes: 30 additions & 0 deletions src/main/resources/locales/en/crown-warned-pdda-list.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"title": "Crown Warned List",
"heading": "Crown Warned List for",
"listUpdated": "Last updated DATE at",
"to": "to",
"headingP1": "The undermentioned cases are warned for the hearing period of week commencing",
"headingP2": "Any representation about the listing of a case should be made to the Listing Officer immediately",
"headingP3": "The prosecuting authority is the Crown Prosecution Service unless otherwise stated",
"headingP4": "*denotes a defendant in custody",
"restrictionInformationHeading": "Restrictions on publishing or writing about these cases",
"restrictionInformationP1": "You must check if any reporting restrictions apply before publishing details on any of the cases listed here either in writing, in a broadcast or by internet, including social media.",
"restrictionInformationBoldText": "You'll be in contempt of court if you publish any information which is protected by a reporting restriction. You could get a fine, prison sentence or both.",
"restrictionInformationP2": "Specific restrictions ordered by the court will be mentioned on the cases listed here.",
"restrictionInformationP3": "However, restrictions are not always listed. Some apply automatically. For example, anonymity given to the victims of certain sexual offences.",
"restrictionInformationP4": "To find out which reporting restrictions apply on a specific case, contact:",
"restrictionBulletPoint1": "the court directly",
"restrictionBulletPoint2": "HM Courts and Tribunals Service on 0330 808 4407",
"versionText": "Version",
"tableHeaders": [
"Fixed For",
"Case Reference",
"Defendant Name(s)",
"Prosecuting Authority",
"Linked Cases",
"Listing Notes"
],
"toBeAllocatedText": "To be allocated",
"dataSource": "Data Source",
"backButton": "Back"
}
1 change: 1 addition & 0 deletions src/main/routes/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ export default function (app: Application): void {
app.get('/crown-firm-pdda-list', (req, res) =>
app.locals.container.cradle.crownPddaListController.get(req, res, 'crown-firm-pdda-list')
);
app.get('/crown-warned-pdda-list', app.locals.container.cradle.crownWarnedPddaListController.get);

//Non-Strategic Paths
app.get('/cst-weekly-hearing-list', (req, res) =>
Expand Down
2 changes: 1 addition & 1 deletion src/main/service/listManipulation/CrownPddaListService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export class CrownPddaListService {
return names.filter(name => name.trim().length > 0).join(', ');
}

private formatDefendantName(defendants): string {
formatDefendantName(defendants): string {
const names = [];
defendants.forEach(defendant => {
names.push(this.useMaskedNameIfRequested(defendant.PersonalDetails));
Expand Down
60 changes: 60 additions & 0 deletions src/main/service/listManipulation/CrownWarnedPddaListService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { CrownPddaListService } from './CrownPddaListService';

const crownPddaListService = new CrownPddaListService();

export class CrownWarnedPddaListService {
public processPayload(warnedPddaListData: JSON): Map<string, object[]> {
const groupedData = new Map<string, object[]>();

warnedPddaListData['WarnedList'].CourtLists.forEach((courtList: any) => {
courtList.WithFixedDate?.forEach((withFixDate: any) => {
this.formatFixture(withFixDate, groupedData, false);
});
courtList.WithoutFixedDate?.forEach((withoutFixDate: any) => {
this.formatFixture(withoutFixDate, groupedData, true);
});
});

// Sort cases by fixed date within each group
groupedData.forEach(cases => {
cases.sort((a: any, b: any) => new Date(a.fixedDate).getTime() - new Date(b.fixedDate).getTime());
});

return groupedData;
}

private formatFixture(fixtureDate: any, groupedData: Map<string, object[]>, isWithoutFixeDate: boolean): any {
const fixedDate = fixtureDate.Fixture.FixedDate;
fixtureDate.Fixture.Cases.forEach((hearingCase: any) => {
hearingCase.Hearing.forEach((hearing: any) => {
const hearingDescription = !isWithoutFixeDate ? hearing.HearingDescription : 'To be allocated';
if (!groupedData.has(hearingDescription)) {
groupedData.set(hearingDescription, []);
}

groupedData.get(hearingDescription)!.push(this.formatCaseInformation(fixedDate, hearing, hearingCase));
});
});
}

private formatCaseInformation(fixedDate: any, hearing: any, hearingCase: any): any {
const caseReference = hearingCase.CaseNumberCaTH;
const defendantNames = hearingCase.Defendants
? crownPddaListService.formatDefendantName(hearingCase.Defendants)
: '';
const prosecutingAuthority = hearingCase.Prosecution?.ProsecutingAuthority
? hearingCase.Prosecution.ProsecutingAuthority
: '';
const linkedCases = hearingCase.LinkedCases?.map((linkedCase: any) => linkedCase.CaseNumber).join(', ') || '';
const listingNotes = hearing.ListNote || '';

return {
fixedDate: fixedDate ? new Date(fixedDate).toLocaleDateString('en-GB') : '',
caseReference: caseReference,
defendantNames: defendantNames,
prosecutingAuthority: prosecutingAuthority,
linkedCases: linkedCases,
listingNotes: listingNotes,
};
}
}
110 changes: 110 additions & 0 deletions src/main/views/style-guide/crown-warned-pdda-list.njk
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
{% from "govuk/components/table/macro.njk" import govukTable as 'govukTable' %}
{% from "../macros/common-components.njk" import goBack, searchInput %}
{% from "govuk/components/warning-text/macro.njk" import govukWarningText %}

{% extends "../list-template.njk" %}
{% block pageTitle %}
{{ title }}
{% endblock %}

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

{% block content %}
<div class="parent-box">
<h1 id='page-heading' class="govuk-heading-l">{{ heading }} {{ locationName }}</h1>
{% if endDate | length %}
<p class="govuk-body govuk-!-font-weight-bold govuk-!-margin-bottom-1">{{ listDate }} {{ startDate }} {{ to }} {{ endDate }}</p>
{% else %}
<p class="govuk-body govuk-!-font-weight-bold govuk-!-margin-bottom-1">{{ listDate }} {{ startDate }}</p>
{% endif %}
<p class="govuk-body">{{ listUpdated | replace("DATE", publishedDate) }} {{ at }} {{ publishedTime }}</p>
<p class="govuk-body">{{ versionText }} {{ version }}</p>

<p class="govuk-body">
{% for line in venueAddress %}
{{ line }}<br />
{% endfor %}
</p>

<div class="govuk-body list-info">
<p>{{ headingP1 }} {{ contentDate }}</p>
<p>{{ headingP2 }}</p>
<p>{{ headingP3 }}</p>
<p>{{ headingP4 }}</p>
</div>

<div class="govuk-grid restriction-list-section govuk-!-margin-bottom-5">
<div class="govuk-body">
<h3>{{ restrictionInformationHeading }}</h3>
<p class="govuk-body">{{ restrictionInformationP1 }}</p>
<div class="govuk-warning-text">
<span class="govuk-warning-text__icon align-warning-icon" aria-hidden="true">!</span>
<strong class="govuk-warning-text__text">
<span class="govuk-warning-text__assistive">Warning</span>
{{ restrictionInformationBoldText }}
</strong>
</div>
<p class="govuk-body">{{ restrictionInformationP2 }}</p>
<p class="govuk-body">{{ restrictionInformationP3 }}</p>
<p class="govuk-body">{{ restrictionInformationP4 }}</p>
<ul class="govuk-list govuk-list--bullet">
<li>{{ restrictionBulletPoint1 }}</li>
<li>{{ restrictionBulletPoint2 }}</li>
</ul>
</div>
</div>

{{ searchInput(text = searchCases) }}
<div class="search-area">
{% set toBeAllocated = "to be allocated" %}
{% set hearingTypeCount = 0 %}
<div class="govuk-accordion" data-module="govuk-accordion" id="accordion-default">
{% for hearingType, rows in listData %}
{% set hearingTypeCount = hearingTypeCount + 1 %}
<div class="govuk-accordion__section govuk-accordion__section--expanded">
<div class="govuk-accordion__section-header">
<h2 class="govuk-accordion__section-heading">
{% if hearingType | lower == toBeAllocated %}
<span class="govuk-accordion__section-button" id="accordion-default-heading-{{ hearingTypeCount }}">{{ toBeAllocatedText }}</span>
{% else %}
<span class="govuk-accordion__section-button" id="accordion-default-heading-{{ hearingTypeCount }}">{{ hearingType }}</span>
{% endif %}
</h2>
</div>
<div id="accordion-default-content-{{ hearingTypeCount }}" class="govuk-accordion__section-content" aria-labelledby="accordion-default-heading-{{ hearingTypeCount }}">
<div class="parent-box overflow-table">
<table class="govuk-table overflow-table" data-module="moj-sortable-table">
<thead class="govuk-table__head">
<tr class="govuk-table__row">
{% for header in tableHeaders %}
<th scope="col" class="govuk-table__header" aria-sort="none">{{ header }}</th>
{% endfor %}
</tr>
</thead>
<tbody class="govuk-table__body">
{% for row in rows %}
{% set noBorder = "no-border-bottom" %}
<tr class="govuk-table__row">
<td class="govuk-table__cell no-wrap" data-sort-value="{{ row.fixedDate | dateToSortValue }}">{{ row.fixedDate }}</td>
<td class="govuk-table__cell no-wrap">{{ row.caseReference }}</td>
<td class="govuk-table__cell">{{ row.defendantNames }}</td>
<td class="govuk-table__cell">{{ row.prosecutingAuthority }}</td>
<td class="govuk-table__cell">{{ row.linkedCases }}</td>
<td class="govuk-table__cell">{{ row.listingNotes }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endfor %}
</div> <!-- Close govuk-accordion div -->
<p class="govuk-body govuk-!-font-size-14 data-source">{{ dataSource }}: {{ provenance | convertDataSourceName(lng) }}</p>
{{ super() }}
</div> <!-- Close search-area div -->
</div> <!-- Close parent-box div -->
{% endblock %}
16 changes: 16 additions & 0 deletions src/test/a11y/tests/style-guide/crown-warned-pdda-list.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import sinon from 'sinon';
import { PublicationService } from '../../../../main/service/PublicationService';
import { testArtefactJsonData, testArtefactMetadata } from '../../common/testData';
import { testAccessibility } from '../../common/pa11yHelper';

const url = '/crown-warned-pdda-list?artefactId=abc';

const jsonData = testArtefactJsonData('crownWarnedPddaList.json');
const metadata = testArtefactMetadata()[0];

sinon.stub(PublicationService.prototype, 'getIndividualPublicationJson').resolves(jsonData);
sinon.stub(PublicationService.prototype, 'getIndividualPublicationMetadata').resolves(metadata);

describe('Accessibility - Crown Warned PDDA List Page', () => {
testAccessibility(url);
});
Loading
Loading