From 8af13a6502d070023e856a6b901920c291088b7b Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Thu, 25 Jul 2024 16:22:54 +0900 Subject: [PATCH] =?UTF-8?q?enhance(backend):=20=E9=80=A3=E5=90=88=E3=81=99?= =?UTF-8?q?=E3=82=8B=E5=BF=85=E8=A6=81=E3=81=AE=E3=81=AA=E3=81=84=E3=83=97?= =?UTF-8?q?=E3=83=AD=E3=83=95=E3=82=A3=E3=83=BC=E3=83=AB=E9=A0=85=E7=9B=AE?= =?UTF-8?q?=E3=81=97=E3=81=8B=E6=9B=B4=E6=96=B0=E3=81=95=E3=82=8C=E3=81=AA?= =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=9F=E5=A0=B4=E5=90=88=E3=81=AB=E3=81=AF?= =?UTF-8?q?Update=E3=82=A2=E3=82=AF=E3=83=86=E3=82=A3=E3=83=93=E3=83=86?= =?UTF-8?q?=E3=82=A3=E3=82=92=E7=99=BA=E8=A1=8C=E3=81=97=E3=81=AA=E3=81=84?= =?UTF-8?q?=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/core/activitypub/ApRendererService.ts | 9 +++++---- packages/backend/src/misc/prelude/object.ts | 8 ++++++++ packages/backend/src/models/User.ts | 18 ++++++++++++++++++ packages/backend/src/models/UserProfile.ts | 9 +++++++++ .../src/server/api/endpoints/i/update.ts | 12 ++++++++++-- 5 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 packages/backend/src/misc/prelude/object.ts diff --git a/packages/backend/src/core/activitypub/ApRendererService.ts b/packages/backend/src/core/activitypub/ApRendererService.ts index 98e944f347..e0715093df 100644 --- a/packages/backend/src/core/activitypub/ApRendererService.ts +++ b/packages/backend/src/core/activitypub/ApRendererService.ts @@ -9,7 +9,8 @@ import { In } from 'typeorm'; import * as mfm from 'mfm-js'; import { DI } from '@/di-symbols.js'; import type { Config } from '@/config.js'; -import type { MiPartialLocalUser, MiLocalUser, MiPartialRemoteUser, MiRemoteUser, MiUser } from '@/models/User.js'; +import type { MiPartialLocalUser, MiLocalUser, MiPartialRemoteUser, MiRemoteUser, MiUser, MiLocalUserForApPersonRender } from '@/models/User.js'; +import type { MiUserProfileForApPersonRender } from '@/models/UserProfile.js'; import type { IMentionedRemoteUsers, MiNote } from '@/models/Note.js'; import type { MiBlocking } from '@/models/Blocking.js'; import type { MiRelay } from '@/models/Relay.js'; @@ -251,7 +252,7 @@ export class ApRendererService { } @bindThis - public renderKey(user: MiLocalUser, key: MiUserKeypair, postfix?: string): IKey { + public renderKey(user: { id: MiUser['id'] }, key: MiUserKeypair, postfix?: string): IKey { return { id: `${this.config.url}/users/${user.id}${postfix ?? '/publickey'}`, type: 'Key', @@ -449,14 +450,14 @@ export class ApRendererService { } @bindThis - public async renderPerson(user: MiLocalUser) { + public async renderPerson(user: MiLocalUserForApPersonRender) { const id = this.userEntityService.genLocalUserUri(user.id); const isSystem = user.username.includes('.'); const [avatar, banner, profile] = await Promise.all([ user.avatarId ? this.driveFilesRepository.findOneBy({ id: user.avatarId }) : undefined, user.bannerId ? this.driveFilesRepository.findOneBy({ id: user.bannerId }) : undefined, - this.userProfilesRepository.findOneByOrFail({ userId: user.id }), + (this.userProfilesRepository.findOneByOrFail({ userId: user.id }) as Promise), ]); const attachment = profile.fields.map(field => ({ diff --git a/packages/backend/src/misc/prelude/object.ts b/packages/backend/src/misc/prelude/object.ts new file mode 100644 index 0000000000..daa18ce1da --- /dev/null +++ b/packages/backend/src/misc/prelude/object.ts @@ -0,0 +1,8 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export function keys(obj: T): (keyof T)[] { + return Object.keys(obj); +} diff --git a/packages/backend/src/models/User.ts b/packages/backend/src/models/User.ts index 9e2d7a3444..758a2e4b91 100644 --- a/packages/backend/src/models/User.ts +++ b/packages/backend/src/models/User.ts @@ -285,6 +285,24 @@ export type MiPartialRemoteUser = Partial & { uri: string; } +export const miLocalUserKeysUsedForApPersonRender = [ + 'id', + 'username', + 'avatarId', + 'bannerId', + 'emojis', + 'tags', + 'isBot', + 'isCat', + 'name', + 'isLocked', + 'isExplorable', + 'movedToUri', + 'alsoKnownAs', +] as const satisfies (keyof MiLocalUser)[]; + +export type MiLocalUserForApPersonRender = Pick; + export const localUsernameSchema = { type: 'string', pattern: /^\w{1,20}$/.toString().slice(1, -1) } as const; export const passwordSchema = { type: 'string', minLength: 1 } as const; export const nameSchema = { type: 'string', minLength: 1, maxLength: 50 } as const; diff --git a/packages/backend/src/models/UserProfile.ts b/packages/backend/src/models/UserProfile.ts index 7dbe0b3717..cf955f6e79 100644 --- a/packages/backend/src/models/UserProfile.ts +++ b/packages/backend/src/models/UserProfile.ts @@ -287,3 +287,12 @@ export class MiUserProfile { } } } + +export const miUserProfileKeysUsedForApPersonRender = [ + 'fields', + 'description', + 'birthday', + 'location', +] as const satisfies (keyof MiUserProfile)[]; + +export type MiUserProfileForApPersonRender = Pick; diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts index a1e2fa5e4c..9111175e47 100644 --- a/packages/backend/src/server/api/endpoints/i/update.ts +++ b/packages/backend/src/server/api/endpoints/i/update.ts @@ -11,6 +11,7 @@ import { JSDOM } from 'jsdom'; import { extractCustomEmojisFromMfm } from '@/misc/extract-custom-emojis-from-mfm.js'; import { extractHashtags } from '@/misc/extract-hashtags.js'; import * as Acct from '@/misc/acct.js'; +import { keys } from '@/misc/prelude/object.js'; import type { UsersRepository, DriveFilesRepository, UserProfilesRepository, PagesRepository } from '@/models/_.js'; import type { MiLocalUser, MiUser } from '@/models/User.js'; import { birthdaySchema, descriptionSchema, locationSchema, nameSchema } from '@/models/User.js'; @@ -34,6 +35,8 @@ import type { Config } from '@/config.js'; import { safeForSql } from '@/misc/safe-for-sql.js'; import { AvatarDecorationService } from '@/core/AvatarDecorationService.js'; import { notificationRecieveConfig } from '@/models/json-schema/user.js'; +import { miLocalUserKeysUsedForApPersonRender } from '@/models/User.js'; +import { miUserProfileKeysUsedForApPersonRender } from '@/models/UserProfile.js'; import { ApiLoggerService } from '../../ApiLoggerService.js'; import { ApiError } from '../../error.js'; @@ -501,8 +504,13 @@ export default class extends Endpoint { // eslint- this.userFollowingService.acceptAllFollowRequests(user); } - // フォロワーにUpdateを配信 - this.accountUpdateService.publishToFollowers(user.id); + // 連合する必要があるプロパティが変更されている場合はフォロワーにUpdateを配信 + if ( + miLocalUserKeysUsedForApPersonRender.some(k => keys(updates).includes(k)) || + miUserProfileKeysUsedForApPersonRender.some(k => keys(profileUpdates).includes(k)) + ) { + this.accountUpdateService.publishToFollowers(user.id); + } const urls = updatedProfile.fields.filter(x => x.value.startsWith('https://')); for (const url of urls) {