diff --git a/packages/backend/src/core/activitypub/ApRendererService.ts b/packages/backend/src/core/activitypub/ApRendererService.ts index 42ee5bc58a..e34872c714 100644 --- a/packages/backend/src/core/activitypub/ApRendererService.ts +++ b/packages/backend/src/core/activitypub/ApRendererService.ts @@ -469,6 +469,7 @@ export class ApRendererService { }; } + // if you change this, also change `server/api/endpoints/i/update.ts` @bindThis public async renderPerson(user: MiLocalUser) { const id = this.userEntityService.genLocalUserUri(user.id); diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts index 8994c3fff6..f0e8dfc832 100644 --- a/packages/backend/src/server/api/endpoints/i/update.ts +++ b/packages/backend/src/server/api/endpoints/i/update.ts @@ -539,7 +539,9 @@ export default class extends Endpoint { // eslint- } // フォロワーにUpdateを配信 - this.accountUpdateService.publishToFollowers(user.id); + if (this.userNeedsPublishing(user, updates) || this.profileNeedsPublishing(profile, updatedProfile)) { + this.accountUpdateService.publishToFollowers(user.id); + } const urls = updatedProfile.fields.filter(x => x.value.startsWith('https://')); for (const url of urls) { @@ -581,4 +583,52 @@ export default class extends Endpoint { // eslint- // なにもしない } } + + // these two methods need to be kept in sync with + // `ApRendererService.renderPerson` + private userNeedsPublishing(oldUser: MiLocalUser, newUser: Partial): boolean { + for (const field of ['avatarId', 'bannerId', 'backgroundId', 'isBot', 'username', 'name', 'isLocked', 'isExplorable', 'isCat', 'noindex', 'speakAsCat', 'movedToUri', 'alsoKnownAs'] as (keyof MiUser)[]) { + if (newUser.hasOwnProperty(field) && oldUser[field] !== newUser[field]) { + return true; + } + } + for (const arrayField of ['emojis', 'tags'] as (keyof MiUser)[]) { + if (newUser.hasOwnProperty(arrayField) !== oldUser.hasOwnProperty(arrayField)) { + return true; + } + + const oldArray = oldUser[arrayField] ?? []; + const newArray = newUser[arrayField] ?? []; + if (!Array.isArray(oldArray) || !Array.isArray(newArray)) { + return true; + } + if (oldArray.join("\0") !== newArray.join("\0")) { + return true; + } + } + return false; + } + + private profileNeedsPublishing(oldProfile: MiUserProfile, newProfile: Partial): boolean { + for (const field of ['description', 'followedMessage', 'birthday', 'location', 'listenbrainz'] as (keyof MiUserProfile)[]) { + if (newProfile.hasOwnProperty(field) && oldProfile[field] !== newProfile[field]) { + return true; + } + } + for (const arrayField of ['fields'] as (keyof MiUserProfile)[]) { + if (newProfile.hasOwnProperty(arrayField) !== oldProfile.hasOwnProperty(arrayField)) { + return true; + } + + const oldArray = oldProfile[arrayField] ?? []; + const newArray = newProfile[arrayField] ?? []; + if (!Array.isArray(oldArray) || !Array.isArray(newArray)) { + return true; + } + if (oldArray.join("\0") !== newArray.join("\0")) { + return true; + } + } + return false; + } }