aboutsummaryrefslogtreecommitdiffstats
path: root/packages/trpc/routers/bookmarks.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/trpc/routers/bookmarks.ts')
-rw-r--r--packages/trpc/routers/bookmarks.ts141
1 files changed, 115 insertions, 26 deletions
diff --git a/packages/trpc/routers/bookmarks.ts b/packages/trpc/routers/bookmarks.ts
index c97383cb..9219adc6 100644
--- a/packages/trpc/routers/bookmarks.ts
+++ b/packages/trpc/routers/bookmarks.ts
@@ -54,7 +54,6 @@ import { parseSearchQuery } from "@hoarder/shared/searchQueryParser";
import {
BookmarkTypes,
DEFAULT_NUM_BOOKMARKS_PER_PAGE,
- zBareBookmarkSchema,
zBookmarkSchema,
zGetBookmarksRequestSchema,
zGetBookmarksResponseSchema,
@@ -419,35 +418,125 @@ export const bookmarksAppRouter = router({
updateBookmark: authedProcedure
.input(zUpdateBookmarksRequestSchema)
- .output(zBareBookmarkSchema)
+ .output(zBookmarkSchema)
.use(ensureBookmarkOwnership)
.mutation(async ({ input, ctx }) => {
- const res = await ctx.db
- .update(bookmarks)
- .set({
- title: input.title,
- archived: input.archived,
- favourited: input.favourited,
- note: input.note,
- summary: input.summary,
- createdAt: input.createdAt,
- })
- .where(
- and(
- eq(bookmarks.userId, ctx.user.id),
- eq(bookmarks.id, input.bookmarkId),
- ),
- )
- .returning();
- if (res.length == 0) {
- throw new TRPCError({
- code: "NOT_FOUND",
- message: "Bookmark not found",
- });
- }
+ await ctx.db.transaction(async (tx) => {
+ let somethingChanged = false;
+
+ // Update link-specific fields if any are provided
+ const linkUpdateData: Partial<{
+ url: string;
+ description: string | null;
+ author: string | null;
+ publisher: string | null;
+ datePublished: Date | null;
+ dateModified: Date | null;
+ }> = {};
+ if (input.url) {
+ linkUpdateData.url = input.url.trim();
+ }
+ if (input.description !== undefined) {
+ linkUpdateData.description = input.description;
+ }
+ if (input.author !== undefined) {
+ linkUpdateData.author = input.author;
+ }
+ if (input.publisher !== undefined) {
+ linkUpdateData.publisher = input.publisher;
+ }
+ if (input.datePublished !== undefined) {
+ linkUpdateData.datePublished = input.datePublished;
+ }
+ if (input.dateModified !== undefined) {
+ linkUpdateData.dateModified = input.dateModified;
+ }
+
+ if (Object.keys(linkUpdateData).length > 0) {
+ const result = await tx
+ .update(bookmarkLinks)
+ .set(linkUpdateData)
+ .where(eq(bookmarkLinks.id, input.bookmarkId));
+ if (result.changes == 0) {
+ throw new TRPCError({
+ code: "BAD_REQUEST",
+ message:
+ "Attempting to set link attributes for non-link type bookmark",
+ });
+ }
+ somethingChanged = true;
+ }
+
+ if (input.text) {
+ const result = await tx
+ .update(bookmarkTexts)
+ .set({
+ text: input.text,
+ })
+ .where(eq(bookmarkLinks.id, input.bookmarkId));
+
+ if (result.changes == 0) {
+ throw new TRPCError({
+ code: "BAD_REQUEST",
+ message:
+ "Attempting to set link attributes for non-text type bookmark",
+ });
+ }
+ somethingChanged = true;
+ }
+
+ // Update common bookmark fields
+ const commonUpdateData: Partial<{
+ title: string | null;
+ archived: boolean;
+ favourited: boolean;
+ note: string | null;
+ summary: string | null;
+ createdAt: Date;
+ modifiedAt: Date; // Always update modifiedAt
+ }> = {
+ modifiedAt: new Date(),
+ };
+ if (input.title !== undefined) {
+ commonUpdateData.title = input.title;
+ }
+ if (input.archived !== undefined) {
+ commonUpdateData.archived = input.archived;
+ }
+ if (input.favourited !== undefined) {
+ commonUpdateData.favourited = input.favourited;
+ }
+ if (input.note !== undefined) {
+ commonUpdateData.note = input.note;
+ }
+ if (input.summary !== undefined) {
+ commonUpdateData.summary = input.summary;
+ }
+ if (input.createdAt !== undefined) {
+ commonUpdateData.createdAt = input.createdAt;
+ }
+
+ if (Object.keys(commonUpdateData).length > 1 || somethingChanged) {
+ await tx
+ .update(bookmarks)
+ .set(commonUpdateData)
+ .where(
+ and(
+ eq(bookmarks.userId, ctx.user.id),
+ eq(bookmarks.id, input.bookmarkId),
+ ),
+ );
+ }
+ });
+
+ // Refetch the updated bookmark data to return the full object
+ const updatedBookmark = await getBookmark(ctx, input.bookmarkId);
+
+ // Trigger re-indexing and webhooks
await triggerSearchReindex(input.bookmarkId);
await triggerWebhook(input.bookmarkId, "edited");
- return res[0];
+
+ return updatedBookmark;
}),
updateBookmarkText: authedProcedure