From 22830965e341c9c961e072b2e92cb7c404f8624d Mon Sep 17 00:00:00 2001 From: MeiMei <30769358+mei23@users.noreply.github.com> Date: Sun, 20 Jan 2019 03:07:12 +0900 Subject: [PATCH] AP Undo Like (#3933) * AP Undo Like * rename --- src/remote/activitypub/kernel/undo/index.ts | 6 +- src/remote/activitypub/kernel/undo/like.ts | 21 +++++++ src/server/api/common/getters.ts | 18 ++++++ .../api/endpoints/notes/reactions/create.ts | 35 ++++-------- .../api/endpoints/notes/reactions/delete.ts | 55 ++++--------------- src/services/note/reaction/delete.ts | 49 +++++++++++++++++ 6 files changed, 117 insertions(+), 67 deletions(-) create mode 100644 src/remote/activitypub/kernel/undo/like.ts create mode 100644 src/server/api/common/getters.ts create mode 100644 src/services/note/reaction/delete.ts diff --git a/src/remote/activitypub/kernel/undo/index.ts b/src/remote/activitypub/kernel/undo/index.ts index ba56dd6328..471988f052 100644 --- a/src/remote/activitypub/kernel/undo/index.ts +++ b/src/remote/activitypub/kernel/undo/index.ts @@ -1,9 +1,10 @@ import * as debug from 'debug'; import { IRemoteUser } from '../../../../models/user'; -import { IUndo, IFollow, IBlock } from '../../type'; +import { IUndo, IFollow, IBlock, ILike } from '../../type'; import unfollow from './follow'; import unblock from './block'; +import undoLike from './like'; import Resolver from '../../resolver'; const log = debug('misskey:activitypub'); @@ -35,6 +36,9 @@ export default async (actor: IRemoteUser, activity: IUndo): Promise => { case 'Block': unblock(actor, object as IBlock); break; + case 'Like': + undoLike(actor, object as ILike); + break; } return null; diff --git a/src/remote/activitypub/kernel/undo/like.ts b/src/remote/activitypub/kernel/undo/like.ts new file mode 100644 index 0000000000..b324ec854c --- /dev/null +++ b/src/remote/activitypub/kernel/undo/like.ts @@ -0,0 +1,21 @@ +import * as mongo from 'mongodb'; +import { IRemoteUser } from '../../../../models/user'; +import { ILike } from '../../type'; +import Note from '../../../../models/note'; +import deleteReaction from '../../../../services/note/reaction/delete'; + +/** + * Process Undo.Like activity + */ +export default async (actor: IRemoteUser, activity: ILike): Promise => { + const id = typeof activity.object == 'string' ? activity.object : activity.object.id; + + const noteId = new mongo.ObjectID(id.split('/').pop()); + + const note = await Note.findOne({ _id: noteId }); + if (note === null) { + throw 'note not found'; + } + + await deleteReaction(actor, note); +}; diff --git a/src/server/api/common/getters.ts b/src/server/api/common/getters.ts new file mode 100644 index 0000000000..1fce58b20a --- /dev/null +++ b/src/server/api/common/getters.ts @@ -0,0 +1,18 @@ +import * as mongo from 'mongodb'; +import Note from "../../../models/note"; + +/** + * Get valied note for API processing + */ +export async function getValiedNote(noteId: mongo.ObjectID) { + const note = await Note.findOne({ + _id: noteId, + deletedAt: { $exists: false } + }); + + if (note === null) { + throw 'note not found'; + } + + return note; +} diff --git a/src/server/api/endpoints/notes/reactions/create.ts b/src/server/api/endpoints/notes/reactions/create.ts index 6c90898250..4037e89943 100644 --- a/src/server/api/endpoints/notes/reactions/create.ts +++ b/src/server/api/endpoints/notes/reactions/create.ts @@ -1,8 +1,10 @@ +import * as mongo from 'mongodb'; import $ from 'cafy'; import ID, { transform } from '../../../../../misc/cafy-id'; -import Note from '../../../../../models/note'; -import create from '../../../../../services/note/reaction/create'; +import createReaction from '../../../../../services/note/reaction/create'; import { validateReaction } from '../../../../../models/note-reaction'; import define from '../../../define'; +import { IUser } from '../../../../../models/user'; +import { getValiedNote } from '../../../common/getters'; export const meta = { stability: 'stable', @@ -34,25 +36,12 @@ export const meta = { } }; -export default define(meta, (ps, user) => new Promise(async (res, rej) => { - // Fetch reactee - const note = await Note.findOne({ - _id: ps.noteId - }); - - if (note === null) { - return rej('note not found'); - } - - if (note.deletedAt != null) { - return rej('this note is already deleted'); - } - - try { - await create(user, note, ps.reaction); - } catch (e) { - rej(e); - } - - res(); +export default define(meta, (ps, user) => new Promise((res, rej) => { + createReactionById(user, ps.noteId, ps.reaction) + .then(r => res(r)).catch(e => rej(e)); })); + +async function createReactionById(user: IUser, noteId: mongo.ObjectID, reaction: string) { + const note = await getValiedNote(noteId); + await createReaction(user, note, reaction); +} diff --git a/src/server/api/endpoints/notes/reactions/delete.ts b/src/server/api/endpoints/notes/reactions/delete.ts index 40139afee1..9ff4edb7f5 100644 --- a/src/server/api/endpoints/notes/reactions/delete.ts +++ b/src/server/api/endpoints/notes/reactions/delete.ts @@ -1,9 +1,10 @@ +import * as mongo from 'mongodb'; import $ from 'cafy'; import ID, { transform } from '../../../../../misc/cafy-id'; -import Reaction from '../../../../../models/note-reaction'; -import Note from '../../../../../models/note'; import define from '../../../define'; -import { publishNoteStream } from '../../../../../stream'; const ms = require('ms'); +import deleteReaction from '../../../../../services/note/reaction/delete'; +import { IUser } from '../../../../../models/user'; +import { getValiedNote } from '../../../common/getters'; export const meta = { desc: { @@ -33,44 +34,12 @@ export const meta = { } }; -export default define(meta, (ps, user) => new Promise(async (res, rej) => { - // Fetch unreactee - const note = await Note.findOne({ - _id: ps.noteId - }); - - if (note === null) { - return rej('note not found'); - } - - // if already unreacted - const exist = await Reaction.findOne({ - noteId: note._id, - userId: user._id, - deletedAt: { $exists: false } - }); - - if (exist === null) { - return rej('never reacted'); - } - - // Delete reaction - await Reaction.remove({ - _id: exist._id - }); - - res(); - - const dec: any = {}; - dec[`reactionCounts.${exist.reaction}`] = -1; - - // Decrement reactions count - Note.update({ _id: note._id }, { - $inc: dec - }); - - publishNoteStream(note._id, 'unreacted', { - reaction: exist.reaction, - userId: user._id - }); +export default define(meta, (ps, user) => new Promise((res, rej) => { + deleteReactionById(user, ps.noteId) + .then(r => res(r)).catch(e => rej(e)); })); + +async function deleteReactionById(user: IUser, noteId: mongo.ObjectID) { + const note = await getValiedNote(noteId); + await deleteReaction(user, note); +} diff --git a/src/services/note/reaction/delete.ts b/src/services/note/reaction/delete.ts new file mode 100644 index 0000000000..b108f0ba75 --- /dev/null +++ b/src/services/note/reaction/delete.ts @@ -0,0 +1,49 @@ +import { IUser, isLocalUser, isRemoteUser } from '../../../models/user'; +import Note, { INote } from '../../../models/note'; +import Reaction from '../../../models/note-reaction'; +import { publishNoteStream } from '../../../stream'; +import renderLike from '../../../remote/activitypub/renderer/like'; +import renderUndo from '../../../remote/activitypub/renderer/undo'; +import pack from '../../../remote/activitypub/renderer'; +import { deliver } from '../../../queue'; + +export default async (user: IUser, note: INote) => new Promise(async (res, rej) => { + // if already unreacted + const exist = await Reaction.findOne({ + noteId: note._id, + userId: user._id, + deletedAt: { $exists: false } + }); + + if (exist === null) { + return rej('never reacted'); + } + + // Delete reaction + await Reaction.remove({ + _id: exist._id + }); + + res(); + + const dec: any = {}; + dec[`reactionCounts.${exist.reaction}`] = -1; + + // Decrement reactions count + Note.update({ _id: note._id }, { + $inc: dec + }); + + publishNoteStream(note._id, 'unreacted', { + reaction: exist.reaction, + userId: user._id + }); + + //#region 配信 + // リアクターがローカルユーザーかつリアクション対象がリモートユーザーの投稿なら配送 + if (isLocalUser(user) && isRemoteUser(note._user)) { + const content = pack(renderUndo(renderLike(user, note, exist.reaction), user)); + deliver(user, content, note._user.inbox); + } + //#endregion +});