From 71f60d519b6f8e655737136484658ea0f1d00507 Mon Sep 17 00:00:00 2001 From: Hazelnoot Date: Wed, 28 May 2025 01:33:55 -0400 Subject: add targetInstance to abuse report schema --- packages/backend/src/models/AbuseUserReport.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'packages/backend/src/models') diff --git a/packages/backend/src/models/AbuseUserReport.ts b/packages/backend/src/models/AbuseUserReport.ts index d43ebf9342..8f8d759004 100644 --- a/packages/backend/src/models/AbuseUserReport.ts +++ b/packages/backend/src/models/AbuseUserReport.ts @@ -4,6 +4,7 @@ */ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; +import { MiInstance } from '@/models/Instance.js'; import { id } from './util/id.js'; import { MiUser } from './User.js'; @@ -88,11 +89,31 @@ export class MiAbuseUserReport { }) public targetUserHost: string | null; + @ManyToOne(() => MiInstance, { + // TODO create a foreign key constraint after hazelnoot/labs/persisted-instance-blocks is merged + createForeignKeyConstraints: false, + }) + @JoinColumn({ + name: 'targetUserHost', + referencedColumnName: 'host', + }) + public targetUserInstance: MiInstance | null; + @Index() @Column('varchar', { length: 128, nullable: true, comment: '[Denormalized]', }) public reporterHost: string | null; + + @ManyToOne(() => MiInstance, { + // TODO create a foreign key constraint after hazelnoot/labs/persisted-instance-blocks is merged + createForeignKeyConstraints: false, + }) + @JoinColumn({ + name: 'reporterHost', + referencedColumnName: 'host', + }) + public reporterInstance: MiInstance | null; //#endregion } -- cgit v1.2.3-freya From 23302fe7d8de4923f4748f6c64d39e3f57c9d98f Mon Sep 17 00:00:00 2001 From: Hazelnoot Date: Wed, 28 May 2025 02:02:27 -0400 Subject: add relation from user->user_profile to speed up UserEntityService.pack and packMany --- .../backend/src/core/entities/UserEntityService.ts | 34 +++++++++++++++++----- packages/backend/src/models/User.ts | 4 +++ packages/backend/src/models/UserProfile.ts | 2 +- 3 files changed, 32 insertions(+), 8 deletions(-) (limited to 'packages/backend/src/models') diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index 3524119ba1..326baaefd4 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -487,7 +487,10 @@ export class UserEntityService implements OnModuleInit { includeSecrets: false, }, options); - const user = typeof src === 'object' ? src : await this.usersRepository.findOneByOrFail({ id: src }); + const user = typeof src === 'object' ? src : await this.usersRepository.findOneOrFail({ + where: { id: src }, + relations: { userProfile: true }, + }); // migration if (user.avatarId != null && user.avatarUrl === null) { @@ -521,7 +524,7 @@ export class UserEntityService implements OnModuleInit { const iAmModerator = me ? await this.roleService.isModerator(me as MiUser) : false; const profile = isDetailed - ? (opts.userProfile ?? await this.userProfilesRepository.findOneByOrFail({ userId: user.id })) + ? (opts.userProfile ?? user.userProfile ?? await this.userProfilesRepository.findOneByOrFail({ userId: user.id })) : null; let relation: UserRelation | null = null; @@ -556,7 +559,7 @@ export class UserEntityService implements OnModuleInit { } } - const mastoapi = !isDetailed ? opts.userProfile ?? await this.userProfilesRepository.findOneByOrFail({ userId: user.id }) : null; + const mastoapi = !isDetailed ? opts.userProfile ?? user.userProfile ?? await this.userProfilesRepository.findOneByOrFail({ userId: user.id }) : null; const followingCount = profile == null ? null : (profile.followingVisibility === 'public') || isMe || iAmModerator ? user.followingCount : @@ -785,8 +788,13 @@ export class UserEntityService implements OnModuleInit { const _users = users.filter((user): user is MiUser => typeof user !== 'string'); if (_users.length !== users.length) { _users.push( - ...await this.usersRepository.findBy({ - id: In(users.filter((user): user is string => typeof user === 'string')), + ...await this.usersRepository.find({ + where: { + id: In(users.filter((user): user is string => typeof user === 'string')), + }, + relations: { + userProfile: true, + }, }), ); } @@ -800,8 +808,20 @@ export class UserEntityService implements OnModuleInit { let pinNotes: Map = new Map(); if (options?.schema !== 'UserLite') { - profilesMap = await this.userProfilesRepository.findBy({ userId: In(_userIds) }) - .then(profiles => new Map(profiles.map(p => [p.userId, p]))); + const _profiles: MiUserProfile[] = []; + const _profilesToFetch: string[] = []; + for (const user of _users) { + if (user.userProfile) { + _profiles.push(user.userProfile); + } else { + _profilesToFetch.push(user.id); + } + } + if (_profilesToFetch.length > 0) { + const fetched = await this.userProfilesRepository.findBy({ userId: In(_profilesToFetch) }); + _profiles.push(...fetched); + } + profilesMap = new Map(_profiles.map(p => [p.userId, p])); const meId = me ? me.id : null; if (meId) { diff --git a/packages/backend/src/models/User.ts b/packages/backend/src/models/User.ts index 3ef5817672..2f13400944 100644 --- a/packages/backend/src/models/User.ts +++ b/packages/backend/src/models/User.ts @@ -8,6 +8,7 @@ import { type UserUnsignedFetchOption, userUnsignedFetchOptions } from '@/const. import { MiInstance } from '@/models/Instance.js'; import { id } from './util/id.js'; import { MiDriveFile } from './DriveFile.js'; +import type { MiUserProfile } from './UserProfile.js'; @Entity('user') @Index(['usernameLower', 'host'], { unique: true }) @@ -395,6 +396,9 @@ export class MiUser { }) public attributionDomains: string[]; + @OneToOne('user_profile', (profile: MiUserProfile) => profile.user) + public userProfile: MiUserProfile | null; + constructor(data: Partial) { if (data == null) return; diff --git a/packages/backend/src/models/UserProfile.ts b/packages/backend/src/models/UserProfile.ts index 29c453dd71..6ee72e6ddd 100644 --- a/packages/backend/src/models/UserProfile.ts +++ b/packages/backend/src/models/UserProfile.ts @@ -17,7 +17,7 @@ export class MiUserProfile { @PrimaryColumn(id()) public userId: MiUser['id']; - @OneToOne(type => MiUser, { + @OneToOne(() => MiUser, user => user.userProfile, { onDelete: 'CASCADE', }) @JoinColumn() -- cgit v1.2.3-freya From b05ccbc3aca8e008555736f25760f9f2b1b2a5e7 Mon Sep 17 00:00:00 2001 From: Hazelnoot Date: Wed, 28 May 2025 02:03:05 -0400 Subject: add relations from abuse_user_report->user_profile to speed up admin/abuse-user-reports endpoint --- packages/backend/src/models/AbuseUserReport.ts | 22 ++++++++++++++++++++++ .../api/endpoints/admin/abuse-user-reports.ts | 10 +++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) (limited to 'packages/backend/src/models') diff --git a/packages/backend/src/models/AbuseUserReport.ts b/packages/backend/src/models/AbuseUserReport.ts index 8f8d759004..c1a44c3d40 100644 --- a/packages/backend/src/models/AbuseUserReport.ts +++ b/packages/backend/src/models/AbuseUserReport.ts @@ -5,6 +5,7 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; import { MiInstance } from '@/models/Instance.js'; +import { MiUserProfile } from '@/models/UserProfile.js'; import { id } from './util/id.js'; import { MiUser } from './User.js'; @@ -25,6 +26,13 @@ export class MiAbuseUserReport { @JoinColumn() public targetUser: MiUser | null; + @ManyToOne(() => MiUserProfile, { + onDelete: 'CASCADE', + createForeignKeyConstraints: false, + }) + @JoinColumn({ name: 'targetUserId', referencedColumnName: 'userId' }) + public targetUserProfile: MiUserProfile | null; + @Index() @Column(id()) public reporterId: MiUser['id']; @@ -35,6 +43,13 @@ export class MiAbuseUserReport { @JoinColumn() public reporter: MiUser | null; + @ManyToOne(() => MiUserProfile, { + onDelete: 'CASCADE', + createForeignKeyConstraints: false, + }) + @JoinColumn({ name: 'reporterId', referencedColumnName: 'userId' }) + public reporterProfile: MiUserProfile | null; + @Column({ ...id(), nullable: true, @@ -47,6 +62,13 @@ export class MiAbuseUserReport { @JoinColumn() public assignee: MiUser | null; + @ManyToOne(() => MiUserProfile, { + onDelete: 'CASCADE', + createForeignKeyConstraints: false, + }) + @JoinColumn({ name: 'assigneeId', referencedColumnName: 'userId' }) + public assigneeProfile: MiUserProfile | null; + @Index() @Column('boolean', { default: false, diff --git a/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts b/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts index f052d3dd14..f9aa3b7ae5 100644 --- a/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts +++ b/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts @@ -120,7 +120,15 @@ export default class extends Endpoint { // eslint- private queryService: QueryService, ) { super(meta, paramDef, async (ps, me) => { - const query = this.queryService.makePaginationQuery(this.abuseUserReportsRepository.createQueryBuilder('report'), ps.sinceId, ps.untilId); + const query = this.queryService.makePaginationQuery(this.abuseUserReportsRepository.createQueryBuilder('report'), ps.sinceId, ps.untilId) + .leftJoinAndSelect('report.targetUser', 'targetUser') + .leftJoinAndSelect('report.targetUserProfile', 'targetUserProfile') + .leftJoinAndSelect('report.targetUserInstance', 'targetUserInstance') + .leftJoinAndSelect('report.reporter', 'reporter') + .leftJoinAndSelect('report.reporterUserProfile', 'reporterUserProfile') + .leftJoinAndSelect('report.assignee', 'assignee') + .leftJoinAndSelect('report.assigneeUserProfile', 'assigneeUserProfile') + ; switch (ps.state) { case 'resolved': query.andWhere('report.resolved = TRUE'); break; -- cgit v1.2.3-freya From b1876bf06e92acda34270cf2582559b2f4cc1001 Mon Sep 17 00:00:00 2001 From: Hazelnoot Date: Wed, 28 May 2025 03:08:34 -0400 Subject: remove report -> profile relations to avoid TypeORM bug https://github.com/typeorm/typeorm/issues/10469 --- packages/backend/src/models/AbuseUserReport.ts | 22 ---------------------- .../api/endpoints/admin/abuse-user-reports.ts | 6 +++--- 2 files changed, 3 insertions(+), 25 deletions(-) (limited to 'packages/backend/src/models') diff --git a/packages/backend/src/models/AbuseUserReport.ts b/packages/backend/src/models/AbuseUserReport.ts index c1a44c3d40..8f8d759004 100644 --- a/packages/backend/src/models/AbuseUserReport.ts +++ b/packages/backend/src/models/AbuseUserReport.ts @@ -5,7 +5,6 @@ import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; import { MiInstance } from '@/models/Instance.js'; -import { MiUserProfile } from '@/models/UserProfile.js'; import { id } from './util/id.js'; import { MiUser } from './User.js'; @@ -26,13 +25,6 @@ export class MiAbuseUserReport { @JoinColumn() public targetUser: MiUser | null; - @ManyToOne(() => MiUserProfile, { - onDelete: 'CASCADE', - createForeignKeyConstraints: false, - }) - @JoinColumn({ name: 'targetUserId', referencedColumnName: 'userId' }) - public targetUserProfile: MiUserProfile | null; - @Index() @Column(id()) public reporterId: MiUser['id']; @@ -43,13 +35,6 @@ export class MiAbuseUserReport { @JoinColumn() public reporter: MiUser | null; - @ManyToOne(() => MiUserProfile, { - onDelete: 'CASCADE', - createForeignKeyConstraints: false, - }) - @JoinColumn({ name: 'reporterId', referencedColumnName: 'userId' }) - public reporterProfile: MiUserProfile | null; - @Column({ ...id(), nullable: true, @@ -62,13 +47,6 @@ export class MiAbuseUserReport { @JoinColumn() public assignee: MiUser | null; - @ManyToOne(() => MiUserProfile, { - onDelete: 'CASCADE', - createForeignKeyConstraints: false, - }) - @JoinColumn({ name: 'assigneeId', referencedColumnName: 'userId' }) - public assigneeProfile: MiUserProfile | null; - @Index() @Column('boolean', { default: false, diff --git a/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts b/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts index bf71cb82c4..b8200c09aa 100644 --- a/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts +++ b/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts @@ -122,12 +122,12 @@ export default class extends Endpoint { // eslint- super(meta, paramDef, async (ps, me) => { const query = this.queryService.makePaginationQuery(this.abuseUserReportsRepository.createQueryBuilder('report'), ps.sinceId, ps.untilId) .leftJoinAndSelect('report.targetUser', 'targetUser') - .leftJoinAndSelect('report.targetUserProfile', 'targetUserProfile') + .leftJoinAndSelect('targetUser.userProfile', 'targetUserProfile') .leftJoinAndSelect('report.targetUserInstance', 'targetUserInstance') .leftJoinAndSelect('report.reporter', 'reporter') - .leftJoinAndSelect('report.reporterProfile', 'reporterProfile') + .leftJoinAndSelect('reporter.userProfile', 'reporterProfile') .leftJoinAndSelect('report.assignee', 'assignee') - .leftJoinAndSelect('report.assigneeProfile', 'assigneeProfile') + .leftJoinAndSelect('assignee.userProfile', 'assigneeProfile') ; switch (ps.state) { -- cgit v1.2.3-freya