Files
fluxer/fluxer_api/src/api/admin/services/AdminUserLookupService.ts
T

61 lines
2.4 KiB
TypeScript

// SPDX-License-Identifier: AGPL-3.0-or-later
import type {ApiContext} from '@app/api/ApiContext';
import {mapUserToAdminResponse} from '@app/api/admin/models/UserTypes';
import {createUserID} from '@app/api/BrandedTypes';
import {isSyntheticUserId} from '@app/api/constants/Core';
import {usesUniqueUsernames} from '@app/api/instance/AccountIdentityModeCache';
import {Logger} from '@app/api/Logger';
import type {User} from '@app/api/models/User';
import {findPersonByLoginHandle, parseLoginHandle} from '@app/api/user/UniqueUsernames';
import type {LookupUserRequest} from '@fluxer/schema/src/domains/admin/AdminUserSchemas';
interface AdminUserLookupServiceDeps {
apiContext: ApiContext;
}
export class AdminUserLookupService {
constructor(private readonly deps: AdminUserLookupServiceDeps) {}
async lookupUser(data: LookupUserRequest, acls: ReadonlySet<string>) {
const {users: userRepository, cache: cacheService} = this.deps.apiContext.services;
if ('user_ids' in data) {
const userIds = data.user_ids.map((id) => createUserID(id));
const users = await userRepository.listUsers(userIds);
return {
users: await Promise.all(users.map((user) => mapUserToAdminResponse(user, cacheService, acls))),
};
}
let user = null;
const query = data.query.trim();
const fluxerTagMatch = query.match(/^(.+)#(\d{1,4})$/);
if (fluxerTagMatch) {
const username = fluxerTagMatch[1];
const discriminator = parseInt(fluxerTagMatch[2], 10);
user = await userRepository.findByUsernameDiscriminator(username, discriminator);
} else if (/^\d+$/.test(query)) {
try {
const userId = createUserID(BigInt(query));
user = isSyntheticUserId(userId) ? null : await userRepository.findUnique(userId);
} catch (error) {
Logger.debug({query, error}, 'Failed to lookup user by numeric ID, invalid ID format');
user = null;
}
} else if (query.includes('@')) {
user = await userRepository.findByEmail(query);
} else {
user = (await this.findPersonByBareUsername(query)) ?? (await userRepository.findByStripeSubscriptionId(query));
}
return {
users: user ? [await mapUserToAdminResponse(user, cacheService, acls)] : [],
};
}
private async findPersonByBareUsername(query: string): Promise<User | null> {
if (!usesUniqueUsernames()) return null;
const handle = parseLoginHandle(query);
if (!handle || handle.discriminator !== null) return null;
return await findPersonByLoginHandle(this.deps.apiContext.services.users, handle);
}
}