Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ jobs:
env:
E2E_BASE_URL: ${{ github.event.deployment_status.environment_url }}
E2E_TOKEN: ${{ secrets.E2E_TOKEN }}
E2E_TOKEN_MEMBER: ${{ secrets.E2E_TOKEN_MEMBER }}
E2E_TOKEN_OLD: ${{ secrets.E2E_TOKEN_OLD }}
E2E_PUBLISHABLE_KEY: ${{ secrets.E2E_PUBLISHABLE_KEY }}
QSTASH_TOKEN: ${{ secrets.QSTASH_TOKEN }}
Expand Down
12 changes: 7 additions & 5 deletions apps/web/app/(ee)/api/cron/import/csv/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { handleAndReturnErrorResponse } from "@/lib/api/errors";
import { bulkCreateLinks, createLink, processLink } from "@/lib/api/links";
import { qstash } from "@/lib/cron";
import { verifyQstashSignature } from "@/lib/cron/verify-qstash";
import { ProcessedLinkProps, WorkspaceProps } from "@/lib/types";
import { ProcessedLinkProps } from "@/lib/types";
import { redis } from "@/lib/upstash";
import { linkMappingSchema } from "@/lib/zod/schemas/import-csv";
import { createLinkBodySchema } from "@/lib/zod/schemas/links";
Expand Down Expand Up @@ -384,6 +384,11 @@ const processMappedLinks = async ({
select: {
id: true,
plan: true,
users: {
where: {
userId,
},
},
},
});

Expand All @@ -397,10 +402,7 @@ const processMappedLinks = async ({
folderId,
}),
},
workspace: {
id: workspaceId,
plan: workspace.plan as WorkspaceProps["plan"],
},
workspace,
userId,
bulk: true,
}),
Expand Down
10 changes: 6 additions & 4 deletions apps/web/app/(ee)/api/cron/links/export/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { formatLinksForExport } from "@/lib/api/links/format-links-for-export";
import { validateLinksQueryFilters } from "@/lib/api/links/validate-links-query-filters";
import { generateExportFilename } from "@/lib/api/utils/generate-export-filename";
import { generateRandomString } from "@/lib/api/utils/generate-random-string";
import { MEGA_WORKSPACE_LINKS_LIMIT } from "@/lib/constants/misc";
import { verifyQstashSignature } from "@/lib/cron/verify-qstash";
import { WorkspaceProps } from "@/lib/types";
import { linksExportQuerySchema } from "@/lib/zod/schemas/links";
Expand Down Expand Up @@ -62,6 +63,7 @@ export async function POST(req: Request) {
id: true,
name: true,
plan: true,
totalLinks: true,
},
});

Expand All @@ -71,7 +73,7 @@ export async function POST(req: Request) {
);
}

