fix: サジェストされるユーザのリストアップ方法を見直し (#14180)
* fix: サジェストされるユーザのリストアップ方法を見直し * fix comment * fix CHANGELOG.md * ノートの無いユーザ(updatedAtが無いユーザ)は含めないらしい * fix test
This commit is contained in:
		| @@ -3,15 +3,9 @@ | ||||
|  * SPDX-License-Identifier: AGPL-3.0-only | ||||
|  */ | ||||
|  | ||||
| import { Brackets } from 'typeorm'; | ||||
| import { Inject, Injectable } from '@nestjs/common'; | ||||
| import type { UsersRepository, FollowingsRepository } from '@/models/_.js'; | ||||
| import type { Config } from '@/config.js'; | ||||
| import type { MiUser } from '@/models/User.js'; | ||||
| import { Injectable } from '@nestjs/common'; | ||||
| import { Endpoint } from '@/server/api/endpoint-base.js'; | ||||
| import { UserEntityService } from '@/core/entities/UserEntityService.js'; | ||||
| import { DI } from '@/di-symbols.js'; | ||||
| import { sqlLikeEscape } from '@/misc/sql-like-escape.js'; | ||||
| import { UserSearchService } from '@/core/UserSearchService.js'; | ||||
|  | ||||
| export const meta = { | ||||
| 	tags: ['users'], | ||||
| @@ -49,89 +43,16 @@ export const paramDef = { | ||||
| @Injectable() | ||||
| export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export | ||||
| 	constructor( | ||||
| 		@Inject(DI.config) | ||||
| 		private config: Config, | ||||
|  | ||||
| 		@Inject(DI.usersRepository) | ||||
| 		private usersRepository: UsersRepository, | ||||
|  | ||||
| 		@Inject(DI.followingsRepository) | ||||
| 		private followingsRepository: FollowingsRepository, | ||||
|  | ||||
| 		private userEntityService: UserEntityService, | ||||
| 		private userSearchService: UserSearchService, | ||||
| 	) { | ||||
| 		super(meta, paramDef, async (ps, me) => { | ||||
| 			const setUsernameAndHostQuery = (query = this.usersRepository.createQueryBuilder('user')) => { | ||||
| 				if (ps.username) { | ||||
| 					query.andWhere('user.usernameLower LIKE :username', { username: sqlLikeEscape(ps.username.toLowerCase()) + '%' }); | ||||
| 				} | ||||
|  | ||||
| 				if (ps.host) { | ||||
| 					if (ps.host === this.config.hostname || ps.host === '.') { | ||||
| 						query.andWhere('user.host IS NULL'); | ||||
| 					} else { | ||||
| 						query.andWhere('user.host LIKE :host', { | ||||
| 							host: sqlLikeEscape(ps.host.toLowerCase()) + '%', | ||||
| 						}); | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 				return query; | ||||
| 			}; | ||||
|  | ||||
| 			const activeThreshold = new Date(Date.now() - (1000 * 60 * 60 * 24 * 30)); // 30日 | ||||
|  | ||||
| 			let users: MiUser[] = []; | ||||
|  | ||||
| 			if (me) { | ||||
| 				const followingQuery = this.followingsRepository.createQueryBuilder('following') | ||||
| 					.select('following.followeeId') | ||||
| 					.where('following.followerId = :followerId', { followerId: me.id }); | ||||
|  | ||||
| 				const query = setUsernameAndHostQuery() | ||||
| 					.andWhere(`user.id IN (${ followingQuery.getQuery() })`) | ||||
| 					.andWhere('user.id != :meId', { meId: me.id }) | ||||
| 					.andWhere('user.isSuspended = FALSE') | ||||
| 					.andWhere(new Brackets(qb => { | ||||
| 						qb | ||||
| 							.where('user.updatedAt IS NULL') | ||||
| 							.orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold }); | ||||
| 					})); | ||||
|  | ||||
| 				query.setParameters(followingQuery.getParameters()); | ||||
|  | ||||
| 				users = await query | ||||
| 					.orderBy('user.usernameLower', 'ASC') | ||||
| 					.limit(ps.limit) | ||||
| 					.getMany(); | ||||
|  | ||||
| 				if (users.length < ps.limit) { | ||||
| 					const otherQuery = setUsernameAndHostQuery() | ||||
| 						.andWhere(`user.id NOT IN (${ followingQuery.getQuery() })`) | ||||
| 						.andWhere('user.isSuspended = FALSE') | ||||
| 						.andWhere('user.updatedAt IS NOT NULL'); | ||||
|  | ||||
| 					otherQuery.setParameters(followingQuery.getParameters()); | ||||
|  | ||||
| 					const otherUsers = await otherQuery | ||||
| 						.orderBy('user.updatedAt', 'DESC') | ||||
| 						.limit(ps.limit - users.length) | ||||
| 						.getMany(); | ||||
|  | ||||
| 					users = users.concat(otherUsers); | ||||
| 				} | ||||
| 			} else { | ||||
| 				const query = setUsernameAndHostQuery() | ||||
| 					.andWhere('user.isSuspended = FALSE') | ||||
| 					.andWhere('user.updatedAt IS NOT NULL'); | ||||
|  | ||||
| 				users = await query | ||||
| 					.orderBy('user.updatedAt', 'DESC') | ||||
| 					.limit(ps.limit - users.length) | ||||
| 					.getMany(); | ||||
| 			} | ||||
|  | ||||
| 			return await this.userEntityService.packMany(users, me, { schema: ps.detail ? 'UserDetailed' : 'UserLite' }); | ||||
| 		super(meta, paramDef, (ps, me) => { | ||||
| 			return this.userSearchService.search({ | ||||
| 				username: ps.username, | ||||
| 				host: ps.host, | ||||
| 			}, { | ||||
| 				limit: ps.limit, | ||||
| 				detail: ps.detail, | ||||
| 			}, me); | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 おさむのひと
					おさむのひと