Skip to content

Commit

Permalink
Merge branch 'main' into embed
Browse files Browse the repository at this point in the history
  • Loading branch information
devkiran committed Mar 3, 2025
2 parents 7b9b8e0 + 563b020 commit d9e5c74
Show file tree
Hide file tree
Showing 59 changed files with 744 additions and 243 deletions.
6 changes: 4 additions & 2 deletions apps/web/app/api/analytics/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
analyticsPathParamsSchema,
analyticsQuerySchema,
} from "@/lib/zod/schemas/analytics";
import { Link } from "@dub/prisma/client";
import { Folder, Link } from "@dub/prisma/client";
import { NextResponse } from "next/server";

// GET /api/analytics – get analytics
Expand Down Expand Up @@ -64,8 +64,9 @@ export const GET = withWorkspace(

const folderIdToVerify = link?.folderId || folderId;

let selectedFolder: Pick<Folder, "id" | "type"> | null = null;
if (folderIdToVerify) {
await verifyFolderAccess({
selectedFolder = await verifyFolderAccess({
workspace,
userId: session.user.id,
folderId: folderIdToVerify,
Expand Down Expand Up @@ -106,6 +107,7 @@ export const GET = withWorkspace(
isDeprecatedClicksEndpoint,
dataAvailableFrom: workspace.createdAt,
folderIds,
isMegaFolder: selectedFolder?.type === "mega",
});

return NextResponse.json(response);
Expand Down
6 changes: 4 additions & 2 deletions apps/web/app/api/events/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { throwIfClicksUsageExceeded } from "@/lib/api/links/usage-checks";
import { withWorkspace } from "@/lib/auth";
import { verifyFolderAccess } from "@/lib/folder/permissions";
import { eventsQuerySchema } from "@/lib/zod/schemas/analytics";
import { Link } from "@dub/prisma/client";
import { Folder, Link } from "@dub/prisma/client";
import { NextResponse } from "next/server";

export const GET = withWorkspace(
Expand Down Expand Up @@ -46,8 +46,9 @@ export const GET = withWorkspace(

const folderIdToVerify = link?.folderId || folderId;

let selectedFolder: Pick<Folder, "id" | "type"> | null = null;
if (folderIdToVerify) {
await verifyFolderAccess({
selectedFolder = await verifyFolderAccess({
workspace,
userId: session.user.id,
folderId: folderIdToVerify,
Expand Down Expand Up @@ -78,6 +79,7 @@ export const GET = withWorkspace(
workspaceId: workspace.id,
folderIds,
folderId: folderId || "",
isMegaFolder: selectedFolder?.type === "mega",
});

return NextResponse.json(response);
Expand Down
17 changes: 15 additions & 2 deletions apps/web/app/api/links/count/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { getFolderIdsToFilter } from "@/lib/analytics/get-folder-ids-to-filter";
import { getDomainOrThrow } from "@/lib/api/domains/get-domain-or-throw";
import { DubApiError } from "@/lib/api/errors";
import { getLinksCount } from "@/lib/api/links";
import { withWorkspace } from "@/lib/auth";
import { verifyFolderAccess } from "@/lib/folder/permissions";
Expand All @@ -18,27 +19,39 @@ export const GET = withWorkspace(
}

if (folderId) {
await verifyFolderAccess({
const selectedFolder = await verifyFolderAccess({
workspace,
userId: session.user.id,
folderId,
requiredPermission: "folders.read",
});
if (selectedFolder.type === "mega") {
throw new DubApiError({
code: "bad_request",
message: "Cannot get links count for mega folders.",
});
}
}

/* we only need to get the folder ids if we are:
- not filtering by folder
- there's a groupBy
- filtering by search, domain, or tags
*/
const folderIds =
let folderIds =
!folderId && (groupBy || search || domain || tagId || tagIds || tagNames)
? await getFolderIdsToFilter({
workspace,
userId: session.user.id,
})
: undefined;

if (Array.isArray(folderIds)) {
folderIds = folderIds?.filter((id) => id !== "");
if (folderIds.length === 0) {
folderIds = undefined;
}
}
const count = await getLinksCount({
searchParams: params,
workspaceId: workspace.id,
Expand Down
14 changes: 12 additions & 2 deletions apps/web/app/api/links/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
getLinksQuerySchemaExtended,
linkEventSchema,
} from "@/lib/zod/schemas/links";
import { Folder } from "@dub/prisma/client";
import { LOCALHOST_IP } from "@dub/utils";
import { waitUntil } from "@vercel/functions";
import { NextResponse } from "next/server";
Expand All @@ -27,8 +28,9 @@ export const GET = withWorkspace(
await getDomainOrThrow({ workspace, domain });
}

let selectedFolder: Pick<Folder, "id" | "type"> | null = null;
if (folderId) {
await verifyFolderAccess({
selectedFolder = await verifyFolderAccess({
workspace,
userId: session.user.id,
folderId,
Expand All @@ -40,18 +42,26 @@ export const GET = withWorkspace(
- not filtering by folder
- filtering by search, domain, or tags
*/
const folderIds =
let folderIds =
!folderId && (search || domain || tagId || tagIds || tagNames)
? await getFolderIdsToFilter({
workspace,
userId: session.user.id,
})
: undefined;

if (Array.isArray(folderIds)) {
folderIds = folderIds?.filter((id) => id !== "");
if (folderIds.length === 0) {
folderIds = undefined;
}
}

const response = await getLinksForWorkspace({
...params,
workspaceId: workspace.id,
folderIds,
searchMode: selectedFolder?.type === "mega" ? "exact" : "fuzzy",
});

return NextResponse.json(response, {
Expand Down
113 changes: 113 additions & 0 deletions apps/web/app/api/partners/sales/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { DubApiError } from "@/lib/api/errors";
import { getProgramOrThrow } from "@/lib/api/programs/get-program-or-throw";
import { calculateSaleEarnings } from "@/lib/api/sales/calculate-sale-earnings";
import { parseRequestBody } from "@/lib/api/utils";
import { withWorkspace } from "@/lib/auth/workspace";
import { determinePartnerReward } from "@/lib/partners/determine-partner-reward";
import { updatePartnerSaleSchema } from "@/lib/zod/schemas/partners";
import { ProgramSaleSchema } from "@/lib/zod/schemas/program-sales";
import { prisma } from "@dub/prisma";
import { NextResponse } from "next/server";

// PATCH /api/partners/sales - update a sale
export const PATCH = withWorkspace(
async ({ req, workspace }) => {
const { programId, invoiceId, amount } = updatePartnerSaleSchema.parse(
await parseRequestBody(req),
);

const program = await getProgramOrThrow({
workspaceId: workspace.id,
programId,
});

const sale = await prisma.commission.findUnique({
where: {
programId_invoiceId: {
programId: program.id,
invoiceId,
},
},
include: {
partner: true,
},
});

if (!sale) {
throw new DubApiError({
code: "not_found",
message: `Sale with invoice ID ${invoiceId} not found for program ${programId}.`,
});
}

if (sale.status === "paid") {
throw new DubApiError({
code: "bad_request",
message: `Cannot update amount: Sale with invoice ID ${invoiceId} has already been paid.`,
});
}

const { partner } = sale;

const reward = await determinePartnerReward({
event: "sale",
partnerId: partner.id,
programId: program.id,
});

if (!reward) {
throw new DubApiError({
code: "not_found",
message: `No reward found for partner ${partner.id} in program ${program.id}.`,
});
}

// Recalculate the earnings based on the new amount
const earnings = calculateSaleEarnings({
reward,
sale: {
amount,
quantity: sale.quantity,
},
});

const updatedSale = await prisma.commission.update({
where: {
id: sale.id,
},
data: {
amount,
earnings,
},
});

// If the sale has already been paid, we need to update the payout
if (sale.status === "processed" && sale.payoutId) {
const earningsDifference = earnings - sale.earnings;

await prisma.payout.update({
where: {
id: sale.payoutId,
},
data: {
amount: {
...(earningsDifference < 0
? { decrement: Math.abs(earningsDifference) }
: { increment: earningsDifference }),
},
},
});
}

return NextResponse.json(ProgramSaleSchema.parse(updatedSale));
},
{
requiredPlan: [
"business",
"business extra",
"business max",
"business plus",
"enterprise",
],
},
);
Loading

0 comments on commit d9e5c74

Please sign in to comment.