This commit is contained in:
syuilo 2018-04-04 23:59:38 +09:00
parent 5bd1451b61
commit 77f056b4fc
9 changed files with 142 additions and 104 deletions

View File

@ -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();
}
}

View File

@ -1,56 +1,63 @@
import FollowedLog from '../../models/followed-log'; import FollowedLog from '../../../models/followed-log';
import Following from '../../models/following'; import Following from '../../../models/following';
import FollowingLog from '../../models/following-log'; import FollowingLog from '../../../models/following-log';
import User, { isRemoteUser, pack as packUser } from '../../models/user'; import User, { isLocalUser, isRemoteUser, pack as packUser } from '../../../models/user';
import stream from '../../publishers/stream'; import stream from '../../../publishers/stream';
import renderFollow from '../../remote/activitypub/renderer/follow'; import renderFollow from '../../../remote/activitypub/renderer/follow';
import renderUndo from '../../remote/activitypub/renderer/undo'; import renderUndo from '../../../remote/activitypub/renderer/undo';
import context from '../../remote/activitypub/renderer/context'; import context from '../../../remote/activitypub/renderer/context';
import request from '../../remote/request'; import request from '../../../remote/request';
import Logger from '../../../utils/logger';
export default async ({ data }) => { export default async ({ data }) => {
// Delete following const following = await Following.findOne({ _id: data.id });
const following = await Following.findOneAndDelete({ _id: data.id });
if (following === null) { if (following === null) {
return; return;
} }
const promisedFollower = User.findOne({ _id: following.followerId }); const [follower, followee] = await Promise.all([
const promisedFollowee = User.findOne({ _id: following.followeeId }); User.findOne({ _id: following.followerId }),
User.findOne({ _id: following.followeeId })
]);
await Promise.all([ if (isLocalUser(follower) && isRemoteUser(followee)) {
// 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
})),
// 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
})),
// 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)); const undo = renderUndo(renderFollow(follower, followee));
undo['@context'] = context; undo['@context'] = context;
await request(follower, followee.account.inbox, undo); await request(follower, followee.account.inbox, undo);
} }
stream(follower._id, 'unfollow', promisedPackedUser); 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
stream(follower._id, 'unfollow', promisedPackedUser);
} catch (error) {
Logger.error(error.toString());
}
}; };

View File

@ -4,10 +4,10 @@ const createDOMPurify = require('dompurify');
import Resolver from '../resolver'; import Resolver from '../resolver';
import DriveFile from '../../../models/drive-file'; import DriveFile from '../../../models/drive-file';
import Post from '../../../models/post'; import Post from '../../../models/post';
import uploadFromUrl from '../../../drive/upload-from-url'; import uploadFromUrl from '../../../api/drive/upload-from-url';
import createPost from '../../../post/create'; import createPost from '../../../api/post/create';
export default async (resolver: Resolver, actor, activity): Promise<void> => { export default async (actor, activity): Promise<void> => {
if ('actor' in activity && actor.account.uri !== activity.actor) { if ('actor' in activity && actor.account.uri !== activity.actor) {
throw new Error('invalid actor'); throw new Error('invalid actor');
} }
@ -31,6 +31,8 @@ export default async (resolver: Resolver, actor, activity): Promise<void> => {
throw new Error(`already registered: ${uri}`); throw new Error(`already registered: ${uri}`);
} }
const resolver = new Resolver();
const object = await resolver.resolve(activity); const object = await resolver.resolve(activity);
switch (object.type) { switch (object.type) {

View File

@ -1,15 +1,9 @@
import { MongoError } from 'mongodb';
import parseAcct from '../../../acct/parse'; import parseAcct from '../../../acct/parse';
import Following, { IFollowing } from '../../../models/following';
import User from '../../../models/user'; import User from '../../../models/user';
import config from '../../../config'; import config from '../../../config';
import queue from '../../../queue'; import follow from '../../../api/following/create';
import context from '../renderer/context';
import renderAccept from '../renderer/accept';
import request from '../../request';
import Resolver from '../resolver';
export default async (resolver: Resolver, actor, activity, distribute) => { export default async (actor, activity): Promise<void> => {
const prefix = config.url + '/@'; const prefix = config.url + '/@';
const id = activity.object.id || activity.object; const id = activity.object.id || activity.object;
@ -27,52 +21,5 @@ export default async (resolver: Resolver, actor, activity, distribute) => {
throw new Error(); throw new Error();
} }
if (!distribute) { await follow(actor, followee, activity);
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<IFollowing>, 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 }
}));
}; };