@@ -3,10 +3,15 @@ import type Stripe from "stripe";
33import { z } from "zod" ;
44
55import { Events , setupAnalytics } from "@openstatus/analytics" ;
6- import { eq } from "@openstatus/db" ;
6+ import { and , asc , eq , isNull , ne } from "@openstatus/db" ;
77import {
8+ invitation ,
9+ monitor ,
10+ notification ,
11+ page ,
812 selectWorkspaceSchema ,
913 user ,
14+ usersToWorkspaces ,
1015 workspace ,
1116} from "@openstatus/db/src/schema" ;
1217
@@ -207,24 +212,108 @@ export const webhookRouter = createTRPCRouter({
207212 ? subscription . customer
208213 : subscription . customer . id ;
209214
210- const _workspace = await opts . ctx . db
211- . update ( workspace )
212- . set ( {
213- subscriptionId : null ,
214- plan : "free" ,
215- paidUntil : null ,
216- } )
217- . where ( eq ( workspace . stripeId , customerId ) )
218- . returning ( ) ;
215+ const _workspace = await opts . ctx . db . transaction ( async ( tx ) => {
216+ const _workspace = await tx
217+ . update ( workspace )
218+ . set ( {
219+ subscriptionId : null ,
220+ plan : "free" ,
221+ paidUntil : null ,
222+ endsAt : null ,
223+ limits : JSON . stringify ( getLimits ( "free" ) ) ,
224+ } )
225+ . where ( eq ( workspace . stripeId , customerId ) )
226+ . returning ( ) ;
219227
220- const customer = await stripe . customers . retrieve ( customerId ) ;
228+ if ( ! _workspace . length ) {
229+ throw new TRPCError ( {
230+ code : "BAD_REQUEST" ,
231+ message : "Workspace not found" ,
232+ } ) ;
233+ }
221234
222- if ( ! _workspace ) {
223- throw new TRPCError ( {
224- code : "BAD_REQUEST" ,
225- message : "Workspace not found" ,
226- } ) ;
227- }
235+ const workspaceId = _workspace [ 0 ] . id ;
236+
237+ const activeMonitors = await tx
238+ . select ( { id : monitor . id } )
239+ . from ( monitor )
240+ . where (
241+ and (
242+ eq ( monitor . workspaceId , workspaceId ) ,
243+ eq ( monitor . active , true ) ,
244+ isNull ( monitor . deletedAt ) ,
245+ ) ,
246+ )
247+ . orderBy ( asc ( monitor . createdAt ) ) ;
248+
249+ for ( const m of activeMonitors . slice ( 1 ) ) {
250+ await tx
251+ . update ( monitor )
252+ . set ( { active : false } )
253+ . where ( eq ( monitor . id , m . id ) )
254+ . run ( ) ;
255+ }
256+
257+ const statusPages = await tx
258+ . select ( { id : page . id } )
259+ . from ( page )
260+ . where ( eq ( page . workspaceId , workspaceId ) )
261+ . orderBy ( asc ( page . createdAt ) ) ;
262+
263+ for ( const p of statusPages . slice ( 1 ) ) {
264+ await tx . delete ( page ) . where ( eq ( page . id , p . id ) ) . run ( ) ;
265+ }
266+
267+ if ( statusPages . length > 0 ) {
268+ await tx
269+ . update ( page )
270+ . set ( {
271+ customDomain : "" ,
272+ password : null ,
273+ accessType : "public" ,
274+ authEmailDomains : null ,
275+ } )
276+ . where ( eq ( page . id , statusPages [ 0 ] . id ) )
277+ . run ( ) ;
278+ }
279+
280+ const notifications = await tx
281+ . select ( { id : notification . id , provider : notification . provider } )
282+ . from ( notification )
283+ . where ( eq ( notification . workspaceId , workspaceId ) )
284+ . orderBy ( asc ( notification . createdAt ) ) ;
285+
286+ const keepNotification =
287+ notifications . find ( ( n ) => n . provider === "email" ) ?? notifications [ 0 ] ;
288+
289+ for ( const n of notifications . filter (
290+ ( n ) => n . id !== keepNotification ?. id ,
291+ ) ) {
292+ await tx . delete ( notification ) . where ( eq ( notification . id , n . id ) ) . run ( ) ;
293+ }
294+
295+ // Remove all non-owner members from the workspace
296+ await tx
297+ . delete ( usersToWorkspaces )
298+ . where (
299+ and (
300+ eq ( usersToWorkspaces . workspaceId , workspaceId ) ,
301+ ne ( usersToWorkspaces . role , "owner" ) ,
302+ ) ,
303+ )
304+ . run ( ) ;
305+
306+ // Remove all pending invitations for the workspace
307+ await tx
308+ . delete ( invitation )
309+ . where ( eq ( invitation . workspaceId , workspaceId ) )
310+ . run ( ) ;
311+
312+ return _workspace ;
313+ } ) ;
314+
315+ const workspaceId = _workspace [ 0 ] . id ;
316+ const customer = await stripe . customers . retrieve ( customerId ) ;
228317
229318 if ( ! customer . deleted && customer . email ) {
230319 const userResult = await opts . ctx . db
@@ -237,7 +326,7 @@ export const webhookRouter = createTRPCRouter({
237326 const analytics = await setupAnalytics ( {
238327 userId : `usr_${ userResult . id } ` ,
239328 email : customer . email || undefined ,
240- workspaceId : String ( _workspace [ 0 ] . id ) ,
329+ workspaceId : String ( workspaceId ) ,
241330 plan : "free" ,
242331 } ) ;
243332 await analytics . track ( Events . DowngradeWorkspace ) ;
0 commit comments