diff --git a/src/api/forms/repositories/aggregation/form-metadata-aggregation.js b/src/api/forms/repositories/aggregation/form-metadata-aggregation.js index d5a25bf8..7b12ccb5 100644 --- a/src/api/forms/repositories/aggregation/form-metadata-aggregation.js +++ b/src/api/forms/repositories/aggregation/form-metadata-aggregation.js @@ -1,4 +1,4 @@ -import { FormStatus } from '@defra/forms-model' +import { FormFilterStatus } from '@defra/forms-model' import { ObjectId } from 'mongodb' import { escapeRegExp } from '~/src/helpers/string-utils.js' @@ -31,11 +31,15 @@ export function buildFilterConditions(options) { } if (status && status.length > 0) { - conditions.$or = status.map((s) => - s === FormStatus.Live - ? { live: { $exists: true } } - : { live: { $exists: false } } - ) + conditions.$or = status.map((s) => { + if (s === FormFilterStatus.Live) { + return { live: { $exists: true } } + } else if (s === FormFilterStatus.Offline) { + return { offline: true } + } else { + return { live: { $exists: false } } + } + }) } return conditions @@ -74,7 +78,16 @@ export function buildFiltersFacet() { _id: null, // Single group for all documents statuses: { $addToSet: { - $cond: [{ $ifNull: ['$live', false] }, 'live', 'draft'] // If live field exists, status is 'live', else 'draft' + $switch: { + // If offline === true, status is 'offline' + // If live field exists, status is 'live' + // Otherwise 'draft' + branches: [ + { case: { $eq: ['$offline', true] }, then: 'offline' }, + { case: { $ifNull: ['$live', false] }, then: 'live' } + ], + default: 'draft' + } } } } @@ -92,7 +105,7 @@ export function buildFiltersFacet() { * @param {string} title - The title to filter by. * @param {string} author - The author to filter by. * @param {string[]} organisations - The organisations to filter by. - * @param {FormStatus[]} status - The status values to filter by. + * @param {FormFilterStatus[]} status - The status values to filter by. * @returns {{ pipeline: PipelineStage[], aggOptions: AggregateOptions }} */ export function buildAggregationPipeline( @@ -134,7 +147,7 @@ export function buildAggregationPipeline( * @param {string} title - The title to filter by. * @param {string} author - The author to filter by. * @param {string[]} organisations - The organisations to filter by. - * @param {FormStatus[]} status - The status values to filter by. + * @param {FormFilterStatus[]} status - The status values to filter by. * @returns {{ pipeline: PipelineStage[], aggOptions: AggregateOptions }} */ export function buildAggregationPipelineWithVersions( diff --git a/src/api/forms/repositories/aggregation/form-metadata-aggregation.test.js b/src/api/forms/repositories/aggregation/form-metadata-aggregation.test.js index 9eb70b10..2637343e 100644 --- a/src/api/forms/repositories/aggregation/form-metadata-aggregation.test.js +++ b/src/api/forms/repositories/aggregation/form-metadata-aggregation.test.js @@ -1,4 +1,4 @@ -import { FormStatus } from '@defra/forms-model' +import { FormFilterStatus } from '@defra/forms-model' import { ObjectId } from 'mongodb' import { @@ -70,14 +70,18 @@ describe('Form metadata aggregation', () => { describe('with status filter', () => { it('should create status filter for live forms', () => { - const result = buildFilterConditions({ status: [FormStatus.Live] }) + const result = buildFilterConditions({ + status: [FormFilterStatus.Live] + }) expect(result).toEqual({ $or: [{ live: { $exists: true } }] }) }) it('should create status filter for draft forms', () => { - const result = buildFilterConditions({ status: [FormStatus.Draft] }) + const result = buildFilterConditions({ + status: [FormFilterStatus.Draft] + }) expect(result).toEqual({ $or: [{ live: { $exists: false } }] }) @@ -87,7 +91,7 @@ describe('Form metadata aggregation', () => { describe('with multiple status values', () => { it('should create combined status filter', () => { const result = buildFilterConditions({ - status: [FormStatus.Live, FormStatus.Draft] + status: [FormFilterStatus.Live, FormFilterStatus.Draft] }) expect(result).toEqual({ $or: [{ live: { $exists: true } }, { live: { $exists: false } }] @@ -101,7 +105,7 @@ describe('Form metadata aggregation', () => { title: 'Wildlife Permit Application', author: 'Henrique Silva', organisations: ['Natural England', 'Defra'], - status: [FormStatus.Live] + status: [FormFilterStatus.Live] }) expect(result).toEqual({ @@ -141,7 +145,7 @@ describe('Form metadata aggregation', () => { 'Wildlife Permit Application', 'Henrique', ['Defra'], - [FormStatus.Live] + [FormFilterStatus.Live] ) expect(pipeline[0]).toHaveProperty('$match') @@ -208,7 +212,7 @@ describe('Form metadata aggregation', () => { 'Wildlife Permit Application', 'Henrique', ['Defra'], - [FormStatus.Live] + [FormFilterStatus.Live] ) expect(pipeline[0]).toHaveProperty('$match') @@ -455,7 +459,13 @@ describe('Form metadata aggregation', () => { _id: null, statuses: { $addToSet: { - $cond: [{ $ifNull: ['$live', false] }, 'live', 'draft'] + $switch: { + branches: [ + { case: { $eq: ['$offline', true] }, then: 'offline' }, + { case: { $ifNull: ['$live', false] }, then: 'live' } + ], + default: 'draft' + } } } } @@ -498,7 +508,7 @@ describe('Form metadata aggregation', () => { { name: 'Sarah Wilson (Natural England)' } ], organisations: [{ name: 'Defra' }, { name: 'Natural England' }], - status: [{ statuses: [FormStatus.Live, FormStatus.Draft] }] + status: [{ statuses: [FormFilterStatus.Live, FormFilterStatus.Draft] }] } const result = processFilterResults(filterResults) diff --git a/src/api/forms/repositories/aggregation/types.js b/src/api/forms/repositories/aggregation/types.js index df384dfe..068ed630 100644 --- a/src/api/forms/repositories/aggregation/types.js +++ b/src/api/forms/repositories/aggregation/types.js @@ -3,7 +3,7 @@ * @property {{ $regex: RegExp }} [title] - Optional MongoDB regex query for title matching * @property {{ displayName: { $regex: RegExp } }} [createdBy] - Optional MongoDB regex query for author matching * @property {{ $in: string[] }} [organisation] - Optional MongoDB $in query for organisation matching - * @property {{ live: { $exists: boolean } }[]} [$or] - Optional MongoDB $or query for status matching + * @property {{ live?: { $exists: boolean }, offline?: boolean }[]} [$or] - Optional MongoDB $or query for status matching * @property {object} [$expr] - Optional MongoDB $expr for expression queries */ @@ -15,7 +15,7 @@ * @typedef {object} FilterAggregationResult * @property {{ name: string }[]} authors - Array of author names * @property {{ name: string }[]} organisations - Array of organisation names - * @property {[{ statuses: FormStatus[] }]} status - Array containing status values + * @property {[{ statuses: FormFilterStatus[] }]} status - Array containing status values */ /** @@ -79,5 +79,5 @@ */ /** - * @import { SearchOptions, FormStatus } from '@defra/forms-model' + * @import { SearchOptions, FormStatus, FormFilterStatus } from '@defra/forms-model' */ diff --git a/src/api/forms/repositories/form-metadata-repository.test.js b/src/api/forms/repositories/form-metadata-repository.test.js index 5b7e5a18..5a56654a 100644 --- a/src/api/forms/repositories/form-metadata-repository.test.js +++ b/src/api/forms/repositories/form-metadata-repository.test.js @@ -1,4 +1,4 @@ -import { FormStatus } from '@defra/forms-model' +import { FormFilterStatus } from '@defra/forms-model' import Boom from '@hapi/boom' import { MongoServerError, ObjectId } from 'mongodb' @@ -249,7 +249,7 @@ describe('form-metadata-repository', () => { title: 'test', author: 'John', organisations: ['Defra'], - status: [FormStatus.Draft] + status: [FormFilterStatus.Draft] } const result = await list(options) @@ -328,7 +328,7 @@ describe('form-metadata-repository', () => { title: 'test form', author: 'Jane Doe', organisations: ['Defra', 'DWP'], - status: [FormStatus.Draft, FormStatus.Live] + status: [FormFilterStatus.Draft, FormFilterStatus.Live] } const result = await listWithVersions(options) diff --git a/src/api/forms/service/definition.test.js b/src/api/forms/service/definition.test.js index e63075b9..28c0c256 100644 --- a/src/api/forms/service/definition.test.js +++ b/src/api/forms/service/definition.test.js @@ -3,7 +3,7 @@ import { ComponentType, Engine, FormDefinitionRequestType, - FormStatus, + FormFilterStatus, formDefinitionSchema, formDefinitionV2Schema } from '@defra/forms-model' @@ -1009,7 +1009,7 @@ describe('Forms service', () => { perPage: 10, author: 'Henrique Chase', organisations: ['Defra'], - status: [FormStatus.Live] + status: [FormFilterStatus.Live] } jest.mocked(formMetadata.list).mockResolvedValue({ @@ -1035,7 +1035,7 @@ describe('Forms service', () => { perPage: 10, author: 'Henrique Chase', organisations: ['Defra', 'Natural England'], - status: [FormStatus.Live, FormStatus.Draft] + status: [FormFilterStatus.Live, FormFilterStatus.Draft] } jest.mocked(formMetadata.list).mockResolvedValue({ diff --git a/src/routes/forms.test.js b/src/routes/forms.test.js index bb7eb6d3..ce37169c 100644 --- a/src/routes/forms.test.js +++ b/src/routes/forms.test.js @@ -1433,7 +1433,7 @@ describe('Forms route', () => { expect(response.headers['content-type']).toContain(jsonContentType) expect(response.result).toMatchObject({ error: 'Bad Request', - message: '"status" must be one of [draft, live]', + message: '"status" must be one of [draft, live, offline]', validation: { keys: ['status'], source: 'query' @@ -1453,7 +1453,7 @@ describe('Forms route', () => { expect(response.result).toMatchObject({ error: 'Bad Request', message: - '"organisations" must be one of [Animal and Plant Health Agency – APHA, Centre for Environment, Fisheries and Aquaculture Science – Cefas, Defra, Environment Agency, Forestry Commission, Marine Management Organisation – MMO, Natural England, Rural Payments Agency – RPA, Veterinary Medicines Directorate – VMD]. "status" must be one of [draft, live]', + '"organisations" must be one of [Animal and Plant Health Agency – APHA, Centre for Environment, Fisheries and Aquaculture Science – Cefas, Defra, Environment Agency, Forestry Commission, Marine Management Organisation – MMO, Natural England, Rural Payments Agency – RPA, Veterinary Medicines Directorate – VMD]. "status" must be one of [draft, live, offline]', validation: { keys: ['organisations', 'status'], source: 'query'