diff --git a/src/ai-integration/services/summarization.service.ts b/src/ai-integration/services/summarization.service.ts index a2fe7fa..5e5894f 100644 --- a/src/ai-integration/services/summarization.service.ts +++ b/src/ai-integration/services/summarization.service.ts @@ -61,12 +61,12 @@ export class AiSummarizationService { const interestsText = response.choices[0]?.message?.content?.trim(); if (!interestsText || interestsText.length === 0) { - return ''; + return ''; } - const normalizedResponse = interestsText.toUpperCase().replace(/[^A-Z]/g, ''); + const normalizedResponse = interestsText.toUpperCase().replaceAll(/[^A-Z]/g, ''); const matchedInterest = ALL_INTERESTS.find( - interest => interest.toUpperCase().replace(/[^A-Z]/g, '') === normalizedResponse + interest => interest.toUpperCase().replaceAll(/[^A-Z]/g, '') === normalizedResponse ); return matchedInterest || ''; diff --git a/src/auth/auth.controller.ts b/src/auth/auth.controller.ts index 1657143..82c25f2 100644 --- a/src/auth/auth.controller.ts +++ b/src/auth/auth.controller.ts @@ -52,7 +52,6 @@ import { ResetPasswordDto } from './dto/reset-password.dto'; import { UpdateEmailDto } from 'src/user/dto/update-email.dto'; import { UpdateUsernameDto } from 'src/user/dto/update-username.dto'; import { EmailDto, VerifyOtpDto } from './dto/email-verification.dto'; -import { AuthJwtPayload } from 'src/types/jwtPayload'; import { AuthenticatedUser } from './interfaces/user.interface'; import { ChangePasswordDto } from './dto/change-password.dto'; import { VerifyPasswordDto } from './dto/verify-password.dto'; @@ -679,7 +678,10 @@ export class AuthController { @Get('github/login') @Public() @UseGuards(GithubAuthGuard) - public githubLogin() {} + public githubLogin() { + // Passport guard redirect handles this - method intentionally empty + return; + } @Get('github/redirect') @Public() diff --git a/src/auth/auth.module.ts b/src/auth/auth.module.ts index 7da3069..8e2c791 100644 --- a/src/auth/auth.module.ts +++ b/src/auth/auth.module.ts @@ -1,7 +1,6 @@ import { Module } from '@nestjs/common'; import { AuthController } from './auth.controller'; import { AuthService } from './auth.service'; -import { PrismaService } from 'src/prisma/prisma.service'; import { UserModule } from 'src/user/user.module'; import { LocalStrategy } from './strategies/local.strategy'; import { JwtModule } from '@nestjs/jwt'; diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts index 5cac9a4..b2271b9 100644 --- a/src/auth/auth.service.ts +++ b/src/auth/auth.service.ts @@ -16,7 +16,7 @@ import { RedisService } from 'src/redis/redis.service'; import { OAuth2Client } from 'google-auth-library'; import googleOauthConfig from './config/google-oauth.config'; import { ConfigType } from '@nestjs/config'; -import { randomBytes } from 'crypto'; +import { randomBytes } from 'node:crypto'; import { OAuthCodeData } from './interfaces/oauth-code-data.interface'; const ISVERIFIED_CACHE_PREFIX = 'verified:'; @@ -25,7 +25,7 @@ const CODE_EXPIRY = 300; // 5 minutes @Injectable() export class AuthService { - private googleClient: OAuth2Client; + private readonly googleClient: OAuth2Client; constructor( @Inject(Services.USER) diff --git a/src/auth/services/email-verification/email-verification.service.ts b/src/auth/services/email-verification/email-verification.service.ts index a00e101..9bd2d01 100644 --- a/src/auth/services/email-verification/email-verification.service.ts +++ b/src/auth/services/email-verification/email-verification.service.ts @@ -5,7 +5,6 @@ import { ConflictException, HttpException, HttpStatus, - NotFoundException, } from '@nestjs/common'; import { EmailService } from 'src/email/email.service'; import { UserService } from 'src/user/user.service'; diff --git a/src/auth/services/jwt-token/jwt-token.service.ts b/src/auth/services/jwt-token/jwt-token.service.ts index 8a338ab..8ca0dfd 100644 --- a/src/auth/services/jwt-token/jwt-token.service.ts +++ b/src/auth/services/jwt-token/jwt-token.service.ts @@ -10,7 +10,7 @@ export class JwtTokenService { public async generateAccessToken(userId: number, username: string): Promise { const payload: AuthJwtPayload = { sub: userId, username }; - const [accessToken] = await Promise.all([this.jwtService.signAsync(payload)]); + const accessToken = await this.jwtService.signAsync(payload); return accessToken; } diff --git a/src/auth/services/password/password.service.ts b/src/auth/services/password/password.service.ts index 4378749..0c01efb 100644 --- a/src/auth/services/password/password.service.ts +++ b/src/auth/services/password/password.service.ts @@ -6,7 +6,7 @@ import { BadRequestException, } from '@nestjs/common'; import * as argon2 from 'argon2'; -import * as crypto from 'crypto'; +import * as crypto from 'node:crypto'; import { RequestPasswordResetDto } from 'src/auth/dto/request-password-reset.dto'; import { EmailService } from 'src/email/email.service'; import { UserService } from 'src/user/user.service'; @@ -149,7 +149,7 @@ export class PasswordService { const key = `${MAX_RESET_ATTEMPTS_PREFIX}${email}`; const attempts = await this.redisService.get(key); - if (attempts && parseInt(attempts) >= MAX_ATTEMPTS) { + if (attempts && Number.parseInt(attempts) >= MAX_ATTEMPTS) { throw new BadRequestException('Too many password reset requests. Please try again later.'); } } @@ -157,7 +157,7 @@ export class PasswordService { private async incrementResetAttempts(email: string): Promise { const key = `${MAX_RESET_ATTEMPTS_PREFIX}${email}`; const current = await this.redisService.get(key); - const count = current ? parseInt(current) + 1 : 1; + const count = current ? Number.parseInt(current) + 1 : 1; await this.redisService.set(key, count.toString(), ATTEMPT_WINDOW_SECONDS); } diff --git a/src/conversations/conversations.service.ts b/src/conversations/conversations.service.ts index 0533106..aa9947c 100644 --- a/src/conversations/conversations.service.ts +++ b/src/conversations/conversations.service.ts @@ -76,7 +76,7 @@ export class ConversationsService { }); const { Messages, ...conversationData } = oldConversation; - const reversedMessages = Messages.reverse(); // Reverse to show oldest first + const reversedMessages = Messages.toReversed(); // Reverse to show oldest first return { data: { diff --git a/src/email/email.controller.ts b/src/email/email.controller.ts index 222ccf5..a83e82f 100644 --- a/src/email/email.controller.ts +++ b/src/email/email.controller.ts @@ -1,7 +1,7 @@ import { Body, Controller, Inject, Post } from '@nestjs/common'; import { EmailService } from './email.service'; -import { join } from 'path'; -import { readFileSync } from 'fs'; +import { join } from 'node:path'; +import { readFileSync } from 'node:fs'; import { Routes, Services } from 'src/utils/constants'; import { Public } from 'src/auth/decorators/public.decorator'; @@ -21,7 +21,6 @@ export class EmailController { 'email-verification.html', ); const template = readFileSync(templatePath, 'utf-8'); - // console.log(template); return this.emailService.sendEmail({ subject: 'Account Verification', recipients: ['mohamedalbaz77@gmail.com'], diff --git a/src/email/email.service.ts b/src/email/email.service.ts index 83fc588..5676dcb 100644 --- a/src/email/email.service.ts +++ b/src/email/email.service.ts @@ -2,8 +2,8 @@ import { Inject, Injectable, Logger, Optional } from '@nestjs/common'; import { ConfigType } from '@nestjs/config'; import mailerConfig from './../common/config/mailer.config'; import { SendEmailDto } from './dto/send-email.dto'; -import { readFileSync } from 'fs'; -import { join } from 'path'; +import { readFileSync } from 'node:fs'; +import { join } from 'node:path'; import { Resend } from 'resend'; import { EmailClient, EmailMessage, KnownEmailSendStatus } from '@azure/communication-email'; import * as nodemailer from 'nodemailer'; @@ -270,7 +270,7 @@ export class EmailService { try { let template = readFileSync(templatePath, 'utf-8'); for (const key of Object.keys(variables)) { - template = template.replace(new RegExp(`{{\\s*${key}\\s*}}`, 'g'), variables[key]); + template = template.replaceAll(new RegExp(`{{\\s*${key}\\s*}}`, 'g'), variables[key]); } return template; diff --git a/src/messages/messages.service.ts b/src/messages/messages.service.ts index 7dfc9bd..7a45b44 100644 --- a/src/messages/messages.service.ts +++ b/src/messages/messages.service.ts @@ -212,7 +212,7 @@ export class MessagesService { }), ]); - const reversedMessages = messages.reverse(); // Return oldest first for chat display + const reversedMessages = messages.toReversed(); // Return oldest first for chat display return { data: reversedMessages, @@ -281,7 +281,7 @@ export class MessagesService { data: messages, metadata: { totalItems: messages.length, - firstMessageId: messages.length > 0 ? messages[messages.length - 1].id : null, + firstMessageId: messages.length > 0 ? messages.at(-1)!.id : null, }, }; } diff --git a/src/notifications/notification.service.ts b/src/notifications/notification.service.ts index 6b3aef5..6150d23 100644 --- a/src/notifications/notification.service.ts +++ b/src/notifications/notification.service.ts @@ -288,7 +288,8 @@ export class NotificationService { private async handleFailedTokens(responses: any[], tokens: string[]): Promise { const invalidTokens: string[] = []; - responses.forEach((response, index) => { + for (let index = 0; index < responses.length; index++) { + const response = responses[index]; if (!response.success) { const errorCode = response.error?.code; // Remove tokens that are invalid, not registered, or expired @@ -299,7 +300,7 @@ export class NotificationService { invalidTokens.push(tokens[index]); } } - }); + } if (invalidTokens.length > 0) { await this.prismaService.deviceToken.deleteMany({ @@ -592,7 +593,7 @@ export class NotificationService { where.type = { notIn: excludeTypes }; } - const [totalItems, notifications, unreadCount] = await Promise.all([ + const [totalItems, notifications] = await Promise.all([ this.prismaService.notification.count({ where }), this.prismaService.notification.findMany({ where, @@ -600,9 +601,6 @@ export class NotificationService { skip: (page - 1) * limit, take: limit, }), - this.prismaService.notification.count({ - where: { recipientId: userId, isRead: false }, - }), ]); // Fetch post data for REPLY, QUOTE, MENTION notifications @@ -717,9 +715,9 @@ export class NotificationService { const unreadNotifications = await notificationsRef.where('isRead', '==', false).get(); const batch = firestore.batch(); - unreadNotifications.docs.forEach((doc) => { + for (const doc of unreadNotifications.docs) { batch.update(doc.ref, { isRead: true }); - }); + } await batch.commit(); } catch (error) { diff --git a/src/post/hashtag.controller.ts b/src/post/hashtag.controller.ts index 57b8526..77478ff 100644 --- a/src/post/hashtag.controller.ts +++ b/src/post/hashtag.controller.ts @@ -1,19 +1,14 @@ import { Controller, Get, - Post, Query, - Param, ParseIntPipe, DefaultValuePipe, - HttpStatus, - HttpException, - UseGuards, Inject, Logger, BadRequestException, } from '@nestjs/common'; -import { ApiOperation, ApiResponse, ApiQuery, ApiCookieAuth } from '@nestjs/swagger'; +import { ApiOperation, ApiResponse, ApiQuery } from '@nestjs/swagger'; import { HashtagTrendService } from './services/hashtag-trends.service'; import { Services } from 'src/utils/constants'; import { TrendCategory, isValidTrendCategory } from './enums/trend-category.enum'; @@ -102,7 +97,6 @@ export class HashtagController { user?.id, ); } - return { status: 'success', data: { trending }, @@ -113,86 +107,4 @@ export class HashtagController { }, }; } - - // @Post('recalculate') - // @ApiCookieAuth() - // @ApiOperation({ - // summary: 'Trigger hashtag trend recalculation', - // description: - // 'Manually triggers recalculation of trends for all active hashtags from the last 7 days, optionally filtered by category', - // }) - // @ApiQuery({ - // name: 'category', - // required: false, - // enum: TrendCategory, - // description: - // 'Category to recalculate trends for. Options: general, news, sports, entertainment, personalized. Defaults to "general" which processes all hashtags.', - // example: TrendCategory.GENERAL, - // }) - // @ApiResponse({ - // status: 200, - // description: 'Successfully queued recalculation', - // schema: { - // example: { - // status: 'success', - // message: 'Queued recalculation for 45 hashtags', - // data: { - // queuedHashtags: 45, - // category: 'sports', - // }, - // }, - // }, - // }) - // @ApiResponse({ - // status: 400, - // description: 'Invalid category', - // }) - // @ApiResponse({ - // status: 500, - // description: 'Internal server error', - // }) - // async recalculate( - // @Query('category', new DefaultValuePipe(TrendCategory.GENERAL)) category: string, - // ) { - // if (!isValidTrendCategory(category)) { - // throw new BadRequestException( - // `Invalid category. Must be one of: ${Object.values(TrendCategory).join(', ')}`, - // ); - // } - - // const count = await this.hashtagTrendService.recalculateTrends(category as TrendCategory); - - // return { - // status: 'success', - // message: `Queued recalculation for ${count} hashtags in ${category} category`, - // data: { - // queuedHashtags: count, - // category, - // }, - // }; - // } - - // @Post('reindex-hashtags') - // @ApiCookieAuth() - // @ApiOperation({ - // summary: 'Reindex all post hashtags', - // description: 'Scans all posts and extracts hashtags, updating the hashtag relations.', - // }) - // @ApiResponse({ - // status: 200, - // description: 'Successfully completed reindexing', - // }) - // @ApiResponse({ - // status: 500, - // description: 'Internal server error', - // }) - // async reindexHashtags() { - // const result = await this.hashtagTrendService.reindexAllPostHashtags(); - - // return { - // status: 'success', - // message: 'Hashtags reindexed', - // result, - // }; - // } } diff --git a/src/post/services/hashtag-trends.service.ts b/src/post/services/hashtag-trends.service.ts index bead0e1..a04751d 100644 --- a/src/post/services/hashtag-trends.service.ts +++ b/src/post/services/hashtag-trends.service.ts @@ -206,10 +206,10 @@ export class HashtagTrendService { category, ); - redisMetadata.forEach((metadata, id) => { + for (const [id, metadata] of redisMetadata) { metadataResults.set(id, metadata); this.setMemoryCachedMetadata(id, metadata.tag, category); - }); + } } const missingFromRedis = hashtagIds.filter((id) => !metadataResults.has(id)); diff --git a/src/post/services/like.service.ts b/src/post/services/like.service.ts index 43019b7..de7f1dd 100644 --- a/src/post/services/like.service.ts +++ b/src/post/services/like.service.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable, NotFoundException } from '@nestjs/common'; +import { Inject, Injectable } from '@nestjs/common'; import { PrismaService } from 'src/prisma/prisma.service'; import { Services } from 'src/utils/constants'; import { EventEmitter2 } from '@nestjs/event-emitter'; diff --git a/src/post/services/mention.service.ts b/src/post/services/mention.service.ts index 37a1ee4..ba33352 100644 --- a/src/post/services/mention.service.ts +++ b/src/post/services/mention.service.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable, NotFoundException } from '@nestjs/common'; +import { Inject, Injectable } from '@nestjs/common'; import { PrismaService } from 'src/prisma/prisma.service'; import { Services } from 'src/utils/constants'; import { PostService } from './post.service'; diff --git a/src/post/services/personalized-trends.service.ts b/src/post/services/personalized-trends.service.ts index 91fe2e7..83b820d 100644 --- a/src/post/services/personalized-trends.service.ts +++ b/src/post/services/personalized-trends.service.ts @@ -4,7 +4,6 @@ import { PrismaService } from 'src/prisma/prisma.service'; import { Services } from 'src/utils/constants'; import { TrendCategory, CATEGORY_TO_INTERESTS } from '../enums/trend-category.enum'; import { RedisTrendingService } from './redis-trending.service'; -import { UserService } from 'src/user/user.service'; import { UsersService } from 'src/users/users.service'; interface UserInterests { @@ -145,8 +144,8 @@ export class PersonalizedTrendsService { } >(); - categoryTrends.forEach(({ category, trends }) => { - trends.forEach(({ hashtagId, score }) => { + for (const { category, trends } of categoryTrends) { + for (const { hashtagId, score } of trends) { if (!hashtagScores.has(hashtagId)) { hashtagScores.set(hashtagId, { scores: new Map(), @@ -160,20 +159,20 @@ export class PersonalizedTrendsService { hashtagData.scores.set(category, score); hashtagData.totalScore += weightedScore; - }); - }); + } + } const rankedTrends = Array.from(hashtagScores.entries()) .map(([hashtagId, data]) => { let primaryCategory = TrendCategory.GENERAL; let maxScore = 0; - data.scores.forEach((score, category) => { + for (const [category, score] of data.scores) { if (score > maxScore) { maxScore = score; primaryCategory = category; } - }); + } return { hashtagId, @@ -200,55 +199,6 @@ export class PersonalizedTrendsService { return 0.3; } - // async getUserInterests(userId: number): Promise { - // const cached = this.userInterestsCache.get(userId); - // if (cached && Date.now() - cached.timestamp < this.USER_INTERESTS_CACHE_TTL * 1000) { - // return cached.interests; - // } - - // const redisCacheKey = `user:interests:${userId}`; - // const redisCached = await this.redisService.getJSON(redisCacheKey); - // if (redisCached) { - // this.userInterestsCache.set(userId, { - // interests: redisCached, - // timestamp: Date.now(), - // }); - // return redisCached; - // } - - // const user = await this.prismaService.user.findUnique({ - // where: { id: userId }, - // include: { - // interests: { - // include: { - // interest: true, - // }, - // }, - // }, - // }); - - // if (!user) { - // throw new Error(`User ${userId} not found`); - // } - - // const interestSlugs = user.interests.map((ui) => ui.interest.slug); - // const categories = this.mapInterestsToCategories(interestSlugs); - - // const userInterests: UserInterests = { - // userId, - // interestSlugs, - // categories, - // }; - - // await this.redisService.setJSON(redisCacheKey, userInterests, this.USER_INTERESTS_CACHE_TTL); - // this.userInterestsCache.set(userId, { - // interests: userInterests, - // timestamp: Date.now(), - // }); - - // return userInterests; - // } - private mapInterestsToCategories(interestSlugs: string[]): TrendCategory[] { const categories = new Set(); @@ -311,74 +261,6 @@ export class PersonalizedTrendsService { this.logger.debug(`Invalidated cache for user ${userId}`); } - // async invalidateAllPersonalizedCache(): Promise { - // await this.redisService.delPattern('personalized:trending:*'); - // this.userInterestsCache.clear(); - // this.logger.log('Invalidated all personalized trending caches'); - // } - - // async batchInvalidateUserCache(userIds: number[]): Promise { - // await Promise.all(userIds.map((userId) => this.invalidateUserCache(userId))); - // this.logger.log(`Invalidated cache for ${userIds.length} users`); - // } - - // async getPersonalizedStats(userId: number): Promise<{ - // userCategories: TrendCategory[]; - // cachedResults: boolean; - // interestsCount: number; - // }> { - // const cacheKey = `personalized:trending:${userId}:10`; - // const cached = await this.redisService.getJSON(cacheKey); - - // let userInterests: UserInterests; - // try { - // userInterests = await this.getUserInterests(userId); - // } catch (error) { - // return { - // userCategories: [], - // cachedResults: false, - // interestsCount: 0, - // }; - // } - - // return { - // userCategories: userInterests.categories, - // cachedResults: cached !== null, - // interestsCount: userInterests.interestSlugs.length, - // }; - // } - - // async prewarmPersonalizedCache(userIds: number[], limit: number = 10): Promise { - // let warmed = 0; - - // for (const userId of userIds) { - // try { - // await this.getPersonalizedTrending(userId, limit); - // warmed++; - // } catch (error) { - // this.logger.warn(`Failed to prewarm cache for user ${userId}:`, error); - // } - // } - - // this.logger.log(`Pre-warmed personalized cache for ${warmed}/${userIds.length} users`); - // return warmed; - // } - - // async getMostActiveUsers(limit: number = 100): Promise { - // const activeUsersKey = 'trending:active_users'; - - // try { - // const results = await this.redisService.zRangeWithScores(activeUsersKey, 0, limit - 1, { - // REV: true, - // }); - - // return results.map((r) => parseInt(r.value, 10)); - // } catch (error) { - // this.logger.error('Failed to get active users:', error); - // return []; - // } - // } - async trackUserActivity(userId: number): Promise { const activeUsersKey = 'trending:active_users'; const score = Date.now(); diff --git a/src/post/services/post.service.ts b/src/post/services/post.service.ts index 3b14ba8..9250a4d 100644 --- a/src/post/services/post.service.ts +++ b/src/post/services/post.service.ts @@ -268,7 +268,9 @@ export class PostService { const statsMap = new Map(); // Initialize map for all requested IDs to ensure 0 counts are returned if no data found - postIds.forEach(id => statsMap.set(id, { replies: 0, quotes: 0 })); + for (const id of postIds) { + statsMap.set(id, { replies: 0, quotes: 0 }); + } for (const row of grouped) { if (row.parent_id) { @@ -384,7 +386,9 @@ export class PostService { }); const parentPostsMap = new Map(); - parentPosts.forEach((p) => parentPostsMap.set(p.postId, p)); + for (const p of parentPosts) { + parentPostsMap.set(p.postId, p); + } return post.map((p) => { if ((p.type === PostType.QUOTE || p.type === PostType.REPLY) && p.parentId) { @@ -413,12 +417,12 @@ export class PostService { if (nestedPostsToEnrich.length > 0) { const nestedEnriched = await this.enrichIfQuoteOrReply(nestedPostsToEnrich, currentUserId); - nestedEnriched.forEach((enrichedPost) => { + for (const enrichedPost of nestedEnriched) { const parentIndex = indexMap.get(enrichedPost.postId); if (parentIndex !== undefined) { posts[parentIndex].originalPostData = enrichedPost; } - }); + } } return posts; @@ -560,7 +564,7 @@ export class PostService { // Emit mention notifications for all mentioned users if (createPostDto.mentionsIds && createPostDto.mentionsIds.length > 0) { - createPostDto.mentionsIds.forEach((mentionedUserId) => { + for (const mentionedUserId of createPostDto.mentionsIds) { // Don't notify yourself if (mentionedUserId !== userId) { // Skip mention notification for parent author if this is a reply or quote (they already got a REPLY/QUOTE notification) @@ -576,7 +580,7 @@ export class PostService { }); } } - }); + } } // Emit post.created event for real-time hashtag tracking @@ -2450,7 +2454,7 @@ private async GetPersonalizedForYouPosts( // Escape and format interest names for SQL IN clause const escapedInterestNames = interestNames - .map((name) => `'${name.replace(/'/g, "''")}'`) + .map((name) => `'${name.replaceAll(/'/g, "''")}'`) .join(', '); const query = ` diff --git a/src/post/services/redis-trending.service.ts b/src/post/services/redis-trending.service.ts index a45b15e..df265ef 100644 --- a/src/post/services/redis-trending.service.ts +++ b/src/post/services/redis-trending.service.ts @@ -205,7 +205,7 @@ export class RedisTrendingService { for (let i = 0; i < bucketsToCount; i++) { const bucket = currentBucket - i; const key = `${this.getHashtagKey(hashtagId, window, category)}:${bucket}`; - promises.push(this.redisService.get(key).then((val) => (val ? parseInt(val, 10) : 0))); + promises.push(this.redisService.get(key).then((val) => (val ? Number.parseInt(val, 10) : 0))); } const counts = await Promise.all(promises); @@ -224,7 +224,7 @@ export class RedisTrendingService { }); return results.map((result) => ({ - hashtagId: parseInt(result.value, 10), + hashtagId: Number.parseInt(result.value, 10), score: result.score, })); } catch (error) { diff --git a/src/user/user.service.ts b/src/user/user.service.ts index 0119643..e3443b4 100644 --- a/src/user/user.service.ts +++ b/src/user/user.service.ts @@ -168,7 +168,11 @@ export class UserService { } public async getUserData(uniqueIdentifier: string) { - const isEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(uniqueIdentifier); + // Simple email check to avoid ReDoS vulnerability from regex backtracking + const atIndex = uniqueIdentifier.indexOf('@'); + const isEmail = atIndex > 0 && + uniqueIdentifier.indexOf('.', atIndex) > atIndex + 1 && + !uniqueIdentifier.includes(' '); const user = await this.prismaService.user.findUnique({ where: isEmail ? { email: uniqueIdentifier } : { username: uniqueIdentifier }, }); diff --git a/src/users/users.service.ts b/src/users/users.service.ts index 84345b6..a29d979 100644 --- a/src/users/users.service.ts +++ b/src/users/users.service.ts @@ -367,7 +367,7 @@ export class UsersService { userId, authenticatedUserId, )) as any[]; - const totalItems = parseInt((totalItemsResult[0] as any).count, 10); + const totalItems = Number.parseInt((totalItemsResult[0] as any).count, 10); const metadata = { totalItems,