Merge remote-tracking branch 'origin/main'

This commit is contained in:
Weblate
2026-09-23 23:46:52 +00:00
3 changed files with 18 additions and 4 deletions
@@ -11,6 +11,7 @@ import {Logger} from '@app/api/Logger';
import {getGuildSearchService, getUserSearchService} from '@app/api/SearchFactory'; import {getGuildSearchService, getUserSearchService} from '@app/api/SearchFactory';
import {FeatureTemporarilyDisabledError} from '@fluxer/errors/src/domains/core/FeatureTemporarilyDisabledError'; import {FeatureTemporarilyDisabledError} from '@fluxer/errors/src/domains/core/FeatureTemporarilyDisabledError';
import {InputValidationError} from '@fluxer/errors/src/domains/core/InputValidationError'; import {InputValidationError} from '@fluxer/errors/src/domains/core/InputValidationError';
import type {UserSearchFilters} from '@fluxer/schema/src/contracts/search/SearchDocumentTypes';
import type {WorkerJobPayload} from '@pkgs/worker/src/contracts/WorkerTypes'; import type {WorkerJobPayload} from '@pkgs/worker/src/contracts/WorkerTypes';
interface RefreshSearchIndexJobPayload extends WorkerJobPayload { interface RefreshSearchIndexJobPayload extends WorkerJobPayload {
@@ -130,16 +131,28 @@ export class AdminSearchService {
throw new FeatureTemporarilyDisabledError(); throw new FeatureTemporarilyDisabledError();
} }
const query = data.query?.trim() || ''; const query = data.query?.trim() || '';
const isBrowseAll = query === '' || query === '*';
const searchFilters: UserSearchFilters = isBrowseAll
? {sortBy: 'createdAt', sortOrder: 'asc'}
: {sortBy: 'relevance'};
const directUserId = /^\d+$/.test(query) ? createUserID(BigInt(query)) : null; const directUserId = /^\d+$/.test(query) ? createUserID(BigInt(query)) : null;
const canResolveDirectUser = directUserId !== null && !isSyntheticUserId(directUserId) && data.offset === 0; const canResolveDirectUser = directUserId !== null && !isSyntheticUserId(directUserId) && data.offset === 0;
const [searchResult, directUser] = await Promise.all([ const [searchResult, directUser] = await Promise.all([
userSearchService.search(query, {}, {limit: data.limit, offset: data.offset}), userSearchService.search(query, searchFilters, {limit: data.limit, offset: data.offset}),
canResolveDirectUser ? userRepository.findUnique(directUserId).catch(() => null) : Promise.resolve(null), canResolveDirectUser ? userRepository.findUnique(directUserId).catch(() => null) : Promise.resolve(null),
]); ]);
const {hits, total} = searchResult; const {hits, total} = searchResult;
const userIds = hits.map((hit) => createUserID(BigInt(hit.id))); const userIds = hits.map((hit) => createUserID(BigInt(hit.id)));
const users = await userRepository.listUsers(userIds); const users = await userRepository.listUsers(userIds);
const response = await Promise.all(users.map((user) => mapUserToAdminResponse(user, cacheService, acls))); const usersById = new Map(users.map((user) => [user.id.toString(), user]));
const orderedUsers = [];
for (const userId of userIds) {
const user = usersById.get(userId.toString());
if (user) {
orderedUsers.push(user);
}
}
const response = await Promise.all(orderedUsers.map((user) => mapUserToAdminResponse(user, cacheService, acls)));
if (directUser && data.offset === 0) { if (directUser && data.offset === 0) {
const directId = directUser.id.toString(); const directId = directUser.id.toString();
if (!response.some((u) => u.id === directId)) { if (!response.some((u) => u.id === directId)) {
@@ -52,7 +52,8 @@ function snowflakeSeconds(snowflake: string): number {
function buildSort(sortBy: string, sortOrder: 'asc' | 'desc' | undefined): Array<string> | undefined { function buildSort(sortBy: string, sortOrder: 'asc' | 'desc' | undefined): Array<string> | undefined {
if (sortBy === 'relevance') return undefined; if (sortBy === 'relevance') return undefined;
return [`${sortBy}:${sortOrder ?? 'desc'}`, 'id:desc']; const direction = sortOrder ?? 'desc';
return [`${sortBy}:${direction}`, `id:${direction}`];
} }
function buildTimestampSort(filters: MessageSearchFilters | AuditLogSearchFilters): Array<string> | undefined { function buildTimestampSort(filters: MessageSearchFilters | AuditLogSearchFilters): Array<string> | undefined {
@@ -117,7 +117,7 @@ describe('MeilisearchMessageAdapter', () => {
'(guildId = "guild-1") AND ((channelId = "channel-\\"quoted\\"" OR channelId = "channel-2")) AND (mentionedUserIds = "user-1")', '(guildId = "guild-1") AND ((channelId = "channel-\\"quoted\\"" OR channelId = "channel-2")) AND (mentionedUserIds = "user-1")',
limit: 10, limit: 10,
offset: 20, offset: 20,
sort: ['createdAt:asc', 'id:desc'], sort: ['createdAt:asc', 'id:asc'],
attributesToSearchOn: ['content', 'embedContent'], attributesToSearchOn: ['content', 'embedContent'],
showRankingScore: false, showRankingScore: false,
}, },