Openstatus www.openstatus.dev

chore: api maintenance notification (#1554)

* chore: api maintenance notification

* chore: add condition

authored by

Maximilian Kaske and committed by
GitHub
8826e499 2ed9713d

+55 -3
+46 -2
apps/server/src/routes/v1/maintenances/post.ts
··· 1 + import { env } from "@/env"; 1 2 import { OpenStatusApiError, openApiErrorResponses } from "@/libs/errors"; 2 3 import { trackMiddleware } from "@/libs/middlewares"; 3 4 import { createRoute } from "@hono/zod-openapi"; 4 5 import { Events } from "@openstatus/analytics"; 5 - import { and, db, eq, inArray, isNull } from "@openstatus/db"; 6 - import { monitor, page } from "@openstatus/db/src/schema"; 6 + import { and, db, eq, inArray, isNotNull, isNull } from "@openstatus/db"; 7 + import { monitor, page, pageSubscriber } from "@openstatus/db/src/schema"; 7 8 import { 8 9 maintenance, 9 10 maintenancesToMonitors, 10 11 } from "@openstatus/db/src/schema/maintenances"; 12 + import { EmailClient } from "@openstatus/emails"; 11 13 import type { maintenancesApi } from "./index"; 12 14 import { MaintenanceSchema } from "./schema"; 15 + 16 + const emailClient = new EmailClient({ apiKey: env.RESEND_API_KEY }); 13 17 14 18 const postRoute = createRoute({ 15 19 method: "post", ··· 43 47 return api.openapi(postRoute, async (c) => { 44 48 const workspaceId = c.get("workspace").id; 45 49 const input = c.req.valid("json"); 50 + const limits = c.get("workspace").limits; 46 51 47 52 const { monitorIds, pageId } = input; 48 53 ··· 102 107 103 108 return newMaintenance; 104 109 }); 110 + 111 + if (limits["status-subscribers"] && _maintenance.pageId) { 112 + const subscribers = await db 113 + .select() 114 + .from(pageSubscriber) 115 + .where( 116 + and( 117 + eq(pageSubscriber.pageId, _maintenance.pageId), 118 + isNotNull(pageSubscriber.acceptedAt), 119 + ), 120 + ) 121 + .all(); 122 + 123 + const _page = await db.query.page.findFirst({ 124 + where: and( 125 + eq(page.id, _maintenance.pageId), 126 + eq(page.workspaceId, workspaceId), 127 + ), 128 + with: { 129 + monitorsToPages: { 130 + with: { 131 + monitor: true, 132 + }, 133 + }, 134 + }, 135 + }); 136 + 137 + if (_page && subscribers.length > 0) { 138 + await emailClient.sendStatusReportUpdate({ 139 + to: subscribers.map((subscriber) => subscriber.email), 140 + pageTitle: _page.title, 141 + reportTitle: _maintenance.title, 142 + status: "maintenance", 143 + message: _maintenance.message, 144 + date: _maintenance.from.toISOString(), 145 + monitors: _page.monitorsToPages.map((i) => i.monitor.name), 146 + }); 147 + } 148 + } 105 149 106 150 const data = MaintenanceSchema.parse({ 107 151 ..._maintenance,
+9 -1
packages/api/src/router/email/index.ts
··· 56 56 57 57 if (!_statusReportUpdate) return; 58 58 if (!_statusReportUpdate.statusReport.page) return; 59 + if ( 60 + _statusReportUpdate.statusReport.page.workspaceId !== 61 + opts.ctx.workspace.id 62 + ) 63 + return; 59 64 if (!_statusReportUpdate.statusReport.page.pageSubscribers.length) 60 65 return; 61 66 ··· 82 87 83 88 if (limits["status-subscribers"]) { 84 89 const _maintenance = await opts.ctx.db.query.maintenance.findFirst({ 85 - where: eq(maintenance.id, opts.input.id), 90 + where: and( 91 + eq(maintenance.id, opts.input.id), 92 + eq(maintenance.workspaceId, opts.ctx.workspace.id), 93 + ), 86 94 with: { 87 95 maintenancesToMonitors: { 88 96 with: {