diff --git a/src/remote/activitypub/resolve-person.ts b/src/remote/activitypub/resolve-person.ts index 39887ef77..b3bac3cd3 100644 --- a/src/remote/activitypub/resolve-person.ts +++ b/src/remote/activitypub/resolve-person.ts @@ -6,6 +6,7 @@ import User, { validateUsername, isValidName, isValidDescription } from '../../m import webFinger from '../webfinger'; import Resolver from './resolver'; import uploadFromUrl from '../../services/drive/upload-from-url'; +import { isCollectionOrOrderedCollection } from './type'; export default async (value, verifier?: string) => { const id = value.id || value; @@ -30,7 +31,21 @@ export default async (value, verifier?: string) => { throw new Error('invalid person'); } - const finger = await webFinger(id, verifier); + const [followersCount = 0, followingCount = 0, postsCount = 0, finger] = await Promise.all([ + resolver.resolve(object.followers).then( + resolved => isCollectionOrOrderedCollection(resolved) ? resolved.totalItems : undefined, + () => undefined + ), + resolver.resolve(object.following).then( + resolved => isCollectionOrOrderedCollection(resolved) ? resolved.totalItems : undefined, + () => undefined + ), + resolver.resolve(object.outbox).then( + resolved => isCollectionOrOrderedCollection(resolved) ? resolved.totalItems : undefined, + () => undefined + ), + webFinger(id, verifier) + ]); const host = toUnicode(finger.subject.replace(/^.*?@/, '')); const hostLower = host.replace(/[A-Z]+/, matched => matched.toLowerCase()); @@ -42,10 +57,10 @@ export default async (value, verifier?: string) => { bannerId: null, createdAt: Date.parse(object.published) || null, description: summaryDOM.textContent, - followersCount: 0, - followingCount: 0, + followersCount, + followingCount, + postsCount, name: object.name, - postsCount: 0, driveCapacity: 1024 * 1024 * 8, // 8MiB username: object.preferredUsername, usernameLower: object.preferredUsername.toLowerCase(), @@ -61,18 +76,14 @@ export default async (value, verifier?: string) => { }, }); - const [avatarId, bannerId] = await Promise.all([ + const [avatarId, bannerId] = (await Promise.all([ object.icon, object.image - ].map(async img => { - if (img === undefined) { - return null; - } - - const file = await uploadFromUrl(img.url, user); - - return file._id; - })); + ].map(img => + img == null + ? Promise.resolve(null) + : uploadFromUrl(img.url, user) + ))).map(file => file != null ? file._id : null); User.update({ _id: user._id }, { $set: { avatarId, bannerId } }); diff --git a/src/remote/activitypub/type.ts b/src/remote/activitypub/type.ts index 94e2c350a..cd7f40630 100644 --- a/src/remote/activitypub/type.ts +++ b/src/remote/activitypub/type.ts @@ -1,3 +1,32 @@ -export type IObject = { +export type Object = { [x: string]: any }; + +export type ActivityType = + 'Create'; + +export interface IObject { + '@context': string | object | any[]; type: string; -}; + id?: string; + summary?: string; +} + +export interface ICollection extends IObject { + type: 'Collection'; + totalItems: number; + items: IObject | string | IObject[] | string[]; +} + +export interface IOrderedCollection extends IObject { + type: 'OrderedCollection'; + totalItems: number; + orderedItems: IObject | string | IObject[] | string[]; +} + +export const isCollection = (object: IObject): object is ICollection => + object.type === 'Collection'; + +export const isOrderedCollection = (object: IObject): object is IOrderedCollection => + object.type === 'OrderedCollection'; + +export const isCollectionOrOrderedCollection = (object: IObject): object is ICollection | IOrderedCollection => + isCollection(object) || isOrderedCollection(object);