diff --git a/src/drive/add-file.ts b/src/api/drive/add-file.ts similarity index 100% rename from src/drive/add-file.ts rename to src/api/drive/add-file.ts diff --git a/src/drive/upload-from-url.ts b/src/api/drive/upload-from-url.ts similarity index 100% rename from src/drive/upload-from-url.ts rename to src/api/drive/upload-from-url.ts diff --git a/src/api/following/create.ts b/src/api/following/create.ts new file mode 100644 index 0000000000..353a6c8920 --- /dev/null +++ b/src/api/following/create.ts @@ -0,0 +1,82 @@ +import User, { isLocalUser, isRemoteUser, pack as packUser, IUser } from '../../models/user'; +import Following from '../../models/following'; +import FollowingLog from '../../models/following-log'; +import FollowedLog from '../../models/followed-log'; +import event from '../../publishers/stream'; +import notify from '../../publishers/notify'; +import context from '../../remote/activitypub/renderer/context'; +import renderFollow from '../../remote/activitypub/renderer/follow'; +import renderAccept from '../../remote/activitypub/renderer/accept'; +import { createHttp } from '../../queue'; + +export default async function(follower: IUser, followee: IUser, activity?) { + const following = await Following.insert({ + createdAt: new Date(), + followerId: follower._id, + followeeId: followee._id + }); + + //#region Increment following count + User.update({ _id: follower._id }, { + $inc: { + followingCount: 1 + } + }); + + FollowingLog.insert({ + createdAt: following.createdAt, + userId: follower._id, + count: follower.followingCount + 1 + }); + //#endregion + + //#region Increment followers count + User.update({ _id: followee._id }, { + $inc: { + followersCount: 1 + } + }); + FollowedLog.insert({ + createdAt: following.createdAt, + userId: followee._id, + count: followee.followersCount + 1 + }); + //#endregion + + // Publish follow event + if (isLocalUser(follower)) { + packUser(followee, follower).then(packed => event(follower._id, 'follow', packed)); + } + + // Publish followed event + if (isLocalUser(followee)) { + packUser(follower, followee).then(packed => event(followee._id, 'followed', packed)), + + // 通知を作成 + notify(followee._id, follower._id, 'follow'); + } + + if (isLocalUser(follower) && isRemoteUser(followee)) { + const content = renderFollow(follower, followee); + content['@context'] = context; + + createHttp({ + type: 'deliver', + user: follower, + content, + to: followee.account.inbox + }).save(); + } + + if (isRemoteUser(follower) && isLocalUser(followee)) { + const content = renderAccept(activity); + content['@context'] = context; + + createHttp({ + type: 'deliver', + user: followee, + content, + to: follower.account.inbox + }).save(); + } +} diff --git a/src/post/create.ts b/src/api/post/create.ts similarity index 100% rename from src/post/create.ts rename to src/api/post/create.ts diff --git a/src/post/distribute.ts b/src/api/post/distribute.ts similarity index 100% rename from src/post/distribute.ts rename to src/api/post/distribute.ts diff --git a/src/post/watch.ts b/src/api/post/watch.ts similarity index 100% rename from src/post/watch.ts rename to src/api/post/watch.ts diff --git a/src/queue/processors/http/unfollow.ts b/src/queue/processors/http/unfollow.ts index d3d5f2246f..801a3612a7 100644 --- a/src/queue/processors/http/unfollow.ts +++ b/src/queue/processors/http/unfollow.ts @@ -1,56 +1,63 @@ -import FollowedLog from '../../models/followed-log'; -import Following from '../../models/following'; -import FollowingLog from '../../models/following-log'; -import User, { isRemoteUser, pack as packUser } from '../../models/user'; -import stream from '../../publishers/stream'; -import renderFollow from '../../remote/activitypub/renderer/follow'; -import renderUndo from '../../remote/activitypub/renderer/undo'; -import context from '../../remote/activitypub/renderer/context'; -import request from '../../remote/request'; +import FollowedLog from '../../../models/followed-log'; +import Following from '../../../models/following'; +import FollowingLog from '../../../models/following-log'; +import User, { isLocalUser, isRemoteUser, pack as packUser } from '../../../models/user'; +import stream from '../../../publishers/stream'; +import renderFollow from '../../../remote/activitypub/renderer/follow'; +import renderUndo from '../../../remote/activitypub/renderer/undo'; +import context from '../../../remote/activitypub/renderer/context'; +import request from '../../../remote/request'; +import Logger from '../../../utils/logger'; export default async ({ data }) => { - // Delete following - const following = await Following.findOneAndDelete({ _id: data.id }); + const following = await Following.findOne({ _id: data.id }); if (following === null) { return; } - const promisedFollower = User.findOne({ _id: following.followerId }); - const promisedFollowee = User.findOne({ _id: following.followeeId }); + const [follower, followee] = await Promise.all([ + User.findOne({ _id: following.followerId }), + User.findOne({ _id: following.followeeId }) + ]); - await Promise.all([ - // Decrement following count - User.update({ _id: following.followerId }, { $inc: { followingCount: -1 } }), - promisedFollower.then(({ followingCount }) => FollowingLog.insert({ - createdAt: new Date(), - userId: following.followerId, - count: followingCount - 1 - })), + if (isLocalUser(follower) && isRemoteUser(followee)) { + const undo = renderUndo(renderFollow(follower, followee)); + undo['@context'] = context; - // Decrement followers count - User.update({ _id: following.followeeId }, { $inc: { followersCount: -1 } }), - promisedFollowee.then(({ followersCount }) => FollowedLog.insert({ - createdAt: new Date(), - userId: following.followeeId, - count: followersCount - 1 - })), + await request(follower, followee.account.inbox, undo); + } + + try { + await Promise.all([ + // Delete following + Following.findOneAndDelete({ _id: data.id }), + + // Decrement following count + User.update({ _id: follower._id }, { $inc: { followingCount: -1 } }), + FollowingLog.insert({ + createdAt: new Date(), + userId: follower._id, + count: follower.followingCount - 1 + }), + + // Decrement followers count + User.update({ _id: followee._id }, { $inc: { followersCount: -1 } }), + FollowedLog.insert({ + createdAt: new Date(), + userId: followee._id, + count: followee.followersCount - 1 + }) + ]); + + if (isLocalUser(follower)) { + return; + } + + const promisedPackedUser = packUser(followee, follower); // Publish follow event - Promise.all([promisedFollower, promisedFollowee]).then(async ([follower, followee]) => { - if (isRemoteUser(follower)) { - return; - } - - const promisedPackedUser = packUser(followee, follower); - - if (isRemoteUser(followee)) { - const undo = renderUndo(renderFollow(follower, followee)); - undo['@context'] = context; - - await request(follower, followee.account.inbox, undo); - } - - stream(follower._id, 'unfollow', promisedPackedUser); - }) - ]); + stream(follower._id, 'unfollow', promisedPackedUser); + } catch (error) { + Logger.error(error.toString()); + } }; diff --git a/src/remote/activitypub/act/create.ts b/src/remote/activitypub/act/create.ts index c1a30ce7d0..7ee9f8dfb7 100644 --- a/src/remote/activitypub/act/create.ts +++ b/src/remote/activitypub/act/create.ts @@ -4,10 +4,10 @@ const createDOMPurify = require('dompurify'); import Resolver from '../resolver'; import DriveFile from '../../../models/drive-file'; import Post from '../../../models/post'; -import uploadFromUrl from '../../../drive/upload-from-url'; -import createPost from '../../../post/create'; +import uploadFromUrl from '../../../api/drive/upload-from-url'; +import createPost from '../../../api/post/create'; -export default async (resolver: Resolver, actor, activity): Promise => { +export default async (actor, activity): Promise => { if ('actor' in activity && actor.account.uri !== activity.actor) { throw new Error('invalid actor'); } @@ -31,6 +31,8 @@ export default async (resolver: Resolver, actor, activity): Promise => { throw new Error(`already registered: ${uri}`); } + const resolver = new Resolver(); + const object = await resolver.resolve(activity); switch (object.type) { diff --git a/src/remote/activitypub/act/follow.ts b/src/remote/activitypub/act/follow.ts index 23fa41df8e..dc173a0acb 100644 --- a/src/remote/activitypub/act/follow.ts +++ b/src/remote/activitypub/act/follow.ts @@ -1,15 +1,9 @@ -import { MongoError } from 'mongodb'; import parseAcct from '../../../acct/parse'; -import Following, { IFollowing } from '../../../models/following'; import User from '../../../models/user'; import config from '../../../config'; -import queue from '../../../queue'; -import context from '../renderer/context'; -import renderAccept from '../renderer/accept'; -import request from '../../request'; -import Resolver from '../resolver'; +import follow from '../../../api/following/create'; -export default async (resolver: Resolver, actor, activity, distribute) => { +export default async (actor, activity): Promise => { const prefix = config.url + '/@'; const id = activity.object.id || activity.object; @@ -27,52 +21,5 @@ export default async (resolver: Resolver, actor, activity, distribute) => { throw new Error(); } - if (!distribute) { - const { _id } = await Following.findOne({ - followerId: actor._id, - followeeId: followee._id - }); - - return { - resolver, - object: { $ref: 'following', $id: _id } - }; - } - - const promisedFollowing = Following.insert({ - createdAt: new Date(), - followerId: actor._id, - followeeId: followee._id - }).then(following => new Promise((resolve, reject) => { - queue.create('http', { - type: 'follow', - following: following._id - }).save(error => { - if (error) { - reject(error); - } else { - resolve(following); - } - }); - }) as Promise, async error => { - // duplicate key error - if (error instanceof MongoError && error.code === 11000) { - return Following.findOne({ - followerId: actor._id, - followeeId: followee._id - }); - } - - throw error; - }); - - const accept = renderAccept(activity); - accept['@context'] = context; - - await request(followee, actor.account.inbox, accept); - - return promisedFollowing.then(({ _id }) => ({ - resolver, - object: { $ref: 'following', $id: _id } - })); + await follow(actor, followee, activity); };