From c012f4f880fb3bf70607f2ab49e8638c0ac87713 Mon Sep 17 00:00:00 2001
From: MeiMei <30769358+mei23@users.noreply.github.com>
Date: Sun, 15 Dec 2019 03:37:54 +0900
Subject: [PATCH] =?UTF-8?q?AP=E5=BC=95=E7=94=A8=E3=81=A7quoteUrl=E3=81=AB?=
 =?UTF-8?q?=E5=AF=BE=E5=BF=9C=20(#5632)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* Supports quoteUrl

* Quote resolveをリトライする

* Update src/remote/activitypub/models/note.ts

Co-Authored-By: Acid Chicken (硫酸鶏) <root@acid-chicken.com>

* Update src/remote/activitypub/models/note.ts

Co-Authored-By: Acid Chicken (硫酸鶏) <root@acid-chicken.com>

* Update src/remote/activitypub/models/note.ts

Co-Authored-By: Acid Chicken (硫酸鶏) <root@acid-chicken.com>

* Update src/remote/activitypub/models/note.ts

Co-Authored-By: Acid Chicken (硫酸鶏) <root@acid-chicken.com>
---
 src/remote/activitypub/models/note.ts   | 44 ++++++++++++++++++++-----
 src/remote/activitypub/renderer/note.ts |  1 +
 src/remote/activitypub/type.ts          |  2 ++
 3 files changed, 38 insertions(+), 9 deletions(-)

diff --git a/src/remote/activitypub/models/note.ts b/src/remote/activitypub/models/note.ts
index 7ce0b6a11..74d764e5e 100644
--- a/src/remote/activitypub/models/note.ts
+++ b/src/remote/activitypub/models/note.ts
@@ -162,16 +162,42 @@ export async function createNote(value: string | IObject, resolver?: Resolver, s
 	// 引用
 	let quote: Note | undefined | null;
 
-	if (note._misskey_quote && typeof note._misskey_quote == 'string') {
-		quote = await resolveNote(note._misskey_quote).catch(e => {
-			// 4xxの場合は引用してないことにする
-			if (e.statusCode >= 400 && e.statusCode < 500) {
-				logger.warn(`Ignored quote target ${note.inReplyTo} - ${e.statusCode} `);
-				return null;
+	if (note._misskey_quote || note.quoteUrl) {
+		const tryResolveNote = async (uri: string): Promise<{
+			status: 'ok';
+			res: Note | null;
+		} | {
+			status: 'permerror' | 'temperror';
+		}> => {
+			if (typeof uri !== 'string' || !uri.match(/^https?:/)) return { status: 'permerror' };
+			try {
+				const res = await resolveNote(uri);
+				if (res) {
+					return {
+						status: 'ok',
+						res
+					};
+				} else {
+					return {
+						status: 'permerror'
+					};
+				}
+			} catch (e) {
+				return {
+					status: e.statusCode >= 400 && e.statusCode < 500 ? 'permerror' : 'temperror'
+				};
 			}
-			logger.warn(`Error in quote target ${note.inReplyTo} - ${e.statusCode || e}`);
-			throw e;
-		});
+		};
+
+		const uris = unique([note._misskey_quote, note.quoteUrl].filter((x): x is string => typeof x === 'string'));
+		const results = await Promise.all(uris.map(uri => tryResolveNote(uri)));
+
+		quote = results.filter((x): x is { status: 'ok', res: Note | null } => x.status === 'ok').map(x => x.res).find(x => x);
+		if (!quote) {
+			if (results.some(x => x.status === 'temperror')) {
+				throw 'quote resolve failed';
+			}
+		}
 	}
 
 	const cw = note.summary === '' ? null : note.summary;
diff --git a/src/remote/activitypub/renderer/note.ts b/src/remote/activitypub/renderer/note.ts
index 31d67edba..f9912b0dd 100644
--- a/src/remote/activitypub/renderer/note.ts
+++ b/src/remote/activitypub/renderer/note.ts
@@ -159,6 +159,7 @@ export default async function renderNote(note: Note, dive = true, isTalk = false
 		content,
 		_misskey_content: text,
 		_misskey_quote: quote,
+		quoteUrl: quote,
 		published: note.createdAt.toISOString(),
 		to,
 		cc,
diff --git a/src/remote/activitypub/type.ts b/src/remote/activitypub/type.ts
index ad3f9638a..76d7ff59c 100644
--- a/src/remote/activitypub/type.ts
+++ b/src/remote/activitypub/type.ts
@@ -75,6 +75,7 @@ export interface INote extends IObject {
 	type: 'Note' | 'Question' | 'Article' | 'Audio' | 'Document' | 'Image' | 'Page' | 'Video';
 	_misskey_content?: string;
 	_misskey_quote?: string;
+	quoteUrl?: string;
 	_misskey_talk: boolean;
 }
 
@@ -82,6 +83,7 @@ export interface IQuestion extends IObject {
 	type: 'Note' | 'Question';
 	_misskey_content?: string;
 	_misskey_quote?: string;
+	quoteUrl?: string;
 	oneOf?: IQuestionChoice[];
 	anyOf?: IQuestionChoice[];
 	endTime?: Date;