aboutsummaryrefslogtreecommitdiffstats
path: root/packages/web/server/api/routers
diff options
context:
space:
mode:
authorMohamedBassem <me@mbassem.com>2024-02-26 12:47:36 +0000
committerMohamedBassem <me@mbassem.com>2024-02-26 12:47:36 +0000
commit3fe20dda157cbae282f55d6afb8e8f99e795945a (patch)
tree59a8ef1e5ab98d75d83c5cd23ea6c12af9615ca0 /packages/web/server/api/routers
parente234d3535c363664902dffe89a2c61ddbc037da4 (diff)
downloadkarakeep-3fe20dda157cbae282f55d6afb8e8f99e795945a.tar.zst
feature: Add support for adding/removing tags
Diffstat (limited to 'packages/web/server/api/routers')
-rw-r--r--packages/web/server/api/routers/bookmarks.ts89
1 files changed, 87 insertions, 2 deletions
diff --git a/packages/web/server/api/routers/bookmarks.ts b/packages/web/server/api/routers/bookmarks.ts
index 2af81d27..3070eac3 100644
--- a/packages/web/server/api/routers/bookmarks.ts
+++ b/packages/web/server/api/routers/bookmarks.ts
@@ -11,7 +11,12 @@ import {
zUpdateBookmarksRequestSchema,
} from "@/lib/types/api/bookmarks";
import { db } from "@hoarder/db";
-import { bookmarkLinks, bookmarks } from "@hoarder/db/schema";
+import {
+ bookmarkLinks,
+ bookmarkTags,
+ bookmarks,
+ tagsOnBookmarks,
+} from "@hoarder/db/schema";
import { LinkCrawlerQueue } from "@hoarder/shared/queues";
import { TRPCError, experimental_trpcMiddleware } from "@trpc/server";
import { User } from "next-auth";
@@ -74,7 +79,10 @@ function toZodSchema(
}
return {
- tags: tagsOnBookmarks.map((t) => t.tag),
+ tags: tagsOnBookmarks.map((t) => ({
+ attachedBy: t.attachedBy,
+ ...t.tag,
+ })),
content,
...rest,
};
@@ -234,4 +242,81 @@ export const bookmarksAppRouter = router({
return { bookmarks: results.map(toZodSchema) };
}),
+
+ updateTags: authedProcedure
+ .input(
+ z.object({
+ bookmarkId: z.string(),
+ attach: z.array(
+ z.object({
+ tagId: z.string().optional(), // If the tag already exists and we know its id
+ tag: z.string(),
+ }),
+ ),
+ detach: z.array(z.string()),
+ }),
+ )
+ .use(ensureBookmarkOwnership)
+ .mutation(async ({ input, ctx }) => {
+ await db.transaction(async (tx) => {
+ // Detaches
+ if (input.detach.length > 0) {
+ await db
+ .delete(tagsOnBookmarks)
+ .where(
+ and(
+ eq(tagsOnBookmarks.bookmarkId, input.bookmarkId),
+ inArray(tagsOnBookmarks.tagId, input.detach),
+ ),
+ );
+ }
+
+ if (input.attach.length == 0) {
+ return;
+ }
+
+ // New Tags
+ const toBeCreatedTags = input.attach
+ .filter((i) => i.tagId === undefined)
+ .map((i) => ({
+ name: i.tag,
+ userId: ctx.user.id,
+ }));
+
+ if (toBeCreatedTags.length > 0) {
+ await db
+ .insert(bookmarkTags)
+ .values(toBeCreatedTags)
+ .onConflictDoNothing()
+ .returning();
+ }
+
+ const allIds = (
+ await db.query.bookmarkTags.findMany({
+ where: and(
+ eq(bookmarkTags.userId, ctx.user.id),
+ inArray(
+ bookmarkTags.name,
+ input.attach.map((t) => t.tag),
+ ),
+ ),
+ columns: {
+ id: true,
+ },
+ })
+ ).map((t) => t.id);
+
+ await db
+ .insert(tagsOnBookmarks)
+ .values(
+ allIds.map((i) => ({
+ tagId: i as string,
+ bookmarkId: input.bookmarkId,
+ attachedBy: "human" as const,
+ userId: ctx.user.id,
+ })),
+ )
+ .onConflictDoNothing();
+ });
+ }),
});