Skip to content

Commit 11d0c5a

Browse files
authored
Release v1.48.0 (#1125)
feat: use FormSG table field in for each fix: clickable area in nested step smaller than step fix: tiles column should be type text not varchar fix: for each template variable check step chore: bump form-data from 4.0.0 to 4.0.4
2 parents acfcef6 + f2e3a24 commit 11d0c5a

File tree

23 files changed

+634
-99
lines changed

23 files changed

+634
-99
lines changed

package-lock.json

Lines changed: 36 additions & 37 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/backend/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
"electrodb": "2.12.0",
5555
"email-validator": "2.0.4",
5656
"express": "4.21.2",
57-
"form-data": "4.0.0",
57+
"form-data": "4.0.4",
5858
"graphql": "16.8.1",
5959
"graphql-middleware": "6.1.35",
6060
"graphql-rate-limit": "3.3.0",
@@ -108,5 +108,5 @@
108108
"tsconfig-paths": "^4.2.0",
109109
"type-fest": "4.10.3"
110110
},
111-
"version": "1.47.0"
111+
"version": "1.48.0"
112112
}

packages/backend/src/apps/formsg/__tests__/auth/decrypt-form-response.test.ts

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { IGlobalVariable, IRequest } from '@plumber/types'
33
import { Settings as LuxonSettings } from 'luxon'
44
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
55

