collab
This commit is contained in:
@@ -55,6 +55,15 @@ export class AuthController {
|
||||
return this.authService.getPublicUser(request.user!.sub);
|
||||
}
|
||||
|
||||
@Get('users/search')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
searchUsers(
|
||||
@Req() request: AuthenticatedRequest,
|
||||
@Query('q') query?: string,
|
||||
) {
|
||||
return this.authService.searchUsers(request.user!.sub, query);
|
||||
}
|
||||
|
||||
@Patch('me/onboarding')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
updateOnboarding(
|
||||
|
||||
@@ -9,7 +9,7 @@ import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { randomBytes, randomUUID, scryptSync, timingSafeEqual } from 'crypto';
|
||||
import { Repository } from 'typeorm';
|
||||
import { Like, Repository } from 'typeorm';
|
||||
import { AuditLogService } from '../audit/audit-log.service';
|
||||
import { LoginDto } from './dto/login.dto';
|
||||
import { RegisterDto } from './dto/register.dto';
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
AuthTokens,
|
||||
JwtTokenPayload,
|
||||
PublicUser,
|
||||
PublicUserSearchResult,
|
||||
} from './auth.types';
|
||||
import { AppEvents } from '../events/app-events';
|
||||
import { RefreshTokenEntity } from './refresh-token.entity';
|
||||
@@ -293,6 +294,41 @@ export class AuthService {
|
||||
return this.toPublicUser(user);
|
||||
}
|
||||
|
||||
async searchUsers(
|
||||
actorUserId: string,
|
||||
query?: string,
|
||||
): Promise<PublicUserSearchResult[]> {
|
||||
const normalizedQuery = query?.trim();
|
||||
|
||||
if (!normalizedQuery || normalizedQuery.length < 2) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const pattern = `%${normalizedQuery}%`;
|
||||
const users = await this.usersRepository.find({
|
||||
where: [
|
||||
{ verified: true, email: Like(pattern) },
|
||||
{ verified: true, name: Like(pattern) },
|
||||
],
|
||||
order: { email: 'ASC' },
|
||||
take: 10,
|
||||
});
|
||||
|
||||
return users
|
||||
.filter((user) => user.id !== actorUserId)
|
||||
.filter(
|
||||
(user, index, allUsers) =>
|
||||
allUsers.findIndex((existingUser) => existingUser.id === user.id) ===
|
||||
index,
|
||||
)
|
||||
.slice(0, 10)
|
||||
.map((user) => ({
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
name: user.name ?? undefined,
|
||||
}));
|
||||
}
|
||||
|
||||
async updateOnboardingCompleted(
|
||||
userId: string,
|
||||
completed: boolean,
|
||||
|
||||
@@ -37,3 +37,9 @@ export interface PublicUser {
|
||||
verified: boolean;
|
||||
onboardingCompleted: boolean;
|
||||
}
|
||||
|
||||
export interface PublicUserSearchResult {
|
||||
id: string;
|
||||
email: string;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
} from 'typeorm';
|
||||
import { ListTemplateEntity } from '../list-templates/list-template.entity';
|
||||
import { UserListEntity } from '../lists/user-list.entity';
|
||||
import { UserListShareEntity } from '../lists/user-list-share.entity';
|
||||
import { RefreshTokenEntity } from './refresh-token.entity';
|
||||
|
||||
@Entity('users')
|
||||
@@ -59,4 +60,7 @@ export class UserEntity {
|
||||
|
||||
@OneToMany(() => UserListEntity, (list) => list.owner)
|
||||
lists?: UserListEntity[];
|
||||
|
||||
@OneToMany(() => UserListShareEntity, (share) => share.user)
|
||||
sharedLists?: UserListShareEntity[];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user