Skip to content

Commit 9dd9fb3

Browse files
authored
Add reactivateProgram (dubinc#3764)
1 parent 2a1e6dd commit 9dd9fb3

File tree

4 files changed

+66
-18
lines changed

4 files changed

+66
-18
lines changed

apps/web/app/(ee)/api/cron/partners/reactivate/route.ts renamed to apps/web/app/(ee)/api/cron/programs/reactivate/route.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const inputSchema = z.object({
1111
programId: z.string(),
1212
});
1313

14-
// POST /api/cron/partners/reactivate - reactivate partners in a program
14+
// POST /api/cron/programs/reactivate - reactivate all partners in a program
1515
export const POST = withCron(async ({ rawBody }) => {
1616
const { programId } = inputSchema.parse(JSON.parse(rawBody));
1717

@@ -69,7 +69,7 @@ export const POST = withCron(async ({ rawBody }) => {
6969
// Self-queue the next batch if there are more partners to process
7070
if (programEnrollments.length === CRON_BATCH_SIZE) {
7171
const response = await qstash.publishJSON({
72-
url: `${APP_DOMAIN_WITH_NGROK}/api/cron/partners/reactivate`,
72+
url: `${APP_DOMAIN_WITH_NGROK}/api/cron/programs/reactivate`,
7373
body: {
7474
programId,
7575
},

apps/web/app/(ee)/api/stripe/webhook/checkout-session-completed.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { createProgram } from "@/lib/actions/partners/create-program";
22
import { claimDotLinkDomain } from "@/lib/api/domains/claim-dot-link-domain";
3+
import { reactivateProgram } from "@/lib/api/programs/reactivate-program";
34
import { onboardingStepCache } from "@/lib/api/workspaces/onboarding-step-cache";
45
import { tokenCache } from "@/lib/auth/token-cache";
6+
import { wouldGainPartnerAccess } from "@/lib/plans/has-partner-access";
57
import { stripe } from "@/lib/stripe";
68
import { WorkspaceProps } from "@/lib/types";
79
import { redis } from "@/lib/upstash";
@@ -54,7 +56,7 @@ export async function checkoutSessionCompleted(
5456
// in the database for easy identification in future webhook events
5557
// also update the billingCycleStart to today's date
5658

57-
const workspace = await prisma.project.update({
59+
const updatedWorkspace = await prisma.project.update({
5860
where: {
5961
id: workspaceId,
6062
},
@@ -102,14 +104,21 @@ export async function checkoutSessionCompleted(
102104
},
103105
});
104106

105-
const users = workspace.users.map(({ user }) => ({
107+
const users = updatedWorkspace.users.map(({ user }) => ({
106108
id: user.id,
107109
name: user.name,
108110
email: user.email,
109111
}));
110112

111113
await Promise.allSettled([
112114
completeOnboarding({ users, workspaceId }),
115+
// if workspace had a program from before and is upgrading to an eligible plan, reactivate it
116+
updatedWorkspace.defaultProgramId &&
117+
wouldGainPartnerAccess({
118+
currentPlan: "free",
119+
newPlan: updatedWorkspace.plan,
120+
}) &&
121+
reactivateProgram(updatedWorkspace.defaultProgramId),
113122
sendBatchEmail(
114123
users.map((user) => ({
115124
to: user.email as string,
@@ -135,7 +144,9 @@ export async function checkoutSessionCompleted(
135144
}),
136145
// expire tokens cache
137146
tokenCache.expireMany({
138-
hashedKeys: workspace.restrictedTokens.map(({ hashedKey }) => hashedKey),
147+
hashedKeys: updatedWorkspace.restrictedTokens.map(
148+
({ hashedKey }) => hashedKey,
149+
),
139150
}),
140151
]);
141152

apps/web/app/(ee)/api/stripe/webhook/utils/update-workspace-plan.ts

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { deleteWorkspaceFolders } from "@/lib/api/folders/delete-workspace-folders";
22
import { deactivateProgram } from "@/lib/api/programs/deactivate-program";
3+
import { reactivateProgram } from "@/lib/api/programs/reactivate-program";
34
import { tokenCache } from "@/lib/auth/token-cache";
4-
import { qstash } from "@/lib/cron";
55
import { syncUserPlanToPlain } from "@/lib/plain/sync-user-plan";
66
import { getPlanCapabilities } from "@/lib/plan-capabilities";
77
import {
@@ -11,7 +11,7 @@ import {
1111
import { WorkspaceProps } from "@/lib/types";
1212
import { webhookCache } from "@/lib/webhook/cache";
1313
import { prisma } from "@dub/prisma";
14-
import { APP_DOMAIN_WITH_NGROK, getPlanAndTierFromPriceId } from "@dub/utils";
14+
import { getPlanAndTierFromPriceId } from "@dub/utils";
1515
import { NEW_BUSINESS_PRICE_IDS } from "@dub/utils/src";
1616
import { waitUntil } from "@vercel/functions";
1717

@@ -187,17 +187,7 @@ export async function updateWorkspacePlan({
187187
}) &&
188188
workspace.defaultProgramId
189189
) {
190-
const response = await qstash.publishJSON({
191-
url: `${APP_DOMAIN_WITH_NGROK}/api/cron/partners/reactivate`,
192-
body: {
193-
programId: workspace.defaultProgramId,
194-
},
195-
deduplicationId: `reactivate-program-${workspace.defaultProgramId}`,
196-
});
197-
198-
console.log("Reactivation job enqueued.", {
199-
response,
200-
});
190+
await reactivateProgram(workspace.defaultProgramId);
201191
}
202192

203193
if (
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { qstash } from "@/lib/cron";
2+
import { DEFAULT_PARTNER_GROUP } from "@/lib/zod/schemas/groups";
3+
import { prisma } from "@dub/prisma";
4+
import { APP_DOMAIN_WITH_NGROK } from "@dub/utils";
5+
6+
export async function reactivateProgram(programId: string) {
7+
if (!programId) {
8+
throw new Error("[reactivateProgram] programId is required");
9+
}
10+
11+
await prisma.$transaction([
12+
prisma.program.update({
13+
where: {
14+
id: programId,
15+
},
16+
data: {
17+
deactivatedAt: null,
18+
},
19+
}),
20+
21+
// republish the default group
22+
prisma.partnerGroup.update({
23+
where: {
24+
programId_slug: {
25+
programId,
26+
slug: DEFAULT_PARTNER_GROUP.slug,
27+
},
28+
},
29+
data: {
30+
applicationFormPublishedAt: new Date(),
31+
landerPublishedAt: new Date(),
32+
},
33+
}),
34+
]);
35+
36+
const response = await qstash.publishJSON({
37+
url: `${APP_DOMAIN_WITH_NGROK}/api/cron/programs/reactivate`,
38+
body: {
39+
programId,
40+
},
41+
deduplicationId: `reactivate-program-${programId}`,
42+
});
43+
44+
console.log("[reactivateProgram] Reactivation job enqueued.", { response });
45+
46+
return response;
47+
}

0 commit comments

Comments
 (0)