Openstatus
www.openstatus.dev
1import { TRPCError } from "@trpc/server";
2import { z } from "zod";
3
4import { Events } from "@openstatus/analytics";
5import { and, eq } from "@openstatus/db";
6import { page, pageSubscriber } from "@openstatus/db/src/schema";
7
8import { createTRPCRouter, protectedProcedure } from "../trpc";
9
10export const pageSubscriberRouter = createTRPCRouter({
11 getPageSubscribersByPageId: protectedProcedure
12 .input(z.object({ id: z.number() }))
13 .query(async (opts) => {
14 const _page = await opts.ctx.db.query.page.findFirst({
15 where: and(
16 eq(page.workspaceId, opts.ctx.workspace.id),
17 eq(page.id, opts.input.id),
18 ),
19 });
20
21 if (!_page) {
22 throw new TRPCError({
23 code: "UNAUTHORIZED",
24 message: "Unauthorized to get subscribers",
25 });
26 }
27
28 const data = await opts.ctx.db.query.pageSubscriber.findMany({
29 where: and(eq(pageSubscriber.pageId, _page.id)),
30 });
31 return data;
32 }),
33
34 unsubscribeById: protectedProcedure
35 .input(z.object({ id: z.number() }))
36 .mutation(async (opts) => {
37 const subscriber = await opts.ctx.db.query.pageSubscriber.findFirst({
38 where: and(eq(pageSubscriber.id, opts.input.id)),
39 });
40
41 if (!subscriber) {
42 throw new TRPCError({
43 code: "NOT_FOUND",
44 message: "Subscriber not found",
45 });
46 }
47
48 const _page = await opts.ctx.db.query.page.findFirst({
49 where: and(
50 eq(page.id, subscriber.pageId),
51 eq(page.workspaceId, opts.ctx.workspace.id),
52 ),
53 });
54
55 if (!_page) {
56 throw new TRPCError({
57 code: "UNAUTHORIZED",
58 message: "Unauthorized to unsubscribe",
59 });
60 }
61
62 return await opts.ctx.db
63 .delete(pageSubscriber)
64 .where(eq(pageSubscriber.id, subscriber.id));
65 }),
66
67 acceptSubscriberById: protectedProcedure
68 .meta({ track: Events.SubscribePage })
69 .input(z.object({ id: z.number() }))
70 .mutation(async (opts) => {
71 const subscriber = await opts.ctx.db.query.pageSubscriber.findFirst({
72 where: and(eq(pageSubscriber.id, opts.input.id)),
73 });
74
75 if (!subscriber) {
76 throw new TRPCError({
77 code: "NOT_FOUND",
78 message: "Subscriber not found",
79 });
80 }
81
82 const _page = await opts.ctx.db.query.page.findFirst({
83 where: and(
84 eq(page.id, subscriber.pageId),
85 eq(page.workspaceId, opts.ctx.workspace.id),
86 ),
87 });
88
89 if (!_page) {
90 throw new TRPCError({
91 code: "UNAUTHORIZED",
92 message: "Unauthorized to unsubscribe",
93 });
94 }
95
96 return await opts.ctx.db
97 .update(pageSubscriber)
98 .set({
99 acceptedAt: new Date(),
100 updatedAt: new Date(),
101 })
102 .where(eq(pageSubscriber.id, subscriber.id));
103 }),
104
105 // DASHBOARD
106
107 list: protectedProcedure
108 .input(
109 z.object({
110 pageId: z.number(),
111 order: z.enum(["asc", "desc"]).optional(),
112 }),
113 )
114 .query(async (opts) => {
115 const data = await opts.ctx.db.transaction(async (tx) => {
116 const _page = await tx.query.page.findFirst({
117 where: and(
118 eq(page.workspaceId, opts.ctx.workspace.id),
119 eq(page.id, opts.input.pageId),
120 ),
121 });
122
123 if (!_page) {
124 throw new TRPCError({
125 code: "NOT_FOUND",
126 message: "Page not found",
127 });
128 }
129
130 return await tx.query.pageSubscriber.findMany({
131 where: eq(pageSubscriber.pageId, _page.id),
132 });
133 });
134
135 return data;
136 }),
137
138 delete: protectedProcedure
139 .input(z.object({ id: z.number(), pageId: z.number() }))
140 .mutation(async (opts) => {
141 await opts.ctx.db.transaction(async (tx) => {
142 const _page = await tx.query.page.findFirst({
143 where: and(
144 eq(page.workspaceId, opts.ctx.workspace.id),
145 eq(page.id, opts.input.pageId),
146 ),
147 });
148
149 if (!_page) {
150 throw new TRPCError({
151 code: "NOT_FOUND",
152 message: "Page not found",
153 });
154 }
155
156 const subscriber = await tx.query.pageSubscriber.findFirst({
157 where: and(
158 eq(pageSubscriber.id, opts.input.id),
159 eq(pageSubscriber.pageId, opts.input.pageId),
160 ),
161 });
162
163 if (!subscriber) {
164 throw new TRPCError({
165 code: "NOT_FOUND",
166 message: "Subscriber not found",
167 });
168 }
169
170 return await tx
171 .delete(pageSubscriber)
172 .where(eq(pageSubscriber.id, opts.input.id));
173 });
174 }),
175});