リモート投稿にリモートでされたリアクションが表示されるように (#5817)
* 第3インスタンスへのLikeも受け入れるように * リアクション済みだったらエラーにせずに置き換えるように * Likeを第3インスタンスにdeliverするように * fix * fix * 同じリアクションがすでにされていたら何もしない * リモートから自身の投稿へリアクションした場合にエラーにならないように
This commit is contained in:
parent
f640da911b
commit
b7a4f286b0
|
@ -1,23 +1,16 @@
|
||||||
import { IRemoteUser } from '../../../models/entities/user';
|
import { IRemoteUser } from '../../../models/entities/user';
|
||||||
import { ILike } from '../type';
|
import { ILike, getApId } from '../type';
|
||||||
import create from '../../../services/note/reaction/create';
|
import create from '../../../services/note/reaction/create';
|
||||||
import { Notes } from '../../../models';
|
import { fetchNote } from '../models/note';
|
||||||
import { apLogger } from '../logger';
|
|
||||||
|
|
||||||
export default async (actor: IRemoteUser, activity: ILike) => {
|
export default async (actor: IRemoteUser, activity: ILike) => {
|
||||||
const id = typeof activity.object == 'string' ? activity.object : activity.object.id;
|
const targetUri = getApId(activity.object);
|
||||||
if (id == null) throw new Error('missing id');
|
|
||||||
|
|
||||||
// Transform:
|
const note = await fetchNote(targetUri);
|
||||||
// https://misskey.ex/notes/xxxx to
|
if (!note) return `skip: target note not found ${targetUri}`;
|
||||||
// xxxx
|
|
||||||
const noteId = id.split('/').pop();
|
|
||||||
|
|
||||||
const note = await Notes.findOne(noteId);
|
if (actor.id === note.userId) return `skip: cannot react to my note`;
|
||||||
if (note == null) {
|
|
||||||
apLogger.warn(`Like activity recivied, but no such note: ${id}`, { id });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await create(actor, note, activity._misskey_reaction || activity.content || activity.name);
|
await create(actor, note, activity._misskey_reaction || activity.content || activity.name);
|
||||||
|
return `ok`;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,21 +1,17 @@
|
||||||
import { IRemoteUser } from '../../../../models/entities/user';
|
import { IRemoteUser } from '../../../../models/entities/user';
|
||||||
import { ILike } from '../../type';
|
import { ILike, getApId } from '../../type';
|
||||||
import deleteReaction from '../../../../services/note/reaction/delete';
|
import deleteReaction from '../../../../services/note/reaction/delete';
|
||||||
import { Notes } from '../../../../models';
|
import { fetchNote } from '../../models/note';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process Undo.Like activity
|
* Process Undo.Like activity
|
||||||
*/
|
*/
|
||||||
export default async (actor: IRemoteUser, activity: ILike): Promise<void> => {
|
export default async (actor: IRemoteUser, activity: ILike) => {
|
||||||
const id = typeof activity.object == 'string' ? activity.object : activity.object.id;
|
const targetUri = getApId(activity.object);
|
||||||
if (id == null) throw new Error('missing id');
|
|
||||||
|
|
||||||
const noteId = id.split('/').pop();
|
const note = await fetchNote(targetUri);
|
||||||
|
if (!note) return `skip: target note not found ${targetUri}`;
|
||||||
const note = await Notes.findOne(noteId);
|
|
||||||
if (note == null) {
|
|
||||||
throw new Error('note not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
await deleteReaction(actor, note);
|
await deleteReaction(actor, note);
|
||||||
|
return `ok`;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,19 +1,18 @@
|
||||||
import { publishNoteStream } from '../../stream';
|
import { publishNoteStream } from '../../stream';
|
||||||
import watch from '../watch';
|
import watch from '../watch';
|
||||||
import renderLike from '../../../remote/activitypub/renderer/like';
|
import renderLike from '../../../remote/activitypub/renderer/like';
|
||||||
import { deliver } from '../../../queue';
|
import DeliverManager from '../../../remote/activitypub/deliver-manager';
|
||||||
import { renderActivity } from '../../../remote/activitypub/renderer';
|
import { renderActivity } from '../../../remote/activitypub/renderer';
|
||||||
import { IdentifiableError } from '../../../misc/identifiable-error';
|
import { IdentifiableError } from '../../../misc/identifiable-error';
|
||||||
import { toDbReaction } from '../../../misc/reaction-lib';
|
import { toDbReaction } from '../../../misc/reaction-lib';
|
||||||
import { User } from '../../../models/entities/user';
|
import { User, IRemoteUser } from '../../../models/entities/user';
|
||||||
import { Note } from '../../../models/entities/note';
|
import { Note } from '../../../models/entities/note';
|
||||||
import { NoteReactions, Users, NoteWatchings, Notes, UserProfiles } from '../../../models';
|
import { NoteReactions, Users, NoteWatchings, Notes, UserProfiles } from '../../../models';
|
||||||
import { Not } from 'typeorm';
|
import { Not } from 'typeorm';
|
||||||
import { perUserReactionsChart } from '../../chart';
|
import { perUserReactionsChart } from '../../chart';
|
||||||
import { genId } from '../../../misc/gen-id';
|
import { genId } from '../../../misc/gen-id';
|
||||||
import { NoteReaction } from '../../../models/entities/note-reaction';
|
|
||||||
import { createNotification } from '../../create-notification';
|
import { createNotification } from '../../create-notification';
|
||||||
import { isDuplicateKeyValueError } from '../../../misc/is-duplicate-key-value-error';
|
import deleteReaction from './delete';
|
||||||
|
|
||||||
export default async (user: User, note: Note, reaction?: string) => {
|
export default async (user: User, note: Note, reaction?: string) => {
|
||||||
// Myself
|
// Myself
|
||||||
|
@ -23,6 +22,21 @@ export default async (user: User, note: Note, reaction?: string) => {
|
||||||
|
|
||||||
reaction = await toDbReaction(reaction);
|
reaction = await toDbReaction(reaction);
|
||||||
|
|
||||||
|
const exist = await NoteReactions.findOne({
|
||||||
|
noteId: note.id,
|
||||||
|
userId: user.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (exist) {
|
||||||
|
if (exist.reaction !== reaction) {
|
||||||
|
// 別のリアクションがすでにされていたら置き換える
|
||||||
|
await deleteReaction(user, note);
|
||||||
|
} else {
|
||||||
|
// 同じリアクションがすでにされていたら何もしない
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create reaction
|
// Create reaction
|
||||||
await NoteReactions.save({
|
await NoteReactions.save({
|
||||||
id: genId(),
|
id: genId(),
|
||||||
|
@ -30,13 +44,6 @@ export default async (user: User, note: Note, reaction?: string) => {
|
||||||
noteId: note.id,
|
noteId: note.id,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
reaction
|
reaction
|
||||||
} as NoteReaction).catch(e => {
|
|
||||||
// duplicate key error
|
|
||||||
if (isDuplicateKeyValueError(e)) {
|
|
||||||
throw new IdentifiableError('51c42bb4-931a-456b-bff7-e5a8a70dd298', 'already reacted');
|
|
||||||
}
|
|
||||||
|
|
||||||
throw e;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Increment reactions count
|
// Increment reactions count
|
||||||
|
@ -86,12 +93,15 @@ export default async (user: User, note: Note, reaction?: string) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
//#region 配信
|
//#region 配信
|
||||||
// リアクターがローカルユーザーかつリアクション対象がリモートユーザーの投稿なら配送
|
if (Users.isLocalUser(user) && !note.localOnly) {
|
||||||
if (Users.isLocalUser(user) && note.userHost !== null) {
|
|
||||||
const content = renderActivity(renderLike(user, note, reaction));
|
const content = renderActivity(renderLike(user, note, reaction));
|
||||||
Users.findOne(note.userId).then(u => {
|
const dm = new DeliverManager(user, content);
|
||||||
deliver(user, content, u!.inbox);
|
if (note.userHost !== null) {
|
||||||
});
|
const reactee = await Users.findOne(note.userId)
|
||||||
|
dm.addDirectRecipe(reactee as IRemoteUser);
|
||||||
|
}
|
||||||
|
dm.addFollowersRecipe();
|
||||||
|
dm.execute();
|
||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,9 +2,9 @@ import { publishNoteStream } from '../../stream';
|
||||||
import renderLike from '../../../remote/activitypub/renderer/like';
|
import renderLike from '../../../remote/activitypub/renderer/like';
|
||||||
import renderUndo from '../../../remote/activitypub/renderer/undo';
|
import renderUndo from '../../../remote/activitypub/renderer/undo';
|
||||||
import { renderActivity } from '../../../remote/activitypub/renderer';
|
import { renderActivity } from '../../../remote/activitypub/renderer';
|
||||||
import { deliver } from '../../../queue';
|
import DeliverManager from '../../../remote/activitypub/deliver-manager';
|
||||||
import { IdentifiableError } from '../../../misc/identifiable-error';
|
import { IdentifiableError } from '../../../misc/identifiable-error';
|
||||||
import { User } from '../../../models/entities/user';
|
import { User, IRemoteUser } from '../../../models/entities/user';
|
||||||
import { Note } from '../../../models/entities/note';
|
import { Note } from '../../../models/entities/note';
|
||||||
import { NoteReactions, Users, Notes } from '../../../models';
|
import { NoteReactions, Users, Notes } from '../../../models';
|
||||||
|
|
||||||
|
@ -39,12 +39,15 @@ export default async (user: User, note: Note) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
//#region 配信
|
//#region 配信
|
||||||
// リアクターがローカルユーザーかつリアクション対象がリモートユーザーの投稿なら配送
|
if (Users.isLocalUser(user) && !note.localOnly) {
|
||||||
if (Users.isLocalUser(user) && (note.userHost !== null)) {
|
|
||||||
const content = renderActivity(renderUndo(renderLike(user, note, exist.reaction), user));
|
const content = renderActivity(renderUndo(renderLike(user, note, exist.reaction), user));
|
||||||
Users.findOne(note.userId).then(u => {
|
const dm = new DeliverManager(user, content);
|
||||||
deliver(user, content, u!.inbox);
|
if (note.userHost !== null) {
|
||||||
});
|
const reactee = await Users.findOne(note.userId)
|
||||||
|
dm.addDirectRecipe(reactee as IRemoteUser);
|
||||||
|
}
|
||||||
|
dm.addFollowersRecipe();
|
||||||
|
dm.execute();
|
||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue