Skip to content

Commit 7a25797

Browse files
authored
Fixbug adresse destination invalide (envoi de SMS) (#4648)
* refactor: améliore la gestion des erreurs des followups * refactor: log pas utile * refactor: inverse l'ordre d'envoi email / sms (followup) * fix: remonte erreur addresse de destination invalide du back + interprete sur le front * fix: message d'erreur dans le followup sauvegardé correctement * refactor: formulation message erreur front - adresse invalide
1 parent 45c8974 commit 7a25797

File tree

6 files changed

+87
-43
lines changed

6 files changed

+87
-43
lines changed

backend/controllers/followups.ts

Lines changed: 26 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ import { SurveyType } from "../../lib/enums/survey.js"
1010
import { FollowupFactory } from "../lib/followup-factory.js"
1111
import { FetchSurvey } from "../../lib/types/survey.d.js"
1212
import Request from "../types/express.d.js"
13-
import { phoneNumberValidation } from "../../lib/phone-number.js"
1413
import config from "../config/index.js"
1514
import { sendSimulationResultsEmail } from "../lib/messaging/email/email-service.js"
1615
import { sendSimulationResultsSms } from "../lib/messaging/sms/sms-service.js"
16+
import { ErrorType, ErrorStatus, ErrorName } from "../../lib/enums/error.js"
1717

1818
export function followup(
1919
req: Request,
@@ -39,23 +39,6 @@ export function followup(
3939
})
4040
}
4141

