From 95b46ba2e4c74c643f4ca97e911db11c731551bd Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Tue, 26 Sep 2023 13:08:05 -1000 Subject: [PATCH] More refactoring, API route fixes --- database/entities/Status.ts | 16 ++++++++-------- database/entities/User.ts | 16 ++++++++++++---- server/api/api/v1/statuses/index.ts | 28 ++++++++++++++++++++++++++++ tests/actor.test.ts | 1 - tests/api.test.ts | 3 --- tests/inbox.test.ts | 24 ++++++++++++++++++++++++ 6 files changed, 72 insertions(+), 16 deletions(-) diff --git a/database/entities/Status.ts b/database/entities/Status.ts index 1494ca73..7683ae3f 100644 --- a/database/entities/Status.ts +++ b/database/entities/Status.ts @@ -7,7 +7,6 @@ import { JoinTable, ManyToMany, ManyToOne, - OneToOne, PrimaryGeneratedColumn, RemoveOptions, UpdateDateColumn, @@ -46,7 +45,10 @@ export class Status extends BaseEntity { }) reblog?: Status; - @OneToOne(() => Status) + @ManyToOne(() => RawObject, { + nullable: true, + onDelete: "SET NULL", + }) object!: RawObject; @Column("boolean") @@ -63,12 +65,12 @@ export class Status extends BaseEntity { @ManyToOne(() => RawObject, { nullable: true, }) - in_reply_to_post!: RawObject; + in_reply_to_post!: RawObject | null; @ManyToOne(() => RawActor, { nullable: true, }) - in_reply_to_account!: RawActor; + in_reply_to_account!: RawActor | null; @Column("boolean") sensitive!: boolean; @@ -99,9 +101,7 @@ export class Status extends BaseEntity { // Delete object await this.object.remove(options); - await super.remove(options); - - return this; + return await super.remove(options); } static async createNew(data: { @@ -225,7 +225,7 @@ export class Status extends BaseEntity { } // TODO: Add default language - + await newStatus.object.save(); await newStatus.save(); return newStatus; } diff --git a/database/entities/User.ts b/database/entities/User.ts index 4088e482..f695de31 100644 --- a/database/entities/User.ts +++ b/database/entities/User.ts @@ -9,6 +9,7 @@ import { ManyToOne, OneToMany, PrimaryGeneratedColumn, + RemoveOptions, UpdateDateColumn, } from "typeorm"; import { APIAccount } from "~types/entities/account"; @@ -174,7 +175,7 @@ export class User extends BaseEntity { return relationship; } - async selfDestruct() { + async remove(options?: RemoveOptions | undefined) { // Clean up tokens const tokens = await Token.findBy({ user: { @@ -182,9 +183,14 @@ export class User extends BaseEntity { }, }); - const statuses = await Status.findBy({ - account: { - id: this.id, + const statuses = await Status.find({ + where: { + account: { + id: this.id, + }, + }, + relations: { + object: true, }, }); @@ -199,6 +205,8 @@ export class User extends BaseEntity { await Promise.all( relationships.map(async relationship => await relationship.remove()) ); + + return await super.remove(options); } async getRelationships() { diff --git a/server/api/api/v1/statuses/index.ts b/server/api/api/v1/statuses/index.ts index df997e09..cd36bc0f 100644 --- a/server/api/api/v1/statuses/index.ts +++ b/server/api/api/v1/statuses/index.ts @@ -1,8 +1,13 @@ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ /* eslint-disable @typescript-eslint/no-unused-vars */ import { getConfig } from "@config"; import { parseRequest } from "@request"; import { errorResponse, jsonResponse } from "@response"; +import { APActor } from "activitypub-types"; import { Application } from "~database/entities/Application"; +import { RawActor } from "~database/entities/RawActor"; +import { RawObject } from "~database/entities/RawObject"; import { Status } from "~database/entities/Status"; import { User } from "~database/entities/User"; @@ -101,6 +106,22 @@ export default async (req: Request): Promise => { return errorResponse("Invalid visibility", 422); } + // Get reply account and status if exists + let replyObject: RawObject | null = null; + let replyActor: RawActor | null = null; + + if (in_reply_to_id) { + replyObject = await RawObject.findOne({ + where: { + id: in_reply_to_id, + }, + }); + + replyActor = await RawActor.getByActorId( + (replyObject?.data.attributedTo as APActor).id ?? "" + ); + } + // Create status const newStatus = await Status.createNew({ account: user, @@ -116,6 +137,13 @@ export default async (req: Request): Promise => { sensitive: sensitive || false, spoiler_text: spoiler_text || "", emojis: [], + reply: + replyObject && replyActor + ? { + actor: replyActor, + object: replyObject, + } + : undefined, }); // TODO: add database jobs to deliver the post diff --git a/tests/actor.test.ts b/tests/actor.test.ts index c3d29c81..27cb037f 100644 --- a/tests/actor.test.ts +++ b/tests/actor.test.ts @@ -80,7 +80,6 @@ afterAll(async () => { ); if (user) { - await user.selfDestruct(); await user.remove(); } }); diff --git a/tests/api.test.ts b/tests/api.test.ts index 8aa481de..994ab0d8 100644 --- a/tests/api.test.ts +++ b/tests/api.test.ts @@ -580,9 +580,6 @@ afterAll(async () => { }) ); - await user.selfDestruct(); await user.remove(); - - await user2.selfDestruct(); await user2.remove(); }); diff --git a/tests/inbox.test.ts b/tests/inbox.test.ts index 09f56eb5..e9f16f77 100644 --- a/tests/inbox.test.ts +++ b/tests/inbox.test.ts @@ -188,6 +188,30 @@ describe("POST /@test/inbox", () => { expect(activity?.actors[0].data).toEqual({ preferredUsername: "test", id: `${config.http.base_url}/@test`, + summary: "", + publicKey: { + id: `${config.http.base_url}/@test/actor#main-key`, + owner: `${config.http.base_url}/@test/actor`, + publicKeyPem: expect.any(String), + }, + outbox: `${config.http.base_url}/@test/outbox`, + manuallyApprovesFollowers: false, + followers: `${config.http.base_url}/@test/followers`, + following: `${config.http.base_url}/@test/following`, + name: "", + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + ], + icon: { + type: "Image", + url: "", + }, + image: { + type: "Image", + url: "", + }, + inbox: `${config.http.base_url}/@test/inbox`, type: "Person", });