Openstatus www.openstatus.dev

🚫 limit sms per workspace (#1326)

* 🚫 limit sms per workspace

* ci: apply automated fixes

* feedback

* ci: apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>

authored by

Thibault Le Ouay
autofix-ci[bot]
and committed by
GitHub
ab8c37c6 c9c75c7d

+58 -1
+54 -1
apps/workflows/src/checker/alerting.ts
··· 1 - import { db, eq, schema } from "@openstatus/db"; 1 + import { and, count, db, eq, gte, inArray, schema } from "@openstatus/db"; 2 2 import type { MonitorStatus } from "@openstatus/db/src/schema"; 3 3 import { 4 4 selectMonitorSchema, 5 5 selectNotificationSchema, 6 + selectWorkspaceSchema, 6 7 } from "@openstatus/db/src/schema"; 7 8 8 9 import type { ··· 46 47 .where(eq(schema.monitor.id, Number(monitorId))) 47 48 .all(); 48 49 for (const notif of notifications) { 50 + // for sms check we are in the quota 51 + if (notif.notification.provider === "sms") { 52 + if (notif.notification.workspaceId === null) { 53 + continue; 54 + } 55 + 56 + const workspace = await db 57 + .select() 58 + .from(schema.workspace) 59 + .where(eq(schema.workspace.id, notif.notification.workspaceId)); 60 + 61 + if (workspace.length !== 1) { 62 + continue; 63 + } 64 + 65 + const data = selectWorkspaceSchema.parse(workspace[0]); 66 + 67 + const oneMonthAgo = new Date(); 68 + oneMonthAgo.setMonth(oneMonthAgo.getMonth() - 1); 69 + 70 + const smsNotification = await db 71 + .select() 72 + .from(schema.notification) 73 + .where( 74 + and( 75 + eq(schema.notification.workspaceId, notif.notification.workspaceId), 76 + eq(schema.notification.provider, "sms"), 77 + ), 78 + ); 79 + const ids = smsNotification.map((notification) => notification.id); 80 + 81 + const smsSent = await db 82 + .select({ count: count() }) 83 + .from(schema.notificationTrigger) 84 + .where( 85 + and( 86 + gte( 87 + schema.notificationTrigger.cronTimestamp, 88 + Math.floor(oneMonthAgo.getTime() / 1000), 89 + ), 90 + inArray(schema.notificationTrigger.notificationId, ids), 91 + ), 92 + ) 93 + .all(); 94 + 95 + if ((smsSent[0]?.count ?? 0) > data.limits["sms-limit"]) { 96 + console.log( 97 + `SMS quota exceeded for workspace ${notif.notification.workspaceId}`, 98 + ); 99 + continue; 100 + } 101 + } 49 102 console.log( 50 103 `💌 sending notification for ${monitorId} and chanel ${notif.notification.provider} for ${notifType}`, 51 104 );
+3
packages/db/src/schema/plan/config.ts
··· 44 44 "white-label": false, 45 45 notifications: true, 46 46 sms: false, 47 + "sms-limit": 0, 47 48 pagerduty: false, 48 49 opsgenie: false, 49 50 "notification-channels": 1, ··· 83 84 pagerduty: true, 84 85 opsgenie: true, 85 86 sms: true, 87 + "sms-limit": 50, 86 88 "notification-channels": 10, 87 89 members: "Unlimited", 88 90 "audit-log": false, ··· 154 156 "white-label": false, 155 157 notifications: true, 156 158 sms: true, 159 + "sms-limit": 100, 157 160 pagerduty: true, 158 161 opsgenie: true, 159 162 "notification-channels": 20,
+1
packages/db/src/schema/plan/schema.ts
··· 41 41 pagerduty: z.boolean().default(false), 42 42 opsgenie: z.boolean().default(false), 43 43 sms: z.boolean().default(false), 44 + "sms-limit": z.number().default(0), 44 45 "notification-channels": z.number().default(1), 45 46 /** 46 47 * Collaboration limits