-
Notifications
You must be signed in to change notification settings - Fork 0
feat: add user preference #107
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Rebase mail
…/user-preferences
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 17
🔭 Outside diff range comments (2)
src/modules/roles/application/dto/update-user-roles.dto.ts (1)
12-25: Consider enforcing mutual exclusivity betweenroleIdandroleIds.Right now the two properties can be supplied together, which may lead to ambiguous behaviour in the consuming use-case.
A minimal fix is to gate each property on the absence of the other:@@ - @IsOptional() - @ValidateIf((o) => o.roleId !== null) + @IsOptional() + @ValidateIf((o) => o.roleIds == null || o.roleIds.length === 0) @IsUUID() roleId?: string | null; @@ - @IsOptional() + @IsOptional() + @ValidateIf((o) => o.roleId == null) @IsArray() @IsUUID('all', { each: true }) roleIds?: string[];(You can also add a class-level custom validator to assert that at least one of the two is present and never both.)
src/modules/email/application/use-cases/send-password-changed-email.use-case.ts (1)
36-39: Consider adding error handling.The use case doesn't handle potential mail service failures. Consider adding try-catch for better error handling.
try { await this.mailService.send(dto); } catch (error) { // Log error or throw domain-specific exception throw new Error(`Failed to send password changed email: ${error.message}`); }
🧹 Nitpick comments (54)
infra (1)
5-12: Colour constants added – verify non-GNUechocompatibility.
echo -ewith ANSI sequences works on GNU bash but may be inconsistent withshordash.
If portability is a concern, preferprintf:-echo -e "${RED}❌ Inconnu: $1${NC}" +printf "%b\n" "${RED}❌ Inconnu: $1${NC}"Otherwise the addition is fine.
src/modules/ssh/application/gateway/ssh.gateway.ts (1)
40-43: Consider retaining error logging for debugging purposes.Removing the error parameter from the catch block eliminates the ability to log actual error details, which could make debugging SSH connection issues more difficult. Consider keeping error logging while still providing the generic user-facing message.
- } catch { + } catch (error) { + console.error('SSH connection error:', error); client.emit('ssh:error', 'Unable to connect'); client.disconnect(true); }src/modules/user-preferences/application/use-cases/index.ts (1)
1-3: Add missing newline at end of file.The file is missing a trailing newline character as indicated by the ESLint rule.
export * from './get-user-preferences.use-case'; export * from './update-user-preferences.use-case'; -export * from './reset-user-preferences.use-case'; +export * from './reset-user-preferences.use-case'; +src/modules/user-preferences/domain/value-objects/timezone.validator.ts (2)
39-39: Fix formatting issue.Add a newline at the end of the file to comply with coding standards.
export function getValidTimezones(): string[] { return [...validTimezones]; } +
1-31: Consider using the IANA timezone database for broader coverage.The current hardcoded whitelist covers major timezones but may not meet all user needs. Consider these alternatives:
- Use a comprehensive timezone library like
moment-timezoneordate-fns-tzfor full IANA support- Document the rationale for this specific subset if intentionally limited
- Make the list configurable through environment variables or configuration files
If you prefer to keep the current approach, consider adding JSDoc comments explaining the selection criteria:
+/** + * Curated list of commonly used timezones for the application. + * Limited to major global regions to reduce complexity. + */ const validTimezones = [src/modules/email/application/dto/send-email.dto.ts (1)
3-8: Well-structured DTO with good type safety.The DTO design is clean and effective:
EmailAddressVOprovides validation and type safety for email addresses- Template literal types ensure only valid templates are used
- Flexible context object supports various template data needs
Consider adding class-validator decorators for runtime validation:
+import { IsNotEmpty, IsString, IsIn, IsObject } from 'class-validator'; + export class SendEmailDto { + @IsNotEmpty() to: EmailAddressVO; + + @IsString() + @IsNotEmpty() subject: string; + + @IsIn(['reset-password', 'password-changed', 'account-created']) template: 'reset-password' | 'password-changed' | 'account-created'; + + @IsObject() context: Record<string, any>; }src/modules/roles/application/use-cases/__tests__/update-user-roles.use-case.spec.ts (1)
73-78: Fix formatting inconsistencies.The current formatting doesn't match the project's prettier configuration. Please run prettier to fix these formatting issues:
npm run formatOr apply the specific fixes suggested by ESLint:
- Use single-line parameter formatting for method calls
- Maintain consistent indentation and spacing
Also applies to: 117-122, 304-309, 497-501
README.md (2)
143-162: Improve documentation formatting and examples.The new email transactional section is helpful but could be enhanced:
Apply these improvements:
-Pour créer un nouveau template, ajoutez un xxx.hbs et un SendXxxEmailUseCase. +Pour créer un nouveau template, ajoutez un {nom}.hbs et un Send{Nom}EmailUseCase.
149-157: Add language specification to fenced code block.The code block should specify the language for proper syntax highlighting.
-``` +```typescript SendAccountCreatedEmailUseCase SendResetPasswordEmailUseCase SendPasswordChangedEmailUseCasesrc/modules/user-preferences/domain/value-objects/__tests__/timezone.validator.spec.ts (1)
92-92: Add missing newline at end of file.+src/modules/user-preferences/application/use-cases/__tests__/get-user-preferences.use-case.spec.ts (1)
1-125: Comprehensive test coverage for user preferences use case.The test suite thoroughly covers both scenarios (existing preferences and default creation) with proper mocking and clear assertions. The test structure is well-organized and validates the expected behavior effectively.
Add a newline at the end of the file to fix the formatting issue:
}); }); +src/modules/user-preferences/domain/interfaces/user-preferences.repository.interface.ts (1)
1-8: Clean and well-defined repository interface.The interface provides a clear contract for user preferences repository operations with appropriate method signatures and return types.
Add a newline at the end of the file to fix the formatting issue:
} +src/modules/email/adapters/zoho-mail.adapter.ts (3)
40-41: Consider extracting the hardcoded logo URL to configuration.The default logo URL is quite long and hardcoded, making it difficult to maintain. Consider moving this to an environment variable or configuration file.
- const defaultLogoUrl = 'https://github.com/Upstra/.github/blob/dcd1f2dc99276f0fd22eea7b8dd7f35902c562cc/PA2025%20Upstra%20Logo.png?raw=true'; + const defaultLogoUrl = process.env.DEFAULT_LOGO_URL || 'https://github.com/Upstra/.github/blob/dcd1f2dc99276f0fd22eea7b8dd7f35902c562cc/PA2025%20Upstra%20Logo.png?raw=true';
56-56: Fix unused variable issue.The
errorvariable is defined but never used in the catch block, as indicated by the static analysis tool.- } catch (error) { + } catch {
40-40: Fix formatting issues.The static analysis tool indicates several formatting issues that need to be addressed.
Apply the prettier formatting corrections as suggested by the linter.
Also applies to: 49-49, 51-51, 54-54
src/modules/email/domain/value-objects/email-address.vo.ts (1)
29-31: Consider the email validation regex complexity.The regex pattern is quite complex and might be worth documenting or replacing with a well-tested library like
validator.jsfor better maintainability and RFC compliance.+ import { isEmail } from 'validator'; public static isValid(email: string): boolean { if (!email || typeof email !== 'string') { return false; } - const re = - /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/; - return re.test(email); + return isEmail(email); }src/migrations/1752097876989-AddNewViewPreferences.ts (1)
6-22: Consider using a more efficient approach for multiple JSONB updates.The nested
jsonb_setoperations work but could be more readable. Consider using the||operator for merging JSONB objects.- UPDATE user_preferences - SET display = jsonb_set( - jsonb_set( - jsonb_set( - display, - '{defaultUpsView}', - '"grid"'::jsonb - ), - '{defaultRoomView}', - '"grid"'::jsonb - ), - '{defaultGroupView}', - '"grid"'::jsonb - ) - WHERE display IS NOT NULL + UPDATE user_preferences + SET display = display || '{"defaultUpsView": "grid", "defaultRoomView": "grid", "defaultGroupView": "grid"}'::jsonb + WHERE display IS NOT NULLsrc/modules/user-preferences/application/use-cases/reset-user-preferences.use-case.ts (3)
31-31: Fix unused variable issue.The
errorvariable is defined but never used in the catch block, as indicated by the static analysis tool.- } catch (error) { + } catch {
16-27: Consider optimizing the logic for existing preferences.The current approach creates a new default object and manually copies each field. Consider using a more maintainable approach that leverages the entity's reset method or spread operator.
if (!preferences) { preferences = UserPreference.createDefault(userId); } else { - const defaultPreferences = UserPreference.createDefault(userId); - preferences.locale = defaultPreferences.locale; - preferences.theme = defaultPreferences.theme; - preferences.timezone = defaultPreferences.timezone; - preferences.notifications = defaultPreferences.notifications; - preferences.display = defaultPreferences.display; - preferences.integrations = defaultPreferences.integrations; - preferences.performance = defaultPreferences.performance; + const defaultPreferences = UserPreference.createDefault(userId); + Object.assign(preferences, { + locale: defaultPreferences.locale, + theme: defaultPreferences.theme, + timezone: defaultPreferences.timezone, + notifications: defaultPreferences.notifications, + display: defaultPreferences.display, + integrations: defaultPreferences.integrations, + performance: defaultPreferences.performance, + }); }
29-33: Consider preserving the original error for debugging.While the domain exception is appropriate for the client, consider logging the original error for debugging purposes.
try { return await this.userPreferencesRepository.update(preferences); - } catch (error) { + } catch (error) { + // Log original error for debugging + console.error('Failed to reset user preferences:', error); throw UserPreferencesExceptions.failedToReset(); }src/modules/user-preferences/domain/entities/__tests__/user-preference.entity.spec.ts (1)
142-142: Fix formatting issue: missing newline at end of file.Add a newline at the end of the file to comply with formatting standards:
+src/modules/email/domain/exceptions/email.exception.ts (2)
3-11: Consider input sanitization for security.The email parameter is directly interpolated into the error message without sanitization, which could potentially lead to log injection or XSS if the error message is displayed in a web interface.
Consider sanitizing the email parameter before including it in the error message:
export class InvalidEmailAddressException extends BadRequestException { constructor(email: string) { + const sanitizedEmail = email.replace(/[<>]/g, ''); super({ statusCode: 400, - message: `Invalid email address: ${email}`, + message: `Invalid email address: ${sanitizedEmail}`, error: 'InvalidEmailAddress', }); } }
13-24: Consider input sanitization for security.Similar to the previous exception, the email parameter is directly interpolated into the error message without sanitization.
Consider sanitizing the email parameter before including it in the error message:
export class EmailSendFailedException extends BadRequestException { constructor(email: string, reason?: string) { + const sanitizedEmail = email.replace(/[<>]/g, ''); - const baseMessage = `Failed to send email to ${email}`; + const baseMessage = `Failed to send email to ${sanitizedEmail}`; const fullMessage = reason ? `${baseMessage}: ${reason}` : baseMessage; super({ statusCode: 400, message: fullMessage, error: 'EmailSendFailed', }); } }src/modules/user-preferences/application/use-cases/get-user-preferences.use-case.ts (4)
4-4: Remove unused import.The
UserPreferencesExceptionsimport is not used in this file and should be removed.-import { UserPreferencesExceptions } from '../../domain/exceptions/user-preferences.exception';
14-14: Fix formatting: add proper line break.- const preferences = await this.userPreferencesRepository.findByUserId(userId); + const preferences = await this.userPreferencesRepository.findByUserId( + userId, + );
23-23: Fix formatting: add newline at end of file.} +
13-22: Consider adding error handling for repository operations.The use case doesn't handle potential errors from repository operations. While the repository interface doesn't specify thrown exceptions, database operations can fail.
Consider wrapping repository calls in try-catch blocks and throwing appropriate domain exceptions:
async execute(userId: string): Promise<UserPreference> { + try { const preferences = await this.userPreferencesRepository.findByUserId(userId); if (!preferences) { const defaultPreferences = UserPreference.createDefault(userId); return await this.userPreferencesRepository.create(defaultPreferences); } return preferences; + } catch (error) { + throw UserPreferencesExceptions.failedToRetrieve(); + } }Note: This would require keeping the
UserPreferencesExceptionsimport and ensuring thefailedToRetrievemethod exists.src/modules/user-preferences/user-preferences.module.ts (1)
12-28: Fix formatting issues in the module configuration.The module structure is solid and follows NestJS best practices, but there are formatting issues that need to be addressed.
exports: [ - 'IUserPreferencesRepository', - GetUserPreferencesUseCase, + 'IUserPreferencesRepository', GetUserPreferencesUseCase ], -}) +})src/core/filters/global-exception.filter.ts (2)
23-29: Improve type safety for exception response handling.The current implementation uses
anytype assertion which could be improved for better type safety.if (exception instanceof HttpException) { status = exception.getStatus(); const exceptionResponse = exception.getResponse(); message = typeof exceptionResponse === 'string' ? exceptionResponse - : (exceptionResponse as any).message || exception.message; + : (exceptionResponse as { message?: string }).message || exception.message; }
32-32: Fix formatting issues.Address the prettier formatting issues flagged by static analysis.
} else if (exception instanceof Error) { message = exception.message; - + if (process.env.NODE_ENV !== 'production') {}); - } + }Also applies to: 50-50
src/modules/auth/application/dto/reset-password-with-token.dto.ts (1)
21-38: Improve the custom validation message implementation.The password validation is comprehensive, but the custom message function could be more robust and cleaner.
@IsStrongPassword( { minLength: 8, minUppercase: 1, minLowercase: 1, minNumbers: 1, minSymbols: 1, }, { - message: (args) => { - return ( - `Le mot de passe doit contenir au moins ${args.constraints[0].minLength} caractères, ` + - `${args.constraints[0].minUppercase} majuscule(s), ${args.constraints[0].minLowercase} minuscule(s), ` + - `${args.constraints[0].minNumbers} chiffre(s), et ${args.constraints[0].minSymbols} symbole(s).` - ); - }, + message: 'Le mot de passe doit contenir au moins 8 caractères, 1 majuscule, 1 minuscule, 1 chiffre, et 1 symbole.', }, )src/modules/email/application/use-cases/send-reset-password-email.use-case.ts (2)
20-20: Make the email subject configurable for internationalization.The French subject line is hardcoded, which limits the application's ability to support multiple languages. Consider making this configurable through a localization service or configuration.
- dto.subject = 'Réinitialisation de votre mot de passe'; + dto.subject = this.configService.get('EMAIL_RESET_PASSWORD_SUBJECT') || 'Réinitialisation de votre mot de passe';
26-30: Consider making date/time locale configurable.The date and time formatting is hardcoded to French locale (
'fr-FR'), which may not be appropriate for all users. Consider making this configurable based on user preferences or application settings.- requestDate: new Date().toLocaleDateString('fr-FR'), - requestTime: new Date().toLocaleTimeString('fr-FR', { - hour: '2-digit', - minute: '2-digit', - }), + requestDate: new Date().toLocaleDateString(locale || 'fr-FR'), + requestTime: new Date().toLocaleTimeString(locale || 'fr-FR', { + hour: '2-digit', + minute: '2-digit', + }),src/modules/user-preferences/infrastructure/repositories/__tests__/user-preferences.repository.spec.ts (2)
28-29: Fix formatting issues identified by ESLint.The static analysis tool identified formatting issues that should be addressed for consistency.
Apply this formatting fix:
- repository = module.get<UserPreferencesRepository>(UserPreferencesRepository); + repository = module.get<UserPreferencesRepository>( + UserPreferencesRepository, + );
111-111: Add missing newline at end of file.The static analysis tool detected a missing newline at the end of the file.
}); +src/migrations/1752086121427-CreateUserPreferencesTable.ts (1)
1-1: Fix import formatting.The imports should be formatted with proper line breaks for better readability.
-import { MigrationInterface, QueryRunner, Table, TableForeignKey } from 'typeorm'; +import { + MigrationInterface, + QueryRunner, + Table, + TableForeignKey, +} from 'typeorm';src/modules/user-preferences/application/use-cases/__tests__/update-user-preferences.use-case.spec.ts (1)
284-284: Add missing newline at end of file.}); +src/modules/user-preferences/application/use-cases/__tests__/reset-user-preferences.use-case.spec.ts (1)
194-194: Fix formatting issue.Add a newline at the end of the file as indicated by the linter.
}); +src/modules/email/infrastructure/listeners/email-event.listener.ts (1)
74-75: Consider adding more specific error handling.While the current error handling is adequate, consider adding more specific error types or additional context to help with debugging email delivery issues.
} catch (error) { this.logger.error( `Failed to send password reset email to ${payload.email}`, { error: error.message, stack: error.stack, resetLink: payload.resetLink, }, ); }src/modules/user-preferences/application/use-cases/update-user-preferences.use-case.ts (1)
54-71: Fix formatting issues in integrations handling.The integrations logic is sound but has formatting issues. The pattern of clearing values with
|| undefinedis appropriate for webhook URLs and email fields.if (updateDto.integrations.slackWebhook !== undefined) { - integrations.slackWebhook = updateDto.integrations.slackWebhook || undefined; + integrations.slackWebhook = + updateDto.integrations.slackWebhook || undefined; } if (updateDto.integrations.discordWebhook !== undefined) { - integrations.discordWebhook = updateDto.integrations.discordWebhook || undefined; + integrations.discordWebhook = + updateDto.integrations.discordWebhook || undefined; } if (updateDto.integrations.teamsWebhook !== undefined) { - integrations.teamsWebhook = updateDto.integrations.teamsWebhook || undefined; + integrations.teamsWebhook = + updateDto.integrations.teamsWebhook || undefined; } if (updateDto.integrations.alertEmail !== undefined) { - integrations.alertEmail = updateDto.integrations.alertEmail || undefined; + integrations.alertEmail = + updateDto.integrations.alertEmail || undefined; }src/modules/email/application/use-cases/send-password-changed-email.use-case.ts (1)
27-31: Consider making date formatting configurable.The hardcoded French locale formatting is functional but could be made more flexible for internationalization.
// Consider making locale configurable const locale = 'fr-FR'; // Could be injected or from user preferences dto.context = { prenom: firstName, email, changeDate: new Date().toLocaleDateString(locale), changeTime: new Date().toLocaleTimeString(locale, { hour: '2-digit', minute: '2-digit', }), // ... rest of context };src/core/guards/__tests__/password-reset-rate-limit.guard.spec.ts (1)
118-132: Fix formatting issues identified by static analysis.ESLint has identified several formatting issues that need to be addressed for code consistency.
Apply this diff to fix the formatting:
- + // Check that rate limit headers are set const headers = mockResponse.setHeader.mock.calls; const limitHeader = headers.find((call) => call[0] === 'RateLimit-Limit'); - const remainingHeader = headers.find((call) => call[0] === 'RateLimit-Remaining'); + const remainingHeader = headers.find( + (call) => call[0] === 'RateLimit-Remaining', + ); expect(limitHeader).toBeDefined(); expect(remainingHeader).toBeDefined(); expect(limitHeader[1]).toBeDefined(); expect(remainingHeader[1]).toBeDefined(); process.env.NODE_ENV = originalEnv; }); }); -}); +}); +src/core/decorators/rate-limit.decorator.ts (1)
30-42: Reasonable default configurations for rate limiting.The predefined configurations are well-balanced for security:
- Password reset: 3 attempts per hour (appropriate for security-sensitive operations)
- Login: 5 attempts per 15 minutes (balances security with user experience)
The French error messages are consistent with the application's localization.
Fix the formatting issues identified by static analysis:
login: { limit: 5, window: 900, // 15 minutes errorMessage: 'Trop de tentatives de connexion. Veuillez réessayer plus tard.', }, -} as const; +} as const; +src/modules/roles/domain/services/__tests__/safe-role-deletion.domain.service.spec.ts (1)
319-335: Proper error handling test for permission deletion failures.The test correctly verifies that permission deletion failures prevent role deletion and propagate the error appropriately, maintaining data integrity.
Fix the formatting issues identified by static analysis:
- permissionVmRepo.deleteByRoleId.mockRejectedValue(new Error('Delete failed')); + permissionVmRepo.deleteByRoleId.mockRejectedValue( + new Error('Delete failed'), + ); - await expect(service.safelyDeleteRole(roleId)).rejects.toThrow('Delete failed'); + await expect(service.safelyDeleteRole(roleId)).rejects.toThrow( + 'Delete failed', + );src/modules/user-preferences/domain/exceptions/user-preferences.exception.ts (2)
3-45: Consider refactoring to use simple functions instead of a static-only class.Following the static analysis hint, this class with only static members could be refactored to use simple exported functions, which would be more idiomatic and easier to import selectively.
-export class UserPreferencesExceptions { - static notFound(): NotFoundException { - return new NotFoundException('User preferences not found'); - } - - static invalidTimezone(timezone: string): BadRequestException { - return new BadRequestException(`Invalid timezone: ${timezone}`); - } +export const notFoundException = (): NotFoundException => + new NotFoundException('User preferences not found'); + +export const invalidTimezoneException = (timezone: string): BadRequestException => + new BadRequestException(`Invalid timezone: ${timezone}`);
5-44: Consider using French for exception messages for consistency.The exception messages are in English while the email template suggests the application is primarily in French. Consider localizing these messages for consistency.
- return new NotFoundException('User preferences not found'); + return new NotFoundException('Préférences utilisateur introuvables');src/core/guards/password-reset-rate-limit.guard.ts (1)
38-55: Fix formatting issues for consistency.Multiple formatting issues need to be addressed for code consistency.
windowMs: parseEnvInt( process.env.RATE_LIMIT_PASSWORD_RESET_WINDOW_MS, 3600000, // 1 hour default - 60000, // 1 minute minimum - 86400000 // 24 hours maximum + 60000, // 1 minute minimum + 86400000, // 24 hours maximum ), max: parseEnvInt( process.env.RATE_LIMIT_PASSWORD_RESET_MAX, 3, // 3 attempts default - 1, // 1 attempt minimum - 10 // 10 attempts maximum + 1, // 1 attempt minimum + 10, // 10 attempts maximum ), message: { - error: 'Trop de tentatives de réinitialisation de mot de passe. Veuillez réessayer dans une heure.', + error: + 'Trop de tentatives de réinitialisation de mot de passe. Veuillez réessayer dans une heure.', statusCode: 429, },src/modules/user-preferences/domain/exceptions/__tests__/user-preferences.exception.spec.ts (1)
1-128: LGTM: Comprehensive test coverage for exception handling.The test suite thoroughly validates all exception methods in the
UserPreferencesExceptionsclass:
- Correct exception types are returned
- Error messages are properly formatted with dynamic content
- Edge cases are tested (e.g., different refresh interval values)
- The final test ensures all exceptions implement the NestJS HTTP exception interface
Please fix the prettier formatting issues identified by ESLint:
const exception = UserPreferencesExceptions.invalidRefreshInterval(interval); expect(exception).toBeInstanceOf(BadRequestException); expect(exception.message).toBe( - `Refresh interval must be between 15 and 300 seconds. Got: ${interval}`, + `Refresh interval must be between 15 and 300 seconds. Got: ${interval}`, );Apply similar formatting fixes to lines 37, 50, and add a newline at the end of the file.
src/modules/user-preferences/application/controllers/__tests__/user-preferences.controller.spec.ts (2)
1-12: Fix unused import issue.The
UserPreferencesResponseDtois imported but never used in the tests.Remove the unused import:
-import { UserPreferencesResponseDto } from '../../dto/user-preferences-response.dto';The tests don't explicitly use this DTO class as they're testing the controller's response transformation directly.
13-279: LGTM: Comprehensive test coverage for user preferences controller.The test suite excellently covers:
- All controller methods (get, update, reset)
- Proper mock setup and dependency injection
- Response DTO structure validation
- Partial updates for nested objects
- Edge cases like integrations and reset behavior
- Proper use case invocation verification
The tests demonstrate good practices with clear arrange-act-assert structure and meaningful test names.
Add a newline at the end of the file to fix the prettier formatting issue.
src/modules/auth/application/use-cases/__tests__/forgot-password.use-case.spec.ts (1)
1-296: LGTM: Excellent test coverage for security-critical password reset functionality.The test suite demonstrates excellent practices for testing security-critical features:
- Security-first approach: Tests verify that generic responses are returned regardless of user existence
- Token security: Validates proper token generation (64-character hex), expiry (1 hour), and reuse logic
- Event-driven architecture: Confirms proper event emission for email notifications
- Logging: Verifies comprehensive audit logging for security events
- Error handling: Tests graceful handling of database errors
The tests cover all critical paths and edge cases, including token reuse optimization and proper cleanup.
Please fix the prettier formatting issues identified by ESLint:
const userWithoutToken = { - ...mockUser, resetPasswordToken: null, resetPasswordExpiry: null + ...mockUser, + resetPasswordToken: null, + resetPasswordExpiry: null, };Apply similar formatting fixes to lines 170, 196, 273, and remove extra spaces on lines 219, 225, 250, 256.
src/modules/user-preferences/application/dto/user-preferences-response.dto.ts (1)
78-120: Fix formatting issue and verify the response structure.The main UserPreferencesResponseDto aggregates all sub-DTOs correctly and includes proper metadata fields.
Fix the formatting issue flagged by ESLint:
@ApiProperty({ description: 'Last update date' }) updatedAt: Date; -} +} +src/modules/user-preferences/application/dto/update-user-preferences.dto.ts (2)
1-16: Remove unused import and improve validation completeness.The imports are comprehensive but there's an unused import that should be removed.
Fix the unused import:
import { IsOptional, IsEnum, IsString, IsBoolean, IsNumber, Min, Max, IsUrl, IsEmail, ValidateNested, MaxLength, - IsIn, } from 'class-validator';
164-187: Fix formatting issue and verify nested validation.The nested validation structure is properly implemented with ValidateNested decorators and Type transformations.
Fix the formatting issue:
@Type(() => UpdatePerformanceDto) performance?: UpdatePerformanceDto; -} +} +
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yamlsrc/modules/email/infrastructures/assets/upstra-logo.pngis excluded by!**/*.png
📒 Files selected for processing (107)
.env.prod.example(1 hunks)README.md(5 hunks)infra(1 hunks)jest.email.config.js(1 hunks)nest-cli.json(1 hunks)package.json(3 hunks)src/app.module.ts(3 hunks)src/core/decorators/rate-limit.decorator.ts(1 hunks)src/core/filters/__tests__/global-exception.filter.spec.ts(1 hunks)src/core/filters/global-exception.filter.ts(1 hunks)src/core/filters/index.ts(1 hunks)src/core/guards/__tests__/password-reset-rate-limit.guard.spec.ts(1 hunks)src/core/guards/password-reset-rate-limit.guard.ts(1 hunks)src/migrations/1752061749877-AddResetPasswordFields.ts(1 hunks)src/migrations/1752086121427-CreateUserPreferencesTable.ts(1 hunks)src/migrations/1752097876989-AddNewViewPreferences.ts(1 hunks)src/modules/auth/application/controllers/auth.controller.spec.ts(4 hunks)src/modules/auth/application/controllers/auth.controller.ts(3 hunks)src/modules/auth/application/dto/__tests__/forgot-password.dto.spec.ts(1 hunks)src/modules/auth/application/dto/__tests__/reset-password-with-token.dto.spec.ts(1 hunks)src/modules/auth/application/dto/forgot-password.dto.ts(1 hunks)src/modules/auth/application/dto/index.ts(1 hunks)src/modules/auth/application/dto/reset-password-with-token.dto.ts(1 hunks)src/modules/auth/application/use-cases/__tests__/forgot-password.use-case.spec.ts(1 hunks)src/modules/auth/application/use-cases/__tests__/register.use-case.spec.ts(4 hunks)src/modules/auth/application/use-cases/__tests__/reset-password-with-token.use-case.spec.ts(1 hunks)src/modules/auth/application/use-cases/forgot-password.use-case.ts(1 hunks)src/modules/auth/application/use-cases/index.ts(3 hunks)src/modules/auth/application/use-cases/register.use-case.ts(3 hunks)src/modules/auth/application/use-cases/reset-password-with-token.use-case.ts(1 hunks)src/modules/auth/auth.module.ts(2 hunks)src/modules/auth/domain/interfaces/extended-jwt-payload.interface.ts(1 hunks)src/modules/email/__tests__/email.module.spec.ts(1 hunks)src/modules/email/adapters/__tests__/zoho-mail.adapter.spec.ts(1 hunks)src/modules/email/adapters/zoho-mail.adapter.ts(1 hunks)src/modules/email/application/__tests__/email-application.module.spec.ts(1 hunks)src/modules/email/application/dto/__tests__/send-email.dto.spec.ts(1 hunks)src/modules/email/application/dto/send-email.dto.ts(1 hunks)src/modules/email/application/email-application.module.ts(1 hunks)src/modules/email/application/use-cases/__tests__/send-account-created-email.use-case.spec.ts(1 hunks)src/modules/email/application/use-cases/__tests__/send-password-changed-email.use-case.spec.ts(1 hunks)src/modules/email/application/use-cases/__tests__/send-reset-password-email.use-case.spec.ts(1 hunks)src/modules/email/application/use-cases/send-account-created-email.use-case.ts(1 hunks)src/modules/email/application/use-cases/send-password-changed-email.use-case.ts(1 hunks)src/modules/email/application/use-cases/send-reset-password-email.use-case.ts(1 hunks)src/modules/email/domain/constants/injection-tokens.ts(1 hunks)src/modules/email/domain/events/email.events.ts(1 hunks)src/modules/email/domain/exceptions/__tests__/email.exception.spec.ts(1 hunks)src/modules/email/domain/exceptions/email.exception.ts(1 hunks)src/modules/email/domain/services/mail.service.ts(1 hunks)src/modules/email/domain/value-objects/__tests__/email-address.vo.spec.ts(1 hunks)src/modules/email/domain/value-objects/email-address.vo.ts(1 hunks)src/modules/email/email.module.ts(1 hunks)src/modules/email/infrastructure/listeners/__tests__/email-event.listener.spec.ts(1 hunks)src/modules/email/infrastructure/listeners/email-event.listener.ts(1 hunks)src/modules/email/infrastructures/email-infrastructure.module.ts(1 hunks)src/modules/email/infrastructures/templates/README.md(1 hunks)src/modules/email/infrastructures/templates/account-created.hbs(1 hunks)src/modules/email/infrastructures/templates/password-changed.hbs(1 hunks)src/modules/email/infrastructures/templates/reset-password.hbs(1 hunks)src/modules/permissions/application/use-cases/permission-server/create-permission-server.use-case.ts(1 hunks)src/modules/permissions/application/use-cases/permission-vm/create-permission-vm.use-case.ts(1 hunks)src/modules/permissions/infrastructure/interfaces/permission.repository.interface.ts(1 hunks)src/modules/permissions/infrastructure/repositories/permission.server.repository.ts(2 hunks)src/modules/permissions/infrastructure/repositories/permission.vm.repository.ts(2 hunks)src/modules/roles/application/controllers/__tests__/role.controller.spec.ts(1 hunks)src/modules/roles/application/controllers/role.controller.ts(2 hunks)src/modules/roles/application/dto/index.ts(1 hunks)src/modules/roles/application/dto/update-user-roles.dto.ts(1 hunks)src/modules/roles/application/dto/user-with-presence.dto.ts(1 hunks)src/modules/roles/application/use-cases/__tests__/get-users-by-role.use-case.spec.ts(2 hunks)src/modules/roles/application/use-cases/__tests__/update-user-role.use-case.spec.ts(1 hunks)src/modules/roles/application/use-cases/__tests__/update-user-roles.use-case.spec.ts(18 hunks)src/modules/roles/application/use-cases/update-user-role.use-case.ts(1 hunks)src/modules/roles/application/use-cases/update-user-roles.use-case.ts(3 hunks)src/modules/roles/domain/exceptions/__tests__/role.exception.spec.ts(3 hunks)src/modules/roles/domain/services/__tests__/safe-role-deletion.domain.service.spec.ts(9 hunks)src/modules/roles/domain/services/safe-role-deletion.domain.service.ts(4 hunks)src/modules/roles/infrastructure/repositories/role.typeorm.repository.ts(1 hunks)src/modules/ssh/application/gateway/ssh.gateway.ts(1 hunks)src/modules/user-preferences/application/controllers/__tests__/user-preferences.controller.spec.ts(1 hunks)src/modules/user-preferences/application/controllers/user-preferences.controller.ts(1 hunks)src/modules/user-preferences/application/dto/update-user-preferences.dto.ts(1 hunks)src/modules/user-preferences/application/dto/user-preferences-response.dto.ts(1 hunks)src/modules/user-preferences/application/use-cases/__tests__/get-user-preferences.use-case.spec.ts(1 hunks)src/modules/user-preferences/application/use-cases/__tests__/reset-user-preferences.use-case.spec.ts(1 hunks)src/modules/user-preferences/application/use-cases/__tests__/update-user-preferences.use-case.spec.ts(1 hunks)src/modules/user-preferences/application/use-cases/get-user-preferences.use-case.ts(1 hunks)src/modules/user-preferences/application/use-cases/index.ts(1 hunks)src/modules/user-preferences/application/use-cases/reset-user-preferences.use-case.ts(1 hunks)src/modules/user-preferences/application/use-cases/update-user-preferences.use-case.ts(1 hunks)src/modules/user-preferences/domain/entities/__tests__/user-preference.entity.spec.ts(1 hunks)src/modules/user-preferences/domain/entities/user-preference.entity.ts(1 hunks)src/modules/user-preferences/domain/exceptions/__tests__/user-preferences.exception.spec.ts(1 hunks)src/modules/user-preferences/domain/exceptions/user-preferences.exception.ts(1 hunks)src/modules/user-preferences/domain/interfaces/user-preferences.repository.interface.ts(1 hunks)src/modules/user-preferences/domain/value-objects/__tests__/timezone.validator.spec.ts(1 hunks)src/modules/user-preferences/domain/value-objects/timezone.validator.ts(1 hunks)src/modules/user-preferences/infrastructure/repositories/__tests__/user-preferences.repository.spec.ts(1 hunks)src/modules/user-preferences/infrastructure/repositories/user-preferences.repository.ts(1 hunks)src/modules/user-preferences/user-preferences.module.ts(1 hunks)src/modules/users/application/controllers/__tests__/user.controller.delete-account.spec.ts(2 hunks)src/modules/users/application/controllers/__tests__/user.controller.reset-password.spec.ts(1 hunks)src/modules/users/application/controllers/__tests__/user.controller.toggle-status.spec.ts(2 hunks)src/modules/users/application/controllers/user.controller.spec.ts(3 hunks)src/modules/users/application/controllers/user.controller.ts(3 hunks)src/modules/users/application/dto/__tests__/user.create.dto.spec.ts(1 hunks)
⛔ Files not processed due to max files limit (17)
- src/modules/users/application/dto/user.create.dto.ts
- src/modules/users/application/use-cases/tests/bulk-activate.use-case.spec.ts
- src/modules/users/application/use-cases/tests/create-user-by-admin.use-case.spec.ts
- src/modules/users/application/use-cases/tests/get-user-by-email.use-case.spec.ts
- src/modules/users/application/use-cases/tests/get-user-by-username.use-case.spec.ts
- src/modules/users/application/use-cases/tests/reset-password.use-case.spec.ts
- src/modules/users/application/use-cases/tests/toggle-user-status.use-case.spec.ts
- src/modules/users/application/use-cases/tests/update-account.use-case.spec.ts
- src/modules/users/application/use-cases/tests/update-user.use-case.spec.ts
- src/modules/users/application/use-cases/create-user-by-admin.use-case.ts
- src/modules/users/application/use-cases/register-user.use-case.ts
- src/modules/users/application/use-cases/reset-password.use-case.ts
- src/modules/users/application/use-cases/update-account.use-case.ts
- src/modules/users/domain/entities/user.entity.ts
- src/modules/users/domain/services/user.domain.service.spec.ts
- src/modules/users/infrastructure/repositories/user.typeorm.repository.ts
- src/modules/users/user.module.ts
🧰 Additional context used
🧬 Code Graph Analysis (31)
src/modules/roles/application/use-cases/__tests__/get-users-by-role.use-case.spec.ts (1)
src/modules/roles/__mocks__/role.mock.ts (1)
createMockRole(7-19)
src/modules/auth/auth.module.ts (2)
src/modules/email/email.module.ts (1)
Module(6-11)src/modules/auth/application/use-cases/index.ts (1)
AuthUseCases(12-23)
src/modules/users/application/controllers/__tests__/user.controller.toggle-status.spec.ts (1)
src/modules/users/application/use-cases/index.ts (1)
CreateUserByAdminUseCase(55-55)
src/modules/email/infrastructures/email-infrastructure.module.ts (2)
src/modules/email/email.module.ts (1)
Module(6-11)src/modules/email/application/email-application.module.ts (1)
Module(9-26)
src/modules/email/domain/services/mail.service.ts (1)
src/modules/email/application/dto/send-email.dto.ts (1)
SendEmailDto(3-8)
src/modules/email/domain/exceptions/__tests__/email.exception.spec.ts (1)
src/modules/email/domain/exceptions/email.exception.ts (2)
InvalidEmailAddressException(3-11)EmailSendFailedException(13-24)
src/modules/user-preferences/domain/value-objects/__tests__/timezone.validator.spec.ts (1)
src/modules/user-preferences/domain/value-objects/timezone.validator.ts (2)
validateTimezone(33-35)getValidTimezones(37-39)
src/modules/email/domain/value-objects/email-address.vo.ts (1)
src/modules/email/domain/exceptions/email.exception.ts (1)
InvalidEmailAddressException(3-11)
src/modules/user-preferences/user-preferences.module.ts (1)
src/app.module.ts (1)
Module(32-65)
src/modules/email/application/__tests__/email-application.module.spec.ts (2)
src/modules/email/domain/services/mail.service.ts (1)
IMailService(3-9)src/modules/email/domain/constants/injection-tokens.ts (1)
MAIL_SERVICE_TOKEN(1-1)
src/modules/user-preferences/application/use-cases/__tests__/update-user-preferences.use-case.spec.ts (3)
src/modules/user-preferences/domain/interfaces/user-preferences.repository.interface.ts (1)
IUserPreferencesRepository(3-8)src/modules/user-preferences/application/dto/update-user-preferences.dto.ts (1)
UpdateUserPreferencesDto(136-187)src/modules/user-preferences/domain/exceptions/user-preferences.exception.ts (1)
UserPreferencesExceptions(3-45)
src/modules/auth/application/dto/__tests__/forgot-password.dto.spec.ts (2)
src/modules/auth/application/dto/forgot-password.dto.ts (1)
ForgotPasswordDto(4-13)src/modules/auth/application/dto/index.ts (1)
ForgotPasswordDto(15-15)
src/modules/user-preferences/application/use-cases/get-user-preferences.use-case.ts (4)
src/modules/user-preferences/application/use-cases/reset-user-preferences.use-case.ts (1)
Injectable(6-35)src/modules/user-preferences/infrastructure/repositories/user-preferences.repository.ts (1)
Injectable(7-29)src/modules/user-preferences/application/use-cases/update-user-preferences.use-case.ts (1)
Injectable(8-86)src/modules/user-preferences/domain/interfaces/user-preferences.repository.interface.ts (1)
IUserPreferencesRepository(3-8)
src/modules/roles/domain/services/safe-role-deletion.domain.service.ts (2)
src/modules/permissions/infrastructure/interfaces/permission.vm.repository.interface.ts (1)
PermissionVmRepositoryInterface(4-5)src/modules/permissions/infrastructure/interfaces/permission.server.repository.interface.ts (1)
PermissionServerRepositoryInterface(4-7)
src/modules/email/application/dto/send-email.dto.ts (1)
src/modules/email/domain/value-objects/email-address.vo.ts (1)
EmailAddressVO(3-33)
src/modules/email/application/use-cases/__tests__/send-account-created-email.use-case.spec.ts (4)
src/modules/email/domain/services/mail.service.ts (1)
IMailService(3-9)src/modules/email/domain/constants/injection-tokens.ts (1)
MAIL_SERVICE_TOKEN(1-1)src/modules/email/application/dto/send-email.dto.ts (1)
SendEmailDto(3-8)src/modules/email/domain/exceptions/email.exception.ts (1)
InvalidEmailAddressException(3-11)
src/modules/roles/domain/services/__tests__/safe-role-deletion.domain.service.spec.ts (3)
src/modules/permissions/infrastructure/interfaces/permission.vm.repository.interface.ts (1)
PermissionVmRepositoryInterface(4-5)src/modules/permissions/infrastructure/interfaces/permission.server.repository.interface.ts (1)
PermissionServerRepositoryInterface(4-7)src/modules/roles/__mocks__/role.mock.ts (1)
createMockRole(7-19)
src/modules/user-preferences/application/use-cases/reset-user-preferences.use-case.ts (4)
src/modules/user-preferences/application/use-cases/get-user-preferences.use-case.ts (1)
Injectable(6-23)src/modules/user-preferences/infrastructure/repositories/user-preferences.repository.ts (1)
Injectable(7-29)src/modules/user-preferences/domain/interfaces/user-preferences.repository.interface.ts (1)
IUserPreferencesRepository(3-8)src/modules/user-preferences/domain/exceptions/user-preferences.exception.ts (1)
UserPreferencesExceptions(3-45)
src/modules/user-preferences/application/use-cases/__tests__/reset-user-preferences.use-case.spec.ts (2)
src/modules/user-preferences/domain/interfaces/user-preferences.repository.interface.ts (1)
IUserPreferencesRepository(3-8)src/modules/user-preferences/domain/exceptions/user-preferences.exception.ts (1)
UserPreferencesExceptions(3-45)
src/modules/email/domain/value-objects/__tests__/email-address.vo.spec.ts (2)
src/modules/email/domain/value-objects/email-address.vo.ts (1)
EmailAddressVO(3-33)src/modules/email/domain/exceptions/email.exception.ts (1)
InvalidEmailAddressException(3-11)
src/modules/user-preferences/application/use-cases/__tests__/get-user-preferences.use-case.spec.ts (1)
src/modules/user-preferences/domain/interfaces/user-preferences.repository.interface.ts (1)
IUserPreferencesRepository(3-8)
src/modules/email/application/use-cases/__tests__/send-password-changed-email.use-case.spec.ts (4)
src/modules/email/domain/services/mail.service.ts (1)
IMailService(3-9)src/modules/email/domain/constants/injection-tokens.ts (1)
MAIL_SERVICE_TOKEN(1-1)src/modules/email/application/dto/send-email.dto.ts (1)
SendEmailDto(3-8)src/modules/email/domain/exceptions/email.exception.ts (1)
InvalidEmailAddressException(3-11)
src/modules/email/application/dto/__tests__/send-email.dto.spec.ts (2)
src/modules/email/application/dto/send-email.dto.ts (1)
SendEmailDto(3-8)src/modules/email/domain/value-objects/email-address.vo.ts (1)
EmailAddressVO(3-33)
src/modules/email/application/use-cases/__tests__/send-reset-password-email.use-case.spec.ts (4)
src/modules/email/domain/services/mail.service.ts (1)
IMailService(3-9)src/modules/email/domain/constants/injection-tokens.ts (1)
MAIL_SERVICE_TOKEN(1-1)src/modules/email/application/dto/send-email.dto.ts (1)
SendEmailDto(3-8)src/modules/email/domain/exceptions/email.exception.ts (1)
InvalidEmailAddressException(3-11)
src/modules/users/application/controllers/user.controller.spec.ts (2)
src/modules/users/application/use-cases/create-user-by-admin.use-case.ts (1)
CreateUserByAdminUseCase(22-87)src/core/types/jwt-payload.interface.ts (1)
JwtPayload(1-4)
src/modules/auth/application/dto/__tests__/reset-password-with-token.dto.spec.ts (1)
src/modules/auth/application/dto/reset-password-with-token.dto.ts (1)
ResetPasswordWithTokenDto(4-40)
src/modules/user-preferences/application/use-cases/update-user-preferences.use-case.ts (7)
src/modules/user-preferences/application/use-cases/get-user-preferences.use-case.ts (1)
Injectable(6-23)src/modules/user-preferences/application/use-cases/reset-user-preferences.use-case.ts (1)
Injectable(6-35)src/modules/user-preferences/infrastructure/repositories/user-preferences.repository.ts (1)
Injectable(7-29)src/modules/user-preferences/domain/interfaces/user-preferences.repository.interface.ts (1)
IUserPreferencesRepository(3-8)src/modules/user-preferences/application/dto/update-user-preferences.dto.ts (1)
UpdateUserPreferencesDto(136-187)src/modules/user-preferences/domain/value-objects/timezone.validator.ts (1)
validateTimezone(33-35)src/modules/user-preferences/domain/exceptions/user-preferences.exception.ts (1)
UserPreferencesExceptions(3-45)
src/modules/auth/application/controllers/auth.controller.spec.ts (2)
src/modules/auth/application/use-cases/index.ts (2)
ForgotPasswordUseCase(34-34)ResetPasswordWithTokenUseCase(35-35)src/modules/auth/application/dto/index.ts (2)
ForgotPasswordDto(15-15)ResetPasswordWithTokenDto(16-16)
src/modules/user-preferences/application/controllers/user-preferences.controller.ts (3)
src/modules/user-preferences/application/dto/user-preferences-response.dto.ts (1)
UserPreferencesResponseDto(78-120)src/core/decorators/current-user.decorator.ts (1)
CurrentUser(3-9)src/modules/user-preferences/application/dto/update-user-preferences.dto.ts (1)
UpdateUserPreferencesDto(136-187)
src/modules/auth/application/controllers/auth.controller.ts (3)
src/modules/auth/application/use-cases/index.ts (2)
ForgotPasswordUseCase(34-34)ResetPasswordWithTokenUseCase(35-35)src/modules/auth/application/dto/forgot-password.dto.ts (1)
ForgotPasswordDto(4-13)src/modules/auth/application/dto/reset-password-with-token.dto.ts (1)
ResetPasswordWithTokenDto(4-40)
src/modules/user-preferences/domain/exceptions/__tests__/user-preferences.exception.spec.ts (1)
src/modules/user-preferences/domain/exceptions/user-preferences.exception.ts (1)
UserPreferencesExceptions(3-45)
🪛 LanguageTool
README.md
[uncategorized] ~161-~161: La lettre x peut être remplacée par un autre signe typographique.
Context: ...r créer un nouveau template, ajoutez un xxx.hbs et un SendXxxEmailUseCase. ### 📊 ...
(ASTERISQUE)
[uncategorized] ~178-~178: Les deux-points sont précédés d’une espace insécable.
Context: ...des métriques personnalisées dans votre code: ```typescript import { Counter, Histog...
(FRENCH_WHITESPACE)
[uncategorized] ~308-~308: Vérifiez la concordance de « automatiques » avec les noms précédents.
Context: ...S et clickjacking - Headers de sécurité automatiques ### ⚡ Rate Limiting Intelligent - **R...
(AGREEMENT_POSTPONED_ADJ)
src/modules/email/infrastructures/templates/README.md
[uncategorized] ~5-~5: Le trait d’union doit être supprimé.
Context: ...ation ## Templates disponibles ### 1. account-created.hbs Email de bienvenue envoyé lors de l...
(MOT_TRAIT_MOT)
[typographical] ~8-~8: Le trait d’union est employé sans espaces pour former des mots, alors que le tiret est encadré par des espaces et placé entre deux mots distincts.
Context: ...tion d'un compte. Variables requises : - {{prenom}} - Prénom de l'utilisateur - {{email}} -...
(TIRET)
[style] ~9-~9: Un tiret long ou un autre signe de ponctuation plus approprié, car le trait d’union ne s’utilise que pour former un mot.
Context: ...quises :** - {{prenom}} - Prénom de l'utilisateur - {{email}} - Email de l'utilisateur - {{loginUrl}} - URL...
(TIRET_LONG_1)
[style] ~10-~10: Un tiret long ou un autre signe de ponctuation plus approprié, car le trait d’union ne s’utilise que pour former un mot.
Context: ...'utilisateur - {{email}} - Email de l'utilisateur - {{loginUrl}} - URL de connexion à l'application ### 2. pa...
(TIRET_LONG_1)
[uncategorized] ~13-~13: Le trait d’union doit être supprimé.
Context: ...RL de connexion à l'application ### 2. password-changed.hbs Notification envoyée lors d'un chan...
(MOT_TRAIT_MOT)
[typographical] ~16-~16: Le trait d’union est employé sans espaces pour former des mots, alors que le tiret est encadré par des espaces et placé entre deux mots distincts.
Context: ... de mot de passe. Variables requises : - {{prenom}} - Prénom de l'utilisateur - {{email}} -...
(TIRET)
[style] ~17-~17: Un tiret long ou un autre signe de ponctuation plus approprié, car le trait d’union ne s’utilise que pour former un mot.
Context: ...quises :** - {{prenom}} - Prénom de l'utilisateur - {{email}} - Email de l'utilisateur - {{changeDate}} - D...
(TIRET_LONG_1)
[style] ~18-~18: Un tiret long ou un autre signe de ponctuation plus approprié, car le trait d’union ne s’utilise que pour former un mot.
Context: ...'utilisateur - {{email}} - Email de l'utilisateur - {{changeDate}} - Date du changement (format: JJ/MM/AAAA) - `{...
(TIRET_LONG_1)
[uncategorized] ~19-~19: Les deux-points sont précédés d’une espace insécable.
Context: ... {{changeDate}} - Date du changement (format: JJ/MM/AAAA) - {{changeTime}} - Heure ...
(FRENCH_WHITESPACE)
[typographical] ~19-~19: Ce signe est un trait d’union, il ne sert qu’à former des mots composés. Employez un tiret ou un autre signe de ponctuation plus approprié.
Context: ...- Date du changement (format: JJ/MM/AAAA) - {{changeTime}} - Heure du changement (format: HH:MM) - `{{logi...
(TIRET)
[uncategorized] ~20-~20: Les deux-points sont précédés d’une espace insécable.
Context: ...{{changeTime}} - Heure du changement (format: HH:MM) - {{loginUrl}} - URL de connex...
(FRENCH_WHITESPACE)
[typographical] ~20-~20: Une espace est requise.
Context: ...ime}}- Heure du changement (format: HH:MM) -{{loginUrl}}` - URL de connexion ...
(DEUX_POINTS_ESPACE)
[typographical] ~20-~20: Ce signe est un trait d’union, il ne sert qu’à former des mots composés. Employez un tiret ou un autre signe de ponctuation plus approprié.
Context: ...}}- Heure du changement (format: HH:MM) -{{loginUrl}}- URL de connexion à l'application -{{ipAdd...
(TIRET)
[style] ~21-~21: Un tiret long ou un autre signe de ponctuation plus approprié, car le trait d’union ne s’utilise que pour former un mot.
Context: ...- {{loginUrl}} - URL de connexion à l'application - {{ipAddress}} - Adresse IP d'où la modification a été effectuée...
(TIRET_LONG_1)
[style] ~22-~22: Un tiret long ou un autre signe de ponctuation plus approprié, car le trait d’union ne s’utilise que pour former un mot.
Context: ...- Adresse IP d'où la modification a été effectuée - {{userAgent}} - Navigateur utilisé - {{location}} - Localisation...
(TIRET_LONG_1)
[style] ~23-~23: Un tiret long ou un autre signe de ponctuation plus approprié, car le trait d’union ne s’utilise que pour former un mot.
Context: ...ffectuée - {{userAgent}} - Navigateur utilisé - {{location}} - Localisation approximative ### 3. reset-password.hb...
(TIRET_LONG_1)
[uncategorized] ~26-~26: Le trait d’union doit être supprimé.
Context: ...}` - Localisation approximative ### 3. reset-password.hbs Email de réinitialisation de mot de...
(MOT_TRAIT_MOT)
[typographical] ~29-~29: Le trait d’union est employé sans espaces pour former des mots, alors que le tiret est encadré par des espaces et placé entre deux mots distincts.
Context: ... de mot de passe. Variables requises : - {{prenom}} - Prénom de l'utilisateur - {{email}} -...
(TIRET)
[style] ~30-~30: Un tiret long ou un autre signe de ponctuation plus approprié, car le trait d’union ne s’utilise que pour former un mot.
Context: ...quises :** - {{prenom}} - Prénom de l'utilisateur - {{email}} - Email de l'utilisateur - {{requestDate}} - ...
(TIRET_LONG_1)
[style] ~31-~31: Un tiret long ou un autre signe de ponctuation plus approprié, car le trait d’union ne s’utilise que pour former un mot.
Context: ...'utilisateur - {{email}} - Email de l'utilisateur - {{requestDate}} - Date de la demande (format: JJ/MM/AAAA) - `{...
(TIRET_LONG_1)
[uncategorized] ~32-~32: Les deux-points sont précédés d’une espace insécable.
Context: ...{{requestDate}} - Date de la demande (format: JJ/MM/AAAA) - {{requestTime}} - Heure...
(FRENCH_WHITESPACE)
[typographical] ~32-~32: Ce signe est un trait d’union, il ne sert qu’à former des mots composés. Employez un tiret ou un autre signe de ponctuation plus approprié.
Context: ...- Date de la demande (format: JJ/MM/AAAA) - {{requestTime}} - Heure de la demande (format: HH:MM) **Variab...
(TIRET)
[uncategorized] ~33-~33: Les deux-points sont précédés d’une espace insécable.
Context: ...{{requestTime}}` - Heure de la demande (format: HH:MM) Variables conditionnelles :...
(FRENCH_WHITESPACE)
[typographical] ~33-~33: Une espace est requise.
Context: ...ime}}- Heure de la demande (format: HH:MM) **Variables conditionnelles :** -...
(DEUX_POINTS_ESPACE)
[typographical] ~35-~35: Le trait d’union est employé sans espaces pour former des mots, alors que le tiret est encadré par des espaces et placé entre deux mots distincts.
Context: ...at: HH:MM) Variables conditionnelles : - {{resetCode}} - Code de réinitialisation (si utilisé) -...
(TIRET)
[typographical] ~36-~36: Ce signe est un trait d’union, il ne sert qu’à former des mots composés. Employez un tiret ou un autre signe de ponctuation plus approprié.
Context: ...- Code de réinitialisation (si utilisé) -{{resetLink}}` - Lien de réinitialisation (si utilisé) ## De...
(TIRET)
[typographical] ~52-~52: Le trait d’union est employé sans espaces pour former des mots, alors que le tiret est encadré par des espaces et placé entre deux mots distincts.
Context: ...F2937 ### Typographie - Sans-serif : -apple-system, BlinkMacSystemFont, 'Segoe...
(TIRET)
[uncategorized] ~56-~56: Le trait d’union doit être supprimé.
Context: ...s templates sont optimisés pour mobile (max-width: 600px) - Support du mode sombre via `p...
(MOT_TRAIT_MOT)
[uncategorized] ~56-~56: Une espace doit être ajoutée entre ces deux mots ou intégrez ce nouveau mot à votre dictionnaire personnel.
Context: ... sont optimisés pour mobile (max-width: 600px) - Support du mode sombre via `prefers-...
(MOTS_COLLES3)
[style] ~59-~59: Alternatives possibles pour cet anglicisme :
Context: ...e sombre via prefers-color-scheme ## Assets Le logo PNG est disponible dans `/asset...
(FR_SIMPLE_REPLACE_ANGLICISM_PREMIUM_ASSETS)
[typographical] ~66-~66: Le trait d’union est employé sans espaces pour former des mots, alors que le tiret est encadré par des espaces et placé entre deux mots distincts.
Context: ...ailAdapter: **Variables automatiques :** -{{logoUrl}}- URL du logo Upstra (par défaut :${APP...
(TIRET)
[style] ~67-~67: Alternatives possibles pour cet anglicisme :
Context: ...l}}- URL du logo Upstra (par défaut :${APP_URL}/assets/upstra-logo.png) - {{loginUrl}}` - UR...
(FR_SIMPLE_REPLACE_ANGLICISM_PREMIUM_ASSETS)
[typographical] ~67-~67: Ce signe est un trait d’union, il ne sert qu’à former des mots composés. Employez un tiret ou un autre signe de ponctuation plus approprié.
Context: ...ut : ${APP_URL}/assets/upstra-logo.png) - {{loginUrl}} - URL de connexion à l'application (par défau...
(TIRET)
[typographical] ~68-~68: Caractère d’apostrophe incorrect.
Context: ...à l'application (par défaut : valeur de APP_URL) - {{currentYear}} - Année en cours p...
(APOS_INCORRECT)
[typographical] ~68-~68: Ce signe est un trait d’union, il ne sert qu’à former des mots composés. Employez un tiret ou un autre signe de ponctuation plus approprié.
Context: ...cation (par défaut : valeur de APP_URL) - {{currentYear}} - Année en cours pour le copyright **Variables...
(TIRET)
[style] ~82-~82: Alternatives possibles pour cet anglicisme :
Context: ... logo est automatiquement servi à l'URL /assets/upstra-logo.png grâce à la configurati...
(FR_SIMPLE_REPLACE_ANGLICISM_PREMIUM_ASSETS)
[typographical] ~82-~82: Caractère d’apostrophe incorrect.
Context: ...logo.pnggrâce à la configuration dansmain.ts`.
(APOS_INCORRECT)
🪛 markdownlint-cli2 (0.17.2)
README.md
151-151: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🪛 ESLint
src/modules/user-preferences/application/use-cases/index.ts
[error] 3-3: Insert ⏎
(prettier/prettier)
src/modules/user-preferences/domain/value-objects/timezone.validator.ts
[error] 39-39: Insert ⏎
(prettier/prettier)
src/core/filters/__tests__/global-exception.filter.spec.ts
[error] 12-12: Delete ····
(prettier/prettier)
[error] 17-17: Delete ····
(prettier/prettier)
[error] 21-21: Delete ····
(prettier/prettier)
[error] 32-32: Delete ····
(prettier/prettier)
[error] 34-34: Delete ····
(prettier/prettier)
[error] 49-49: Delete ····
(prettier/prettier)
[error] 51-51: Delete ····
(prettier/prettier)
[error] 63-63: Delete ····
(prettier/prettier)
[error] 65-65: Delete ····
(prettier/prettier)
[error] 79-79: Delete ····
(prettier/prettier)
[error] 81-81: Delete ····
(prettier/prettier)
[error] 96-96: Delete ····
(prettier/prettier)
[error] 99-99: Delete ····
(prettier/prettier)
[error] 101-101: Delete ····
(prettier/prettier)
[error] 106-106: Delete ····
(prettier/prettier)
[error] 113-113: Delete ····
(prettier/prettier)
[error] 116-116: Delete ····
(prettier/prettier)
[error] 118-118: Delete ····
(prettier/prettier)
[error] 124-124: Delete ····
(prettier/prettier)
[error] 127-127: Insert ⏎
(prettier/prettier)
src/modules/user-preferences/domain/value-objects/__tests__/timezone.validator.spec.ts
[error] 92-92: Insert ⏎
(prettier/prettier)
src/modules/user-preferences/user-preferences.module.ts
[error] 24-27: Replace ⏎····'IUserPreferencesRepository',⏎····GetUserPreferencesUseCase,⏎·· with 'IUserPreferencesRepository',·GetUserPreferencesUseCase
(prettier/prettier)
[error] 29-29: Insert ⏎
(prettier/prettier)
src/modules/user-preferences/domain/interfaces/user-preferences.repository.interface.ts
[error] 8-8: Insert ⏎
(prettier/prettier)
src/modules/user-preferences/application/use-cases/__tests__/update-user-preferences.use-case.spec.ts
[error] 284-284: Insert ⏎
(prettier/prettier)
src/modules/user-preferences/application/use-cases/get-user-preferences.use-case.ts
[error] 4-4: 'UserPreferencesExceptions' is defined but never used. Allowed unused vars must match /^_/u.
(@typescript-eslint/no-unused-vars)
[error] 4-4: 'UserPreferencesExceptions' is defined but never used.
(unused-imports/no-unused-imports)
[error] 14-14: Insert ⏎·····
(prettier/prettier)
[error] 23-23: Insert ⏎
(prettier/prettier)
src/modules/roles/domain/services/safe-role-deletion.domain.service.ts
[error] 103-103: Delete ······
(prettier/prettier)
src/modules/permissions/infrastructure/repositories/permission.server.repository.ts
[error] 112-112: Replace ``Deleted·all·server·permissions·for·role·${roleId},·result:,·result with `⏎······`Deleted·all·server·permissions·for·role·${roleId},·result:`,⏎······result,⏎····`
(prettier/prettier)
src/modules/roles/domain/services/__tests__/safe-role-deletion.domain.service.spec.ts
[error] 329-329: Replace new·Error('Delete·failed') with ⏎········new·Error('Delete·failed'),⏎······
(prettier/prettier)
[error] 331-331: Replace 'Delete·failed' with ⏎········'Delete·failed',⏎······
(prettier/prettier)
src/modules/user-preferences/domain/entities/__tests__/user-preference.entity.spec.ts
[error] 142-142: Insert ⏎
(prettier/prettier)
src/modules/user-preferences/application/use-cases/reset-user-preferences.use-case.ts
[error] 31-31: 'error' is defined but never used.
(@typescript-eslint/no-unused-vars)
[error] 35-35: Insert ⏎
(prettier/prettier)
src/modules/user-preferences/application/use-cases/__tests__/reset-user-preferences.use-case.spec.ts
[error] 194-194: Insert ⏎
(prettier/prettier)
src/core/filters/global-exception.filter.ts
[error] 32-32: Delete ······
(prettier/prettier)
[error] 50-50: Insert ⏎
(prettier/prettier)
src/modules/user-preferences/application/use-cases/__tests__/get-user-preferences.use-case.spec.ts
[error] 126-126: Insert ⏎
(prettier/prettier)
src/modules/roles/application/use-cases/__tests__/update-user-roles.use-case.spec.ts
[error] 73-78: Replace ⏎········userId,⏎········roleId,⏎········undefined,⏎········currentUserId,⏎······ with userId,·roleId,·undefined,·currentUserId
(prettier/prettier)
[error] 117-122: Replace ⏎········userId,⏎········roleId,⏎········undefined,⏎········currentUserId,⏎······ with userId,·roleId,·undefined,·currentUserId
(prettier/prettier)
[error] 304-309: Replace ⏎········userId,⏎········undefined,⏎········roleIds,⏎········currentUserId,⏎······ with userId,·undefined,·roleIds,·currentUserId
(prettier/prettier)
[error] 497-501: Replace ⏎········userId,⏎········roleId,⏎········undefined,⏎······ with userId,·roleId,·undefined
(prettier/prettier)
src/core/guards/__tests__/password-reset-rate-limit.guard.spec.ts
[error] 118-118: Delete ······
(prettier/prettier)
[error] 122-122: Replace (call)·=>·call[0]·===·'RateLimit-Remaining'); with ⏎········(call)·=>·call[0]·===·'RateLimit-Remaining',
(prettier/prettier)
[error] 123-123: Insert );⏎
(prettier/prettier)
[error] 132-132: Insert ⏎
(prettier/prettier)
src/core/decorators/rate-limit.decorator.ts
[error] 40-40: Insert ⏎·····
(prettier/prettier)
[error] 42-42: Insert ⏎
(prettier/prettier)
src/modules/email/adapters/zoho-mail.adapter.ts
[error] 40-40: Insert ⏎·····
(prettier/prettier)
[error] 49-49: Delete ······
(prettier/prettier)
[error] 51-51: Replace Logo·URL·is·not·HTTPS:·${configuredLogoUrl},·using·default with ⏎··········Logo·URL·is·not·HTTPS:·${configuredLogoUrl},·using·default,⏎········
(prettier/prettier)
[error] 54-54: Delete ······
(prettier/prettier)
[error] 56-56: 'error' is defined but never used.
(@typescript-eslint/no-unused-vars)
src/core/guards/password-reset-rate-limit.guard.ts
[error] 14-14: Delete ····
(prettier/prettier)
[error] 19-19: Delete ····
(prettier/prettier)
[error] 42-42: Delete ··
(prettier/prettier)
[error] 43-43: Insert ,
(prettier/prettier)
[error] 49-49: Insert ,
(prettier/prettier)
[error] 52-52: Insert ⏎·······
(prettier/prettier)
[error] 79-79: Insert ⏎
(prettier/prettier)
src/modules/user-preferences/application/use-cases/update-user-preferences.use-case.ts
[error] 58-58: Insert ⏎·········
(prettier/prettier)
[error] 61-61: Insert ⏎·········
(prettier/prettier)
[error] 64-64: Insert ⏎·········
(prettier/prettier)
[error] 67-67: Insert ⏎·········
(prettier/prettier)
[error] 82-82: 'error' is defined but never used.
(@typescript-eslint/no-unused-vars)
[error] 86-86: Insert ⏎
(prettier/prettier)
src/modules/user-preferences/infrastructure/repositories/__tests__/user-preferences.repository.spec.ts
[error] 28-28: Replace UserPreferencesRepository with ⏎······UserPreferencesRepository,⏎····
(prettier/prettier)
[error] 111-111: Insert ⏎
(prettier/prettier)
src/migrations/1752086121427-CreateUserPreferencesTable.ts
[error] 1-1: Replace ·MigrationInterface,·QueryRunner,·Table,·TableForeignKey· with ⏎··MigrationInterface,⏎··QueryRunner,⏎··Table,⏎··TableForeignKey,⏎
(prettier/prettier)
src/modules/user-preferences/domain/exceptions/user-preferences.exception.ts
[error] 45-45: Insert ⏎
(prettier/prettier)
src/modules/permissions/infrastructure/repositories/permission.vm.repository.ts
[error] 107-107: Replace ``Deleted·all·VM·permissions·for·role·${roleId},·result:,·result with `⏎······`Deleted·all·VM·permissions·for·role·${roleId},·result:`,⏎······result,⏎····`
(prettier/prettier)
src/modules/user-preferences/application/controllers/__tests__/user-preferences.controller.spec.ts
[error] 8-8: 'UserPreferencesResponseDto' is defined but never used. Allowed unused vars must match /^_/u.
(@typescript-eslint/no-unused-vars)
[error] 8-8: 'UserPreferencesResponseDto' is defined but never used.
(unused-imports/no-unused-imports)
[error] 279-279: Insert ⏎
(prettier/prettier)
src/modules/user-preferences/application/controllers/user-preferences.controller.ts
[error] 53-53: Replace user.userId with ⏎······user.userId,⏎····
(prettier/prettier)
[error] 97-97: Replace user.userId with ⏎······user.userId,⏎····
(prettier/prettier)
src/modules/user-preferences/infrastructure/repositories/user-preferences.repository.ts
[error] 29-29: Insert ⏎
(prettier/prettier)
src/modules/auth/application/use-cases/__tests__/forgot-password.use-case.spec.ts
[error] 154-154: Replace ·...mockUser,·resetPasswordToken:·null,·resetPasswordExpiry:·null with ⏎········...mockUser,⏎········resetPasswordToken:·null,⏎········resetPasswordExpiry:·null,⏎·····
(prettier/prettier)
[error] 170-170: Replace ·...mockUser,·resetPasswordToken:·null,·resetPasswordExpiry:·null with ⏎········...mockUser,⏎········resetPasswordToken:·null,⏎········resetPasswordExpiry:·null,⏎·····
(prettier/prettier)
[error] 196-196: Replace ·...mockUser,·resetPasswordToken:·null,·resetPasswordExpiry:·null with ⏎········...mockUser,⏎········resetPasswordToken:·null,⏎········resetPasswordExpiry:·null,⏎·····
(prettier/prettier)
[error] 219-219: Delete ······
(prettier/prettier)
[error] 225-225: Delete ······
(prettier/prettier)
[error] 250-250: Delete ······
(prettier/prettier)
[error] 256-256: Delete ······
(prettier/prettier)
[error] 273-273: Replace ·...mockUser,·resetPasswordToken:·null,·resetPasswordExpiry:·null with ⏎········...mockUser,⏎········resetPasswordToken:·null,⏎········resetPasswordExpiry:·null,⏎·····
(prettier/prettier)
src/modules/user-preferences/domain/exceptions/__tests__/user-preferences.exception.spec.ts
[error] 27-27: Insert ⏎·······
(prettier/prettier)
[error] 37-37: Insert ⏎·······
(prettier/prettier)
[error] 50-50: Replace service,·url with ⏎········service,⏎········url,⏎······
(prettier/prettier)
[error] 128-128: Insert ⏎
(prettier/prettier)
src/modules/auth/application/use-cases/forgot-password.use-case.ts
[error] 78-80: Replace ⏎········Error·in·forgot·password·use·case:·${error.message},⏎······ with Error·in·forgot·password·use·case:·${error.message}
(prettier/prettier)
src/modules/user-preferences/application/dto/update-user-preferences.dto.ts
[error] 14-14: 'IsIn' is defined but never used. Allowed unused vars must match /^_/u.
(@typescript-eslint/no-unused-vars)
[error] 14-14: 'IsIn' is defined but never used.
(unused-imports/no-unused-imports)
[error] 187-187: Insert ⏎
(prettier/prettier)
src/modules/user-preferences/application/dto/user-preferences-response.dto.ts
[error] 120-120: Insert ⏎
(prettier/prettier)
src/modules/user-preferences/domain/entities/user-preference.entity.ts
[error] 133-133: Insert ⏎
(prettier/prettier)
🪛 Gitleaks (8.26.0)
src/modules/auth/application/dto/__tests__/reset-password-with-token.dto.spec.ts
8-8: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
🪛 Biome (1.9.4)
src/modules/user-preferences/domain/exceptions/user-preferences.exception.ts
[error] 3-45: Avoid classes that contain only static members.
Prefer using simple functions instead of classes with only static members.
(lint/complexity/noStaticOnlyClass)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (152)
src/modules/roles/application/dto/update-user-roles.dto.ts (1)
26-26: Extra newline – 👍POSIX-friendly newline added; no further action required.
src/modules/users/application/dto/__tests__/user.create.dto.spec.ts (1)
286-286: No functional changes detected.Only EOF newline added – tests remain intact.
src/modules/roles/application/dto/index.ts (1)
6-11: Re-format export block looks good.The explicit multi-line export improves diff-friendliness; no issues spotted.
src/modules/roles/application/dto/user-with-presence.dto.ts (1)
10-10: EOF newline inserted – all good.src/modules/roles/domain/exceptions/__tests__/role.exception.spec.ts (1)
77-79: LGTM: Formatting improvements enhance readability.The multi-line format for
.toBe()assertions improves code readability, especially for longer error messages. Good consistency improvement.Also applies to: 88-90, 103-105, 109-109
src/modules/auth/domain/interfaces/extended-jwt-payload.interface.ts (1)
8-8: LGTM: Good formatting practice.Adding a trailing newline is a good formatting practice that ensures consistent file endings.
src/modules/roles/application/use-cases/__tests__/get-users-by-role.use-case.spec.ts (1)
39-42: LGTM: Consistent formatting improvements.The trailing comma and additional spacing improve code consistency and readability without affecting test functionality.
Also applies to: 71-71
src/modules/roles/infrastructure/repositories/role.typeorm.repository.ts (1)
115-115: LGTM: Syntax consistency improvement.Adding parentheses around the arrow function parameter is a minor syntax improvement that likely aligns with linting rules or code style preferences without affecting functionality.
src/modules/users/application/controllers/__tests__/user.controller.toggle-status.spec.ts (2)
19-19: Import addition looks correct.The
CreateUserByAdminUseCaseimport is properly added to the existing import statement from the use-cases index file.
118-121: Mock provider follows consistent pattern.The mock provider for
CreateUserByAdminUseCaseis correctly structured with a jest mock for theexecutemethod, maintaining consistency with other use case mocks in the providers array.src/core/filters/index.ts (1)
12-12: Import statement follows existing pattern.The import for
GlobalExceptionFilteris correctly added and follows the same pattern as other filter imports in the file.src/modules/roles/application/use-cases/update-user-role.use-case.ts (1)
121-121: Code formatting improvement.The trailing whitespace removal improves code cleanliness without affecting functionality.
Also applies to: 127-127
src/modules/roles/application/controllers/role.controller.ts (3)
250-252: API documentation formatting improvement.The multi-line format for the
@ApiBodydescription improves readability of the API documentation.
253-257: API operation description formatting enhancement.Converting the
@ApiOperationdescription to multi-line format makes the documentation more readable and maintainable.
266-266: Code formatting cleanup.The removal of the extraneous empty line improves code consistency.
src/modules/email/domain/constants/injection-tokens.ts (1)
1-1: Well-defined injection token.The
MAIL_SERVICE_TOKENconstant is properly defined with a descriptive name and matching string value, following NestJS dependency injection best practices for avoiding magic strings.src/modules/users/application/controllers/__tests__/user.controller.delete-account.spec.ts (1)
24-24: LGTM: Proper test dependency setup.The addition of
CreateUserByAdminUseCaseto the imports and providers ensures the testing module has all required dependencies properly mocked, maintaining consistency with other UserController test files.Also applies to: 106-109
src/modules/permissions/application/use-cases/permission-server/create-permission-server.use-case.ts (1)
42-42: LGTM: Improved logging specificity.The change from generic
'CREATE'to'CREATE_PERMISSION_SERVER'makes the log action more descriptive and easier to analyze, which is beneficial for debugging and audit purposes.src/modules/permissions/application/use-cases/permission-vm/create-permission-vm.use-case.ts (1)
43-43: LGTM: Improved logging specificity.The change from generic
'CREATE'to'CREATE_PERMISSION_VM'enhances log clarity and maintains consistency with the similar improvement made in the permission-server use case.src/modules/roles/application/use-cases/__tests__/update-user-role.use-case.spec.ts (1)
183-185: LGTM: Improved test readability.The formatting change to use multiline object notation makes the test assertion more readable and easier to understand.
src/modules/auth/application/dto/index.ts (2)
6-7: LGTM: Clean DTO exports for password reset functionalityThe new DTO exports follow the established pattern and integrate well with the existing authentication DTOs.
15-16: LGTM: Consistent export pattern maintainedThe exports maintain consistency with the existing DTO structure and properly expose the new password reset DTOs.
src/modules/roles/application/controllers/__tests__/role.controller.spec.ts (1)
260-265: LGTM: Improved readability with multi-line formattingThe multi-line formatting improves readability for the function call with multiple parameters without changing the test logic.
nest-cli.json (1)
10-19: LGTM: Asset configuration supports email template developmentThe asset configuration properly enables watching and hot reloading for Handlebars templates and static assets, which will improve the development experience for the new email module.
src/modules/email/__tests__/email.module.spec.ts (2)
5-12: LGTM: Standard module compilation testThe module compilation test follows NestJS testing conventions and properly verifies that the EmailModule can be instantiated.
14-22: LGTM: Provider availability test validates module integrationThe test properly verifies that the EmailEventListener provider is available and correctly instantiated within the module.
src/modules/auth/auth.module.ts (3)
14-16: LGTM: Clean module imports for extended functionalityThe imports for EmailModule and HistoryModule appropriately extend the authentication module's capabilities with email notifications and history logging.
23-24: LGTM: Module dependencies properly integratedThe EmailModule and HistoryModule are correctly added to the imports array, enabling the authentication module to utilize email and history services.
37-43: LGTM: Rate limiting guard properly configuredThe PasswordResetRateLimitGuard is correctly added to the providers array, enabling rate limiting protection for password reset endpoints.
.env.prod.example (1)
59-64: LGTM! Environment variables for email configuration added correctly.The new mail configuration variables are properly structured and follow standard naming conventions. Placing them at the end of the file is appropriate, and leaving them empty in the example file is the correct approach.
src/app.module.ts (2)
3-3: LGTM! Module imports are correctly structured.The new imports for EventEmitterModule, EmailModule, and UserPreferencesModule are appropriately placed and follow NestJS conventions.
Also applies to: 29-30
37-37: LGTM! Module registrations are properly configured.The EventEmitterModule.forRoot() configuration is correct for enabling the event-driven email system, and the new modules are properly registered in the imports array.
Also applies to: 60-61
src/modules/email/application/email-application.module.ts (1)
1-26: LGTM! Well-structured email application module.The module follows NestJS best practices with proper dependency injection, clean separation of concerns, and appropriate use of injection tokens. The provider configuration and exports are correctly implemented.
src/modules/email/domain/services/mail.service.ts (1)
1-9: LGTM! Clean and well-documented interface design.The IMailService interface is properly structured with clear method signature, appropriate return type, and comprehensive JSDoc documentation. The use of SendEmailDto as the parameter type aligns well with the DTO structure.
src/modules/auth/application/dto/forgot-password.dto.ts (1)
1-13: LGTM! Well-implemented DTO with proper validation.The ForgotPasswordDto follows NestJS best practices with comprehensive validation, clear Swagger documentation, and appropriate use of the readonly modifier. The French validation messages are consistent with the application's localization approach.
src/migrations/1752061749877-AddResetPasswordFields.ts (1)
3-3: Migration timestamp is valid and sequentialThe timestamp 1752061749877 corresponds to Wed Jul 9 11:49:09 UTC 2025, which is already in the past relative to the current time and correctly fits between your other migrations in src/migrations/. No changes are needed.
src/modules/roles/application/use-cases/update-user-roles.use-case.ts (2)
54-58: LGTM: Improved code formatting.The multi-line union type annotation improves readability and follows TypeScript formatting conventions.
161-165: LGTM: Method signature formatting improvement.The multi-line method signature improves readability and maintains consistency with the codebase style.
src/modules/email/email.module.ts (1)
6-11: LGTM: Well-structured email module.The module properly separates infrastructure and application concerns, correctly provides the event listener, and exports the appropriate services. The structure follows NestJS best practices.
src/modules/auth/application/use-cases/register.use-case.ts (2)
33-33: LGTM: Proper dependency injection for event emitter.The EventEmitter2 injection is correctly added to support the new email notification feature.
56-57: LGTM: Appropriate data for account creation event.The event payload correctly includes the user's email and uses a sensible fallback for the firstname (DTO firstName or username). This provides sufficient information for the email template.
src/modules/email/application/dto/__tests__/send-email.dto.spec.ts (1)
1-70: Excellent test coverage for the SendEmailDto.The test suite comprehensively covers all aspects of the DTO:
- Basic instantiation and type checking
- Property assignment validation
- Template type constraints
- Complex context object handling
- Edge cases (empty context, undefined properties)
The tests are well-structured and follow good testing practices.
package.json (2)
3-3: Version bump looks good.The patch version increment from 0.9.1 to 0.9.2 is appropriate for this feature addition.
31-31: Email-related dependencies are well-chosen.The added dependencies properly support the email functionality:
@nestjs-modules/mailerfor NestJS email integration@nestjs/event-emitterfor event-driven email sendinghandlebarsfor email templatingnodemailerandnodemailer-express-handlebarsfor email sending and template renderingAll versions appear to be current and stable.
Also applies to: 35-35, 51-51, 54-56
src/modules/user-preferences/domain/value-objects/timezone.validator.ts (1)
33-38: Functions are well-implemented.Both
validateTimezoneandgetValidTimezonesare correctly implemented with proper encapsulation and defensive copying.src/modules/roles/application/use-cases/__tests__/update-user-roles.use-case.spec.ts (1)
55-59: Approve the multi-line object formatting.The multi-line formatting for object literals improves readability, especially for objects with multiple properties.
Also applies to: 100-104, 231-235, 411-415
src/modules/email/application/__tests__/email-application.module.spec.ts (1)
1-60: Excellent test coverage for module integration.The test suite comprehensively validates the EmailApplicationModule's dependency injection and exports. The mock setup is clean and the tests verify all essential functionality without unnecessary complexity.
src/modules/auth/application/dto/__tests__/forgot-password.dto.spec.ts (1)
1-120: Comprehensive validation testing with excellent edge case coverage.The test suite thoroughly validates the ForgotPasswordDto across multiple scenarios:
- Valid email formats (basic, subdomains, plus signs)
- Invalid formats (malformed, missing parts, spaces)
- Edge cases (null, undefined, empty strings)
- Custom error message verification
The test structure is clean and the coverage is excellent for a DTO validation suite.
src/modules/permissions/infrastructure/interfaces/permission.repository.interface.ts (1)
17-18: Clean interface extension for enhanced deletion capabilities.The new methods provide logical extensions to the existing deletion functionality:
deleteByIdallows direct deletion by unique identifierdeleteByRoleIdenables cascading deletion of role-associated permissionsBoth methods follow consistent patterns with the existing interface and use appropriate return types.
src/modules/user-preferences/domain/value-objects/__tests__/timezone.validator.spec.ts (1)
1-92: Excellent comprehensive testing of timezone validation.The test suite thoroughly validates both functions with excellent coverage:
- validateTimezone: Tests valid/invalid formats, case sensitivity, edge cases
- getValidTimezones: Tests immutability, major timezone inclusion, copy behavior
The immutability tests are particularly valuable for preventing accidental modifications to the timezone list.
src/modules/email/infrastructures/templates/README.md (1)
1-82: Well-structured documentation for email templates.This comprehensive documentation effectively describes the email template system, including template variables, design system, and configuration details. The French typography issues flagged by static analysis are cosmetic and don't impact the functionality or usefulness of the documentation.
src/modules/permissions/infrastructure/repositories/permission.server.repository.ts (1)
70-70: Consistent return type improvement.Good change to return an empty array instead of null when
disableThrowis true, maintaining consistency with the expected return type.jest.email.config.js (1)
1-26: Well-configured Jest setup for email module testing.The configuration is properly structured with appropriate test matching patterns, coverage collection, and high coverage thresholds. The module path mapping aligns with the project structure.
src/modules/email/domain/value-objects/email-address.vo.ts (2)
21-23: Email comparison is case-sensitive.The
equalsmethod performs case-sensitive comparison, which may not align with email address standards where the local part can be case-sensitive but is often treated as case-insensitive in practice. Consider if this is the intended behavior.Verify if case-sensitive email comparison is the intended behavior for your use case. Email addresses are technically case-sensitive in the local part according to RFC standards, but many systems treat them as case-insensitive in practice.
3-33: LGTM! Well-structured value object implementation.The implementation follows good domain-driven design principles with proper encapsulation, validation, and immutability. The exception handling and method signatures are appropriate.
src/migrations/1752097876989-AddNewViewPreferences.ts (1)
3-47: LGTM! Well-structured migration with proper rollback.The migration correctly adds new view preferences to the JSONB column and updates the default values. The rollback logic properly removes the added fields and restores the original default.
src/modules/email/domain/value-objects/__tests__/email-address.vo.spec.ts (2)
109-114: Good test coverage for case sensitivity behavior.The test correctly verifies that email comparison is case-sensitive, which documents the intended behavior clearly. This aligns with the earlier concern about case sensitivity in the equals method.
4-116: Excellent test coverage!The test suite comprehensively covers:
- Valid email formats including edge cases
- Invalid email formats and error handling
- Null/undefined input validation
- String representation methods
- Equality comparison behavior
- Case sensitivity documentation
This provides good confidence in the EmailAddressVO implementation.
src/modules/user-preferences/application/use-cases/reset-user-preferences.use-case.ts (1)
6-34: LGTM! Well-structured use case implementation.The use case correctly handles both scenarios (existing and non-existing preferences) and provides appropriate error handling with domain exceptions. The dependency injection and overall structure follow good practices.
src/modules/email/domain/exceptions/__tests__/email.exception.spec.ts (1)
1-94: Excellent comprehensive test coverage for email exceptions.The test suite provides thorough coverage of both exception classes with proper edge case handling, including empty strings, undefined values, and potential security concerns like XSS attempts. The test structure follows Jest best practices with clear describe blocks and appropriate assertions.
src/modules/user-preferences/domain/entities/__tests__/user-preference.entity.spec.ts (1)
1-142: Excellent comprehensive test coverage for UserPreference entity.The test suite thoroughly covers the
createDefaultmethod with proper verification of default values, deep copying behavior, and entity instantiation. The tests ensure that different instances don't share references and that all properties can be set correctly.src/modules/email/application/use-cases/__tests__/send-account-created-email.use-case.spec.ts (1)
1-86: Excellent comprehensive test coverage for email use case.The test suite provides thorough coverage with proper mocking, error handling verification, and edge case testing. The tests verify all aspects of the email sending functionality including parameter validation, template usage, and error propagation.
src/modules/auth/application/use-cases/index.ts (3)
9-10: LGTM! Clean addition of password reset use cases.The imports follow the existing pattern and are properly structured.
21-22: LGTM! Consistent with existing use case registration.The use cases are properly added to the AuthUseCases array following the established pattern.
34-35: LGTM! Proper named exports for the new use cases.The named exports are consistent with the imports and array registration above.
src/modules/user-preferences/user-preferences.module.ts (1)
1-11: LGTM! Clean imports following NestJS conventions.The imports are well-organized and follow the established patterns for a NestJS module.
src/core/filters/global-exception.filter.ts (1)
30-41: LGTM! Proper error handling with environment-aware logging.The error handling logic correctly differentiates between development and production environments for logging stack traces.
src/modules/auth/application/dto/reset-password-with-token.dto.ts (1)
1-12: LGTM! Clean token field validation.The token field has proper validation with clear API documentation and appropriate error messages.
src/modules/permissions/infrastructure/repositories/permission.vm.repository.ts (1)
29-29: LGTM! Improved error handling consistency.Returning an empty array instead of null is more consistent with the expected return type and follows better practices.
src/modules/roles/domain/services/safe-role-deletion.domain.service.ts (4)
11-12: LGTM - Clean dependency importsThe imports for permission repository interfaces are well-structured and follow the established patterns in the codebase.
23-26: LGTM - Proper dependency injection setupThe injection of permission repositories follows the established DI pattern and enables the service to perform comprehensive cleanup.
35-36: LGTM - Updated documentation reflects new functionalityThe comments accurately describe the enhanced role deletion process including permission cleanup.
86-87: LGTM - Proper placement of permission deletionThe permission deletion is correctly placed after user role updates but before role deletion, ensuring data consistency.
src/modules/email/application/use-cases/send-account-created-email.use-case.ts (1)
1-21: LGTM - Clean and well-structured email use caseThe implementation follows established patterns with proper dependency injection, DTO construction, and email service usage. The French localization is consistent with the application's target audience.
Key strengths:
- Proper use of value objects for email validation
- Clean separation of concerns
- Appropriate template selection and context data
- Consistent with other email use cases in the module
src/modules/email/application/use-cases/__tests__/send-reset-password-email.use-case.spec.ts (1)
1-121: LGTM - Comprehensive test coverage for reset password email use caseThe test suite is well-structured and provides excellent coverage of the
SendResetPasswordEmailUseCasefunctionality.Strengths:
- Comprehensive test scenarios covering happy path, error cases, and edge cases
- Proper mocking of dependencies with
jest.Mocked<IMailService>- Good assertions verifying email parameters (recipient, subject, template, context)
- Tests for invalid email handling and mail service error propagation
- Edge case testing (empty reset link)
- Proper verification of generated timestamp fields (
requestDate,requestTime)- Clean test structure with good setup and teardown
The test coverage ensures the use case behaves correctly under various conditions and properly handles errors.
src/modules/auth/application/use-cases/__tests__/reset-password-with-token.use-case.spec.ts (1)
1-233: LGTM - Excellent comprehensive test coverageThis test suite provides outstanding coverage of the
ResetPasswordWithTokenUseCasefunctionality with well-structured tests covering all critical scenarios.Strengths:
- Comprehensive scenario coverage: Happy path, error cases, edge cases, and fallback behaviors
- Proper mocking strategy: All dependencies are properly mocked with
jest.Mocked- Complete flow verification: Tests verify password hashing, token validation, event emission, and history logging
- Edge case handling: Tests for missing firstName (fallback to username), expired tokens, missing tokens
- Error propagation: Tests database errors and proper error handling
- State verification: Tests proper cleanup of reset token fields after successful reset
- Event system integration: Verifies correct event emission for password changed notifications
- History logging: Ensures proper audit trail is maintained
The test structure is clean, well-organized, and follows testing best practices. The French localization in error messages is consistent with the application's target audience.
src/modules/email/application/use-cases/send-reset-password-email.use-case.ts (1)
7-34: Implementation looks good overall.The use case follows clean architecture principles with proper dependency injection and separation of concerns. The email composition logic is clear and well-structured.
src/modules/users/application/controllers/user.controller.spec.ts (3)
75-78: Good addition of the missing provider.Adding the
CreateUserByAdminUseCaseprovider ensures consistency across the test suite and prevents potential injection errors.
218-235: Excellent test enhancement for request context.The addition of mock request objects with
ipandgetmethods properly tests the new functionality where request context is extracted and passed to the use case. The test correctly verifies that the context object contains the expectedipAddressanduserAgentproperties.
243-266: Comprehensive test update for admin password reset.The test properly includes both admin user context and request object mocking, ensuring that the admin-initiated password reset functionality is thoroughly tested with all required parameters.
src/modules/email/application/use-cases/__tests__/send-password-changed-email.use-case.spec.ts (2)
1-149: Excellent comprehensive test coverage.This test suite demonstrates excellent testing practices with:
- Proper dependency mocking using Jest
- Comprehensive scenario coverage including happy path, error cases, and edge cases
- Validation of default values when optional parameters are not provided
- Testing of different user scenarios
- Proper error propagation testing
The test structure is clean and follows consistent patterns throughout.
63-79: Good test for default parameter handling.The test for default values when optional parameters are not provided is particularly valuable as it verifies the fallback behavior with French default messages.
src/modules/email/adapters/__tests__/zoho-mail.adapter.spec.ts (2)
1-195: Comprehensive test suite with excellent coverage.The test suite covers all important scenarios:
- Basic email sending functionality
- Context enrichment with additional data
- Error handling and exception propagation
- Logging verification
- Complex context object handling
The test structure is clean and follows good testing practices.
100-115: Good logging verification.The test properly verifies that successful email sending is logged, which is important for monitoring and debugging in production environments.
src/modules/user-preferences/infrastructure/repositories/__tests__/user-preferences.repository.spec.ts (2)
1-111: Well-structured repository test suite.The test suite properly covers all CRUD operations with:
- Proper TypeORM repository mocking
- Clear test scenarios for each method
- Good error case coverage (null returns, non-existent deletes)
- Consistent test structure and naming
104-110: Good test for graceful deletion handling.The test properly verifies that deleting non-existent preferences doesn't throw an error, which is important for robust error handling.
src/migrations/1752086121427-CreateUserPreferencesTable.ts (1)
6-84: Well-structured migration with proper schema design.The migration properly creates the user_preferences table with:
- Appropriate use of UUID primary keys
- Foreign key constraint with cascade delete
- Enum types for locale and theme
- JSONB columns for flexible preference storage
- Sensible default values
The up/down methods are correctly implemented for migration reversibility.
src/modules/user-preferences/application/use-cases/__tests__/update-user-preferences.use-case.spec.ts (1)
8-283: Excellent test coverage with comprehensive scenarios.The test suite demonstrates excellent practices:
- Proper mocking of dependencies
- Clear test organization with descriptive names
- Comprehensive coverage of success and error scenarios
- Tests for partial updates and nested object merging
- Proper validation of repository method calls
The tests cover all critical paths including preference creation, updates, validation errors, and repository failures.
src/modules/auth/application/dto/__tests__/reset-password-with-token.dto.spec.ts (1)
4-223: Comprehensive validation testing with excellent coverage.The test suite thoroughly validates both token and password fields:
- Token validation tests cover empty, null, and undefined cases
- Password validation tests cover all strength requirements (length, uppercase, lowercase, numbers, symbols)
- Edge cases are well-covered including multiple field validation
- Clear test organization with descriptive names
- Proper use of class-validator for validation testing
src/modules/auth/application/use-cases/reset-password-with-token.use-case.ts (1)
18-61: Solid implementation with excellent security practices.The use case properly handles password reset with:
- Thorough token validation including existence and expiry checks
- Secure password hashing via domain service
- Proper cleanup of reset token and expiry after use
- Event emission for email notifications
- Comprehensive audit logging with structured metadata
- Appropriate error handling with user-friendly French messages
The implementation follows security best practices and maintains good separation of concerns.
src/modules/email/infrastructures/templates/reset-password.hbs (1)
1-235: Professional email template with excellent design practices.The template demonstrates excellent email design practices:
- Responsive design with mobile-specific styles
- Proper accessibility attributes (role="presentation", aria-roledescription)
- Dark mode support with
@media (prefers-color-scheme: dark)- Conditional content for reset code vs reset link scenarios
- Comprehensive security advice and user guidance
- Professional branding with consistent styling
- Table-based layout for broad email client compatibility
- Proper fallback mechanisms (plain URL for broken buttons)
The template provides a great user experience while maintaining security awareness.
src/modules/user-preferences/application/use-cases/__tests__/reset-user-preferences.use-case.spec.ts (6)
1-32: Test setup looks well-structured.The test module setup properly configures the use case with mocked dependencies. The repository mock includes all necessary methods from the interface.
37-122: Comprehensive test coverage for the reset functionality.The test correctly validates:
- Resetting existing preferences to defaults
- Preserving the ID from existing preferences
- Proper transformation of all preference fields
- Expected repository method calls
The test data structure matches the expected UserPreference entity structure.
124-142: Good coverage for the case when no preferences exist.The test properly verifies that default preferences are created when none exist for the user. The mock setup and assertions are correct.
144-163: ID preservation test is valuable.This test ensures that the existing preference ID is maintained during reset operations, which is crucial for maintaining referential integrity.
165-177: Error handling test is well-implemented.The test correctly verifies that repository failures are properly wrapped in domain-specific exceptions using
UserPreferencesExceptions.failedToReset().
179-192: Edge case coverage is thorough.This test covers the scenario where a user has no existing preferences, ensuring the use case handles the creation flow correctly.
src/modules/email/infrastructure/listeners/email-event.listener.ts (4)
1-22: Well-structured event listener with proper dependencies.The class properly injects the required email use cases and follows NestJS patterns. The logger instance is correctly configured.
23-37: Account created event handler is well-implemented.The handler properly:
- Uses async event handling
- Logs the operation start
- Calls the appropriate use case with correct parameters
- Catches and logs errors with stack traces
39-56: Password changed event handler follows consistent pattern.The handler maintains consistency with other handlers while properly handling the additional metadata parameters (IP address, user agent, location).
58-73: Password reset event handler is correctly implemented.The handler follows the same pattern and properly handles the reset link parameter.
src/modules/user-preferences/application/use-cases/update-user-preferences.use-case.ts (6)
1-13: Proper dependency injection and imports.The use case correctly imports required dependencies and uses proper NestJS dependency injection patterns.
15-23: Good pattern for handling missing preferences.The use case correctly creates default preferences when none exist, ensuring the update operation can proceed.
25-31: Simple field updates are handled correctly.The conditional updates for locale and theme are properly implemented.
33-38: Timezone validation is properly implemented.The use case correctly validates timezone values using the domain validator and throws appropriate exceptions.
40-52: Nested object updates use proper spreading.The notifications and display objects are correctly updated using spread syntax to preserve existing values.
73-78: Performance object update is correctly implemented.The spread pattern is consistently applied for nested object updates.
src/modules/email/application/use-cases/send-password-changed-email.use-case.ts (4)
1-11: Proper dependency injection setup.The use case correctly imports dependencies and uses proper NestJS dependency injection with the mail service token.
13-19: Method signature is well-designed.The execute method properly handles required parameters (email, firstName) and optional security metadata (ipAddress, userAgent, location).
20-35: Email construction is comprehensive.The email DTO construction is thorough:
- Proper email address validation via EmailAddressVO
- Appropriate French subject line
- Correct template reference
- Comprehensive context with formatted dates and fallback values
32-34: Good use of nullish coalescing for defaults.The fallback values for optional parameters are appropriate and user-friendly in French.
src/modules/auth/application/use-cases/__tests__/register.use-case.spec.ts (7)
1-9: Proper imports for event testing.The test correctly imports the EventEmitter2 and EmailEventType for testing event emission functionality.
16-16: EventEmitter mock setup is correct.The mock setup for EventEmitter2 is properly configured for testing event emission.
40-49: Test setup includes event emitter properly.The useCase instantiation correctly includes the mocked EventEmitter2 in the constructor.
74-82: Event emission verification is well-implemented.The test correctly verifies that the ACCOUNT_CREATED event is emitted with the proper payload structure including email and firstName.
84-103: Edge case testing is valuable.The test correctly handles the case where firstName is not provided, ensuring the event uses the username as fallback. This is important for consistent email personalization.
156-176: Optional dependency handling is well-tested.The test verifies that the use case works correctly even when the optional logHistory service is not provided, which is good for backward compatibility.
96-102: No inconsistency in event payload property nameThe
ACCOUNT_CREATEDevent payload key is consistently namedfirstnamein both the implementation (register.use-case.tsline 57) and all related tests (register.use-case.spec.tslines 79 and 100). You can safely ignore this comment.Likely an incorrect or invalid review comment.
src/core/guards/__tests__/password-reset-rate-limit.guard.spec.ts (2)
54-76: Good test coverage for environment-specific behavior.The test correctly verifies that rate limiting is bypassed in test environments and for localhost IPs, which is appropriate for development and testing scenarios.
78-108: Well-structured tests for rate limit key generation.The tests properly verify that both IP and email are used for rate limiting keys when available, and fallback to IP-only when email is not provided. This ensures comprehensive rate limiting coverage.
src/modules/users/application/controllers/user.controller.ts (2)
202-206: Good integration of request context for password reset operations.The addition of request context extraction enhances security auditing by capturing IP address and user agent information for password reset operations. The implementation is consistent with established patterns in the codebase.
218-228: Proper context passing for admin-initiated password resets.The admin password reset method correctly passes both the request context and the admin user ID, enabling proper audit trails for administrative actions. This aligns with security best practices for administrative operations.
src/modules/auth/application/controllers/auth.controller.spec.ts (3)
10-11: Well-integrated test setup for new password reset functionality.The new imports and mock providers are properly integrated into the existing test structure, maintaining consistency with the established testing patterns.
Also applies to: 27-28, 41-45
149-183: Comprehensive test coverage for forgot password functionality.The tests properly verify both success and error scenarios for the forgot password feature, including proper use case invocation and error propagation. The test structure follows established patterns.
185-242: Thorough testing of password reset with token functionality.The tests cover multiple scenarios including successful password reset, invalid token handling, and expired token handling. This ensures robust error handling and proper use case integration.
src/core/decorators/rate-limit.decorator.ts (1)
1-26: Well-designed rate limiting decorator with proper TypeScript interfaces.The decorator implementation is clean and follows NestJS patterns effectively. The
RateLimitOptionsinterface provides good type safety and the decorator factory pattern is appropriate for this use case.src/modules/roles/domain/services/__tests__/safe-role-deletion.domain.service.spec.ts (3)
4-5: Proper integration of permission repositories into test setup.The addition of permission repository interfaces and their integration into the service constructor enhances the test coverage for permission cleanup during role deletion. The mock setup is comprehensive and follows established patterns.
Also applies to: 17-18, 35-54
76-77: Excellent test coverage for permission deletion.The tests properly verify that permission deletion occurs before role deletion across all scenarios. This ensures data integrity and prevents orphaned permissions in the system.
Also applies to: 113-114, 140-141, 174-175, 213-214
301-317: Good test for explicit permission deletion verification.This test specifically verifies that permissions are deleted before role deletion, which is crucial for maintaining data consistency.
src/modules/email/infrastructures/templates/password-changed.hbs (1)
1-210: Excellent email template implementation with security best practices.This template demonstrates excellent practices for transactional email:
- Responsive design with mobile-first approach
- Proper accessibility attributes and semantic HTML
- Security recommendations for unauthorized changes
- Comprehensive contextual information (IP, user agent, location)
- Dark mode support and email client compatibility
- French localization matching the application's target audience
src/modules/email/domain/events/email.events.ts (1)
1-25: Well-structured event definitions with good type safety.The event types and interfaces are well-designed with:
- Consistent naming pattern for event types
- Appropriate field types and optional parameters
- Clear separation of concerns between different event types
Apply this formatting fix:
resetLink: string; } +src/core/guards/password-reset-rate-limit.guard.ts (2)
11-21: Good security approach for rate limiting key generation.The combination of IP address and email for rate limiting provides a good balance between preventing abuse and allowing legitimate password reset requests.
23-26: Test Environment Skip Logic & NODE_ENV Usage Verified
- The rate-limit guard (
src/core/guards/password-reset-rate-limit.guard.ts) only skips whenprocess.env.NODE_ENV === 'test'or the request comes from localhost (127.0.0.1,::1,::ffff:127.0.0.1).- A code-wide grep confirmed consistent
process.env.NODE_ENVchecks in tests (setting both'test'and'production') and in configuration (e.g.src/core/config/typeorm.config.ts).- There is no built-in default for
NODE_ENV—ensure your production deployments explicitly setNODE_ENV=productionto avoid any accidental skips.src/modules/user-preferences/infrastructure/repositories/user-preferences.repository.ts (1)
7-29: Standard and well-implemented repository pattern.The repository implementation follows TypeORM best practices with:
- Proper dependency injection using @InjectRepository
- Interface implementation for better abstraction
- Standard CRUD operations using TypeORM methods
- Appropriate return types and async/await usage
Apply this formatting fix:
async delete(id: string): Promise<void> { await this.repository.delete(id); } } +src/modules/auth/application/controllers/auth.controller.ts (3)
15-16: LGTM: Proper imports and dependency injection for password reset feature.The imports for the new DTOs and use cases are correctly added and properly injected into the controller constructor.
Also applies to: 21-22, 27-27, 36-37
139-162: LGTM: Well-implemented forgot password endpoint with proper security measures.The endpoint implementation includes essential security features:
- Rate limiting with
PasswordResetRateLimitGuard- Generic response message that doesn't reveal user existence
- Comprehensive Swagger documentation
- Proper error handling
The 429 response documentation for rate limiting is a good security practice.
164-189: LGTM: Reset password endpoint is properly implemented.The endpoint correctly:
- Uses the token and new password from the DTO
- Includes proper Swagger documentation for success/failure responses
- Handles authentication errors with 401 status
- Follows REST conventions
src/modules/email/infrastructures/templates/account-created.hbs (2)
1-42: LGTM: Excellent email template with modern best practices.The template demonstrates excellent email development practices:
- Proper DOCTYPE and meta tags for email clients
- MSO-specific styles for Outlook compatibility
- Responsive design with media queries
- Dark mode support with
prefers-color-scheme- Accessibility features with ARIA roles and semantic HTML
43-240: LGTM: Well-structured template with professional design and dynamic content.The template body includes:
- Professional branding and styling
- Clear feature highlights for the Upstra platform
- Proper use of Handlebars variables for personalization
- Responsive table-based layout for email client compatibility
- Security recommendations in the footer
The design is clean, professional, and follows email best practices.
src/modules/email/infrastructure/listeners/__tests__/email-event.listener.spec.ts (1)
1-168: Well-structured test coverage!The test suite comprehensively covers all event handlers with both success and error scenarios. Good practices observed:
- Proper mocking of dependencies
- Testing optional parameters
- Verifying both use case execution and logging behavior
- Consistent test structure across all handlers
src/modules/user-preferences/domain/entities/user-preference.entity.ts (1)
1-133: Well-designed entity with appropriate default values!The entity structure is excellent:
- Good use of JSONB columns for complex preference objects
- Proper cascade delete configuration for user relationship
- Comprehensive default values
- Clean static factory method for creating default preferences
src/modules/users/application/controllers/__tests__/user.controller.reset-password.spec.ts (1)
1-358: Excellent test coverage with comprehensive edge case handling!The test suite thoroughly covers:
- Both user and admin password reset scenarios
- Graceful handling of missing request data (IP, user agent)
- Fallback logic for IP address extraction
- RequestContextDto factory method testing
- Proper request context construction
src/modules/auth/application/use-cases/forgot-password.use-case.ts (2)
62-62: Add validation for FRONTEND_URL environment variable.The reset link construction assumes
FRONTEND_URLexists but doesn't validate it, which could cause issues in production if not configured.Consider adding validation at the beginning of the execute method:
async execute(email: string): Promise<{ message: string }> { + if (!process.env.FRONTEND_URL) { + this.logger.error('FRONTEND_URL environment variable is not configured'); + throw new Error('System configuration error'); + } + try {Alternatively, validate this during module initialization to fail fast on startup.
28-36: Excellent security implementation!Good security practices observed:
- Returns the same generic message regardless of user existence
- Prevents user enumeration attacks
- Logs attempts for non-existent emails for security monitoring
Also applies to: 73-76
src/modules/user-preferences/application/dto/user-preferences-response.dto.ts (4)
3-15: LGTM! Well-structured notifications DTO.The NotificationsDto class correctly defines boolean flags for all notification types with clear API documentation.
17-50: LGTM! Comprehensive display settings DTO.The DisplayDto class properly defines enum-based view options for different entities with appropriate constraints. The different view types (table/card, grid/list, sections/flow) align well with typical UI requirements.
52-64: LGTM! Well-defined integrations DTO.The IntegrationsDto class correctly defines optional fields for external service integrations with clear documentation.
66-76: LGTM! Properly constrained performance DTO.The PerformanceDto class correctly defines refresh settings with appropriate constraints (15-300 seconds range).
src/modules/user-preferences/application/dto/update-user-preferences.dto.ts (4)
18-38: LGTM! Proper validation for notifications DTO.The UpdateNotificationsDto class correctly implements optional boolean validation for all notification types.
40-90: LGTM! Comprehensive display settings validation.The UpdateDisplayDto class properly validates enum values for different view types with appropriate constraints.
92-115: LGTM! Secure integrations validation.The UpdateIntegrationsDto class correctly enforces HTTPS protocols for webhook URLs and proper email validation, which is good for security.
117-134: LGTM! Proper performance constraints validation.The UpdatePerformanceDto class correctly validates the refresh interval with appropriate min/max constraints (15-300 seconds).
src/modules/user-preferences/application/use-cases/update-user-preferences.use-case.ts
Outdated
Show resolved
Hide resolved
src/modules/user-preferences/application/controllers/user-preferences.controller.ts
Show resolved
Hide resolved
src/modules/user-preferences/application/dto/update-user-preferences.dto.ts
Show resolved
Hide resolved
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
♻️ Duplicate comments (1)
src/modules/email/adapters/zoho-mail.adapter.ts (1)
19-19: APP_URL fallback issue remains unaddressed.The fallback to
http://localhost:3000is still present and inappropriate for production environments.
🧹 Nitpick comments (2)
src/modules/email/adapters/zoho-mail.adapter.ts (1)
40-41: Consider making the default logo URL configurable.The hardcoded GitHub URL for the default logo could become outdated or inaccessible. Consider moving it to environment configuration or a constants file.
- const defaultLogoUrl = - 'https://github.com/Upstra/.github/blob/dcd1f2dc99276f0fd22eea7b8dd7f35902c562cc/PA2025%20Upstra%20Logo.png?raw=true'; + const defaultLogoUrl = process.env.DEFAULT_LOGO_URL || + 'https://github.com/Upstra/.github/blob/dcd1f2dc99276f0fd22eea7b8dd7f35902c562cc/PA2025%20Upstra%20Logo.png?raw=true';src/modules/user-preferences/domain/exceptions/user-preferences.exception.ts (1)
3-45: Consider refactoring to use plain functions instead of static-only class.While the current implementation is functionally correct, the static analysis tool correctly identifies that classes with only static members can be simplified to plain functions or a namespace.
-export class UserPreferencesExceptions { - static notFound(): NotFoundException { - return new NotFoundException('User preferences not found'); - } - - static invalidTimezone(timezone: string): BadRequestException { - return new BadRequestException(`Invalid timezone: ${timezone}`); - } - - // ... other static methods -} +export const UserPreferencesExceptions = { + notFound: (): NotFoundException => + new NotFoundException('User preferences not found'), + + invalidTimezone: (timezone: string): BadRequestException => + new BadRequestException(`Invalid timezone: ${timezone}`), + + // ... other methods +} as const;Alternatively, export individual functions:
-export class UserPreferencesExceptions { - static notFound(): NotFoundException { - return new NotFoundException('User preferences not found'); - } -} +export const notFound = (): NotFoundException => + new NotFoundException('User preferences not found');
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (40)
package.json(3 hunks)src/core/decorators/rate-limit.decorator.ts(1 hunks)src/core/filters/__tests__/global-exception.filter.spec.ts(1 hunks)src/core/filters/global-exception.filter.ts(1 hunks)src/core/guards/__tests__/password-reset-rate-limit.guard.spec.ts(1 hunks)src/core/guards/password-reset-rate-limit.guard.ts(1 hunks)src/core/migrations/1752100192730-CleanupUserPreferencesConstraints.ts(1 hunks)src/migrations/1752086121427-CreateUserPreferencesTable.ts(1 hunks)src/modules/auth/application/use-cases/__tests__/forgot-password.use-case.spec.ts(1 hunks)src/modules/auth/application/use-cases/forgot-password.use-case.ts(1 hunks)src/modules/email/adapters/zoho-mail.adapter.ts(1 hunks)src/modules/permissions/infrastructure/repositories/permission.server.repository.ts(2 hunks)src/modules/permissions/infrastructure/repositories/permission.vm.repository.ts(2 hunks)src/modules/roles/application/use-cases/__tests__/update-user-roles.use-case.spec.ts(18 hunks)src/modules/roles/domain/services/__tests__/safe-role-deletion.domain.service.spec.ts(9 hunks)src/modules/roles/domain/services/safe-role-deletion.domain.service.ts(4 hunks)src/modules/user-preferences/application/controllers/__tests__/user-preferences.controller.spec.ts(1 hunks)src/modules/user-preferences/application/controllers/user-preferences.controller.ts(1 hunks)src/modules/user-preferences/application/dto/update-user-preferences.dto.ts(1 hunks)src/modules/user-preferences/application/dto/user-preferences-response.dto.ts(1 hunks)src/modules/user-preferences/application/use-cases/__tests__/get-user-preferences.use-case.spec.ts(1 hunks)src/modules/user-preferences/application/use-cases/__tests__/reset-user-preferences.use-case.spec.ts(1 hunks)src/modules/user-preferences/application/use-cases/__tests__/update-user-preferences.use-case.spec.ts(1 hunks)src/modules/user-preferences/application/use-cases/get-user-preferences.use-case.ts(1 hunks)src/modules/user-preferences/application/use-cases/index.ts(1 hunks)src/modules/user-preferences/application/use-cases/reset-user-preferences.use-case.ts(1 hunks)src/modules/user-preferences/application/use-cases/update-user-preferences.use-case.ts(1 hunks)src/modules/user-preferences/domain/entities/__tests__/user-preference.entity.spec.ts(1 hunks)src/modules/user-preferences/domain/entities/user-preference.entity.ts(1 hunks)src/modules/user-preferences/domain/exceptions/__tests__/user-preferences.exception.spec.ts(1 hunks)src/modules/user-preferences/domain/exceptions/user-preferences.exception.ts(1 hunks)src/modules/user-preferences/domain/interfaces/user-preferences.repository.interface.ts(1 hunks)src/modules/user-preferences/domain/value-objects/__tests__/timezone.validator.spec.ts(1 hunks)src/modules/user-preferences/domain/value-objects/timezone.validator.ts(1 hunks)src/modules/user-preferences/infrastructure/repositories/__tests__/user-preferences.repository.spec.ts(1 hunks)src/modules/user-preferences/infrastructure/repositories/user-preferences.repository.ts(1 hunks)src/modules/user-preferences/user-preferences.module.ts(1 hunks)src/modules/users/application/use-cases/create-user-by-admin.use-case.ts(4 hunks)src/modules/users/application/use-cases/register-user.use-case.ts(3 hunks)src/modules/users/domain/entities/user.entity.ts(1 hunks)
✅ Files skipped from review due to trivial changes (2)
- src/modules/user-preferences/domain/value-objects/tests/timezone.validator.spec.ts
- src/core/decorators/rate-limit.decorator.ts
🚧 Files skipped from review as they are similar to previous changes (30)
- src/modules/user-preferences/application/use-cases/index.ts
- src/modules/user-preferences/domain/value-objects/timezone.validator.ts
- src/modules/roles/application/use-cases/tests/update-user-roles.use-case.spec.ts
- src/modules/user-preferences/domain/entities/tests/user-preference.entity.spec.ts
- src/core/filters/global-exception.filter.ts
- package.json
- src/modules/user-preferences/application/use-cases/get-user-preferences.use-case.ts
- src/modules/user-preferences/application/use-cases/tests/get-user-preferences.use-case.spec.ts
- src/modules/user-preferences/user-preferences.module.ts
- src/modules/user-preferences/application/use-cases/reset-user-preferences.use-case.ts
- src/modules/permissions/infrastructure/repositories/permission.server.repository.ts
- src/modules/user-preferences/domain/interfaces/user-preferences.repository.interface.ts
- src/core/filters/tests/global-exception.filter.spec.ts
- src/modules/user-preferences/application/use-cases/update-user-preferences.use-case.ts
- src/modules/user-preferences/application/use-cases/tests/reset-user-preferences.use-case.spec.ts
- src/core/guards/password-reset-rate-limit.guard.ts
- src/core/guards/tests/password-reset-rate-limit.guard.spec.ts
- src/migrations/1752086121427-CreateUserPreferencesTable.ts
- src/modules/user-preferences/infrastructure/repositories/user-preferences.repository.ts
- src/modules/roles/domain/services/safe-role-deletion.domain.service.ts
- src/modules/user-preferences/application/controllers/tests/user-preferences.controller.spec.ts
- src/modules/auth/application/use-cases/tests/forgot-password.use-case.spec.ts
- src/modules/user-preferences/infrastructure/repositories/tests/user-preferences.repository.spec.ts
- src/modules/user-preferences/application/controllers/user-preferences.controller.ts
- src/modules/permissions/infrastructure/repositories/permission.vm.repository.ts
- src/modules/user-preferences/domain/exceptions/tests/user-preferences.exception.spec.ts
- src/modules/auth/application/use-cases/forgot-password.use-case.ts
- src/modules/user-preferences/application/dto/update-user-preferences.dto.ts
- src/modules/user-preferences/domain/entities/user-preference.entity.ts
- src/modules/user-preferences/application/dto/user-preferences-response.dto.ts
🧰 Additional context used
🧬 Code Graph Analysis (4)
src/modules/users/application/use-cases/register-user.use-case.ts (1)
src/modules/user-preferences/domain/interfaces/user-preferences.repository.interface.ts (1)
IUserPreferencesRepository(3-8)
src/modules/users/application/use-cases/create-user-by-admin.use-case.ts (1)
src/modules/user-preferences/domain/interfaces/user-preferences.repository.interface.ts (1)
IUserPreferencesRepository(3-8)
src/modules/user-preferences/application/use-cases/__tests__/update-user-preferences.use-case.spec.ts (3)
src/modules/user-preferences/domain/interfaces/user-preferences.repository.interface.ts (1)
IUserPreferencesRepository(3-8)src/modules/user-preferences/application/dto/update-user-preferences.dto.ts (1)
UpdateUserPreferencesDto(135-186)src/modules/user-preferences/domain/exceptions/user-preferences.exception.ts (1)
UserPreferencesExceptions(3-45)
src/modules/roles/domain/services/__tests__/safe-role-deletion.domain.service.spec.ts (3)
src/modules/permissions/infrastructure/interfaces/permission.vm.repository.interface.ts (1)
PermissionVmRepositoryInterface(4-5)src/modules/permissions/infrastructure/interfaces/permission.server.repository.interface.ts (1)
PermissionServerRepositoryInterface(4-7)src/modules/roles/__mocks__/role.mock.ts (1)
createMockRole(7-19)
🪛 ESLint
src/core/migrations/1752100192730-CleanupUserPreferencesConstraints.ts
[error] 1-1: Replace "typeorm" with 'typeorm'
(prettier/prettier)
[error] 3-3: Replace ·implements·MigrationInterface· with ⏎··implements·MigrationInterface⏎
(prettier/prettier)
[error] 4-5: Delete ⏎··
(prettier/prettier)
[error] 6-6: Replace ········ with ····
(prettier/prettier)
[error] 7-7: Delete ····
(prettier/prettier)
[error] 12-12: Delete ········
(prettier/prettier)
[error] 13-13: Delete ····
(prettier/prettier)
[error] 14-14: Delete ····
(prettier/prettier)
[error] 18-18: Delete ········
(prettier/prettier)
[error] 19-19: Delete ····
(prettier/prettier)
[error] 20-20: Replace ········ with ····
(prettier/prettier)
[error] 24-24: Delete ········
(prettier/prettier)
[error] 25-25: Delete ····
(prettier/prettier)
[error] 26-26: Delete ····
(prettier/prettier)
[error] 37-37: Delete ··
(prettier/prettier)
[error] 39-39: Delete ··
(prettier/prettier)
[error] 40-40: Replace ········ with ····
(prettier/prettier)
[error] 41-41: Delete ····
(prettier/prettier)
[error] 45-45: Delete ········
(prettier/prettier)
[error] 46-46: Delete ····
(prettier/prettier)
[error] 47-47: Delete ····
(prettier/prettier)
[error] 51-52: Replace ··}⏎ with }
(prettier/prettier)
src/modules/email/adapters/zoho-mail.adapter.ts
[error] 59-59: 'error' is defined but never used.
(@typescript-eslint/no-unused-vars)
🪛 Biome (1.9.4)
src/modules/user-preferences/domain/exceptions/user-preferences.exception.ts
[error] 3-45: Avoid classes that contain only static members.
Prefer using simple functions instead of classes with only static members.
(lint/complexity/noStaticOnlyClass)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (17)
src/modules/roles/domain/services/__tests__/safe-role-deletion.domain.service.spec.ts (8)
4-5: LGTM: Clean import additions for permission repositories.The imports are properly structured and align with the enhanced functionality for permission deletion during role deletion.
17-18: LGTM: Proper mock variable declarations.The mock variables are correctly typed with
jest.Mocked<>for both permission repository interfaces.
35-48: LGTM: Comprehensive mock setup for permission repositories.The mock implementations include all the necessary methods (
findAllByField,deletePermission,deleteById,deleteByRoleId) that would be expected from the repository interfaces. The setup ensures proper isolation for testing.
49-54: LGTM: Service constructor properly updated with new dependencies.The service constructor correctly includes the permission repositories as dependencies, maintaining the dependency injection pattern.
76-78: LGTM: Proper assertion for permission deletion in role deletion flow.The test correctly verifies that both permission repositories'
deleteByRoleIdmethods are called with the role ID during the deletion process.
113-115: LGTM: Consistent permission deletion verification across all test scenarios.All existing test cases have been properly updated to include assertions for permission deletion, ensuring comprehensive coverage of the new functionality across different user role scenarios.
Also applies to: 140-142, 174-176, 213-215
301-317: LGTM: Dedicated test for permission deletion behavior.This test specifically focuses on verifying that permissions are deleted before the role deletion occurs. The test setup is clean and the assertions are appropriate for validating the core functionality.
319-339: LGTM: Excellent error handling test coverage.This test properly verifies that:
- When permission deletion fails, the error is propagated
- Role deletion does not proceed if permission deletion fails
- The error handling maintains system integrity
The test setup with
mockRejectedValueand the expectation thatroleRepo.deleteRoleis not called demonstrates proper error boundary testing.src/modules/user-preferences/application/use-cases/__tests__/update-user-preferences.use-case.spec.ts (1)
8-371: Excellent test coverage and structure.This test suite provides comprehensive coverage of the UpdateUserPreferencesUseCase with well-structured scenarios:
- ✅ Update existing preferences
- ✅ Create preferences when none exist
- ✅ Nested object updates (notifications, display, integrations, performance)
- ✅ Partial updates preserving existing values
- ✅ Edge cases (empty strings, undefined values)
- ✅ Error handling (invalid timezone, repository failures)
- ✅ Integration webhooks and email handling
The test structure follows good practices with proper mocking, clear test names, and comprehensive assertions.
src/modules/users/domain/entities/user.entity.ts (1)
64-68: LGTM! Password reset fields properly implemented.The addition of
resetPasswordTokenandresetPasswordExpiryfields correctly supports password reset functionality:
- ✅ Both fields are nullable, appropriate for optional reset tokens
- ✅ Proper TypeScript typing with optional properties
- ✅ Follows existing column definition patterns
- ✅
varchartype suitable for tokens,timestampfor expirysrc/modules/users/application/use-cases/register-user.use-case.ts (2)
35-36: Good integration pattern with optional dependency injection.The optional injection of
IUserPreferencesRepositoryprovides a clean way to integrate user preferences without breaking existing functionality.
67-70: Proper integration of default preferences creation.The conditional creation of default preferences is well-implemented:
- ✅ Checks for repository availability before attempting creation
- ✅ Uses factory method
UserPreference.createDefault()- ✅ Placed after user creation but before logging
- ✅ Maintains existing error handling flow
src/modules/users/application/use-cases/create-user-by-admin.use-case.ts (3)
29-31: Consistent dependency injection pattern.The addition of
EventEmitter2and optionalIUserPreferencesRepositoryfollows the same pattern as the register use case, maintaining consistency across the codebase.
73-76: Proper integration of default preferences creation.The conditional creation of default preferences maintains the same pattern as the register use case, ensuring consistency across user creation flows.
80-83: Good email event emission with fallback handling.The email event emission is well-implemented:
- ✅ Uses proper event type from domain events
- ✅ Includes necessary data (email, firstname)
- ✅ Provides fallback to username when firstName is unavailable
- ✅ Emitted after user creation and preferences setup
src/core/migrations/1752100192730-CleanupUserPreferencesConstraints.ts (2)
26-36: Excellent defensive programming with conditional constraint addition.The DO block properly checks for constraint existence before adding it, preventing migration failures on re-runs.
3-3: Verify migration timestamp validityThe timestamp prefix
1752100192730resolves to a date in mid-2025. Confirm that this matches your project’s migration naming scheme (e.g. milliseconds-since-epoch at generation time) and that your system clock was correct when this migration was created.
- File:
src/core/migrations/1752100192730-CleanupUserPreferencesConstraints.ts- To double-check, you can run:
python3 - << 'EOF' import datetime print(datetime.datetime.utcfromtimestamp(1752100192730/1000).isoformat()) EOF
| logoUrl, | ||
| loginUrl: process.env.APP_URL ?? 'http://localhost:3000', | ||
| currentYear: new Date().getFullYear(), | ||
| supportEmail: process.env.SUPPORT_EMAIL || '[email protected]', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider making SUPPORT_EMAIL a required environment variable.
Similar to the APP_URL issue, the fallback to [email protected] might not be appropriate for all environments and could lead to support emails being sent to the wrong address.
- supportEmail: process.env.SUPPORT_EMAIL || '[email protected]',
+ supportEmail: process.env.SUPPORT_EMAIL || (() => {
+ this.logger.warn('SUPPORT_EMAIL not configured, using default fallback');
+ return '[email protected]';
+ })(),📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| supportEmail: process.env.SUPPORT_EMAIL || '[email protected]', | |
| supportEmail: process.env.SUPPORT_EMAIL || (() => { | |
| this.logger.warn('SUPPORT_EMAIL not configured, using default fallback'); | |
| return '[email protected]'; | |
| })(), |
🤖 Prompt for AI Agents
In src/modules/email/adapters/zoho-mail.adapter.ts at line 21, the SUPPORT_EMAIL
environment variable currently falls back to a default email address, which may
cause support emails to be sent incorrectly. Remove the fallback default and
instead ensure SUPPORT_EMAIL is always set by throwing an error or failing the
application startup if it is missing, making it a required environment variable.
| } | ||
|
|
||
| return configuredLogoUrl; | ||
| } catch (error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix unused error parameter.
The error parameter in the catch block is defined but never used, which violates the ESLint rule.
- } catch (error) {
- this.logger.warn(`Invalid logo URL: ${configuredLogoUrl}, using default`);
+ } catch (error) {
+ this.logger.warn(`Invalid logo URL: ${configuredLogoUrl}, using default. Error: ${error.message}`);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| } catch (error) { | |
| } catch (error) { | |
| this.logger.warn( | |
| `Invalid logo URL: ${configuredLogoUrl}, using default. Error: ${error.message}` | |
| ); | |
| } |
🧰 Tools
🪛 ESLint
[error] 59-59: 'error' is defined but never used.
(@typescript-eslint/no-unused-vars)
🤖 Prompt for AI Agents
In src/modules/email/adapters/zoho-mail.adapter.ts at line 59, the catch block
defines an error parameter that is not used, causing an ESLint violation. Remove
the unused error parameter from the catch block to fix the issue.
| await queryRunner.query(` | ||
| DELETE FROM user_preferences | ||
| WHERE user_id IS NULL | ||
| OR user_id::uuid NOT IN (SELECT id FROM "user") | ||
| `); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potential issue with UUID casting in DELETE query.
The DELETE query assumes all user_id values can be safely cast to UUID. If there are any invalid UUID strings in the user_id column, this migration will fail.
Consider adding error handling or validation:
- await queryRunner.query(`
- DELETE FROM user_preferences
- WHERE user_id IS NULL
- OR user_id::uuid NOT IN (SELECT id FROM "user")
- `);
+ await queryRunner.query(`
+ DELETE FROM user_preferences
+ WHERE user_id IS NULL
+ OR user_id = ''
+ OR (user_id ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'
+ AND user_id::uuid NOT IN (SELECT id FROM "user"))
+ `);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| await queryRunner.query(` | |
| DELETE FROM user_preferences | |
| WHERE user_id IS NULL | |
| OR user_id::uuid NOT IN (SELECT id FROM "user") | |
| `); | |
| await queryRunner.query(` | |
| DELETE FROM user_preferences | |
| WHERE user_id IS NULL | |
| OR user_id = '' | |
| OR (user_id ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$' | |
| AND user_id::uuid NOT IN (SELECT id FROM "user")) | |
| `); |
🧰 Tools
🪛 ESLint
[error] 7-7: Delete ····
(prettier/prettier)
🤖 Prompt for AI Agents
In src/core/migrations/1752100192730-CleanupUserPreferencesConstraints.ts around
lines 7 to 11, the DELETE query casts user_id to UUID without validating if all
user_id values are valid UUIDs, which can cause the migration to fail. To fix
this, modify the query to filter out or exclude rows where user_id is not a
valid UUID before casting, for example by using a safe UUID validation function
or a regex check in SQL, ensuring only valid UUIDs are cast and compared in the
subquery.
| await queryRunner.query(` | ||
| ALTER TABLE user_preferences | ||
| DROP CONSTRAINT IF EXISTS FK_user_preferences_user | ||
| `); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Foreign key constraint not recreated after dropping.
The migration drops the foreign key constraint but doesn't recreate it in the up method. This could leave the table without proper referential integrity unless handled elsewhere.
Verify that referential integrity is maintained:
🏁 Script executed:
#!/bin/bash
# Description: Check if foreign key constraints are defined elsewhere (entity definitions, other migrations)
# Expected: Find foreign key definition for user_preferences.user_id -> user.id
# Search for foreign key definitions in entity files
rg -A 3 -B 3 "user_preferences.*user.*foreign|user.*user_preferences.*foreign" --type ts
# Search for foreign key constraints in other migrations
rg -A 3 -B 3 "FK_user_preferences_user|user_preferences.*FOREIGN KEY" --type tsLength of output: 932
Missing foreign key recreation in CleanupUserPreferencesConstraints migration
The up method in src/core/migrations/1752100192730-CleanupUserPreferencesConstraints.ts drops the FK but never re-adds it, leaving user_preferences.user_id unprotected.
Locations needing attention:
- File: src/core/migrations/1752100192730-CleanupUserPreferencesConstraints.ts
Lines: ~14–17 (after theDROP CONSTRAINTand column alteration)
Suggested fix (add after making user_id NOT NULL):
await queryRunner.query(`
ALTER TABLE user_preferences
DROP CONSTRAINT IF EXISTS FK_user_preferences_user
`);
+ await queryRunner.query(`
+ ALTER TABLE user_preferences
+ ADD CONSTRAINT FK_user_preferences_user
+ FOREIGN KEY (user_id) REFERENCES "user"(id)
+ `);Also ensure the down method drops this new FK before reversing the column change.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| await queryRunner.query(` | |
| ALTER TABLE user_preferences | |
| DROP CONSTRAINT IF EXISTS FK_user_preferences_user | |
| `); | |
| await queryRunner.query(` | |
| ALTER TABLE user_preferences | |
| DROP CONSTRAINT IF EXISTS FK_user_preferences_user | |
| `); | |
| await queryRunner.query(` | |
| ALTER TABLE user_preferences | |
| ADD CONSTRAINT FK_user_preferences_user | |
| FOREIGN KEY (user_id) REFERENCES "user"(id) | |
| `); |
🧰 Tools
🪛 ESLint
[error] 14-14: Delete ····
(prettier/prettier)
🤖 Prompt for AI Agents
In src/core/migrations/1752100192730-CleanupUserPreferencesConstraints.ts around
lines 14 to 17, after dropping the foreign key constraint and altering the
user_id column, add a query to recreate the foreign key constraint on
user_preferences.user_id referencing the users table. Also, update the down
method to drop this newly added foreign key constraint before reversing the
user_id column changes to maintain migration consistency.
| public async down(queryRunner: QueryRunner): Promise<void> { | ||
| // Remove unique constraint | ||
| await queryRunner.query(` | ||
| ALTER TABLE user_preferences | ||
| DROP CONSTRAINT IF EXISTS UQ_user_preferences_user_id | ||
| `); | ||
|
|
||
| // Make user_id nullable | ||
| await queryRunner.query(` | ||
| ALTER TABLE user_preferences | ||
| ALTER COLUMN user_id DROP NOT NULL | ||
| `); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Incomplete rollback in down method.
The down method doesn't attempt to recreate the foreign key constraint that was dropped in the up method, making the rollback incomplete.
Consider adding foreign key constraint recreation:
public async down(queryRunner: QueryRunner): Promise<void> {
// Remove unique constraint
await queryRunner.query(`
ALTER TABLE user_preferences
DROP CONSTRAINT IF EXISTS UQ_user_preferences_user_id
`);
+ // Recreate foreign key constraint
+ await queryRunner.query(`
+ ALTER TABLE user_preferences
+ ADD CONSTRAINT FK_user_preferences_user
+ FOREIGN KEY (user_id) REFERENCES "user"(id) ON DELETE CASCADE
+ `);
+
// Make user_id nullable
await queryRunner.query(`
ALTER TABLE user_preferences
ALTER COLUMN user_id DROP NOT NULL
`);
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| public async down(queryRunner: QueryRunner): Promise<void> { | |
| // Remove unique constraint | |
| await queryRunner.query(` | |
| ALTER TABLE user_preferences | |
| DROP CONSTRAINT IF EXISTS UQ_user_preferences_user_id | |
| `); | |
| // Make user_id nullable | |
| await queryRunner.query(` | |
| ALTER TABLE user_preferences | |
| ALTER COLUMN user_id DROP NOT NULL | |
| `); | |
| } | |
| public async down(queryRunner: QueryRunner): Promise<void> { | |
| // Remove unique constraint | |
| await queryRunner.query(` | |
| ALTER TABLE user_preferences | |
| DROP CONSTRAINT IF EXISTS UQ_user_preferences_user_id | |
| `); | |
| // Recreate foreign key constraint | |
| await queryRunner.query(` | |
| ALTER TABLE user_preferences | |
| ADD CONSTRAINT FK_user_preferences_user | |
| FOREIGN KEY (user_id) REFERENCES "user"(id) ON DELETE CASCADE | |
| `); | |
| // Make user_id nullable | |
| await queryRunner.query(` | |
| ALTER TABLE user_preferences | |
| ALTER COLUMN user_id DROP NOT NULL | |
| `); | |
| } |
🧰 Tools
🪛 ESLint
[error] 39-39: Delete ··
(prettier/prettier)
[error] 40-40: Replace ········ with ····
(prettier/prettier)
[error] 41-41: Delete ····
(prettier/prettier)
[error] 45-45: Delete ········
(prettier/prettier)
[error] 46-46: Delete ····
(prettier/prettier)
[error] 47-47: Delete ····
(prettier/prettier)
🤖 Prompt for AI Agents
In src/core/migrations/1752100192730-CleanupUserPreferencesConstraints.ts around
lines 39 to 51, the down method removes the unique constraint and makes user_id
nullable but does not recreate the foreign key constraint dropped in the up
method. To fix this, add a query in the down method to recreate the foreign key
constraint on user_id referencing the users table, ensuring the rollback fully
restores the original database schema state.



Summary by CodeRabbit
New Features
Improvements
Bug Fixes
Documentation
Tests
Chores