From c1df4bd5794ebcebd68d082fcbcaa2201bd2f658 Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Fri, 29 Sep 2023 14:24:06 +0200 Subject: [PATCH] [mastodon-client] POST /statuses/:id/bookmark, /statuses/:id/unbookmark --- .../server/api/mastodon/endpoints/status.ts | 52 ++++++++++++++----- .../src/server/api/mastodon/helpers/note.ts | 32 +++++++++++- 2 files changed, 69 insertions(+), 15 deletions(-) diff --git a/packages/backend/src/server/api/mastodon/endpoints/status.ts b/packages/backend/src/server/api/mastodon/endpoints/status.ts index dd99506b1..e2095a2bf 100644 --- a/packages/backend/src/server/api/mastodon/endpoints/status.ts +++ b/packages/backend/src/server/api/mastodon/endpoints/status.ts @@ -414,14 +414,26 @@ export function apiStatusMastodon(router: Router): void { router.post<{ Params: { id: string } }>( "/v1/statuses/:id/bookmark", async (ctx) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); try { - const data = await client.bookmarkStatus( - convertId(ctx.params.id, IdType.IceshrimpId), - ); - ctx.body = convertStatus(data.data); + const auth = await authenticate(ctx.headers.authorization, null); + const user = auth[0] ?? null; + + if (!user) { + ctx.status = 401; + return; + } + + const id = convertId(ctx.params.id, IdType.IceshrimpId); + const note = await getNote(id, user).catch(_ => null); + + if (note === null) { + ctx.status = 404; + return; + } + + ctx.body = await NoteHelpers.bookmarkNote(note, user) + .then(p => NoteConverter.encode(p, user)) + .then(p => convertStatus(p)); } catch (e: any) { console.error(e); ctx.status = 401; @@ -433,14 +445,26 @@ export function apiStatusMastodon(router: Router): void { router.post<{ Params: { id: string } }>( "/v1/statuses/:id/unbookmark", async (ctx) => { - const BASE_URL = `${ctx.protocol}://${ctx.hostname}`; - const accessTokens = ctx.headers.authorization; - const client = getClient(BASE_URL, accessTokens); try { - const data = await client.unbookmarkStatus( - convertId(ctx.params.id, IdType.IceshrimpId), - ); - ctx.body = convertStatus(data.data); + const auth = await authenticate(ctx.headers.authorization, null); + const user = auth[0] ?? null; + + if (!user) { + ctx.status = 401; + return; + } + + const id = convertId(ctx.params.id, IdType.IceshrimpId); + const note = await getNote(id, user).catch(_ => null); + + if (note === null) { + ctx.status = 404; + return; + } + + ctx.body = await NoteHelpers.unbookmarkNote(note, user) + .then(p => NoteConverter.encode(p, user)) + .then(p => convertStatus(p)); } catch (e: any) { console.error(e); ctx.status = 401; diff --git a/packages/backend/src/server/api/mastodon/helpers/note.ts b/packages/backend/src/server/api/mastodon/helpers/note.ts index 4e383ee2c..fa69afba7 100644 --- a/packages/backend/src/server/api/mastodon/helpers/note.ts +++ b/packages/backend/src/server/api/mastodon/helpers/note.ts @@ -1,5 +1,5 @@ import { makePaginationQuery } from "@/server/api/common/make-pagination-query.js"; -import { Metas, Notes, Users } from "@/models/index.js"; +import { Metas, NoteFavorites, Notes, Users } from "@/models/index.js"; import { generateVisibilityQuery } from "@/server/api/common/generate-visibility-query.js"; import { generateMutedUserQuery } from "@/server/api/common/generate-muted-user-query.js"; import { generateBlockedUserQuery } from "@/server/api/common/generate-block-query.js"; @@ -10,6 +10,7 @@ import createReaction from "@/services/note/reaction/create.js"; import deleteReaction from "@/services/note/reaction/delete.js"; import createNote from "@/services/note/create.js"; import deleteNote from "@/services/note/delete.js"; +import { genId } from "@/misc/gen-id.js"; export class NoteHelpers { public static async getDefaultReaction(): Promise { @@ -48,6 +49,35 @@ export class NoteHelpers { .then(_ => getNote(note.id, user)); } + public static async bookmarkNote(note: Note, user: ILocalUser): Promise { + const bookmarked = await NoteFavorites.exist({ + where: { + noteId: note.id, + userId: user.id, + }, + }); + + if (!bookmarked) { + await NoteFavorites.insert({ + id: genId(), + createdAt: new Date(), + noteId: note.id, + userId: user.id, + }); + } + + return note; + } + + public static async unbookmarkNote(note: Note, user: ILocalUser): Promise { + return await NoteFavorites.findOneBy({ + noteId: note.id, + userId: user.id, + }) + .then(p => p !== null ? NoteFavorites.delete(p.id) : null) + .then(_ => note); + } + public static async getNoteDescendants(note: Note | string, user: ILocalUser | null, limit: number = 10, depth: number = 2): Promise { const noteId = typeof note === "string" ? note : note.id; const query = makePaginationQuery(Notes.createQueryBuilder("note"))