From 4f4d2b7c5389ac73af1198577902379f7920326f Mon Sep 17 00:00:00 2001
From: Johann150 <johann.galle@protonmail.com>
Date: Thu, 23 Jun 2022 14:32:17 +0200
Subject: [PATCH] refactor: simplify ap/show with DbResolver (#8838)

Using the existing code in DbResolver we can avoid separate code for
parsing the URIs in this endpoint.

Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
---
 .../src/server/api/endpoints/ap/show.ts       | 132 +++++-------------
 1 file changed, 33 insertions(+), 99 deletions(-)

diff --git a/packages/backend/src/server/api/endpoints/ap/show.ts b/packages/backend/src/server/api/endpoints/ap/show.ts
index 3c0c0642e3..6442a1412c 100644
--- a/packages/backend/src/server/api/endpoints/ap/show.ts
+++ b/packages/backend/src/server/api/endpoints/ap/show.ts
@@ -2,12 +2,13 @@ import define from '../../define.js';
 import config from '@/config/index.js';
 import { createPerson } from '@/remote/activitypub/models/person.js';
 import { createNote } from '@/remote/activitypub/models/note.js';
+import DbResolver from '@/remote/activitypub/db-resolver.js';
 import Resolver from '@/remote/activitypub/resolver.js';
 import { ApiError } from '../../error.js';
 import { extractDbHost } from '@/misc/convert-host.js';
 import { Users, Notes } from '@/models/index.js';
 import { Note } from '@/models/entities/note.js';
-import { User } from '@/models/entities/user.js';
+import { CacheableLocalUser, User } from '@/models/entities/user.js';
 import { fetchMeta } from '@/misc/fetch-meta.js';
 import { isActor, isPost, getApId } from '@/remote/activitypub/type.js';
 import ms from 'ms';
@@ -77,8 +78,8 @@ export const paramDef = {
 } as const;
 
 // eslint-disable-next-line import/no-default-export
-export default define(meta, paramDef, async (ps) => {
-	const object = await fetchAny(ps.uri);
+export default define(meta, paramDef, async (ps, me) => {
+	const object = await fetchAny(ps.uri, me);
 	if (object) {
 		return object;
 	} else {
@@ -89,48 +90,18 @@ export default define(meta, paramDef, async (ps) => {
 /***
  * URIからUserかNoteを解決する
  */
-async function fetchAny(uri: string): Promise<SchemaType<typeof meta['res']> | null> {
-	// URIがこのサーバーを指しているなら、ローカルユーザーIDとしてDBからフェッチ
-	if (uri.startsWith(config.url + '/')) {
-		const parts = uri.split('/');
-		const id = parts.pop();
-		const type = parts.pop();
-
-		if (type === 'notes') {
-			const note = await Notes.findOneBy({ id });
-
-			if (note) {
-				return {
-					type: 'Note',
-					object: await Notes.pack(note, null, { detail: true }),
-				};
-			}
-		} else if (type === 'users') {
-			const user = await Users.findOneBy({ id });
-
-			if (user) {
-				return {
-					type: 'User',
-					object: await Users.pack(user, null, { detail: true }),
-				};
-			}
-		}
-	}
-
+async function fetchAny(uri: string, me: CacheableLocalUser | null | undefined): Promise<SchemaType<typeof meta['res']> | null> {
 	// ブロックしてたら中断
 	const fetchedMeta = await fetchMeta();
 	if (fetchedMeta.blockedHosts.includes(extractDbHost(uri))) return null;
 
-	// URI(AP Object id)としてDB検索
-	{
-		const [user, note] = await Promise.all([
-			Users.findOneBy({ uri: uri }),
-			Notes.findOneBy({ uri: uri }),
-		]);
+	const dbResolver = new DbResolver();
 
-		const packed = await mergePack(user, note);
-		if (packed !== null) return packed;
-	}
+	let local = await mergePack(me, ...await Promise.all([
+		dbResolver.getUserFromApId(uri),
+		dbResolver.getNoteFromApId(uri),
+	]));
+	if (local != null) return local;
 
 	// リモートから一旦オブジェクトフェッチ
 	const resolver = new Resolver();
@@ -139,74 +110,37 @@ async function fetchAny(uri: string): Promise<SchemaType<typeof meta['res']> | n
 	// /@user のような正規id以外で取得できるURIが指定されていた場合、ここで初めて正規URIが確定する
 	// これはDBに存在する可能性があるため再度DB検索
 	if (uri !== object.id) {
-		if (object.id.startsWith(config.url + '/')) {
-			const parts = object.id.split('/');
-			const id = parts.pop();
-			const type = parts.pop();
-
-			if (type === 'notes') {
-				const note = await Notes.findOneBy({ id });
-
-				if (note) {
-					return {
-						type: 'Note',
-						object: await Notes.pack(note, null, { detail: true }),
-					};
-				}
-			} else if (type === 'users') {
-				const user = await Users.findOneBy({ id });
-
-				if (user) {
-					return {
-						type: 'User',
-						object: await Users.pack(user, null, { detail: true }),
-					};
-				}
-			}
-		}
-
-		const [user, note] = await Promise.all([
-			Users.findOneBy({ uri: object.id }),
-			Notes.findOneBy({ uri: object.id }),
-		]);
-
-		const packed = await mergePack(user, note);
-		if (packed !== null) return packed;
+		local = await mergePack(me, ...await Promise.all([
+			dbResolver.getUserFromApId(object.id),
+			dbResolver.getNoteFromApId(object.id),
+		]));
+		if (local != null) return local;
 	}
 
-	// それでもみつからなければ新規であるため登録
-	if (isActor(object)) {
-		const user = await createPerson(getApId(object));
-		return {
-			type: 'User',
-			object: await Users.pack(user, null, { detail: true }),
-		};
-	}
-
-	if (isPost(object)) {
-		const note = await createNote(getApId(object), undefined, true);
-		return {
-			type: 'Note',
-			object: await Notes.pack(note!, null, { detail: true }),
-		};
-	}
-
-	return null;
+	return await mergePack(
+		me,
+		isActor(object) ? await createPerson(getApId(object)) : null,
+		isPost(object) ? await createNote(getApId(object), undefined, true) : null,
+	);
 }
 
-async function mergePack(user: User | null | undefined, note: Note | null | undefined): Promise<SchemaType<typeof meta.res> | null> {
+async function mergePack(me: CacheableLocalUser | null | undefined, user: User | null | undefined, note: Note | null | undefined): Promise<SchemaType<typeof meta.res> | null> {
 	if (user != null) {
 		return {
 			type: 'User',
-			object: await Users.pack(user, null, { detail: true }),
+			object: await Users.pack(user, me, { detail: true }),
 		};
-	}
+	} else if (note != null) {
+		try {
+			const object = await Notes.pack(note, me, { detail: true });
 
-	if (note != null) {
-		return {
-			type: 'Note',
-			object: await Notes.pack(note, null, { detail: true }),
-		};
+			return {
+				type: 'Note',
+				object,
+			};
+		} catch (e) {
+			return null;
+		}
 	}
 
 	return null;