Skip to content

Commit

Permalink
Merge branch 'main' into feat/bff-my-pages
Browse files Browse the repository at this point in the history
  • Loading branch information
snaerseljan authored Nov 25, 2024
2 parents 1558a81 + 1b49305 commit 590ab0b
Show file tree
Hide file tree
Showing 66 changed files with 1,263 additions and 408 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,10 @@ import { ApplicationResponseDto } from './dto/application.response.dto'
import { PresignedUrlResponseDto } from './dto/presignedUrl.response.dto'
import { AssignApplicationDto } from './dto/assignApplication.dto'
import { verifyToken } from './utils/tokenUtils'
import { getApplicationLifecycle } from './utils/application'
import {
getApplicationLifecycle,
removeObjectWithKeyFromAnswers,
} from './utils/application'
import { DecodedAssignmentToken } from './types'
import { ApplicationAccessService } from './tools/applicationAccess.service'
import { CurrentLocale } from './utils/currentLocale'
Expand Down Expand Up @@ -870,6 +873,10 @@ export class ApplicationController {
existingApplication.id,
{
attachments: omit(existingApplication.attachments, key),
answers: removeObjectWithKeyFromAnswers(
existingApplication.answers,
key,
),
},
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,105 @@ export const mockApplicationFromTypeId = (
status: ApplicationStatus.IN_PROGRESS,
}
}

type RecordType = Record<string, unknown>

const MAX_DEPTH = 100

export const removeObjectWithKeyFromAnswers = (
answers: object,
keyToRemove: string,
depth = 0,
): object => {
if (depth >= MAX_DEPTH) {
console.warn(
'Maximum recursion depth reached while calling removeObjectWithKeyFromAnswers',
)
return answers
}
// Handle arrays
if (Array.isArray(answers)) {
return cleanArray(answers, keyToRemove, depth)
}

// Handle objects
if (isValidObject(answers)) {
return cleanObject(answers, keyToRemove, depth)
}

return answers
}

const cleanArray = (
array: unknown[],
keyToRemove: string,
depth: number,
): unknown[] => {
const filteredArray = array.filter((item) => {
if (isValidObject(item)) {
return !containsKey(item, keyToRemove)
}
return item !== keyToRemove
})

return filteredArray.map((item) => {
if (isObject(item)) {
return removeObjectWithKeyFromAnswers(item, keyToRemove, depth + 1)
}
return item
})
}

const cleanObject = (
obj: object,
keyToRemove: string,
depth: number,
): RecordType => {
return Object.entries(obj).reduce<RecordType>((acc, [field, value]) => {
if (isValidObject(value)) {
if (!Array.isArray(value) && containsKey(value, keyToRemove)) {
return acc
}

const cleanedValue = removeObjectWithKeyFromAnswers(
value,
keyToRemove,
depth + 1,
)

// For arrays or objects with content, keep them
if (hasContent(cleanedValue)) {
acc[field] = cleanedValue
}
// Special case: keep empty arrays
else if (Array.isArray(value)) {
acc[field] = cleanedValue
}
return acc
}

// Handle primitive values
if (value !== keyToRemove) {
acc[field] = value
}
return acc
}, {})
}

const isValidObject = (value: unknown): value is object => {
return value !== null && typeof value === 'object'
}

const containsKey = (obj: object, key: string): boolean => {
return Object.values(obj).includes(key)
}

const hasContent = (value: unknown): boolean => {
if (Array.isArray(value)) {
return value.length > 0
}
if (isValidObject(value)) {
return Object.keys(value).length > 0
}
return false
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
getApplicationNameTranslationString,
getApplicationStatisticsNameTranslationString,
getPaymentStatusForAdmin,
removeObjectWithKeyFromAnswers,
} from './application'
import {
createApplication,
Expand Down Expand Up @@ -196,4 +197,208 @@ describe('Testing utility functions for applications', () => {
})
})
})

