Skip to content

Commit 908d7ad

Browse files
committed
donotmerge: send fake sms
1 parent 4657f22 commit 908d7ad

File tree

3 files changed

+158
-1
lines changed

3 files changed

+158
-1
lines changed
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import sendFakeSms from './send-fake-sms'
12
import sendSms from './send-sms'
23

3-
export default [sendSms]
4+
export default [sendSms, sendFakeSms]
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import type { IRawAction } from '@plumber/types'
2+
3+
import axios from 'axios'
4+
import { ZodError } from 'zod'
5+
6+
import HttpError from '@/errors/http'
7+
import StepError, { GenericSolution } from '@/errors/step'
8+
import logger from '@/helpers/logger'
9+
import { ensureZodObjectKey, firstZodParseError } from '@/helpers/zod-utils'
10+
11+
import { authDataSchema } from '../../auth/schema'
12+
13+
// import getDataOutMetadata from './send-sms/get-data-out-metadata'
14+
import { fieldSchema, MAX_SMS_CHARS } from './schema'
15+
16+
const action = {
17+
name: 'Send FAKE SMS',
18+
key: 'sendFakeSms',
19+
description: 'Sends an SMS under Gov.SG sender ID',
20+
21+
/**
22+
* FEATURE NOTE
23+
* ---
24+
* This is a simplified feature where we don't enable users to specify
25+
* template variables (e.g. via a multi-row)
26+
*
27+
* This is because Postman does not provide an API to query template
28+
* variables, nor template contents (which we can parse). It's more than
29+
* likely that users will just get confused if we present them with a
30+
* "Template Variables" multi-select.
31+
*
32+
* Instead, for this action, we will instruct users to set up a campaign whose
33+
* template is just a {{body}} variable. We will provide a more advanced "Send
34+
* SMS with Variables" action later on, for users who are comfortable working
35+
* with template variables.
36+
*/
37+
arguments: [
38+
{
39+
label: 'Recipient phone number',
40+
description: 'Include country code prefix, e.g. +6581237123',
41+
key: ensureZodObjectKey(fieldSchema, 'recipient'),
42+
type: 'string' as const,
43+
required: true,
44+
variables: true,
45+
},
46+
{
47+
label: 'Message Body',
48+
description: `This corresponds to {{body}} in your campaign template. Max ${MAX_SMS_CHARS.toLocaleString()} characters`,
49+
key: ensureZodObjectKey(fieldSchema, 'message'),
50+
type: 'string' as const,
51+
required: true,
52+
variables: true,
53+
},
54+
],
55+
56+
// getDataOutMetadata,
57+
58+
async run($) {
59+
try {
60+
const parsedParams = fieldSchema.parse($.step.parameters)
61+
const authData = authDataSchema.parse($.auth.data)
62+
63+
const response = await axios.post(
64+
'https://kqbwrjfognb7gcslkta5dq37py0tswwl.lambda-url.ap-southeast-1.on.aws/',
65+
{
66+
recipient: parsedParams.recipient,
67+
language: 'english',
68+
values: {
69+
body: parsedParams.message,
70+
},
71+
},
72+
{
73+
urlPathParams: {
74+
campaignId: authData.campaignId,
75+
},
76+
},
77+
)
78+
79+
logger.error('Postman send single SMS response changed', {
80+
event: 'api-response-change',
81+
appName: 'postman-sms',
82+
eventName: 'sendSms',
83+
})
84+
$.setActionItem({
85+
raw: {
86+
// Signal to the user that an SMS has at least been created by now.
87+
...response.data,
88+
},
89+
})
90+
} catch (error) {
91+
if (error instanceof ZodError) {
92+
throw new StepError(
93+
`Configuration problem: '${firstZodParseError(error)}'`,
94+
GenericSolution.ReconfigureInvalidField,
95+
$.step.position,
96+
$.app.name,
97+
)
98+
}
99+
100+
// This happens if user did not create a template in the format we expect.
101+
if (
102+
error instanceof HttpError &&
103+
error.response.status === 400 &&
104+
error.response.data.error?.code === 'parameter_invalid'
105+
) {
106+
throw new StepError(
107+
'Campaign template was not set up correctly',
108+
'Ensure that you have followed the instructions in our guide to set up your campaign template.',
109+
$.step.position,
110+
$.app.name,
111+
)
112+
}
113+
114+
throw new StepError(
115+
'Error sending SMS',
116+
error.message,
117+
$.step.position,
118+
$.app.name,
119+
)
120+
}
121+
},
122+
} satisfies IRawAction
123+
124+
export default action
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import z from 'zod'
2+
3+
// From Postman API docs
4+
// https://postman-v2.guides.gov.sg/faq/postman-v2-api-faq/campaign-related-inquiries
5+
export const MAX_SMS_CHARS = 1000
6+
7+
const telephoneNumberSchema = z
8+
.string()
9+
.trim()
10+
.min(1, { message: 'Enter a phone number' })
11+
// Also allow dash, brackets and spaces, which are commonly used as spacers in
12+
// phone numbers. We'll strip them out later.
13+
.regex(/^\+?[\d \-()]+$/g, 'Enter a valid phone number')
14+
.transform((phoneNumber) => phoneNumber.replaceAll(/[^\d]/g, ''))
15+
16+
export const fieldSchema = z.object({
17+
recipient: telephoneNumberSchema,
18+
message: z
19+
.string()
20+
.trim()
21+
.min(1, { message: 'Provide a non-empty message' })
22+
.max(MAX_SMS_CHARS, {
23+
message: `Message cannot exceed ${MAX_SMS_CHARS.toLocaleString()} characters`,
24+
}),
25+
})
26+
27+
// Subset of the full reply; the other fields are not needed.
28+
// https://postman-v2.guides.gov.sg/endpoints-for-api-users/single-send
29+
export const postmanMessageSchema = z.object({
30+
createdAt: z.string().datetime({ offset: true }),
31+
id: z.string(),
32+
})

0 commit comments

Comments
 (0)