enhance(backend): 連合する必要のないプロフィール項目しか更新されなかった場合にはUpdateアクティビティを発行しないように
This commit is contained in:
parent
32651aba67
commit
8af13a6502
|
@ -9,7 +9,8 @@ import { In } from 'typeorm';
|
||||||
import * as mfm from 'mfm-js';
|
import * as mfm from 'mfm-js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { Config } from '@/config.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 { IMentionedRemoteUsers, MiNote } from '@/models/Note.js';
|
||||||
import type { MiBlocking } from '@/models/Blocking.js';
|
import type { MiBlocking } from '@/models/Blocking.js';
|
||||||
import type { MiRelay } from '@/models/Relay.js';
|
import type { MiRelay } from '@/models/Relay.js';
|
||||||
|
@ -251,7 +252,7 @@ export class ApRendererService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public renderKey(user: MiLocalUser, key: MiUserKeypair, postfix?: string): IKey {
|
public renderKey(user: { id: MiUser['id'] }, key: MiUserKeypair, postfix?: string): IKey {
|
||||||
return {
|
return {
|
||||||
id: `${this.config.url}/users/${user.id}${postfix ?? '/publickey'}`,
|
id: `${this.config.url}/users/${user.id}${postfix ?? '/publickey'}`,
|
||||||
type: 'Key',
|
type: 'Key',
|
||||||
|
@ -449,14 +450,14 @@ export class ApRendererService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async renderPerson(user: MiLocalUser) {
|
public async renderPerson(user: MiLocalUserForApPersonRender) {
|
||||||
const id = this.userEntityService.genLocalUserUri(user.id);
|
const id = this.userEntityService.genLocalUserUri(user.id);
|
||||||
const isSystem = user.username.includes('.');
|
const isSystem = user.username.includes('.');
|
||||||
|
|
||||||
const [avatar, banner, profile] = await Promise.all([
|
const [avatar, banner, profile] = await Promise.all([
|
||||||
user.avatarId ? this.driveFilesRepository.findOneBy({ id: user.avatarId }) : undefined,
|
user.avatarId ? this.driveFilesRepository.findOneBy({ id: user.avatarId }) : undefined,
|
||||||
user.bannerId ? this.driveFilesRepository.findOneBy({ id: user.bannerId }) : undefined,
|
user.bannerId ? this.driveFilesRepository.findOneBy({ id: user.bannerId }) : undefined,
|
||||||
this.userProfilesRepository.findOneByOrFail({ userId: user.id }),
|
(this.userProfilesRepository.findOneByOrFail({ userId: user.id }) as Promise<MiUserProfileForApPersonRender>),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const attachment = profile.fields.map(field => ({
|
const attachment = profile.fields.map(field => ({
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function keys<T extends { [x: string]: unknown }>(obj: T): (keyof T)[] {
|
||||||
|
return Object.keys(obj);
|
||||||
|
}
|
|
@ -285,6 +285,24 @@ export type MiPartialRemoteUser = Partial<MiUser> & {
|
||||||
uri: string;
|
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<MiLocalUser, typeof miLocalUserKeysUsedForApPersonRender[number]>;
|
||||||
|
|
||||||
export const localUsernameSchema = { type: 'string', pattern: /^\w{1,20}$/.toString().slice(1, -1) } as const;
|
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 passwordSchema = { type: 'string', minLength: 1 } as const;
|
||||||
export const nameSchema = { type: 'string', minLength: 1, maxLength: 50 } as const;
|
export const nameSchema = { type: 'string', minLength: 1, maxLength: 50 } as const;
|
||||||
|
|
|
@ -287,3 +287,12 @@ export class MiUserProfile {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const miUserProfileKeysUsedForApPersonRender = [
|
||||||
|
'fields',
|
||||||
|
'description',
|
||||||
|
'birthday',
|
||||||
|
'location',
|
||||||
|
] as const satisfies (keyof MiUserProfile)[];
|
||||||
|
|
||||||
|
export type MiUserProfileForApPersonRender = Pick<MiUserProfile, typeof miUserProfileKeysUsedForApPersonRender[number]>;
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { JSDOM } from 'jsdom';
|
||||||
import { extractCustomEmojisFromMfm } from '@/misc/extract-custom-emojis-from-mfm.js';
|
import { extractCustomEmojisFromMfm } from '@/misc/extract-custom-emojis-from-mfm.js';
|
||||||
import { extractHashtags } from '@/misc/extract-hashtags.js';
|
import { extractHashtags } from '@/misc/extract-hashtags.js';
|
||||||
import * as Acct from '@/misc/acct.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 { UsersRepository, DriveFilesRepository, UserProfilesRepository, PagesRepository } from '@/models/_.js';
|
||||||
import type { MiLocalUser, MiUser } from '@/models/User.js';
|
import type { MiLocalUser, MiUser } from '@/models/User.js';
|
||||||
import { birthdaySchema, descriptionSchema, locationSchema, nameSchema } 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 { safeForSql } from '@/misc/safe-for-sql.js';
|
||||||
import { AvatarDecorationService } from '@/core/AvatarDecorationService.js';
|
import { AvatarDecorationService } from '@/core/AvatarDecorationService.js';
|
||||||
import { notificationRecieveConfig } from '@/models/json-schema/user.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 { ApiLoggerService } from '../../ApiLoggerService.js';
|
||||||
import { ApiError } from '../../error.js';
|
import { ApiError } from '../../error.js';
|
||||||
|
|
||||||
|
@ -501,8 +504,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
this.userFollowingService.acceptAllFollowRequests(user);
|
this.userFollowingService.acceptAllFollowRequests(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
// フォロワーにUpdateを配信
|
// 連合する必要があるプロパティが変更されている場合はフォロワーにUpdateを配信
|
||||||
|
if (
|
||||||
|
miLocalUserKeysUsedForApPersonRender.some(k => keys(updates).includes(k)) ||
|
||||||
|
miUserProfileKeysUsedForApPersonRender.some(k => keys(profileUpdates).includes(k))
|
||||||
|
) {
|
||||||
this.accountUpdateService.publishToFollowers(user.id);
|
this.accountUpdateService.publishToFollowers(user.id);
|
||||||
|
}
|
||||||
|
|
||||||
const urls = updatedProfile.fields.filter(x => x.value.startsWith('https://'));
|
const urls = updatedProfile.fields.filter(x => x.value.startsWith('https://'));
|
||||||
for (const url of urls) {
|
for (const url of urls) {
|
||||||
|
|
Loading…
Reference in New Issue