42-
async function sendFollowupNotifications(followup: Followup, res: Response) {
43-
const { email, phone } = followup
44-
if (phone) {
45-
if (
46-
phoneNumberValidation(phone, config.smsService.internationalDiallingCodes)
47-
) {
48-
await sendSimulationResultsSms(followup)
49-
} else {
50-
return res.status(422).send("Unsupported phone number format")
51-
}
52-
}
53-
if (email) {
54-
await sendSimulationResultsEmail(followup)
55-
}
56-
return res.send({ result: "OK" })
57-
}
58-
5942
async function createSimulationRecapUrl(req: Request, res: Response) {
6043
const followup = await FollowupFactory.create(req.simulation)
6144
await followup.addSurveyIfMissing(
@@ -69,6 +52,7 @@ async function createSimulationRecapUrl(req: Request, res: Response) {
6952
export async function persist(req: Request, res: Response) {
7053
const { surveyOptin, email, phone } = req.body
7154
const simulation = req.simulation
55+
7256
try {
7357
if (email || phone) {
7458
const followup = await FollowupFactory.createWithResults(
@@ -77,17 +61,27 @@ export async function persist(req: Request, res: Response) {
7761
email,
7862
phone
7963
)
80-
return sendFollowupNotifications(followup, res)
81-
} else {
82-
return createSimulationRecapUrl(req, res)
64+
if (email) await sendSimulationResultsEmail(followup)
65+
if (phone) await sendSimulationResultsSms(followup)
66+
return res.send({ result: "OK" })
8367
}
68+
69+
return createSimulationRecapUrl(req, res)
8470
} catch (error: any) {
8571
Sentry.captureException(error)
86-
if (error.name === "ValidationError") {
87-
return res.status(403).send(error.message)
88-
} else {
89-
return res.status(500).send(`Error while persisting followup`)
72+
73+
let status: number = ErrorStatus.InternalServerError
74+
75+
if (
76+
error.name === ErrorName.ValidationError ||
77+
error.message === ErrorType.UnsupportedPhoneNumberFormat
78+
) {
79+
status = ErrorStatus.UnprocessableEntity
9080
}
81+
82+
return res
83+
.status(status)
84+
.send(error.message || ErrorType.PersistingFollowup)
9185
}
9286
}
9387

@@ -117,7 +111,7 @@ export function showFollowup(req: Request, res: Response) {
117111
})
118112
.catch((error: Error) => {
119113
console.error("error", error)
120-
return res.sendStatus(400)
114+
return res.sendStatus(ErrorStatus.BadRequest)
121115
})
122116
}
123117

@@ -142,12 +136,13 @@ export function showSurveyResults(req: Request, res: Response) {
142136
export function showSurveyResultByEmail(req: Request, res: Response) {
143137
Followups.findByEmail(req.params.email)
144138
.then((followups: Followup[]) => {
145-
if (!followups || !followups.length) return res.sendStatus(404)
139+
if (!followups || !followups.length)
140+
return res.sendStatus(ErrorStatus.NotFound)
146141
res.send(followups)
147142
})
148143
.catch((error: Error) => {
149144
console.error("error", error)
150-
return res.sendStatus(400)
145+
return res.sendStatus(ErrorStatus.BadRequest)
151146
})
152147
}
153148

@@ -160,7 +155,7 @@ export async function followupByAccessToken(
160155
const followup: Followup | null = await Followups.findOne({
161156
accessToken,
162157
})
163-
if (!followup) return res.sendStatus(404)
158+
if (!followup) return res.sendStatus(ErrorStatus.NotFound)
164159
req.followup = followup
165160
next()
166161
}
@@ -216,7 +211,7 @@ async function getRedirectUrl(req: Request) {
216211
case SurveyType.TousABordNotification:
217212
return "https://www.tadao.fr/713-Demandeur-d-emploi.html"
218213
default:
219-
throw new Error(`Unknown survey type: ${surveyType}`)
214+
throw new Error(`${ErrorType.UnknownSurveyType} : ${surveyType}`)
220215
}
221216
}
222217

@@ -227,7 +222,6 @@ export async function logSurveyLinkClick(req: Request, res: Response) {
227222
res.redirect(redirectUrl)
228223
} catch (error) {
229224
Sentry.captureException(error)
230-
console.error("error", error)
231-
return res.sendStatus(404)
225+
return res.sendStatus(ErrorStatus.NotFound)
232226
}
233227
}

backend/lib/messaging/email/email-service.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@ import { EmailType } from "../../../../lib/enums/messaging.js"
77
import { SurveyType } from "../../../../lib/enums/survey.js"
88
import { Survey } from "../../../../lib/types/survey.js"
99
import { Followup } from "../../../../lib/types/followup.js"
10+
import { ErrorType } from "../../../../lib/enums/error.js"
1011
import dayjs from "dayjs"
1112

1213
export async function sendSimulationResultsEmail(
1314
followup: Followup
1415
): Promise<Followup> {
1516
if (!followup.email) {
16-
throw new Error("Missing followup email")
17+
throw new Error(ErrorType.MissingFollowupEmail)
1718
}
1819
const render: any = await emailRender(EmailType.SimulationResults, followup)
1920
const sendEmailSmtpResponse = await sendEmailSmtp({

backend/lib/messaging/sms/sms-service.ts

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
import axios from "axios"
22
import config from "../../../config/index.js"
3-
import { phoneNumberFormatting } from "./../../../../lib/phone-number.js"
3+
import {
4+
phoneNumberFormatting,
5+
phoneNumberValidation,
6+
} from "./../../../../lib/phone-number.js"
47
import { SmsType } from "../../../../lib/enums/messaging.js"
58
import { Followup } from "../../../../lib/types/followup.js"
69
import { Survey } from "../../../../lib/types/survey.d.js"
710
import { SurveyType } from "../../../../lib/enums/survey.js"
11+
import { ErrorType } from "../../../../lib/enums/error.js"
812
import dayjs from "dayjs"
913
import Sentry from "@sentry/node"
1014

@@ -69,7 +73,16 @@ export async function sendSimulationResultsSms(
6973
): Promise<Followup> {
7074
try {
7175
if (!followup.phone) {
72-
throw new Error("Missing followup phone")
76+
throw new Error(ErrorType.MissingFollowupPhone)
77+
}
78+
79+
if (
80+
!phoneNumberValidation(
81+
followup.phone,
82+
config.smsService.internationalDiallingCodes
83+
)
84+
) {
85+
throw new Error(ErrorType.UnsupportedPhoneNumberFormat)
7386
}
7487

7588
const { username, password } = await getSMSConfig()
@@ -90,10 +103,14 @@ export async function sendSimulationResultsSms(
90103
followup.smsSentAt = dayjs().toDate()
91104
followup.smsMessageId = data.messageIds[0]
92105
return await followup.save()
93-
} catch (err) {
94-
Sentry.captureException(err)
95-
followup.smsError = JSON.stringify(err, null, 2)
96-
throw err
106+
} catch (error: any) {
107+
// Avoid sending invalid destination address error to sentry
108+
if (!error?.message?.includes("Invalid destination address")) {
109+
Sentry.captureException(error)
110+
}
111+
followup.smsError = error?.message
112+
await followup.save()
113+
throw error
97114
}
98115
}
99116

lib/enums/error.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
export enum ErrorType {
2+
UnsupportedPhoneNumberFormat = "Unsupported phone number format",
3+
PersistingFollowup = "Persisting followup error",
4+
MissingFollowupPhone = "Missing followup phone",
5+
MissingFollowupEmail = "Missing followup email",
6+
UnknownSurveyType = "Unknown survey type",
7+
}
8+
9+
export enum ErrorStatus {
10+
BadRequest = 400,
11+
Unauthorized = 401,
12+
Forbidden = 403,
13+
UnprocessableEntity = 422,
14+
NotFound = 404,
15+
InternalServerError = 500,
16+
}
17+
18+
export enum ErrorName {
19+
ValidationError = "ValidationError",
20+
}

src/components/modals/errors-email-and-sms-modal.vue

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,16 @@ const recapEmailState = computed(() => store.recapEmailState)
2525
}}
2626
</p>
2727
</div>
28+
<div
29+
v-if="recapPhoneState === 'invalid-address'"
30+
class="fr-alert fr-alert--error"
31+
>
32+
<p>
33+
Une erreur s'est produite dans l'envoi du récapitulatif par SMS :
34+
l'adresse de destination est invalide. Veuillez réessayer avec un
35+
numéro valide ou utiliser l'envoi par email seulement.
36+
</p>
37+
</div>
2838
<div
2939
v-if="recapPhoneState === 'ok' && recapEmailState === 'ok'"
3040
class="fr-alert fr-alert--success"

src/components/recap-email-and-sms-form.vue

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,12 @@ const sendRecap = async (surveyOptin) => {
8181
ABTestingService.getValues().CTA_EmailRecontact
8282
)
8383
}
84-
} catch (error) {
85-
console.error(error)
86-
Sentry.captureException(error)
84+
} catch (error: any) {
85+
if (!error?.response?.data?.includes("Invalid destination address")) {
86+
Sentry.captureException(error)
87+
} else {
88+
store.setFormRecapPhoneState("invalid-address")
89+
}
8790
}
8891
}
8992
@@ -181,7 +184,6 @@ const sendRecapByEmail = async (surveyOptin) => {
181184
store.setModalState(undefined)
182185
await postFollowup(surveyOptin, emailValue.value)
183186
} catch (error) {
184-
Sentry.captureException(error)
185187
store.setFormRecapEmailState("error")
186188
throw error
187189
}

0 commit comments

Comments
 (0)