Skip to content

Commit 5822024

Browse files
authored
chore: raise postman attachment size limit (#1227)
## Problem Users are unable to upload attachments larger than 2 MB to send via Email by Postman. This was imposed as the following was mentioned in Postman's API [docs](https://postman-v1.guides.gov.sg/email-api-guide/programmatic-email-api/send-email-api/attachments): > - Each email can have up to 10 attachments. > - Each attachment should not exceed 2MB in size. > - The cumulative size of all attachments should not exceed 10MB. ## Solution Following various tests, it was concluded that: - The cumulative size of all attachments should not exceed 10MB. - The maximum file size of a single attachment is 10MB. With that we relax the limits on Plumber to the following: - Each attachment should not exceed 10MB ins size. - The cumulative size of all attachments should not exceed 10MB. ## Bugfix Discovered a bug that was not computing the cumulative size correctly, allowing for files to still be selected even after exceeding the 10MB limit. ## Tests New limits - [ ] Can upload and send attachments that are larger than 2MB but less than 10MB. - [ ] Can upload and send multiple attachments as long as cumulative size is less than 10MB. Bugfix - [ ] Cannot select new file if the new file causes the cumulative size to exceed 10MB Existing Pipes - [ ] Pipes with existing attachments work as per normal
1 parent 331811c commit 5822024

File tree

5 files changed

+25
-15
lines changed

5 files changed

+25
-15
lines changed

packages/backend/src/graphql/__tests__/mutations/generate-presigned-post.itest.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ vi.mock('@/helpers/s3', () => ({
2020
COMMON_S3_BUCKET: 'test-bucket',
2121
COMMON_S3_MOCK_FOLDER_PREFIX: 's3:test-bucket:mock/',
2222
parseS3Id: vi.fn(),
23-
MAX_FILE_SIZE: 1024 * 1024 * 2,
23+
MAX_FILE_SIZE: 1024 * 1024 * 10,
2424
ACCEPTED_FILE_TYPES: ['text/plain'],
2525
validateObjectKey: vi.fn((objectKey) => {
2626
const invalidCharacters = /[\\{}^`%~#<>|[\]]/
@@ -88,10 +88,10 @@ describe('generatePresignedPost', () => {
8888
userId: context.currentUser.id,
8989
})
9090

91-
const tooLargeParams = { ...VALID_PARAMS, size: 2 * 1024 * 1024 + 1 }
91+
const tooLargeParams = { ...VALID_PARAMS, size: 10 * 1024 * 1024 + 1 }
9292
await expect(
9393
generatePresignedPost(null, { input: tooLargeParams }, context),
94-
).rejects.toThrow('Size of attachment exceeds 2MB')
94+
).rejects.toThrow('Size of attachment exceeds 10MB')
9595
})
9696

9797
it.each([

packages/backend/src/graphql/mutations/generate-presigned-post.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const generatePresignedPost: MutationResolvers['generatePresignedPost'] =
1717
const { flowId, filename, fileType, size, updatedAt } = params.input
1818

1919
if (size > MAX_FILE_SIZE) {
20-
throw new Error('Size of attachment exceeds 2MB')
20+
throw new Error('Size of attachment exceeds 10MB')
2121
}
2222
if (!ACCEPTED_FILE_TYPES.includes(fileType)) {
2323
throw new Error('Unsupported file type')

packages/backend/src/helpers/s3.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ export const ACCEPTED_FILE_TYPES = [
7272
'video/x-ms-wmv', // .wmv
7373
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xlsx
7474
]
75-
export const MAX_FILE_SIZE = 1024 * 1024 * 2 // 2 MB
75+
export const MAX_FILE_SIZE = 1024 * 1024 * 10 // 10MB
7676

7777
function throwAttachmentError(
7878
errorType: string,

packages/frontend/src/components/AttachmentSuggestions/index.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,11 @@ function AttachmentSuggestions(props: AttachmentSuggestionsProps) {
9595
if (!checked) {
9696
onChange?.(currentValues.filter((v: string) => v !== nameToCheck))
9797
} else {
98-
const { isValid, error } = validateFiles(variable, currentValues)
98+
const { isValid, error } = validateFiles(
99+
variable,
100+
options,
101+
getValues(name),
102+
)
99103
if (!isValid) {
100104
setError(name, { type: 'invalidFile', message: error })
101105
} else {
@@ -140,14 +144,14 @@ function AttachmentSuggestions(props: AttachmentSuggestionsProps) {
140144

141145
const processFile = useCallback(
142146
async (file: File) => {
143-
const { isValid, error } = validateFiles(file, getValues(name))
147+
const { isValid, error } = validateFiles(file, options, getValues(name))
144148
if (!isValid) {
145149
setError(name, { type: 'invalidFile', message: error })
146150
} else {
147151
await uploadToS3(file, flowId)
148152
}
149153
},
150-
[flowId, getValues, name, setError, uploadToS3],
154+
[flowId, getValues, name, options, setError, uploadToS3],
151155
)
152156

153157
return (

packages/frontend/src/components/AttachmentSuggestions/utils.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ import { FieldValues } from 'react-hook-form'
44

55
import { type CheckboxVariable } from './components/Checkbox'
66

7+
const KB = 1024
8+
const MB = KB * KB
79
export const MAX_NUM_FILES = 10
8-
const MAX_FILE_SIZE = 2 * 1024 * 1024 // 2MB in bytes
9-
const MAX_TOTAL_FILE_SIZE = 5 * MAX_FILE_SIZE // 10MB in bytes
10+
const MAX_FILE_SIZE = 10 * MB // 10MB
11+
const MAX_TOTAL_FILE_SIZE = 10 * MB // 10MB
1012

1113
export const ACCEPTED_FILE_TYPES = [
1214
'text/plain', // .txt, .asc
@@ -54,13 +56,13 @@ type FileSizeValidationResult = {
5456
}
5557

5658
export function formatFileSizeToStr(sizeInBytes: number): string {
57-
if (sizeInBytes < 1024) {
59+
if (sizeInBytes < KB) {
5860
return `${sizeInBytes} B` // Bytes
59-
} else if (sizeInBytes < 1024 * 1024) {
60-
const sizeInKB = (sizeInBytes / 1024).toFixed(2) // Kilobytes with 2 decimal places
61+
} else if (sizeInBytes < MB) {
62+
const sizeInKB = (sizeInBytes / KB).toFixed(2) // Kilobytes with 2 decimal places
6163
return `${sizeInKB} KB`
6264
} else {
63-
const sizeInMB = (sizeInBytes / (1024 * 1024)).toFixed(2) // Megabytes with 2 decimal places
65+
const sizeInMB = (sizeInBytes / MB).toFixed(2) // Megabytes with 2 decimal places
6466
return `${sizeInMB} MB`
6567
}
6668
}
@@ -164,9 +166,13 @@ export function reformatToAttachmentConfig(
164166

165167
export function validateFiles(
166168
file: File | CheckboxVariable,
167-
selectedOptions: (AttachmentConfigInput | CheckboxVariable)[],
169+
options: CheckboxVariable[],
170+
currentSelection: string[],
168171
): FileSizeValidationResult {
169172
const fileSize = file.size ?? 0
173+
const selectedOptions = options.filter((o) =>
174+
currentSelection.includes(o.name),
175+
)
170176
const currentTotalSize = selectedOptions.reduce(
171177
(acc, curr) => acc + (curr?.size ?? 0),
172178
0,

0 commit comments

Comments
 (0)