From ef624977770c4d4b501a0e167804e69752c9ca44 Mon Sep 17 00:00:00 2001
From: MeiMei <30769358+mei23@users.noreply.github.com>
Date: Sat, 8 Sep 2018 05:24:55 +0900
Subject: [PATCH] =?UTF-8?q?ActivityPub=20Outbox=E3=81=AE=E4=BF=AE=E6=AD=A3?=
 =?UTF-8?q?=E3=81=A8activity=20id=E3=81=AEURL=E3=82=92=E5=AE=9F=E8=A3=85?=
 =?UTF-8?q?=20=20(#2662)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* Fix Outbox structure

* Implement activity endpoint

* Use in instead of or

* Use in, addition
---
 src/remote/activitypub/renderer/announce.ts |  2 +-
 src/server/activitypub.ts                   | 18 +++++++++++-
 src/server/activitypub/outbox.ts            | 31 +++++++++++++--------
 3 files changed, 37 insertions(+), 14 deletions(-)

diff --git a/src/remote/activitypub/renderer/announce.ts b/src/remote/activitypub/renderer/announce.ts
index f6276ade04..18e23cc336 100644
--- a/src/remote/activitypub/renderer/announce.ts
+++ b/src/remote/activitypub/renderer/announce.ts
@@ -5,7 +5,7 @@ export default (object: any, note: INote) => {
 	const attributedTo = `${config.url}/users/${note.userId}`;
 
 	return {
-		id: `${config.url}/notes/${note._id}`,
+		id: `${config.url}/notes/${note._id}/activity`,
 		actor: `${config.url}/users/${note.userId}`,
 		type: 'Announce',
 		published: note.createdAt.toISOString(),
diff --git a/src/server/activitypub.ts b/src/server/activitypub.ts
index f04f9e91e9..3d346693d8 100644
--- a/src/server/activitypub.ts
+++ b/src/server/activitypub.ts
@@ -10,7 +10,7 @@ import User, { isLocalUser, ILocalUser, IUser } from '../models/user';
 import renderNote from '../remote/activitypub/renderer/note';
 import renderKey from '../remote/activitypub/renderer/key';
 import renderPerson from '../remote/activitypub/renderer/person';
-import Outbox from './activitypub/outbox';
+import Outbox, { packActivity } from './activitypub/outbox';
 import Followers from './activitypub/followers';
 import Following from './activitypub/following';
 
@@ -77,6 +77,22 @@ router.get('/notes/:note', async (ctx, next) => {
 	setResponseType(ctx);
 });
 
+// note activity
+router.get('/notes/:note/activity', async ctx => {
+	const note = await Note.findOne({
+		_id: new mongo.ObjectID(ctx.params.note),
+		visibility: { $in: ['public', 'home'] }
+	});
+
+	if (note === null) {
+		ctx.status = 404;
+		return;
+	}
+
+	ctx.body = pack(await packActivity(note));
+	setResponseType(ctx);
+});
+
 // outbox
 router.get('/users/:user/outbox', Outbox);
 
diff --git a/src/server/activitypub/outbox.ts b/src/server/activitypub/outbox.ts
index a5e762eea8..9a4c881774 100644
--- a/src/server/activitypub/outbox.ts
+++ b/src/server/activitypub/outbox.ts
@@ -8,8 +8,10 @@ import renderOrderedCollection from '../../remote/activitypub/renderer/ordered-c
 import renderOrderedCollectionPage from '../../remote/activitypub/renderer/ordered-collection-page';
 import { setResponseType } from '../activitypub';
 
-import Note from '../../models/note';
+import Note, { INote } from '../../models/note';
 import renderNote from '../../remote/activitypub/renderer/note';
+import renderCreate from '../../remote/activitypub/renderer/create';
+import renderAnnounce from '../../remote/activitypub/renderer/announce';
 import { countIf } from '../../prelude/array';
 
 export default async (ctx: Router.IRouterContext) => {
@@ -53,15 +55,7 @@ export default async (ctx: Router.IRouterContext) => {
 
 		const query = {
 			userId: user._id,
-			$and: [{
-				$or: [ { visibility: 'public' }, { visibility: 'home' } ]
-			}, { // exclude renote, but include quote
-				$or: [{
-					text: { $ne: null }
-				}, {
-					fileIds: { $ne: [] }
-				}]
-			}]
+			visibility: { $in: ['public', 'home'] }
 		} as any;
 
 		if (sinceId) {
@@ -85,10 +79,10 @@ export default async (ctx: Router.IRouterContext) => {
 
 		if (sinceId) notes.reverse();
 
-		const renderedNotes = await Promise.all(notes.map(note => renderNote(note, false)));
+		const activities = await Promise.all(notes.map(note => packActivity(note)));
 		const rendered = renderOrderedCollectionPage(
 			`${partOf}?page=true${sinceId ? `&since_id=${sinceId}` : ''}${untilId ? `&until_id=${untilId}` : ''}`,
-			user.notesCount, renderedNotes, partOf,
+			user.notesCount, activities, partOf,
 			notes.length > 0 ? `${partOf}?page=true&since_id=${notes[0]._id}` : null,
 			notes.length > 0 ? `${partOf}?page=true&until_id=${notes[notes.length - 1]._id}` : null
 		);
@@ -105,3 +99,16 @@ export default async (ctx: Router.IRouterContext) => {
 		setResponseType(ctx);
 	}
 };
+
+/**
+ * Pack Create<Note> or Announce Activity
+ * @param note Note
+ */
+export async function packActivity(note: INote): Promise<object> {
+	if (note.renoteId && note.text == null) {
+		const renote = await Note.findOne(note.renoteId);
+		return renderAnnounce(renote.uri ? renote.uri : `${config.url}/notes/${renote._id}`, note);
+	}
+
+	return renderCreate(await renderNote(note, false), note);
+}