From 7da191396469642de14655c30eba86926882e98c Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Tue, 3 Apr 2018 00:59:38 +0900
Subject: [PATCH] [wip] Implement like activity

---
 src/models/post-reaction.ts             |  2 +-
 src/remote/activitypub/act/like.ts      | 48 +++++++++++++++++++++++++
 src/remote/activitypub/renderer/note.ts |  2 +-
 3 files changed, 50 insertions(+), 2 deletions(-)
 create mode 100644 src/remote/activitypub/act/like.ts

diff --git a/src/models/post-reaction.ts b/src/models/post-reaction.ts
index 3fc33411fb..81be95b8d8 100644
--- a/src/models/post-reaction.ts
+++ b/src/models/post-reaction.ts
@@ -5,12 +5,12 @@ import Reaction from './post-reaction';
 import { pack as packUser } from './user';
 
 const PostReaction = db.get<IPostReaction>('postReactions');
+PostReaction.createIndex(['userId', 'postId'], { unique: true });
 export default PostReaction;
 
 export interface IPostReaction {
 	_id: mongo.ObjectID;
 	createdAt: Date;
-	deletedAt: Date;
 	postId: mongo.ObjectID;
 	userId: mongo.ObjectID;
 	reaction: string;
diff --git a/src/remote/activitypub/act/like.ts b/src/remote/activitypub/act/like.ts
new file mode 100644
index 0000000000..d2ddba89a9
--- /dev/null
+++ b/src/remote/activitypub/act/like.ts
@@ -0,0 +1,48 @@
+import { MongoError } from 'mongodb';
+import Post from '../../../models/post';
+import Reaction from '../../../models/post-reaction';
+import config from '../../../config';
+import queue from '../../../queue';
+
+export default async (actor, activity) => {
+	const prefix = config.url + '/posts';
+	const id = activity.object.id || activity.object;
+	let reaction;
+
+	if (!id.startsWith(prefix)) {
+		return null;
+	}
+
+	const postId = id.slice(prefix.length);
+
+	const post = await Post.findOne({ _id: postId });
+	if (post === null) {
+		throw new Error();
+	}
+
+	try {
+		reaction = await Reaction.insert({
+			createdAt: new Date(),
+			postId,
+			userId: actor._id,
+			reaction: 'pudding'
+		});
+	} catch (exception) {
+		// duplicate key error
+		if (exception instanceof MongoError && exception.code === 11000) {
+			return null;
+		}
+
+		throw exception;
+	}
+
+	await new Promise((resolve, reject) => {
+		queue.create('http', { type: 'like', reaction: reaction._id }).save(error => {
+			if (error) {
+				reject(error);
+			} else {
+				resolve(null);
+			}
+		});
+	});
+};
diff --git a/src/remote/activitypub/renderer/note.ts b/src/remote/activitypub/renderer/note.ts
index 43531b121a..36f8578ec4 100644
--- a/src/remote/activitypub/renderer/note.ts
+++ b/src/remote/activitypub/renderer/note.ts
@@ -30,7 +30,7 @@ export default async (user, post) => {
 	const attributedTo = `${config.url}/@${user.username}`;
 
 	return {
-		id: `${attributedTo}/${post._id}`,
+		id: `${config.url}/posts/${post._id}}`,
 		type: 'Note',
 		attributedTo,
 		content: post.textHtml,