aboutsummaryrefslogtreecommitdiffstats
path: root/packages
diff options
context:
space:
mode:
authorMohamedBassem <me@mbassem.com>2024-02-14 01:26:45 +0000
committerMohamedBassem <me@mbassem.com>2024-02-14 10:36:38 +0000
commit50c3c5e132643fc33d39fb9dc1fe951efe766337 (patch)
tree0af73f6b3835833792b6cac67fea01a6e943b296 /packages
parent580b842f7835a3d1fa171afdc7e0b52cc3f9dfc6 (diff)
downloadkarakeep-50c3c5e132643fc33d39fb9dc1fe951efe766337.tar.zst
feature: Add ability to refresh bookmark details
Diffstat (limited to 'packages')
-rw-r--r--packages/shared/queues.ts1
-rw-r--r--packages/web/app/dashboard/bookmarks/components/BookmarkOptions.tsx25
-rw-r--r--packages/web/server/api/routers/bookmarks.ts39
-rw-r--r--packages/workers/crawler.ts14
-rw-r--r--packages/workers/openai.ts1
5 files changed, 76 insertions, 4 deletions
diff --git a/packages/shared/queues.ts b/packages/shared/queues.ts
index 6a49d749..190aef85 100644
--- a/packages/shared/queues.ts
+++ b/packages/shared/queues.ts
@@ -9,7 +9,6 @@ export const queueConnectionDetails = {
// Link Crawler
export const zCrawlLinkRequestSchema = z.object({
bookmarkId: z.string(),
- url: z.string().url(),
});
export type ZCrawlLinkRequest = z.infer<typeof zCrawlLinkRequestSchema>;
diff --git a/packages/web/app/dashboard/bookmarks/components/BookmarkOptions.tsx b/packages/web/app/dashboard/bookmarks/components/BookmarkOptions.tsx
index 4496d820..4123dc36 100644
--- a/packages/web/app/dashboard/bookmarks/components/BookmarkOptions.tsx
+++ b/packages/web/app/dashboard/bookmarks/components/BookmarkOptions.tsx
@@ -11,7 +11,7 @@ import {
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
-import { Archive, MoreHorizontal, Star, Trash2 } from "lucide-react";
+import { Archive, MoreHorizontal, RotateCw, Star, Trash2 } from "lucide-react";
export default function BookmarkOptions({ bookmark }: { bookmark: ZBookmark }) {
const { toast } = useToast();
@@ -55,6 +55,25 @@ export default function BookmarkOptions({ bookmark }: { bookmark: ZBookmark }) {
router.refresh();
};
+ const crawlBookmark = async () => {
+ try {
+ await api.bookmarks.recrawlBookmark.mutate({
+ bookmarkId: linkId,
+ });
+ toast({
+ description: "Re-fetch has been enqueued!",
+ });
+ } catch (e) {
+ toast({
+ variant: "destructive",
+ title: "Something went wrong",
+ description: "There was a problem with your request.",
+ });
+ }
+
+ router.refresh();
+ };
+
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
@@ -82,6 +101,10 @@ export default function BookmarkOptions({ bookmark }: { bookmark: ZBookmark }) {
<Archive className="mr-2 size-4" />
<span>{bookmark.archived ? "Un-archive" : "Archive"}</span>
</DropdownMenuItem>
+ <DropdownMenuItem onClick={crawlBookmark}>
+ <RotateCw className="mr-2 size-4" />
+ <span>Refresh</span>
+ </DropdownMenuItem>
<DropdownMenuItem className="text-destructive" onClick={unbookmarkLink}>
<Trash2 className="mr-2 size-4" />
<span>Delete</span>
diff --git a/packages/web/server/api/routers/bookmarks.ts b/packages/web/server/api/routers/bookmarks.ts
index 953dab66..a77275d9 100644
--- a/packages/web/server/api/routers/bookmarks.ts
+++ b/packages/web/server/api/routers/bookmarks.ts
@@ -11,6 +11,8 @@ import {
} from "@/lib/types/api/bookmarks";
import { prisma } from "@remember/db";
import { LinkCrawlerQueue } from "@remember/shared/queues";
+import { TRPCError, experimental_trpcMiddleware } from "@trpc/server";
+import { User } from "next-auth";
const defaultBookmarkFields = {
id: true,
@@ -33,6 +35,32 @@ const defaultBookmarkFields = {
},
};
+const ensureBookmarkOwnership = experimental_trpcMiddleware<{
+ ctx: { user: User };
+ input: { bookmarkId: string };
+}>().create(async (opts) => {
+ const bookmark = await prisma.bookmark.findUnique({
+ where: { id: opts.input.bookmarkId },
+ select: {
+ userId: true,
+ },
+ });
+ if (!bookmark) {
+ throw new TRPCError({
+ code: "NOT_FOUND",
+ message: "Bookmark not found",
+ });
+ }
+ if (bookmark.userId != opts.ctx.user.id) {
+ throw new TRPCError({
+ code: "FORBIDDEN",
+ message: "User is not allowed to access resource",
+ });
+ }
+
+ return opts.next();
+});
+
async function dummyPrismaReturnType() {
const x = await prisma.bookmark.findFirstOrThrow({
select: defaultBookmarkFields,
@@ -82,7 +110,6 @@ export const bookmarksAppRouter = router({
// Enqueue crawling request
await LinkCrawlerQueue.add("crawl", {
bookmarkId: bookmark.id,
- url: url,
});
return toZodSchema(bookmark);
@@ -91,6 +118,7 @@ export const bookmarksAppRouter = router({
updateBookmark: authedProcedure
.input(zUpdateBookmarksRequestSchema)
.output(zBookmarkSchema)
+ .use(ensureBookmarkOwnership)
.mutation(async ({ input, ctx }) => {
const bookmark = await prisma.bookmark.update({
where: {
@@ -108,6 +136,7 @@ export const bookmarksAppRouter = router({
deleteBookmark: authedProcedure
.input(z.object({ bookmarkId: z.string() }))
+ .use(ensureBookmarkOwnership)
.mutation(async ({ input, ctx }) => {
await prisma.bookmark.delete({
where: {
@@ -116,6 +145,14 @@ export const bookmarksAppRouter = router({
},
});
}),
+ recrawlBookmark: authedProcedure
+ .input(z.object({ bookmarkId: z.string() }))
+ .use(ensureBookmarkOwnership)
+ .mutation(async ({ input }) => {
+ await LinkCrawlerQueue.add("crawl", {
+ bookmarkId: input.bookmarkId,
+ });
+ }),
getBookmarks: authedProcedure
.input(zGetBookmarksRequestSchema)
.output(zGetBookmarksResponseSchema)
diff --git a/packages/workers/crawler.ts b/packages/workers/crawler.ts
index 45d2f530..4febc1ca 100644
--- a/packages/workers/crawler.ts
+++ b/packages/workers/crawler.ts
@@ -70,6 +70,17 @@ export class CrawlerWorker {
}
}
+async function getBookmarkUrl(bookmarkId: string) {
+ const bookmark = await prisma.bookmarkedLink.findUnique({
+ where: { id: bookmarkId },
+ });
+
+ if (!bookmark) {
+ throw new Error("The bookmark either doesn't exist or not a link");
+ }
+ return bookmark.url;
+}
+
async function crawlPage(url: string) {
if (!browser) {
throw new Error("The browser must have been initalized by this point.");
@@ -98,7 +109,8 @@ async function runCrawler(job: Job<ZCrawlLinkRequest, void>) {
return;
}
- const { url, bookmarkId } = request.data;
+ const { bookmarkId } = request.data;
+ const url = await getBookmarkUrl(bookmarkId);
logger.info(
`[Crawler][${jobId}] Will crawl "${url}" for link with id "${bookmarkId}"`,
diff --git a/packages/workers/openai.ts b/packages/workers/openai.ts
index 1adedeba..7c45b2cb 100644
--- a/packages/workers/openai.ts
+++ b/packages/workers/openai.ts
@@ -140,6 +140,7 @@ async function createTags(tags: string[], userId: string) {
async function connectTags(bookmarkId: string, tagIds: string[]) {
// TODO: Prisma doesn't support createMany in Sqlite
+ // TODO: This could fail on refetch if the tags are already there
await Promise.all(
tagIds.map((tagId) => {
return prisma.tagsOnBookmarks.create({