From 42b51e31fd75438e93c3f939e1b07eedc1bc51e6 Mon Sep 17 00:00:00 2001 From: Hazelnoot Date: Sun, 14 Sep 2025 20:53:31 -0400 Subject: [PATCH] return movedAt, movedTo, and alsoKnownAs from admin/show-user endpoint --- .../server/api/endpoints/admin/show-user.ts | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/packages/backend/src/server/api/endpoints/admin/show-user.ts b/packages/backend/src/server/api/endpoints/admin/show-user.ts index 6f0081f1f7..49ce0f8bd4 100644 --- a/packages/backend/src/server/api/endpoints/admin/show-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/show-user.ts @@ -13,6 +13,8 @@ import { IdService } from '@/core/IdService.js'; import { notificationRecieveConfig } from '@/models/json-schema/user.js'; import { isSystemAccount } from '@/misc/is-system-account.js'; import { CacheService } from '@/core/CacheService.js'; +import { UserEntityService } from '@/core/entities/UserEntityService.js'; +import { ApPersonService } from '@/core/activitypub/models/ApPersonService.js'; export const meta = { tags: ['admin'], @@ -225,6 +227,46 @@ export const meta = { type: 'string', optional: false, nullable: true, }, + movedAt: { + type: 'string', + optional: true, nullable: true, + }, + movedTo: { + type: 'object', + optional: true, nullable: true, + properties: { + uri: { + type: 'string', + format: 'uri', + nullable: false, optional: false, + }, + user: { + type: 'object', + ref: 'UserDetailed', + nullable: true, optional: true, + }, + }, + }, + alsoKnownAs: { + type: 'array', + nullable: true, optional: true, + items: { + type: 'object', + nullable: false, optional: false, + properties: { + uri: { + type: 'string', + format: 'uri', + nullable: false, optional: false, + }, + user: { + type: 'object', + ref: 'UserDetailed', + nullable: true, optional: true, + }, + }, + }, + }, }, }, } as const; @@ -253,6 +295,8 @@ export default class extends Endpoint { // eslint- private roleEntityService: RoleEntityService, private idService: IdService, private readonly cacheService: CacheService, + private readonly apPersonService: ApPersonService, + private readonly userEntityService: UserEntityService, ) { super(meta, paramDef, async (ps, me) => { const [user, profile] = await Promise.all([ @@ -280,6 +324,22 @@ export default class extends Endpoint { // eslint- const followStats = await this.cacheService.getFollowStats(user.id); + const movedAt = user.movedAt?.toISOString(); + + const movedToUser = user.movedToUri ? await this.apPersonService.resolvePerson(user.movedToUri) : null; + const movedTo = user.movedToUri ? { + uri: user.movedToUri, + user: movedToUser ? await this.userEntityService.pack(movedToUser, me, { schema: 'UserDetailed' }) : undefined, + } : null; + + // This is kinda heavy, but it's an admin endpoint so ok. + const aka = await this.userEntityService.resolveAlsoKnownAs(user); + const akaUsers = aka ? await this.userEntityService.packMany(aka.map(aka => aka.id).filter(id => id != null), me, { schema: 'UserDetailed' }) : []; + const alsoKnownAs = aka?.map(aka => ({ + uri: aka.uri, + user: aka.id ? akaUsers.find(u => u.id === aka.id) : undefined, + })); + return { email: profile.email, emailVerified: profile.emailVerified, @@ -318,6 +378,9 @@ export default class extends Endpoint { // eslint- totalFollowers: Math.max(user.followersCount, followStats.localFollowers + followStats.remoteFollowers), totalFollowing: Math.max(user.followingCount, followStats.localFollowing + followStats.remoteFollowing), }, + movedAt, + movedTo, + alsoKnownAs, }; }); }