-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'link-folders' of https://github.com/dubinc/dub into lin…
…k-folders
- Loading branch information
Showing
92 changed files
with
2,044 additions
and
871 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
import { queueDomainDeletion } from "@/lib/api/domains/queue"; | ||
import { handleAndReturnErrorResponse } from "@/lib/api/errors"; | ||
import { linkCache } from "@/lib/api/links/cache"; | ||
import { verifyQstashSignature } from "@/lib/cron/verify-qstash"; | ||
import { storage } from "@/lib/storage"; | ||
import { recordLink } from "@/lib/tinybird/record-link"; | ||
import { prisma } from "@dub/prisma"; | ||
import { R2_URL } from "@dub/utils"; | ||
import { z } from "zod"; | ||
|
||
export const dynamic = "force-dynamic"; | ||
|
||
const schema = z.object({ | ||
domain: z.string(), | ||
workspaceId: z.string(), | ||
}); | ||
|
||
// POST /api/cron/domains/delete | ||
export async function POST(req: Request) { | ||
try { | ||
const body = await req.json(); | ||
|
||
await verifyQstashSignature(req, body); | ||
|
||
const { domain, workspaceId } = schema.parse(body); | ||
|
||
const domainRecord = await prisma.domain.findUnique({ | ||
where: { | ||
slug: domain, | ||
}, | ||
}); | ||
|
||
if (!domainRecord) { | ||
return new Response(`Domain ${domain} not found. Skipping...`); | ||
} | ||
|
||
const links = await prisma.link.findMany({ | ||
where: { | ||
domain, | ||
}, | ||
include: { | ||
tags: true, | ||
}, | ||
take: 100, // TODO: We can adjust this number based on the performance | ||
}); | ||
|
||
if (links.length === 0) { | ||
return new Response("No more links to delete. Exiting..."); | ||
} | ||
|
||
const response = await Promise.allSettled([ | ||
// Remove the link from Redis | ||
linkCache.deleteMany(links), | ||
|
||
// Record link in the Tinybird | ||
recordLink( | ||
links.map((link) => ({ | ||
link_id: link.id, | ||
domain: link.domain, | ||
key: link.key, | ||
url: link.url, | ||
tag_ids: link.tags.map((tag) => tag.id), | ||
folder_id: link.folderId, | ||
program_id: link.programId ?? "", | ||
workspace_id: workspaceId, | ||
created_at: link.createdAt, | ||
deleted: true, | ||
})), | ||
), | ||
|
||
// Remove image from R2 storage if it exists | ||
links | ||
.filter((link) => link.image?.startsWith(`${R2_URL}/images/${link.id}`)) | ||
.map((link) => storage.delete(link.image!.replace(`${R2_URL}/`, ""))), | ||
|
||
// Remove the link from MySQL | ||
prisma.link.deleteMany({ | ||
where: { | ||
id: { in: links.map((link) => link.id) }, | ||
}, | ||
}), | ||
]); | ||
|
||
console.log(response); | ||
|
||
response.forEach((promise) => { | ||
if (promise.status === "rejected") { | ||
console.error("deleteDomainAndLinks", { | ||
reason: promise.reason, | ||
domain, | ||
workspaceId, | ||
}); | ||
} | ||
}); | ||
|
||
const remainingLinks = await prisma.link.count({ | ||
where: { | ||
domain, | ||
}, | ||
}); | ||
|
||
console.log("remainingLinks", remainingLinks); | ||
|
||
if (remainingLinks > 0) { | ||
await queueDomainDeletion({ | ||
workspaceId, | ||
domain, | ||
delay: 2, | ||
}); | ||
return new Response( | ||
`Deleted ${links.length} links, ${remainingLinks} remaining. Starting next batch...`, | ||
); | ||
} | ||
|
||
// After all links are deleted, delete the domain and image | ||
await Promise.all([ | ||
prisma.domain.delete({ | ||
where: { | ||
slug: domain, | ||
}, | ||
}), | ||
domainRecord.logo && | ||
storage.delete(domainRecord.logo.replace(`${R2_URL}/`, "")), | ||
]); | ||
|
||
return new Response( | ||
`Deleted ${links.length} links, no more links remaining. Domain deleted.`, | ||
); | ||
} catch (error) { | ||
return handleAndReturnErrorResponse(error); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import { queueDomainUpdate } from "@/lib/api/domains/queue"; | ||
import { handleAndReturnErrorResponse } from "@/lib/api/errors"; | ||
import { linkCache } from "@/lib/api/links/cache"; | ||
import { verifyQstashSignature } from "@/lib/cron/verify-qstash"; | ||
import { recordLink } from "@/lib/tinybird"; | ||
import { prisma } from "@dub/prisma"; | ||
import { z } from "zod"; | ||
|
||
export const dynamic = "force-dynamic"; | ||
|
||
const schema = z.object({ | ||
newDomain: z.string(), | ||
oldDomain: z.string(), | ||
workspaceId: z.string(), | ||
page: z.number(), | ||
}); | ||
|
||
const pageSize = 100; | ||
|
||
// POST /api/cron/domains/update | ||
export async function POST(req: Request) { | ||
try { | ||
const body = await req.json(); | ||
|
||
await verifyQstashSignature(req, body); | ||
|
||
const { newDomain, oldDomain, workspaceId, page } = schema.parse(body); | ||
|
||
const newDomainRecord = await prisma.domain.findUnique({ | ||
where: { | ||
slug: newDomain, | ||
}, | ||
}); | ||
|
||
if (!newDomainRecord) { | ||
return new Response(`Domain ${newDomain} not found. Skipping update...`); | ||
} | ||
|
||
const links = await prisma.link.findMany({ | ||
where: { | ||
domain: newDomain, | ||
}, | ||
include: { | ||
tags: true, | ||
}, | ||
skip: (page - 1) * pageSize, | ||
take: pageSize, | ||
}); | ||
|
||
if (links.length === 0) { | ||
return new Response("No more links to update. Exiting..."); | ||
} | ||
|
||
await Promise.all([ | ||
// rename redis keys | ||
linkCache.rename({ | ||
links, | ||
oldDomain, | ||
}), | ||
|
||
// update links in Tinybird | ||
recordLink( | ||
links.map((link) => ({ | ||
link_id: link.id, | ||
domain: link.domain, | ||
key: link.key, | ||
url: link.url, | ||
tag_ids: link.tags.map((tag) => tag.tagId), | ||
folder_id: link.folderId, | ||
program_id: link.programId ?? "", | ||
workspace_id: link.projectId, | ||
created_at: link.createdAt, | ||
})), | ||
), | ||
]); | ||
|
||
await queueDomainUpdate({ | ||
workspaceId, | ||
oldDomain, | ||
newDomain, | ||
page: page + 1, | ||
delay: 2, | ||
}); | ||
|
||
return new Response("Domain's links updated."); | ||
} catch (error) { | ||
return handleAndReturnErrorResponse(error); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.