describe('removeAttachmentFromAnswers', () => {
it('Should remove an object from an array that contains the given key and leave the array empty', () => {
const givenAnswers = {
documents: [
{ id: 'doc1', attachmentId: 'some-key-123', name: 'Document 1' },
],
}
const expectedAnswers = {
documents: [],
}

const result = removeObjectWithKeyFromAnswers(
givenAnswers,
'some-key-123',
)

expect(result).toEqual(expectedAnswers)
})

it('Should remove nested objects that contain the given key', () => {
const givenAnswers = {
section1: {
attachment: { id: 'some-key-123', name: 'Remove me' },
otherData: 'keep this',
},
section2: {
data: 'keep this too',
},
}
const expectedAnswers = {
section1: {
otherData: 'keep this',
},
section2: {
data: 'keep this too',
},
}

const result = removeObjectWithKeyFromAnswers(
givenAnswers,
'some-key-123',
)

expect(result).toEqual(expectedAnswers)
})

it('Should remove an object from an array that contains the given key', () => {
const givenAnswers = {
documents: [
{ id: 'doc1', attachmentId: 'some-key-123', name: 'Document 1' },
{ id: 'doc2', attachmentId: 'keep-this-key', name: 'Document 2' },
],
}
const expectedAnswers = {
documents: [
{ id: 'doc2', attachmentId: 'keep-this-key', name: 'Document 2' },
],
}

const result = removeObjectWithKeyFromAnswers(
givenAnswers,
'some-key-123',
)

expect(result).toEqual(expectedAnswers)
})

it('Should remove nested objects that contain the given key', () => {
const givenAnswers = {
section1: {
attachment: { id: 'some-key-123', name: 'Remove me' },
otherData: 'keep this',
},
section2: {
data: 'keep this too',
},
}
const expectedAnswers = {
section1: {
otherData: 'keep this',
},
section2: {
data: 'keep this too',
},
}

const result = removeObjectWithKeyFromAnswers(
givenAnswers,
'some-key-123',
)

expect(result).toEqual(expectedAnswers)
})

it('Should handle deeply nested arrays and objects', () => {
const givenAnswers = {
deepSection: {
documents: [
{
files: [
{ id: 'file1', attachmentId: 'some-key-123' },
{ id: 'file2', attachmentId: 'keep-this' },
],
},
{
files: [{ id: 'file3', attachmentId: 'also-keep-this' }],
},
],
},
}
const expectedAnswers = {
deepSection: {
documents: [
{
files: [{ id: 'file2', attachmentId: 'keep-this' }],
},
{
files: [{ id: 'file3', attachmentId: 'also-keep-this' }],
},
],
},
}

const result = removeObjectWithKeyFromAnswers(
givenAnswers,
'some-key-123',
)

expect(result).toEqual(expectedAnswers)
})

it('Should handle even more complex deeply nested arrays and objects', () => {
const givenAnswers = {
deepSection: {
someRandomProp: { data: 'Some data' },
deeperSection: {
documents: [
{
files: [
{ id: 'file1', attachmentId: 'some-key-123', nr: 77 },
{ id: 'file2', attachmentId: 'keep-this', nr: 55 },
],
},
{
files: [{ id: 'file3', attachmentId: 'also-keep-this' }],
},
],
otherSection: {
nr: 100,
name: 'Some Name',
kids: [
{ kid: 'Some kid', phone: 1234567 },
{ kid: 'Some other kid', phone: 1234568 },
],
},
},
},
}

const expectedAnswers = {
deepSection: {
someRandomProp: { data: 'Some data' },
deeperSection: {
documents: [
{
files: [{ id: 'file2', attachmentId: 'keep-this', nr: 55 }],
},
{
files: [{ id: 'file3', attachmentId: 'also-keep-this' }],
},
],
otherSection: {
nr: 100,
name: 'Some Name',
kids: [
{ kid: 'Some kid', phone: 1234567 },
{ kid: 'Some other kid', phone: 1234568 },
],
},
},
},
}

const result = removeObjectWithKeyFromAnswers(
givenAnswers,
'some-key-123',
)

expect(result).toEqual(expectedAnswers)
})

it('Should return empty object when no answers provided', () => {
const givenAnswers = {}
const expectedAnswers = {}

const result = removeObjectWithKeyFromAnswers(
givenAnswers,
'some-key-123',
)

expect(result).toEqual(expectedAnswers)
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,9 @@ export class UpdateDefendantInput {
@IsOptional()
@Field(() => Boolean, { nullable: true })
readonly caseFilesSharedWithDefender?: boolean

@Allow()
@IsOptional()
@Field(() => Boolean, { nullable: true })
readonly isSentToPrisonAdmin?: boolean
}
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,10 @@ export class Defendant {

@Field(() => Boolean, { nullable: true })
readonly caseFilesSharedWithDefender?: boolean

@Field(() => Boolean, { nullable: true })
readonly isSentToPrisonAdmin?: boolean

@Field(() => String, { nullable: true })
readonly sentToPrisonAdminDate?: string
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
'use strict'

module.exports = {
up(queryInterface, Sequelize) {
return queryInterface.sequelize.transaction((transaction) =>
queryInterface.addColumn(
'defendant',
'is_sent_to_prison_admin',
{
type: Sequelize.BOOLEAN,
allowNull: true,
},
{ transaction },
),
)
},

down(queryInterface) {
return queryInterface.sequelize.transaction((transaction) =>
queryInterface.removeColumn('defendant', 'is_sent_to_prison_admin', {
transaction,
}),
)
},
}
Loading

0 comments on commit 590ab0b

Please sign in to comment.