Skip to content

Commit df33a5b

Browse files
committed
Merge branch '2432-initial-update-to-provide-to-use-metrics-and-logging-allowing-initial-dashboard-creation' of https://github.com/digital-land/submit into 2432-initial-update-to-provide-to-use-metrics-and-logging-allowing-initial-dashboard-creation
2 parents aa0a0de + 4209418 commit df33a5b

2 files changed

Lines changed: 188 additions & 0 deletions

File tree

config/plan-fallback.json

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
{
2+
"specification": "plan",
3+
"name": "plan",
4+
"long-name": "local plan, minerals and waste plan, and supplementary plan",
5+
"long-plural": "local plans, minerals and waste plans, and supplementary plans",
6+
"plural": "plans",
7+
"description": "headline information about local plans, minerals and waste plans, and supplementary plans",
8+
"specification-status": "working-draft",
9+
"specification-reason": "local-plans-2025",
10+
"consideration": "development-plans-and-timetables",
11+
"document-url": "https://digital-land.github.io/specification/specification/plan/",
12+
"date-precision": "YYYY-MM-DD",
13+
"start-date": "",
14+
"end-date": "",
15+
"entry-date": "2026-03-24",
16+
"github-discussion": 26,
17+
"datasets": [
18+
{
19+
"dataset": "local-plan",
20+
"fields": [
21+
{ "field": "reference" },
22+
{
23+
"field": "name",
24+
"assertions": [
25+
{
26+
"reference": "plan-A001",
27+
"text": "match the title of the document at `document-url`."
28+
}
29+
]
30+
},
31+
{ "field": "dataset" },
32+
{ "field": "period-start-date" },
33+
{ "field": "period-end-date" },
34+
{ "field": "local-planning-authorities" },
35+
{ "field": "documentation-url" },
36+
{
37+
"field": "document-url",
38+
"assertions": [
39+
{
40+
"reference": "plan-A002",
41+
"text": "link to the core plan document described by this data."
42+
}
43+
]
44+
},
45+
{ "field": "required-housing" },
46+
{ "field": "entry-date" },
47+
{ "field": "notes" }
48+
]
49+
},
50+
{
51+
"dataset": "supplementary-plan",
52+
"fields": [
53+
{ "field": "reference" },
54+
{
55+
"field": "name",
56+
"assertions": [
57+
{
58+
"reference": "plan-A001",
59+
"text": "match the title of the document at `document-url`."
60+
}
61+
]
62+
},
63+
{ "field": "dataset" },
64+
{ "field": "period-start-date" },
65+
{ "field": "period-end-date" },
66+
{ "field": "local-planning-authorities" },
67+
{ "field": "documentation-url" },
68+
{
69+
"field": "document-url",
70+
"assertions": [
71+
{
72+
"reference": "plan-A002",
73+
"text": "link to the core plan document described by this data."
74+
}
75+
]
76+
},
77+
{ "field": "entry-date" },
78+
{ "field": "notes" }
79+
]
80+
},
81+
{
82+
"dataset": "minerals-plan",
83+
"fields": [
84+
{ "field": "reference" },
85+
{
86+
"field": "name",
87+
"assertions": [
88+
{
89+
"reference": "plan-A001",
90+
"text": "match the title of the document at `document-url`."
91+
}
92+
]
93+
},
94+
{ "field": "dataset" },
95+
{ "field": "period-start-date" },
96+
{ "field": "period-end-date" },
97+
{ "field": "mineral-planning-authorities" },
98+
{ "field": "documentation-url" },
99+
{
100+
"field": "document-url",
101+
"assertions": [
102+
{
103+
"reference": "plan-A002",
104+
"text": "link to the core plan document described by this data."
105+
}
106+
]
107+
},
108+
{ "field": "document-count" },
109+
{ "field": "entry-date" },
110+
{ "field": "notes" }
111+
]
112+
},
113+
{
114+
"dataset": "waste-plan",
115+
"fields": [
116+
{ "field": "reference" },
117+
{
118+
"field": "name",
119+
"assertions": [
120+
{
121+
"reference": "plan-A001",
122+
"text": "match the title of the document at `document-url`."
123+
}
124+
]
125+
},
126+
{ "field": "dataset" },
127+
{ "field": "period-start-date" },
128+
{ "field": "period-end-date" },
129+
{ "field": "waste-planning-authorities" },
130+
{ "field": "documentation-url" },
131+
{
132+
"field": "document-url",
133+
"assertions": [
134+
{
135+
"reference": "plan-A002",
136+
"text": "link to the core plan document described by this data."
137+
}
138+
]
139+
},
140+
{ "field": "document-count" },
141+
{ "field": "entry-date" },
142+
{ "field": "notes" }
143+
]
144+
},
145+
{
146+
"dataset": "plan-timetable",
147+
"fields": [
148+
{ "field": "reference" },
149+
{ "field": "plan" },
150+
{
151+
"field": "plan-event",
152+
"dataset": "plan-event"
153+
},
154+
{ "field": "event-date" },
155+
{ "field": "actual-date" },
156+
{ "field": "entry-date" },
157+
{ "field": "notes" }
158+
]
159+
}
160+
]
161+
}

src/middleware/common.middleware.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ import { errorTemplateContext, MiddlewareError } from '../utils/errors.js'
1515
import { dataRangeParams } from '../routes/schemas.js'
1616
import platformApi from '../services/platformApi.js'
1717
import config from '../../config/index.js'
18+
import { readFileSync } from 'node:fs'
1819

20+
const planFallback = JSON.parse(readFileSync(new URL('../../config/plan-fallback.json', import.meta.url), 'utf8'))
21+
const PLAN_FALLBACK_DATASETS_JSON = JSON.stringify(planFallback.datasets)
1922
/**
2023
* Middleware. Set `req.handlerName` to a string that will identify
2124
* the function that threw the error.
@@ -381,6 +384,28 @@ export const fetchDatasetFields = fetchMany({
381384
result: 'datasetFields'
382385
})
383386

387+
/**
388+
* @name checkSpecificationFallback
389+
* @function
390+
* @description Middleware that overrides the specification with a local fallback for plan datasets
391+
* that are not yet in a production-ready format in the specification table. When the fetched
392+
* specification is for 'local-plan', it checks whether the current dataset exists in the
393+
* plan-fallback.json config and, if so, replaces req.specification with the fallback data
394+
* so that pullOutDatasetSpecification can extract the correct dataset-specific fields.
395+
*/
396+
export const checkSpecificationFallback = (req, res, next) => {
397+
const { specification } = req
398+
399+
if (specification && specification.specification === 'local-plan') {
400+
const fallbackDataset = planFallback.datasets.find(d => d.dataset === req.dataset.dataset)
401+
if (fallbackDataset) {
402+
req.specification = { json: PLAN_FALLBACK_DATASETS_JSON }
403+
}
404+
}
405+
406+
return next()
407+
}
408+
384409
export const pullOutDatasetSpecification = (req, res, next) => {
385410
const { specification } = req
386411
let collectionSpecifications
@@ -494,6 +519,8 @@ export const constructSpecificationTable = (req, res, next) => {
494519
*/
495520
export const processSpecificationMiddlewares = [
496521
fetchSpecification,
522+
// Certain Specification are not at production level format, so override here
523+
checkSpecificationFallback,
497524
pullOutDatasetSpecification,
498525
// When specification exists, use field mappings from transform table
499526
onlyIf(req => req.specification, replaceUnderscoreInSpecification),

0 commit comments

Comments
 (0)