From ee3d4a386f3e12335bc7ff40d7c9849f4def3e48 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Fri, 22 Sep 2023 15:31:41 -1000 Subject: [PATCH] Add new user note API endpoint --- README.md | 1 + server/api/api/v1/accounts/[id]/note.ts | 57 +++++++++++++++++++++++++ tests/api.test.ts | 24 +++++++++++ 3 files changed, 82 insertions(+) create mode 100644 server/api/api/v1/accounts/[id]/note.ts diff --git a/README.md b/README.md index 5c80a352..ad48a899 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,7 @@ Working endpoints are: - `/api/v1/accounts/:id/unmute` - `/api/v1/accounts/:id/pin` - `/api/v1/accounts/:id/unpin` +- `/api/v1/accounts/:id/note` - `/api/v1/accounts/update_credentials` - `/api/v1/accounts/verify_credentials` - `/api/v1/statuses` diff --git a/server/api/api/v1/accounts/[id]/note.ts b/server/api/api/v1/accounts/[id]/note.ts new file mode 100644 index 00000000..04a321e9 --- /dev/null +++ b/server/api/api/v1/accounts/[id]/note.ts @@ -0,0 +1,57 @@ +import { getUserByToken } from "@auth"; +import { parseRequest } from "@request"; +import { errorResponse, jsonResponse } from "@response"; +import { MatchedRoute } from "bun"; +import { Relationship } from "~database/entities/Relationship"; +import { User } from "~database/entities/User"; + +/** + * Sets a user note + */ +export default async ( + req: Request, + matchedRoute: MatchedRoute +): Promise => { + const id = matchedRoute.params.id; + + // Check auth token + const token = req.headers.get("Authorization")?.split(" ")[1] || null; + + if (!token) + return errorResponse("This method requires an authenticated user", 422); + + const self = await getUserByToken(token); + + if (!self) return errorResponse("Unauthorized", 401); + + const { comment } = await parseRequest<{ + comment: string; + }>(req); + + const user = await User.findOneBy({ + id, + }); + + if (!user) return errorResponse("User not found", 404); + + // Check if already following + let relationship = await self.getRelationshipToOtherUser(user); + + if (!relationship) { + // Create new relationship + + const newRelationship = await Relationship.createNew(self, user); + + self.relationships.push(newRelationship); + await self.save(); + + relationship = newRelationship; + } + + relationship.note = comment ?? ""; + + // TODO: Implement duration + + await relationship.save(); + return jsonResponse(await relationship.toAPI()); +}; diff --git a/tests/api.test.ts b/tests/api.test.ts index de8f2e3a..af14fb7c 100644 --- a/tests/api.test.ts +++ b/tests/api.test.ts @@ -459,6 +459,30 @@ describe("POST /api/v1/accounts/:id/unpin", () => { }); }); +describe("POST /api/v1/accounts/:id/note", () => { + test("should update the specified account's note and return the updated account object", async () => { + const response = await fetch( + `${config.http.base_url}/api/v1/accounts/${user2.id}/note`, + { + method: "POST", + headers: { + Authorization: `Bearer ${token.access_token}`, + "Content-Type": "application/json", + }, + body: JSON.stringify({ comment: "This is a new note" }), + } + ); + + expect(response.status).toBe(200); + expect(response.headers.get("content-type")).toBe("application/json"); + + const account: APIAccount = await response.json(); + + expect(account.id).toBe(user2.id); + expect(account.note).toBe("This is a new note"); + }); +}); + afterAll(async () => { const activities = await RawActivity.createQueryBuilder("activity") .where("activity.data->>'actor' = :actor", {