Skip to content

Commit

Permalink
ref: extract common functions getMyInfoPrefix and getAnswersForChild …
Browse files Browse the repository at this point in the history
…to shared submission.utils
  • Loading branch information
wanlingt committed Nov 14, 2023
1 parent 2d814f4 commit cf430b0
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 159 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,8 @@ export interface IPopulatedEmailFormWithResponsesAndHash {
parsedResponses: ParsedResponsesObject
hashedFields?: Set<MyInfoKey>
}

export interface IPopulatedStorageFormWithResponsesAndHash {
parsedResponses: ParsedResponsesObject
hashedFields?: Set<MyInfoKey>
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
import { StatusCodes } from 'http-status-codes'
import { compact } from 'lodash'

import { MYINFO_ATTRIBUTE_MAP } from '../../../../../shared/constants/field/myinfo'
import {
BasicField,
FormAuthType,
MyInfoAttribute,
} from '../../../../../shared/types'
import { BasicField, FormAuthType } from '../../../../../shared/types'
import {
EmailAdminDataField,
EmailDataCollationToolField,
Expand Down Expand Up @@ -58,7 +53,6 @@ import {
MyInfoMissingLoginCookieError,
} from '../../myinfo/myinfo.errors'
import { MyInfoKey } from '../../myinfo/myinfo.types'
import { getMyInfoChildHashKey } from '../../myinfo/myinfo.util'
import {
SgidInvalidJwtError,
SgidMissingJwtError,
Expand All @@ -80,14 +74,13 @@ import {
} from '../submission.errors'
import {
ProcessedCheckboxResponse,
ProcessedChildrenResponse,
ProcessedFieldResponse,
ProcessedTableResponse,
} from '../submission.types'
import { getAnswersForChild, getMyInfoPrefix } from '../submission.utils'

import {
ATTACHMENT_PREFIX,
MYINFO_PREFIX,
TABLE_PREFIX,
VERIFIED_PREFIX,
} from './email-submission.constants'
Expand All @@ -96,22 +89,6 @@ import { ResponseFormattedForEmail } from './email-submission.types'

const logger = createLoggerWithLabel(module)

/**
* Determines the prefix for a question based on whether it is verified
* by MyInfo.
* @param response
* @param hashedFields Field ids of hashed fields.
* @returns the prefix
*/
const getMyInfoPrefix = (
response: ResponseFormattedForEmail,
hashedFields: Set<MyInfoKey>,
): string => {
return !!response.myInfo?.attr && hashedFields.has(response._id)
? MYINFO_PREFIX
: ''
}

/**
* Determines the prefix for a question based on whether it was verified
* by a user during form submission.
Expand Down Expand Up @@ -214,44 +191,6 @@ export const getAnswerForCheckbox = (
}
}

export const getAnswersForChild = (
response: ProcessedChildrenResponse,
): ResponseFormattedForEmail[] => {
const subFields = response.childSubFieldsArray
const qnChildIdx = response.childIdx ?? 0
if (!subFields) {
return []
}
return response.answerArray.flatMap((arr, childIdx) => {
// First array element is always child name
const childName = arr[0]
return arr.map((answer, idx) => {
const subfield = subFields[idx]
return {
_id: getMyInfoChildHashKey(
response._id,
subFields[idx],
childIdx,
childName,
),
fieldType: response.fieldType,
// qnChildIdx represents the index of the MyInfo field
// childIdx represents the index of the child in this MyInfo field
// as there might be >1 child for each MyInfo child field if "Add another child" is used
question: `Child ${qnChildIdx + childIdx + 1} ${
MYINFO_ATTRIBUTE_MAP[subfield].description
}`,
myInfo: {
attr: subFields[idx] as unknown as MyInfoAttribute,
},
isVisible: response.isVisible,
isUserVerified: response.isUserVerified,
answer,
}
})
})
}

/**
* Formats the response for sending to the submitter (autoReplyData),
* the table that is sent to the admin (formData),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import { JoiPaymentProduct } from '../../form/admin-form/admin-form.payments.con
import * as FormService from '../../form/form.service'
import { MyInfoService } from '../../myinfo/myinfo.service'
import { extractMyInfoLoginJwt } from '../../myinfo/myinfo.util'
import { IPopulatedEmailFormWithResponsesAndHash } from '../email-submission/email-submission.types'
import { IPopulatedStorageFormWithResponsesAndHash } from '../email-submission/email-submission.types'
import ParsedResponsesObject from '../ParsedResponsesObject.class'
import { sharedSubmissionParams } from '../submission.constants'
import * as SubmissionService from '../submission.service'
Expand Down Expand Up @@ -62,7 +62,10 @@ import {
StorageSubmissionMiddlewareHandlerType,
ValidateSubmissionMiddlewareHandlerRequest,
} from './encrypt-submission.types'
import { mapRouteError, SubmissionStorageObj } from './encrypt-submission.utils'
import {
formatMyInfoStorageResponseData,
mapRouteError,
} from './encrypt-submission.utils'
import IncomingEncryptSubmission from './IncomingEncryptSubmission.class'

const logger = createLoggerWithLabel(module)
Expand Down Expand Up @@ -468,9 +471,8 @@ export const validateStorageSubmission = async (
hashes,
),
)
.map<IPopulatedEmailFormWithResponsesAndHash>(
.map<IPopulatedStorageFormWithResponsesAndHash>(
(hashedFields) => ({
form,
hashedFields,
parsedResponses,
}),
Expand All @@ -490,19 +492,17 @@ export const validateStorageSubmission = async (
})
})
default:
return ok<IPopulatedEmailFormWithResponsesAndHash, never>({
form,
return ok<IPopulatedStorageFormWithResponsesAndHash, never>({
parsedResponses,
})
}
})
.map(({ form, parsedResponses, hashedFields }) => {
const storageFormData = new SubmissionStorageObj(
.map(({ parsedResponses, hashedFields }) => {
const storageFormData = formatMyInfoStorageResponseData(
parsedResponses.getAllResponses(),
hashedFields,
form.authType,
)
req.body.responses = storageFormData.formData
req.body.responses = storageFormData
return next()
})
.mapErr((error) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import { StatusCodes } from 'http-status-codes'
import moment from 'moment-timezone'

import { MYINFO_ATTRIBUTE_MAP } from '../../../../../shared/constants/field/myinfo'
import {
FormAuthType,
FormPaymentsField,
MyInfoAttribute,
PaymentFieldsDto,
PaymentType,
StorageModeSubmissionContentDto,
Expand Down Expand Up @@ -53,7 +50,6 @@ import {
PrivateFormError,
} from '../../form/form.errors'
import { MyInfoKey } from '../../myinfo/myinfo.types'
import { getMyInfoChildHashKey } from '../../myinfo/myinfo.util'
import { PaymentNotFoundError } from '../../payments/payments.errors'
import {
SgidInvalidJwtError,
Expand All @@ -67,7 +63,6 @@ import {
VerifyJwtError,
} from '../../spcp/spcp.errors'
import { MissingUserError } from '../../user/user.errors'
import { MYINFO_PREFIX } from '../email-submission/email-submission.constants'
import {
AttachmentTooLargeError,
ConflictError,
Expand All @@ -78,11 +73,8 @@ import {
SubmissionNotFoundError,
ValidateFieldError,
} from '../submission.errors'
import {
ProcessedChildrenResponse,
ProcessedFieldResponse,
ProcessedSingleAnswerResponse,
} from '../submission.types'
import { ProcessedFieldResponse } from '../submission.types'
import { getAnswersForChild, getMyInfoPrefix } from '../submission.utils'

import {
AttachmentSizeLimitExceededError,
Expand Down Expand Up @@ -372,88 +364,23 @@ export const getPaymentIntentDescription = (
}
}

/**
* Determines the prefix for a question based on whether it is verified
* by MyInfo.
* @param response
* @param hashedFields Field ids of hashed fields.
* @returns the prefix
*/
const getMyInfoPrefix = (
response: ProcessedFieldResponse,
hashedFields: Set<MyInfoKey>,
): string => {
return !!response.myInfo?.attr && hashedFields.has(response._id)
? MYINFO_PREFIX
: ''
}

export const getAnswersForChild = (
response: ProcessedChildrenResponse,
): ProcessedSingleAnswerResponse[] => {
const subFields = response.childSubFieldsArray
const qnChildIdx = response.childIdx ?? 0
if (!subFields) {
return []
}
return response.answerArray.flatMap((arr, childIdx) => {
// First array element is always child name
const childName = arr[0]
return arr.map((answer, idx) => {
const subfield = subFields[idx]
return {
_id: getMyInfoChildHashKey(
response._id,
subFields[idx],
childIdx,
childName,
),
// qnChildIdx represents the index of the MyInfo field
// childIdx represents the index of the child in this MyInfo field
// as there might be >1 child for each MyInfo child field if "Add another child" is used
question: `Child ${qnChildIdx + childIdx + 1} ${
MYINFO_ATTRIBUTE_MAP[subfield].description
}`,
answer,
fieldType: MYINFO_ATTRIBUTE_MAP[subfield].fieldType,
isVisible: response.isVisible,
myInfo: {
attr: subFields[idx] as unknown as MyInfoAttribute,
},
}
})
})
}

export class SubmissionStorageObj {
parsedResponses: ProcessedFieldResponse[]
hashedFields: Set<MyInfoKey>
authType: FormAuthType

constructor(
parsedResponses: ProcessedFieldResponse[],
hashedFields: Set<MyInfoKey> = new Set<MyInfoKey>(),
authType: FormAuthType,
) {
this.parsedResponses = parsedResponses
this.hashedFields = hashedFields
this.authType = authType
}

/**
* Getter function to return formData which is used to send responses to admin
*/
get formData() {
return this.parsedResponses.flatMap((response) => {
export const formatMyInfoStorageResponseData = (
parsedResponses: ProcessedFieldResponse[],
hashedFields?: Set<MyInfoKey>,
) => {
if (!hashedFields) {
return parsedResponses
} else {
return parsedResponses.flatMap((response) => {
if (isProcessedChildResponse(response)) {
return getAnswersForChild(response).map((childField) => {
const myInfoPrefix = getMyInfoPrefix(childField, this.hashedFields)
const myInfoPrefix = getMyInfoPrefix(childField, hashedFields)
childField.question = `${myInfoPrefix}${childField.question}`
return childField
})
} else {
// Obtain prefix for question based on whether it is verified by MyInfo.
const myInfoPrefix = getMyInfoPrefix(response, this.hashedFields)
const myInfoPrefix = getMyInfoPrefix(response, hashedFields)
response.question = `${myInfoPrefix}${response.question}`
return response
}
Expand Down
Loading

0 comments on commit cf430b0

Please sign in to comment.