Skip to content

Commit a23ed30

Browse files
committed
Rearrange partners cron workflows
1 parent 4fdfe7c commit a23ed30

File tree

10 files changed

+122
-115
lines changed

10 files changed

+122
-115
lines changed
Lines changed: 2 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,109 +1,4 @@
1-
import { getPartnerApplicationRisks } from "@/lib/api/fraud/get-partner-application-risks";
2-
import { withCron } from "@/lib/cron/with-cron";
3-
import { approvePartnerEnrollment } from "@/lib/partners/approve-partner-enrollment";
4-
import { getPlanCapabilities } from "@/lib/plan-capabilities";
5-
import { prisma } from "@dub/prisma";
6-
import * as z from "zod/v4";
7-
import { logAndRespond } from "../utils";
8-
91
export const dynamic = "force-dynamic";
102

11-
const schema = z.object({
12-
programId: z.string(),
13-
partnerId: z.string(),
14-
});
15-
16-
// POST /api/cron/auto-approve-partner
17-
// This route is used to auto-approve a partner enrolled in a program
18-
export const POST = withCron(async ({ rawBody }) => {
19-
const { programId, partnerId } = schema.parse(JSON.parse(rawBody));
20-
21-
const programEnrollment = await prisma.programEnrollment.findUnique({
22-
where: {
23-
partnerId_programId: {
24-
partnerId,
25-
programId,
26-
},
27-
},
28-
include: {
29-
partnerGroup: true,
30-
partner: {
31-
include: {
32-
platforms: true,
33-
},
34-
},
35-
},
36-
});
37-
38-
if (!programEnrollment) {
39-
return logAndRespond(
40-
`Partner ${partnerId} not found in program ${programId}. Skipping auto-approval.`,
41-
);
42-
}
43-
44-
const group = programEnrollment.partnerGroup;
45-
46-
if (!group) {
47-
return logAndRespond(
48-
`Group not found for partner ${partnerId} in program ${programId}. Skipping auto-approval.`,
49-
);
50-
}
51-
52-
if (!group.autoApprovePartnersEnabledAt) {
53-
return logAndRespond(
54-
`Group ${group.id} does not have auto-approval enabled. Skipping auto-approval.`,
55-
);
56-
}
57-
58-
if (programEnrollment.status !== "pending") {
59-
return logAndRespond(
60-
`${partnerId} is in ${programEnrollment.status} status. Skipping auto-approval.`,
61-
);
62-
}
63-
64-
// Check if the workspace plan has fraud event management capabilities
65-
// If enabled, we'll evaluate risk signals before auto-approving
66-
const program = await prisma.program.findUniqueOrThrow({
67-
where: {
68-
id: programId,
69-
},
70-
include: {
71-
workspace: {
72-
include: {
73-
users: {
74-
where: {
75-
role: "owner",
76-
},
77-
take: 1,
78-
},
79-
},
80-
},
81-
},
82-
});
83-
84-
const { canManageFraudEvents } = getPlanCapabilities(program.workspace.plan);
85-
86-
if (canManageFraudEvents) {
87-
const { riskSeverity } = await getPartnerApplicationRisks({
88-
program,
89-
partner: programEnrollment.partner,
90-
});
91-
92-
if (riskSeverity === "high") {
93-
return logAndRespond(
94-
`Partner ${partnerId} has high risk. Skipping auto-approval.`,
95-
);
96-
}
97-
}
98-
99-
await approvePartnerEnrollment({
100-
programId,
101-
partnerId,
102-
userId: program.workspace.users[0].userId,
103-
groupId: programEnrollment.groupId,
104-
});
105-
106-
return logAndRespond(
107-
`Successfully auto-approved partner ${partnerId} in program ${programId}.`,
108-
);
109-
});
3+
// TODO: Remove in 5 mins
4+
export { POST } from "../partners/auto-approve/route";
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import { getPartnerApplicationRisks } from "@/lib/api/fraud/get-partner-application-risks";
2+
import { withCron } from "@/lib/cron/with-cron";
3+
import { approvePartnerEnrollment } from "@/lib/partners/approve-partner-enrollment";
4+
import { getPlanCapabilities } from "@/lib/plan-capabilities";
5+
import { prisma } from "@dub/prisma";
6+
import * as z from "zod/v4";
7+
import { logAndRespond } from "../../utils";
8+
9+
export const dynamic = "force-dynamic";
10+
11+
const schema = z.object({
12+
programId: z.string(),
13+
partnerId: z.string(),
14+
});
15+
16+
// POST /api/cron/partners/auto-approve
17+
// This route is used to auto-approve a partner enrolled in a program
18+
export const POST = withCron(async ({ rawBody }) => {
19+
const { programId, partnerId } = schema.parse(JSON.parse(rawBody));
20+
21+
const programEnrollment = await prisma.programEnrollment.findUnique({
22+
where: {
23+
partnerId_programId: {
24+
partnerId,
25+
programId,
26+
},
27+
},
28+
include: {
29+
partnerGroup: true,
30+
partner: {
31+
include: {
32+
platforms: true,
33+
},
34+
},
35+
},
36+
});
37+
38+
if (!programEnrollment) {
39+
return logAndRespond(
40+
`Partner ${partnerId} not found in program ${programId}. Skipping auto-approval.`,
41+
);
42+
}
43+
44+
const group = programEnrollment.partnerGroup;
45+
46+
if (!group) {
47+
return logAndRespond(
48+
`Group not found for partner ${partnerId} in program ${programId}. Skipping auto-approval.`,
49+
);
50+
}
51+
52+
if (!group.autoApprovePartnersEnabledAt) {
53+
return logAndRespond(
54+
`Group ${group.id} does not have auto-approval enabled. Skipping auto-approval.`,
55+
);
56+
}
57+
58+
if (programEnrollment.status !== "pending") {
59+
return logAndRespond(
60+
`${partnerId} is in ${programEnrollment.status} status. Skipping auto-approval.`,
61+
);
62+
}
63+
64+
// Check if the workspace plan has fraud event management capabilities
65+
// If enabled, we'll evaluate risk signals before auto-approving
66+
const program = await prisma.program.findUniqueOrThrow({
67+
where: {
68+
id: programId,
69+
},
70+
include: {
71+
workspace: {
72+
include: {
73+
users: {
74+
where: {
75+
role: "owner",
76+
},
77+
take: 1,
78+
},
79+
},
80+
},
81+
},
82+
});
83+
84+
const { canManageFraudEvents } = getPlanCapabilities(program.workspace.plan);
85+
86+
if (canManageFraudEvents) {
87+
const { riskSeverity } = await getPartnerApplicationRisks({
88+
program,
89+
partner: programEnrollment.partner,
90+
});
91+
92+
if (riskSeverity === "high") {
93+
return logAndRespond(
94+
`Partner ${partnerId} has high risk. Skipping auto-approval.`,
95+
);
96+
}
97+
}
98+
99+
await approvePartnerEnrollment({
100+
programId,
101+
partnerId,
102+
userId: program.workspace.users[0].userId,
103+
groupId: programEnrollment.groupId,
104+
});
105+
106+
return logAndRespond(
107+
`Successfully auto-approved partner ${partnerId} in program ${programId}.`,
108+
);
109+
});