6+
import { FOR_EACH_INPUT_SOURCE } from '@/apps/toolbox/common/constants'
7+
68
import app from '../..'
79
import { decryptFormResponse } from '../../auth/decrypt-form-response'
810
import { NricFilter } from '../../triggers/new-submission'
@@ -724,6 +726,47 @@ describe('decrypt form response', () => {
724726
tableField: {
725727
fieldType: 'table',
726728
question: 'What are your hobbies and when do you do them?',
729+
answer: JSON.stringify({
730+
rows: [
731+
{
732+
data: {
733+
[Buffer.from('Col 1').toString('hex')]: 'reading',
734+
[Buffer.from('Col 2').toString('hex')]: 'night',
735+
},
736+
},
737+
{
738+
data: {
739+
[Buffer.from('Col 1').toString('hex')]: 'gaming',
740+
[Buffer.from('Col 2').toString('hex')]: 'weekend',
741+
},
742+
},
743+
{
744+
data: {
745+
[Buffer.from('Col 1').toString('hex')]: 'coding',
746+
[Buffer.from('Col 2').toString('hex')]: 'day',
747+
},
748+
},
749+
],
750+
columns: [
751+
{
752+
id: Buffer.from('Col 1').toString('hex'),
753+
label: 'Col 1',
754+
name: 'Col 1',
755+
value: `data.rows.*.data.${Buffer.from('Col 1').toString(
756+
'hex',
757+
)}`,
758+
},
759+
{
760+
id: Buffer.from('Col 2').toString('hex'),
761+
label: 'Col 2',
762+
name: 'Col 2',
763+
value: `data.rows.*.data.${Buffer.from('Col 2').toString(
764+
'hex',
765+
)}`,
766+
},
767+
],
768+
inputSource: FOR_EACH_INPUT_SOURCE.FORMSG_TABLE,
769+
}),
727770
answerArray: [
728771
['reading', 'night'],
729772
['gaming', 'weekend'],
@@ -781,6 +824,41 @@ describe('decrypt form response', () => {
781824
['reading', 'night'],
782825
['gaming', 'weekend'],
783826
],
827+
answer: JSON.stringify({
828+
rows: [
829+
{
830+
data: {
831+
[Buffer.from('Col 1').toString('hex')]: 'reading',
832+
[Buffer.from('Col 2').toString('hex')]: 'night',
833+
},
834+
},
835+
{
836+
data: {
837+
[Buffer.from('Col 1').toString('hex')]: 'gaming',
838+
[Buffer.from('Col 2').toString('hex')]: 'weekend',
839+
},
840+
},
841+
],
842+
columns: [
843+
{
844+
id: Buffer.from('Col 1').toString('hex'),
845+
label: 'Col 1',
846+
name: 'Col 1',
847+
value: `data.rows.*.data.${Buffer.from('Col 1').toString(
848+
'hex',
849+
)}`,
850+
},
851+
{
852+
id: Buffer.from('Col 2').toString('hex'),
853+
label: 'Col 2',
854+
name: 'Col 2',
855+
value: `data.rows.*.data.${Buffer.from('Col 2').toString(
856+
'hex',
857+
)}`,
858+
},
859+
],
860+
inputSource: FOR_EACH_INPUT_SOURCE.FORMSG_TABLE,
861+
}),
784862
order: 2,
785863
},
786864
},

packages/backend/src/apps/formsg/__tests__/triggers/new-submission.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,40 @@ describe('new submission trigger for answer array fields', () => {
484484
['sleeping', 'night'],
485485
['eating', 'all day'],
486486
],
487+
answer: JSON.stringify({
488+
rows: [
489+
{
490+
data: {
491+
[Buffer.from('Column 1').toString('hex')]: 'sleeping',
492+
[Buffer.from('Column 2').toString('hex')]: 'night',
493+
},
494+
},
495+
{
496+
data: {
497+
[Buffer.from('Column 1').toString('hex')]: 'eating',
498+
[Buffer.from('Column 2').toString('hex')]: 'all day',
499+
},
500+
},
501+
],
502+
columns: [
503+
{
504+
id: Buffer.from('Column 1').toString('hex'),
505+
label: 'Column 1',
506+
name: 'Column 1',
507+
value: `data.rows.*.data.${Buffer.from('Column 1').toString(
508+
'hex',
509+
)}`,
510+
},
511+
{
512+
id: Buffer.from('Column 2').toString('hex'),
513+
label: 'Column 2',
514+
name: 'Column 2',
515+
value: `data.rows.*.data.${Buffer.from('Column 2').toString(
516+
'hex',
517+
)}`,
518+
},
519+
],
520+
}),
487521
},
488522
textFieldId3: {
489523
question: 'Unknown question',

packages/backend/src/apps/formsg/auth/decrypt-form-response.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { sha256Hash } from '@/helpers/crypto'
1010
import logger from '@/helpers/logger'
1111

1212
import { getSdk, parseFormEnv } from '../common/form-env'
13+
import convertTableAnswerArrayToTableObject from '../common/process-table-field'
1314
import { NricFilter } from '../triggers/new-submission/index'
1415

1516
import storeAttachmentInS3 from './helpers/store-attachment-in-s3'
@@ -128,6 +129,11 @@ export async function decryptFormResponse(
128129
rest.answerArray = (rest.answerArray as string[][]).map((row) =>
129130
row.map((column) => column.replaceAll('\u0000', '')),
130131
)
132+
133+
rest.answer = convertTableAnswerArrayToTableObject(
134+
rest.question,
135+
rest.answerArray,
136+
)
131137
} else {
132138
rest.answerArray = (rest.answerArray as string[]).map((answer) =>
133139
answer.replaceAll('\u0000', ''),
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { FOR_EACH_INPUT_SOURCE } from '@/apps/toolbox/common/constants'
2+
3+
import { extractLastTopLevelBracketContent } from '../triggers/new-submission/get-data-out-metadata'
4+
5+
type TableColumn = {
6+
id: string
7+
label: string
8+
name: string
9+
value: string
10+
}
11+
12+
const createColumn = (label: string): TableColumn => {
13+
const id = Buffer.from(label).toString('hex')
14+
return {
15+
id,
16+
label,
17+
name: label,
18+
value: `data.rows.*.data.${id}`,
19+
}
20+
}
21+
22+
export default function convertTableAnswerArrayToTableObject(
23+
question: string,
24+
answerArray: string[][],
25+
) {
26+
const { content: columnNames } = extractLastTopLevelBracketContent(question)
27+
const columnNamesArray = columnNames.split(',').map((name) => name.trim())
28+
29+
const columns =
30+
// make sure that column names do not contain commas
31+
columnNamesArray.length === answerArray[0].length
32+
? columnNamesArray.map(createColumn)
33+
: answerArray[0].map((_, index) => createColumn(`Col ${index + 1}`))
34+
35+
/**
36+
* NOTE: we do not show table rows that do not have any data
37+
*/
38+
const rows = (answerArray as string[][])
39+
.filter((row) => !row.every((v) => v === ''))
40+
.map((row) => {
41+
const rowData: Record<string, string | number> = {}
42+
row.forEach((v: string, i: number) => {
43+
rowData[columns[i].id] = v.replaceAll('\u0000', '')
44+
})
45+
return { data: rowData }
46+
})
47+
48+
return JSON.stringify({
49+
rows,
50+
columns,
51+
inputSource: FOR_EACH_INPUT_SOURCE.FORMSG_TABLE,
52+
})
53+
}

0 commit comments

Comments
 (0)