diff --git a/database/entities/Like.ts b/database/entities/Like.ts index 70ecc929..6d1af5c9 100644 --- a/database/entities/Like.ts +++ b/database/entities/Like.ts @@ -46,3 +46,30 @@ export const createLike = async ( // TODO: Add database jobs for federating this } }; + +export const deleteLike = async ( + user: UserWithRelations, + status: StatusWithRelations +) => { + await client.like.deleteMany({ + where: { + likedId: status.id, + likerId: user.id, + }, + }); + + // Notify the user that their post has been favourited + await client.notification.deleteMany({ + where: { + accountId: user.id, + type: "favourite", + notifiedId: status.authorId, + statusId: status.id, + }, + }); + + if (user.instanceId === null) { + // User is local, federate the delete + // TODO: Federate this + } +}; diff --git a/server/api/api/v1/statuses/[id]/unfavourite.ts b/server/api/api/v1/statuses/[id]/unfavourite.ts index d893901a..36de4fe2 100644 --- a/server/api/api/v1/statuses/[id]/unfavourite.ts +++ b/server/api/api/v1/statuses/[id]/unfavourite.ts @@ -3,6 +3,7 @@ import { applyConfig } from "@api"; import { errorResponse, jsonResponse } from "@response"; import type { MatchedRoute } from "bun"; import { client } from "~database/datasource"; +import { deleteLike } from "~database/entities/Like"; import { isViewableByUser, statusAndUserRelations, @@ -46,12 +47,7 @@ export default async ( if (!status || !isViewableByUser(status, user)) return errorResponse("Record not found", 404); - await client.like.deleteMany({ - where: { - likedId: status.id, - likerId: user.id, - }, - }); + await deleteLike(user, status); return jsonResponse({ ...(await statusToAPI(status, user)), diff --git a/server/api/users/[uuid]/inbox/index.ts b/server/api/users/[uuid]/inbox/index.ts index 8903d522..f749908d 100644 --- a/server/api/users/[uuid]/inbox/index.ts +++ b/server/api/users/[uuid]/inbox/index.ts @@ -7,7 +7,7 @@ import { errorResponse, jsonResponse } from "@response"; import type { MatchedRoute } from "bun"; import { client } from "~database/datasource"; import { parseEmojis } from "~database/entities/Emoji"; -import { createLike } from "~database/entities/Like"; +import { createLike, deleteLike } from "~database/entities/Like"; import { createFromObject } from "~database/entities/Object"; import { createNewStatus, @@ -21,6 +21,7 @@ import type { LysandAction, LysandPublication, Patch, + Undo, } from "~types/lysand/Object"; export const meta = applyConfig({ @@ -274,6 +275,10 @@ export default async ( case "Dislike": { // Store the object in the LysandObject table await createFromObject(body); + + return jsonResponse({ + info: "Dislikes are not supported by this software", + }); break; } case "Follow": { @@ -332,8 +337,61 @@ export default async ( break; } case "Undo": { + const undo = body as Undo; // Store the object in the LysandObject table await createFromObject(body); + + const object = await client.lysandObject.findUnique({ + where: { + uri: undo.object, + }, + }); + + if (!object) { + return errorResponse("Object not found", 404); + } + + switch (object.type) { + case "Like": { + const status = await client.status.findUnique({ + where: { + uri: undo.object, + authorId: author.id, + }, + include: statusAndUserRelations, + }); + + if (!status) { + return errorResponse("Status not found", 404); + } + + await deleteLike(author, status); + break; + } + case "Announce": { + await client.status.delete({ + where: { + uri: undo.object, + authorId: author.id, + }, + include: statusAndUserRelations, + }); + break; + } + case "Note": { + await client.status.delete({ + where: { + uri: undo.object, + authorId: author.id, + }, + include: statusAndUserRelations, + }); + break; + } + default: { + return errorResponse("Invalid object type", 400); + } + } break; } case "Extension": {