From 3e85aad80a882abc764c13a0fc40e3333bb61c4b Mon Sep 17 00:00:00 2001 From: MeiMei <30769358+mei23@users.noreply.github.com> Date: Sun, 15 Dec 2019 03:37:19 +0900 Subject: Implement Talk has read federation (#5636) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Talk read * fix * 複数のRead ActivityはCollectionとして送るように * あ --- src/remote/activitypub/kernel/index.ts | 5 +++- src/remote/activitypub/kernel/read.ts | 27 ++++++++++++++++++++++ src/remote/activitypub/models/note.ts | 2 +- .../activitypub/renderer/ordered-collection.ts | 2 +- src/remote/activitypub/renderer/read.ts | 9 ++++++++ src/remote/activitypub/type.ts | 5 ++++ 6 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 src/remote/activitypub/kernel/read.ts create mode 100644 src/remote/activitypub/renderer/read.ts (limited to 'src/remote/activitypub') diff --git a/src/remote/activitypub/kernel/index.ts b/src/remote/activitypub/kernel/index.ts index c8298dc797..615edff88c 100644 --- a/src/remote/activitypub/kernel/index.ts +++ b/src/remote/activitypub/kernel/index.ts @@ -1,8 +1,9 @@ -import { IObject, isCreate, isDelete, isUpdate, isFollow, isAccept, isReject, isAdd, isRemove, isAnnounce, isLike, isUndo, isBlock, isCollectionOrOrderedCollection, isCollection } from '../type'; +import { IObject, isCreate, isDelete, isUpdate, isRead, isFollow, isAccept, isReject, isAdd, isRemove, isAnnounce, isLike, isUndo, isBlock, isCollectionOrOrderedCollection, isCollection } from '../type'; import { IRemoteUser } from '../../../models/entities/user'; import create from './create'; import performDeleteActivity from './delete'; import performUpdateActivity from './update'; +import { performReadActivity } from './read'; import follow from './follow'; import undo from './undo'; import like from './like'; @@ -41,6 +42,8 @@ async function performOneActivity(actor: IRemoteUser, activity: IObject): Promis await performDeleteActivity(actor, activity); } else if (isUpdate(activity)) { await performUpdateActivity(actor, activity); + } else if (isRead(activity)) { + await performReadActivity(actor, activity); } else if (isFollow(activity)) { await follow(actor, activity); } else if (isAccept(activity)) { diff --git a/src/remote/activitypub/kernel/read.ts b/src/remote/activitypub/kernel/read.ts new file mode 100644 index 0000000000..e4049fa7ef --- /dev/null +++ b/src/remote/activitypub/kernel/read.ts @@ -0,0 +1,27 @@ +import { IRemoteUser } from '../../../models/entities/user'; +import { IRead, getApId } from '../type'; +import { isSelfHost, extractDbHost } from '../../../misc/convert-host'; +import { MessagingMessages } from '../../../models'; +import { readUserMessagingMessage } from '../../../server/api/common/read-messaging-message'; + +export const performReadActivity = async (actor: IRemoteUser, activity: IRead): Promise => { + const id = await getApId(activity.object); + + if (!isSelfHost(extractDbHost(id))) { + return `skip: Read to foreign host (${id})`; + } + + const messageId = id.split('/').pop(); + + const message = await MessagingMessages.findOne(messageId); + if (message == null) { + return `skip: message not found`; + } + + if (actor.id != message.recipientId) { + return `skip: actor is not a message recipient`; + } + + await readUserMessagingMessage(message.recipientId!, message.userId, [message.id]); + return `ok: mark as read (${message.userId} => ${message.recipientId} ${message.id})`; +}; diff --git a/src/remote/activitypub/models/note.ts b/src/remote/activitypub/models/note.ts index 17c3721bdb..7ce0b6a11f 100644 --- a/src/remote/activitypub/models/note.ts +++ b/src/remote/activitypub/models/note.ts @@ -226,7 +226,7 @@ export async function createNote(value: string | IObject, resolver?: Resolver, s if (note._misskey_talk && visibility === 'specified') { for (const recipient of visibleUsers) { - await createMessage(actor, recipient, undefined, text || undefined, (files && files.length > 0) ? files[0] : null); + await createMessage(actor, recipient, undefined, text || undefined, (files && files.length > 0) ? files[0] : null, object.id); return null; } } diff --git a/src/remote/activitypub/renderer/ordered-collection.ts b/src/remote/activitypub/renderer/ordered-collection.ts index 5461005983..68870a0ecd 100644 --- a/src/remote/activitypub/renderer/ordered-collection.ts +++ b/src/remote/activitypub/renderer/ordered-collection.ts @@ -6,7 +6,7 @@ * @param last URL of last page (optional) * @param orderedItems attached objects (optional) */ -export default function(id: string, totalItems: any, first?: string, last?: string, orderedItems?: object) { +export default function(id: string | null, totalItems: any, first?: string, last?: string, orderedItems?: object) { const page: any = { id, type: 'OrderedCollection', diff --git a/src/remote/activitypub/renderer/read.ts b/src/remote/activitypub/renderer/read.ts new file mode 100644 index 0000000000..c53b47859f --- /dev/null +++ b/src/remote/activitypub/renderer/read.ts @@ -0,0 +1,9 @@ +import config from '../../../config'; +import { ILocalUser } from '../../../models/entities/user'; +import { MessagingMessage } from '../../../models/entities/messaging-message'; + +export const renderReadActivity = (user: ILocalUser, message: MessagingMessage) => ({ + type: 'Read', + actor: `${config.url}/users/${user.id}`, + object: message.uri +}); diff --git a/src/remote/activitypub/type.ts b/src/remote/activitypub/type.ts index 5670df243d..ad3f9638a7 100644 --- a/src/remote/activitypub/type.ts +++ b/src/remote/activitypub/type.ts @@ -140,6 +140,10 @@ export interface IUpdate extends IActivity { type: 'Update'; } +export interface IRead extends IActivity { + type: 'Read'; +} + export interface IUndo extends IActivity { type: 'Undo'; } @@ -180,6 +184,7 @@ export interface IBlock extends IActivity { export const isCreate = (object: IObject): object is ICreate => object.type === 'Create'; export const isDelete = (object: IObject): object is IDelete => object.type === 'Delete'; export const isUpdate = (object: IObject): object is IUpdate => object.type === 'Update'; +export const isRead = (object: IObject): object is IRead => object.type === 'Read'; export const isUndo = (object: IObject): object is IUndo => object.type === 'Undo'; export const isFollow = (object: IObject): object is IFollow => object.type === 'Follow'; export const isAccept = (object: IObject): object is IAccept => object.type === 'Accept'; -- cgit v1.2.3-freya