apps/web/app/(ee)/api/cron/partners/ban/process/cancel-commissions.ts renamed to apps/web/app/(ee)/api/cron/partners/ban/cancel-commissions.ts

File renamed without changes.

apps/web/app/(ee)/api/cron/partners/ban/process/route.ts renamed to apps/web/app/(ee)/api/cron/partners/ban/route.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@ import PartnerBanned from "@dub/email/templates/partner-banned";
1515
import { prisma } from "@dub/prisma";
1616
import { FraudRuleType } from "@dub/prisma/client";
1717
import * as z from "zod/v4";
18-
import { logAndRespond } from "../../../utils";
18+
import { logAndRespond } from "../../utils";
1919
import { cancelCommissions } from "./cancel-commissions";
2020

2121
const schema = z.object({
2222
programId: z.string(),
2323
partnerId: z.string(),
2424
});
2525

26-
// POST /api/cron/partners/ban/process - do the post-ban processing
26+
// POST /api/cron/partners/ban - handle all side effects of banning a partner
2727
export const POST = withCron(async ({ rawBody }) => {
2828
const { programId, partnerId } = schema.parse(JSON.parse(rawBody));
2929

@@ -78,6 +78,9 @@ export const POST = withCron(async ({ rawBody }) => {
7878
},
7979
data: {
8080
status: "rejected",
81+
rejectionReason: "other",
82+
rejectionNote:
83+
"Rejected automatically because the partner was banned.",
8184
},
8285
}),
8386

apps/web/app/(ee)/api/cron/merge-partner-accounts/route.ts renamed to apps/web/app/(ee)/api/cron/partners/merge-accounts/route.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const schema = z.object({
2424

2525
const CACHE_KEY_PREFIX = "merge-partner-accounts";
2626

27-
// POST /api/cron/merge-partner-accounts
27+
// POST /api/cron/partners/merge-accounts
2828
// This route is used to merge a partner account into another account
2929
export async function POST(req: Request) {
3030
let userId: string | null = null;

apps/web/lib/actions/partners/ban-partner.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ export const banPartner = async ({
122122
}),
123123

124124
queue.enqueueJSON({
125-
url: `${APP_DOMAIN_WITH_NGROK}/api/cron/partners/ban/process`,
125+
url: `${APP_DOMAIN_WITH_NGROK}/api/cron/partners/ban`,
126126
deduplicationId: `ban-${programId}-${partnerId}`,
127127
method: "POST",
128128
body: {

apps/web/lib/actions/partners/bulk-ban-partners.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ export const bulkBanPartnersAction = authActionClient
106106
enqueueBatchJobs(
107107
programEnrollments.map(({ programId, partnerId }) => ({
108108
queueName: "ban-partner",
109-
url: `${APP_DOMAIN_WITH_NGROK}/api/cron/partners/ban/process`,
109+
url: `${APP_DOMAIN_WITH_NGROK}/api/cron/partners/ban`,
110110
deduplicationId: `ban-${programId}-${partnerId}`,
111111
body: {
112112
programId,

apps/web/lib/actions/partners/create-program-application.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ async function createApplicationAndEnrollment({
262262
// Auto-approve the partner if the group has auto-approval enabled
263263
group.autoApprovePartnersEnabledAt
264264
? qstash.publishJSON({
265-
url: `${APP_DOMAIN_WITH_NGROK}/api/cron/auto-approve-partner`,
265+
url: `${APP_DOMAIN_WITH_NGROK}/api/cron/partners/auto-approve`,
266266
delay: 5 * 60,
267267
body: {
268268
programId: program.id,

apps/web/lib/actions/partners/merge-partner-accounts.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ const mergeAccounts = async ({ userId }: { userId: string }) => {
348348
const { sourceEmail, targetEmail } = accounts;
349349

350350
await qstash.publishJSON({
351-
url: `${APP_DOMAIN_WITH_NGROK}/api/cron/merge-partner-accounts`,
351+
url: `${APP_DOMAIN_WITH_NGROK}/api/cron/partners/merge-accounts`,
352352
body: {
353353
userId,
354354
sourceEmail,

apps/web/lib/partners/complete-program-applications.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ export async function completeProgramApplications(userEmail: string) {
197197
// Auto-approve the partner if the group has auto-approval enabled
198198
group?.autoApprovePartnersEnabledAt
199199
? qstash.publishJSON({
200-
url: `${APP_DOMAIN_WITH_NGROK}/api/cron/auto-approve-partner`,
200+
url: `${APP_DOMAIN_WITH_NGROK}/api/cron/partners/auto-approve`,
201201
delay: 5 * 60,
202202
body: {
203203
programId: program.id,

0 commit comments

Comments
 (0)