diff --git a/src/remote/activitypub/objects/note.ts b/src/remote/activitypub/objects/note.ts index 3edcb8c63f..221d502f06 100644 --- a/src/remote/activitypub/objects/note.ts +++ b/src/remote/activitypub/objects/note.ts @@ -6,7 +6,7 @@ import Resolver from '../resolver'; import Note, { INote } from '../../../models/note'; import post from '../../../services/note/create'; import { INote as INoteActivityStreamsObject, IObject } from '../type'; -import { resolvePerson } from './person'; +import { resolvePerson, updatePerson } from './person'; import { resolveImage } from './image'; import { IRemoteUser } from '../../../models/user'; @@ -75,6 +75,11 @@ export async function createNote(value: any, resolver?: Resolver, silent = false const { window } = new JSDOM(note.content); + // ユーザーの情報が古かったらついでに更新しておく + if (actor.updatedAt && Date.now() - actor.updatedAt.getTime() > 1000 * 60 * 60 * 24) { + updatePerson(note.attributedTo); + } + return await post(actor, { createdAt: new Date(note.published), media, diff --git a/src/remote/activitypub/objects/person.ts b/src/remote/activitypub/objects/person.ts index b0539fd73b..b755b2603a 100644 --- a/src/remote/activitypub/objects/person.ts +++ b/src/remote/activitypub/objects/person.ts @@ -119,6 +119,86 @@ export async function createPerson(value: any, resolver?: Resolver): Promise { + const uri = typeof value == 'string' ? value : value.id; + + // URIがこのサーバーを指しているならスキップ + if (uri.startsWith(config.url + '/')) { + return; + } + + //#region このサーバーに既に登録されているか + const exist = await User.findOne({ uri }) as IRemoteUser; + + if (exist == null) { + return; + } + //#endregion + + if (resolver == null) resolver = new Resolver(); + + const object = await resolver.resolve(value) as any; + + if ( + object == null || + object.type !== 'Person' + ) { + log(`invalid person: ${JSON.stringify(object, null, 2)}`); + throw new Error('invalid person'); + } + + const person: IPerson = object; + + log(`Updating the Person: ${person.id}`); + + const [followersCount = 0, followingCount = 0, notesCount = 0] = await Promise.all([ + resolver.resolve(person.followers).then( + resolved => isCollectionOrOrderedCollection(resolved) ? resolved.totalItems : undefined, + () => undefined + ), + resolver.resolve(person.following).then( + resolved => isCollectionOrOrderedCollection(resolved) ? resolved.totalItems : undefined, + () => undefined + ), + resolver.resolve(person.outbox).then( + resolved => isCollectionOrOrderedCollection(resolved) ? resolved.totalItems : undefined, + () => undefined + ) + ]); + + const summaryDOM = JSDOM.fragment(person.summary); + + // アイコンとヘッダー画像をフェッチ + const [avatarId, bannerId] = (await Promise.all([ + person.icon, + person.image + ].map(img => + img == null + ? Promise.resolve(null) + : resolveImage(exist, img) + ))).map(file => file != null ? file._id : null); + + // Update user + await User.update({ _id: exist._id }, { + $set: { + updatedAt: new Date(), + avatarId, + bannerId, + description: summaryDOM.textContent, + followersCount, + followingCount, + notesCount, + name: person.name, + url: person.url + } + }); +} + /** * Personを解決します。 *