diff --git a/apps/web/app/(ee)/api/cron/groups/remap-default-links/route.ts b/apps/web/app/(ee)/api/cron/groups/remap-default-links/route.ts index 66d989531c4..87a745c249c 100644 --- a/apps/web/app/(ee)/api/cron/groups/remap-default-links/route.ts +++ b/apps/web/app/(ee)/api/cron/groups/remap-default-links/route.ts @@ -4,7 +4,7 @@ import { generatePartnerLink } from "@/lib/api/partners/generate-partner-link"; import { qstash } from "@/lib/cron"; import { verifyQstashSignature } from "@/lib/cron/verify-qstash"; import { WorkspaceProps } from "@/lib/types"; -import { MAX_DEFAULT_PARTNER_LINKS } from "@/lib/zod/schemas/groups"; +import { MAX_DEFAULT_LINKS_PER_GROUP } from "@/lib/zod/schemas/groups"; import { prisma } from "@dub/prisma"; import { APP_DOMAIN_WITH_NGROK, isFulfilled, log } from "@dub/utils"; import { z } from "zod"; @@ -86,7 +86,7 @@ export async function POST(req: Request) { orderBy: { createdAt: "asc", }, - take: MAX_DEFAULT_PARTNER_LINKS, // there can only be up to MAX_DEFAULT_PARTNER_LINKS default links per group + take: MAX_DEFAULT_LINKS_PER_GROUP, // there can only be up to MAX_DEFAULT_LINKS_PER_GROUP default links per group }, }, }), diff --git a/apps/web/app/(ee)/api/groups/[groupIdOrSlug]/default-links/route.ts b/apps/web/app/(ee)/api/groups/[groupIdOrSlug]/default-links/route.ts index fea5d0203a5..6e184c4e2b8 100644 --- a/apps/web/app/(ee)/api/groups/[groupIdOrSlug]/default-links/route.ts +++ b/apps/web/app/(ee)/api/groups/[groupIdOrSlug]/default-links/route.ts @@ -8,7 +8,7 @@ import { withWorkspace } from "@/lib/auth"; import { qstash } from "@/lib/cron"; import { createOrUpdateDefaultLinkSchema, - MAX_DEFAULT_PARTNER_LINKS, + MAX_DEFAULT_LINKS_PER_GROUP, PartnerGroupDefaultLinkSchema, } from "@/lib/zod/schemas/groups"; import { prisma } from "@dub/prisma"; @@ -90,10 +90,10 @@ export const POST = withWorkspace( }, }); - if (count >= MAX_DEFAULT_PARTNER_LINKS) { + if (count >= MAX_DEFAULT_LINKS_PER_GROUP) { throw new DubApiError({ code: "bad_request", - message: `You can't create more than ${MAX_DEFAULT_PARTNER_LINKS} default links for a group.`, + message: `You can't create more than ${MAX_DEFAULT_LINKS_PER_GROUP} default links for a group.`, }); } diff --git a/apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/groups/[groupSlug]/links/group-default-links.tsx b/apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/groups/[groupSlug]/links/group-default-links.tsx index 28701aa93de..a9bbf4a2016 100644 --- a/apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/groups/[groupSlug]/links/group-default-links.tsx +++ b/apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/program/groups/[groupSlug]/links/group-default-links.tsx @@ -5,7 +5,7 @@ import useGroup from "@/lib/swr/use-group"; import usePartnerGroupDefaultLinks from "@/lib/swr/use-partner-group-default-links"; import useWorkspace from "@/lib/swr/use-workspace"; import { PartnerGroupDefaultLink } from "@/lib/types"; -import { MAX_DEFAULT_PARTNER_LINKS } from "@/lib/zod/schemas/groups"; +import { MAX_DEFAULT_LINKS_PER_GROUP } from "@/lib/zod/schemas/groups"; import { useConfirmModal } from "@/ui/modals/confirm-modal"; import { ThreeDots } from "@/ui/shared/icons"; import { @@ -28,7 +28,7 @@ export function GroupDefaultLinks() { usePartnerGroupDefaultLinks(); const hasReachedMaxLinks = defaultLinks - ? defaultLinks.length >= MAX_DEFAULT_PARTNER_LINKS + ? defaultLinks.length >= MAX_DEFAULT_LINKS_PER_GROUP : false; return ( @@ -97,7 +97,7 @@ function CreateDefaultLinkButton({ disabled={hasReachedMaxLinks || isLoadingGroup} disabledTooltip={ hasReachedMaxLinks - ? `You can only create up to ${MAX_DEFAULT_PARTNER_LINKS} default links.` + ? `You can only create up to ${MAX_DEFAULT_LINKS_PER_GROUP} default links.` : undefined } /> diff --git a/apps/web/lib/actions/partners/create-program.ts b/apps/web/lib/actions/partners/create-program.ts index 8c7213774a2..888b4959277 100644 --- a/apps/web/lib/actions/partners/create-program.ts +++ b/apps/web/lib/actions/partners/create-program.ts @@ -8,14 +8,17 @@ import { getPlanCapabilities } from "@/lib/plan-capabilities"; import { isStored, storage } from "@/lib/storage"; import { PlanProps } from "@/lib/types"; import { redis } from "@/lib/upstash"; -import { DEFAULT_PARTNER_GROUP } from "@/lib/zod/schemas/groups"; +import { + DEFAULT_ADDITIONAL_PARTNER_LINKS, + DEFAULT_PARTNER_GROUP, +} from "@/lib/zod/schemas/groups"; import { programDataSchema } from "@/lib/zod/schemas/program-onboarding"; import { REWARD_EVENT_COLUMN_MAPPING } from "@/lib/zod/schemas/rewards"; import { sendEmail } from "@dub/email"; import ProgramInvite from "@dub/email/templates/program-invite"; import ProgramWelcome from "@dub/email/templates/program-welcome"; import { prisma } from "@dub/prisma"; -import { nanoid, R2_URL } from "@dub/utils"; +import { getDomainWithoutWWW, nanoid, R2_URL } from "@dub/utils"; import { Program, Project, User } from "@prisma/client"; import { waitUntil } from "@vercel/functions"; import { redirect } from "next/navigation"; @@ -150,6 +153,13 @@ export const createProgram = async ({ ...(createdReward && { [REWARD_EVENT_COLUMN_MAPPING[createdReward.event]]: createdReward.id, }), + additionalLinks: [ + { + domain: getDomainWithoutWWW(programData.url!)!, + validationMode: "domain", + }, + ], + maxPartnerLinks: DEFAULT_ADDITIONAL_PARTNER_LINKS, partnerGroupDefaultLinks: { create: { id: createId({ prefix: "pgdl_" }), diff --git a/apps/web/lib/firstpromoter/import-campaigns.ts b/apps/web/lib/firstpromoter/import-campaigns.ts index 8cbd7f81d5a..f394ef826be 100644 --- a/apps/web/lib/firstpromoter/import-campaigns.ts +++ b/apps/web/lib/firstpromoter/import-campaigns.ts @@ -1,8 +1,9 @@ import { RESOURCE_COLORS } from "@/ui/colors"; import { prisma } from "@dub/prisma"; -import { randomValue } from "@dub/utils"; +import { getDomainWithoutWWW, randomValue } from "@dub/utils"; import slugify from "@sindresorhus/slugify"; import { createId } from "../api/create-id"; +import { DEFAULT_ADDITIONAL_PARTNER_LINKS } from "../zod/schemas/groups"; import { FirstPromoterApi } from "./api"; import { firstPromoterImporter, MAX_BATCHES } from "./importer"; import { FirstPromoterImportPayload } from "./types"; @@ -64,6 +65,13 @@ export async function importCampaigns(payload: FirstPromoterImportPayload) { slug: slugify(campaign.campaign.name), name: campaign.campaign.name, color: randomValue(RESOURCE_COLORS), + additionalLinks: [ + { + domain: getDomainWithoutWWW(program.url!), + validationMode: "domain", + }, + ], + maxPartnerLinks: DEFAULT_ADDITIONAL_PARTNER_LINKS, })), skipDuplicates: true, }); diff --git a/apps/web/lib/partnerstack/import-groups.ts b/apps/web/lib/partnerstack/import-groups.ts index a1be75a70f7..a62a86b22f0 100644 --- a/apps/web/lib/partnerstack/import-groups.ts +++ b/apps/web/lib/partnerstack/import-groups.ts @@ -1,7 +1,8 @@ import { RESOURCE_COLORS } from "@/ui/colors"; import { prisma } from "@dub/prisma"; -import { randomValue } from "@dub/utils"; +import { getDomainWithoutWWW, randomValue } from "@dub/utils"; import { createId } from "../api/create-id"; +import { DEFAULT_ADDITIONAL_PARTNER_LINKS } from "../zod/schemas/groups"; import { PartnerStackApi } from "./api"; import { partnerStackImporter } from "./importer"; import { PartnerStackImportPayload } from "./types"; @@ -55,6 +56,13 @@ export async function importGroups(payload: PartnerStackImportPayload) { name: group.name, slug: group.slug, color: randomValue(RESOURCE_COLORS), + additionalLinks: [ + { + domain: getDomainWithoutWWW(program.url), + validationMode: "domain", + }, + ], + maxPartnerLinks: DEFAULT_ADDITIONAL_PARTNER_LINKS, partnerGroupDefaultLinks: { create: { id: createId({ prefix: "pgdl_" }), diff --git a/apps/web/lib/rewardful/import-campaigns.ts b/apps/web/lib/rewardful/import-campaigns.ts index f375ddaad99..4f793de7c06 100644 --- a/apps/web/lib/rewardful/import-campaigns.ts +++ b/apps/web/lib/rewardful/import-campaigns.ts @@ -1,12 +1,13 @@ import { RESOURCE_COLORS } from "@/ui/colors"; import { prisma } from "@dub/prisma"; import { EventType, Prisma, RewardStructure } from "@dub/prisma/client"; -import { randomValue } from "@dub/utils"; +import { getDomainWithoutWWW, randomValue } from "@dub/utils"; import { differenceInSeconds } from "date-fns"; import { createId } from "../api/create-id"; import { serializeReward } from "../api/partners/serialize-reward"; import { getRewardAmount } from "../partners/get-reward-amount"; +import { DEFAULT_ADDITIONAL_PARTNER_LINKS } from "../zod/schemas/groups"; import { RewardfulApi } from "./api"; import { rewardfulImporter } from "./importer"; import { RewardfulImportPayload } from "./types"; @@ -63,6 +64,13 @@ export async function importCampaigns(payload: RewardfulImportPayload) { name: `(Rewardful) ${campaign.name}`, slug: groupSlug, color: randomValue(RESOURCE_COLORS), + additionalLinks: [ + { + domain: getDomainWithoutWWW(program.url), + validationMode: "domain", + }, + ], + maxPartnerLinks: DEFAULT_ADDITIONAL_PARTNER_LINKS, partnerGroupDefaultLinks: { create: { id: createId({ prefix: "pgdl_" }), diff --git a/apps/web/lib/zod/schemas/groups.ts b/apps/web/lib/zod/schemas/groups.ts index feb209b8c60..163fd185044 100644 --- a/apps/web/lib/zod/schemas/groups.ts +++ b/apps/web/lib/zod/schemas/groups.ts @@ -18,7 +18,11 @@ export const DEFAULT_PARTNER_GROUP = { color: null, } as const; -export const MAX_DEFAULT_PARTNER_LINKS = 5; +// max number of partnerGroupDefaultLinks per group +export const MAX_DEFAULT_LINKS_PER_GROUP = 5; + +// for the maxPartnerLinks setting (alongside additionalLinks) +export const DEFAULT_ADDITIONAL_PARTNER_LINKS = 10; export const MAX_ADDITIONAL_PARTNER_LINKS = 100; export const GROUPS_MAX_PAGE_SIZE = 100; diff --git a/apps/web/tests/partner-groups/index.test.ts b/apps/web/tests/partner-groups/index.test.ts index 42c4770621c..4e5ac1999f4 100644 --- a/apps/web/tests/partner-groups/index.test.ts +++ b/apps/web/tests/partner-groups/index.test.ts @@ -4,7 +4,10 @@ import { GroupProps, GroupWithProgramProps, } from "@/lib/types"; -import { GroupSchema } from "@/lib/zod/schemas/groups"; +import { + DEFAULT_ADDITIONAL_PARTNER_LINKS, + GroupSchema, +} from "@/lib/zod/schemas/groups"; import { RESOURCE_COLORS } from "@/ui/colors"; import { randomValue } from "@dub/utils"; import slugify from "@sindresorhus/slugify"; @@ -20,7 +23,7 @@ const expectedGroup: Partial = { leadReward: null, saleReward: null, discount: null, - maxPartnerLinks: 10, + maxPartnerLinks: DEFAULT_ADDITIONAL_PARTNER_LINKS, linkStructure: "short", additionalLinks: expect.any(Array), }; diff --git a/packages/prisma/schema/program.prisma b/packages/prisma/schema/program.prisma index 804da4a7975..13aa7990a8a 100644 --- a/packages/prisma/schema/program.prisma +++ b/packages/prisma/schema/program.prisma @@ -18,11 +18,6 @@ enum PartnerBannedReason { brand_abuse } -enum PartnerUrlValidationMode { - domain // domain match (e.g. if URL is example.com/path, example.com and example.com/another-path are allowed) - exact // exact match (e.g. if URL is example.com/path, only example.com/path is allowed) -} - model Program { id String @id @default(cuid()) workspaceId String