const { selectedFolder, folderIds } = await validateLinksQueryFilters({
const { folderIds } = await validateLinksQueryFilters({
...filters,
userId,
workspace: workspace as WorkspaceProps,
Expand All @@ -87,16 +89,16 @@ export async function POST(req: Request) {

// Fetch links in batches and build CSV
const allLinks: Record<string, any>[] = [];
const searchMode: "fuzzy" | "exact" =
selectedFolder?.type === "mega" ? "exact" : "fuzzy";

const linksFilters = {
...filters,
...(interval !== "all" && {
startDate,
endDate,
}),
searchMode,
searchMode: (workspace.totalLinks > MEGA_WORKSPACE_LINKS_LIMIT
? "exact"
: "fuzzy") as "exact" | "fuzzy",
includeDashboard: false,
includeUser: false,
includeWebhooks: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ export const PATCH = withReferralsEmbedToken(
workspace: {
id: program.workspaceId,
plan: "business",
users: [{ role: "owner" }],
},
userId: link.userId!,
skipKeyChecks,
Expand Down
1 change: 1 addition & 0 deletions apps/web/app/(ee)/api/embed/referrals/links/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ export const POST = withReferralsEmbedToken(
workspace: {
id: program.workspaceId,
plan: "business",
users: [{ role: "owner" }],
},
userId: workspaceOwner?.userId,
skipFolderChecks: true, // can't be changed by the partner
Expand Down
5 changes: 2 additions & 3 deletions apps/web/app/(ee)/api/events/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { assertValidDateRangeForPlan } from "@/lib/api/utils/assert-valid-date-r
import { withWorkspace } from "@/lib/auth";
import { verifyFolderAccess } from "@/lib/folder/permissions";
import { eventsQuerySchema } from "@/lib/zod/schemas/analytics";
import { Folder, Link } from "@dub/prisma/client";
import { Link } from "@dub/prisma/client";
import { NextResponse } from "next/server";

// GET /api/events
Expand Down Expand Up @@ -47,9 +47,8 @@ export const GET = withWorkspace(

const folderIdToVerify = link?.folderId || folderId;

let selectedFolder: Pick<Folder, "id" | "type"> | null = null;
if (folderIdToVerify) {
selectedFolder = await verifyFolderAccess({
await verifyFolderAccess({
workspace,
userId: session.user.id,
folderId: folderIdToVerify,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ export const PATCH = withPartnerProfile(
workspace: {
id: program.workspaceId,
plan: "business",
users: [{ role: "owner" }],
},
userId: session.user.id,
skipKeyChecks,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ export const POST = withPartnerProfile(
workspace: {
id: program.workspaceId,
plan: "business",
users: [{ role: "owner" }],
},
userId: session.user.id, // TODO: Hm, this is the partner user, not the workspace user?
skipFolderChecks: true, // can't be changed by the partner
Expand Down
2 changes: 1 addition & 1 deletion apps/web/app/api/analytics/export/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export const GET = withWorkspace(

const zipData = await zip.generateAsync({ type: "nodebuffer" });

return new Response(zipData, {
return new Response(zipData as unknown as BodyInit, {
headers: {
"Content-Type": "application/zip",
"Content-Disposition": "attachment; filename=analytics_export.zip",
Expand Down
15 changes: 9 additions & 6 deletions apps/web/app/api/folders/[folderId]/users/route.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { withWorkspace } from "@/lib/auth";
import {
findUserFolderRole,
findFolderUserRole,
verifyFolderAccess,
} from "@/lib/folder/permissions";
import { prisma } from "@dub/prisma";
Expand Down Expand Up @@ -52,13 +52,15 @@ export const GET = withWorkspace(
}),
]);

const users = workspaceUsers.map(({ user }) => {
const folderUser =
folderUsers.find((folderUser) => folderUser.userId === user.id) || null;
const users = workspaceUsers.map(({ user, role: workspaceRole }) => {
const folderUser = folderUsers.find(
(folderUser) => folderUser.userId === user.id,
);

const role = findUserFolderRole({
const role = findFolderUserRole({
folder,
user: folderUser,
user: folderUser || null,
workspaceRole,
});

return {
Expand All @@ -67,6 +69,7 @@ export const GET = withWorkspace(
email: user.email,
image: user.image,
role,
workspaceRole,
};
});

Expand Down
39 changes: 23 additions & 16 deletions apps/web/app/api/folders/count/route.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { withWorkspace } from "@/lib/auth";
import { listFoldersQuerySchema } from "@/lib/zod/schemas/folders";
import { prisma } from "@dub/prisma";
import { WorkspaceRole } from "@dub/prisma/client";
import { NextResponse } from "next/server";

// GET /api/folders/count - get count of folders
Expand All @@ -10,26 +11,32 @@ export const GET = withWorkspace(
.omit({ page: true, pageSize: true })
.parse(searchParams);

const workspaceRole = workspace.users[0]?.role;

const count = await prisma.folder.count({
where: {
projectId: workspace.id,
OR: [
{ accessLevel: { not: null } },
{
users: {
some: {
userId: session.user.id,
role: { not: null },
...(workspaceRole !== WorkspaceRole.owner
? {
OR: [
{ accessLevel: { not: null } },
{
users: {
some: {
userId: session.user.id,
role: { not: null },
},
},
},
],
users: {
none: {
userId: session.user.id,
role: null,
},
},
},
},
],
users: {
none: {
userId: session.user.id,
role: null,
},
},
}
: {}),
...(search && {
name: {
contains: search,
Expand Down
7 changes: 4 additions & 3 deletions apps/web/app/api/folders/permissions/route.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { withWorkspace } from "@/lib/auth";
import { getFolders } from "@/lib/folder/get-folders";
import {
findUserFolderRole,
findFolderUserRole,
getFolderPermissions,
} from "@/lib/folder/permissions";
import { prisma } from "@dub/prisma";
Expand Down Expand Up @@ -30,15 +30,16 @@ export const GET = withWorkspace(
folderUsers.find((folderUser) => folderUser.folderId === folder.id) ||
null;

const role = findUserFolderRole({
const userFolderRole = findFolderUserRole({
folder,
user: folderUser,
workspaceRole: workspace.users[0]?.role,
});

return {
id: folder.id,
name: folder.name,
permissions: getFolderPermissions(role),
permissions: getFolderPermissions(userFolderRole),
};
});

Expand Down
16 changes: 8 additions & 8 deletions apps/web/app/api/links/bulk/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import { parseRequestBody } from "@/lib/api/utils";
import { withWorkspace } from "@/lib/auth";
import { exceededLimitError } from "@/lib/exceeded-limit-error";
import {
checkFolderPermissions,
verifyFolderAccess,
verifyFolderAccessBulk,
} from "@/lib/folder/permissions";
import { storage } from "@/lib/storage";
import { NewLinkProps, ProcessedLinkProps } from "@/lib/types";
Expand Down Expand Up @@ -173,8 +173,8 @@ export const POST = withWorkspace(
),
];

const folderPermissions = await checkFolderPermissions({
workspaceId: workspace.id,
const folderPermissions = await verifyFolderAccessBulk({
workspace,
userId: session.user.id,
folderIds,
requiredPermission: "folders.links.write",
Expand Down Expand Up @@ -350,8 +350,8 @@ export const PATCH = withWorkspace(
new Set(links.map((link) => link.folderId).filter(Boolean) as string[]),
);

const folderPermissions = await checkFolderPermissions({
workspaceId: workspace.id,
const folderPermissions = await verifyFolderAccessBulk({
workspace,
userId: session.user.id,
folderIds,
requiredPermission: "folders.links.write",
Expand All @@ -368,7 +368,7 @@ export const PATCH = withWorkspace(

if (!validFolder?.hasPermission) {
errorLinks.push({
error: `You don't have permission to move this link to the folder: ${link.folderId}`,
error: `You don't have permission to update links in this folder: ${link.folderId}`,
code: "forbidden",
link,
});
Expand Down Expand Up @@ -522,8 +522,8 @@ export const DELETE = withWorkspace(
),
];

const folderPermissions = await checkFolderPermissions({
workspaceId: workspace.id,
const folderPermissions = await verifyFolderAccessBulk({
workspace,
userId: session.user.id,
folderIds,
requiredPermission: "folders.links.write",
Expand Down
6 changes: 4 additions & 2 deletions apps/web/app/api/links/export/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { getLinksForWorkspace } from "@/lib/api/links/get-links-for-workspace";
import { throwIfClicksUsageExceeded } from "@/lib/api/links/usage-checks";
import { validateLinksQueryFilters } from "@/lib/api/links/validate-links-query-filters";
import { withWorkspace } from "@/lib/auth";
import { MEGA_WORKSPACE_LINKS_LIMIT } from "@/lib/constants/misc";
import { qstash } from "@/lib/cron";
import { linksExportQuerySchema } from "@/lib/zod/schemas/links";
import { APP_DOMAIN_WITH_NGROK } from "@dub/utils";
Expand All @@ -21,7 +22,7 @@ export const GET = withWorkspace(

const { columns, ...filters } = linksExportQuerySchema.parse(searchParams);

const { selectedFolder, folderIds } = await validateLinksQueryFilters({
const { folderIds } = await validateLinksQueryFilters({
...filters,
workspace,
userId: session.user.id,
Expand Down Expand Up @@ -61,7 +62,8 @@ export const GET = withWorkspace(
startDate,
endDate,
}),
searchMode: selectedFolder?.type === "mega" ? "exact" : "fuzzy",
searchMode:
workspace.totalLinks > MEGA_WORKSPACE_LINKS_LIMIT ? "exact" : "fuzzy",
includeDashboard: false,
includeUser: false,
includeWebhooks: false,
Expand Down
6 changes: 4 additions & 2 deletions apps/web/app/api/links/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { throwIfLinksUsageExceeded } from "@/lib/api/links/usage-checks";
import { validateLinksQueryFilters } from "@/lib/api/links/validate-links-query-filters";
import { parseRequestBody } from "@/lib/api/utils";
import { withWorkspace } from "@/lib/auth";
import { MEGA_WORKSPACE_LINKS_LIMIT } from "@/lib/constants/misc";
import { ratelimit } from "@/lib/upstash";
import { sendWorkspaceWebhook } from "@/lib/webhook/publish";
import {
Expand All @@ -20,7 +21,7 @@ export const GET = withWorkspace(
async ({ headers, searchParams, workspace, session }) => {
const filters = getLinksQuerySchemaExtended.parse(searchParams);

const { selectedFolder, folderIds } = await validateLinksQueryFilters({
const { folderIds } = await validateLinksQueryFilters({
...filters,
workspace,
userId: session.user.id,
Expand All @@ -30,7 +31,8 @@ export const GET = withWorkspace(
...filters,
workspaceId: workspace.id,
folderIds,
searchMode: selectedFolder?.type === "mega" ? "exact" : "fuzzy",
searchMode:
workspace.totalLinks > MEGA_WORKSPACE_LINKS_LIMIT ? "exact" : "fuzzy",
});

return NextResponse.json(response, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,9 @@ export function CampaignsTable() {
)}
addButton={!isFiltered ? <CreateCampaignButton /> : undefined}
learnMoreHref={
!isFiltered ? "https://dub.co/docs/email-campaigns" : undefined
!isFiltered
? "https://dub.co/help/article/email-campaigns"
: undefined
}
/>
)}
Expand Down
Loading