Skip to content

Commit 902a3d1

Browse files
authored
Merge pull request #90 from Plant-for-the-Planet-org/main
Rebasing Main
2 parents 34360fd + 68cd140 commit 902a3d1

File tree

3 files changed

+90
-20
lines changed

3 files changed

+90
-20
lines changed

apps/server/src/Services/Notifier/Notifier/DeviceNotifier.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,35 @@ import {type NotificationParameters} from '../../../Interfaces/NotificationParam
22
import type Notifier from '../Notifier';
33
import {NOTIFICATION_METHOD} from '../methodConstants';
44
import {env} from '../../../env.mjs';
5-
import {logger} from '../../../../src/server/logger';
5+
import {logger} from '../../../server/logger';
6+
import {prisma} from '../../../server/db';
67

78
class DeviceNotifier implements Notifier {
89
getSupportedMethods(): Array<string> {
910
return [NOTIFICATION_METHOD.DEVICE];
1011
}
1112

13+
async deleteNotificationAndDevice(destination: string, notificationId: string): Promise<void> {
14+
try {
15+
// Delete the notification
16+
await prisma.notification.delete({
17+
where: {
18+
id: notificationId,
19+
},
20+
});
21+
// Unverify and disable the alertMethod
22+
await prisma.alertMethod.deleteMany({
23+
where: {
24+
destination: destination,
25+
method: NOTIFICATION_METHOD.DEVICE,
26+
}
27+
});
28+
logger(`Notification with ID: ${notificationId} deleted and alertMethod for destination: ${destination} has been unverified and disabled.`, "info");
29+
} catch (error) {
30+
logger(`Database Error: Couldn't modify the alertMethod or delete the notification: ${error}`, "error");
31+
}
32+
}
33+
1234
// OneSignal can send both iOS and android notifications,
1335
// "destination" from AlertMethod for method "device"
1436
// is the OneSignal player ID of the device.
@@ -43,9 +65,13 @@ class DeviceNotifier implements Notifier {
4365
console.log(response);
4466
if (!response.ok) {
4567
logger(
46-
`Failed to send notification. Error: ${response.statusText}`,
68+
`Failed to send device notification. Error: ${response.statusText} for ${parameters.id}`,
4769
'error',
4870
);
71+
// If device not found
72+
if(response.status === 404){
73+
await this.deleteNotificationAndDevice(destination, parameters.id)
74+
}
4975
return false;
5076
}
5177

apps/server/src/Services/Notifier/Notifier/WebhookNotifier.ts

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import {prisma} from '../../../server/db';
12
import {logger} from '../../../../src/server/logger';
23
import {type NotificationParameters} from '../../../Interfaces/NotificationParameters';
34
import type Notifier from '../Notifier';
@@ -8,6 +9,31 @@ class WebhookNotifier implements Notifier {
89
return [NOTIFICATION_METHOD.WEBHOOK];
910
}
1011

12+
async deleteNotificationDisableAndUnverifyWebhook(destination: string, notificationId: string): Promise<void> {
13+
try {
14+
// Delete the notification
15+
await prisma.notification.delete({
16+
where: {
17+
id: notificationId,
18+
},
19+
});
20+
// Unverify and disable the alertMethod
21+
await prisma.alertMethod.updateMany({
22+
where: {
23+
destination: destination,
24+
method: NOTIFICATION_METHOD.WEBHOOK,
25+
},
26+
data: {
27+
isVerified: false,
28+
isEnabled: false,
29+
},
30+
});
31+
logger(`Notification with ID: ${notificationId} deleted and alertMethod for destination: ${destination} has been unverified and disabled.`, "info");
32+
} catch (error) {
33+
logger(`Database Error: Couldn't modify the alertMethod or delete the notification: ${error}`, "error");
34+
}
35+
}
36+
1137
async notify(
1238
destination: string,
1339
parameters: NotificationParameters,
@@ -34,12 +60,27 @@ class WebhookNotifier implements Notifier {
3460

3561
if (!response.ok) {
3662
logger(
37-
`Failed to send notification. Error: ${response.statusText}`,
63+
`Failed to send webhook notification. Error: ${response.statusText} for ${parameters.id}.`,
3864
'error',
3965
);
66+
// Specific status code handling
67+
if (response.status === 404) {
68+
// Webhook URL Not Found - Token not found
69+
await this.deleteNotificationDisableAndUnverifyWebhook(destination, parameters.id);
70+
} else if (response.status === 401){
71+
// Unauthorized
72+
await this.deleteNotificationDisableAndUnverifyWebhook(destination, parameters.id);
73+
} else if (response.status === 403){
74+
// Forbidden
75+
await this.deleteNotificationDisableAndUnverifyWebhook(destination, parameters.id);
76+
} else {
77+
logger(
78+
`Failed to send webhook notification. Something went wrong. Try again in next run.`,
79+
'error',
80+
);
81+
}
4082
return false;
4183
}
42-
4384
return true;
4485
}
4586
}

apps/server/src/server/api/zodSchemas/alertMethod.schema.ts

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,34 @@
1-
import { z } from 'zod';
1+
import {z} from 'zod';
22
import phone from 'phone'
33
import validator from 'validator';
44

55
export const createAlertMethodSchema = z.object({
66
method: z.enum(["email", "sms", "device", "whatsapp", "webhook"]),
77
destination: z.string({
88
required_error: 'Destination of alert method must be specified'
9-
}).refine((value) => {
10-
const sanitized = validator.escape(value);
11-
return sanitized === value;
12-
}, {
13-
message: 'Contains invalid characters',
14-
}),
9+
}),
1510
deviceName: z.string().optional(),
1611
deviceId: z.string().optional(),
1712
}).refine((obj) => {
18-
if (obj.method === 'sms') {
19-
// Check if the destination is a valid phone number in E.164 format
20-
const { isValid } = phone(obj.destination);
21-
return isValid;
22-
}
23-
if (obj.method === 'email') {
24-
return z.string().email().safeParse(obj.destination).success;
13+
if(obj.method === 'webhook'){
14+
return true;
15+
}else{
16+
const sanitized = validator.escape(obj.destination);
17+
if (sanitized !== obj.destination){
18+
return false;
19+
}
20+
if (obj.method === 'sms') {
21+
// Check if the destination is a valid phone number in E.164 format
22+
const { isValid } = phone(obj.destination);
23+
return isValid;
24+
}
25+
if (obj.method === 'email') {
26+
return z.string().email().safeParse(obj.destination).success;
27+
}
28+
return true; // Return true for other methods
2529
}
26-
return true; // Return true for other methods
2730
}, {
28-
message: 'Must be a valid phone number in E.164 format when the method is "sms"'
31+
message: `Invalid Destination`
2932
});
3033

3134
export const params = z.object({

0 commit comments

Comments
 (0)