@solidstarters/solid-core 1.2.143 → 1.2.144

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/dist/constants/error-messages.d.ts +83 -0
  2. package/dist/constants/error-messages.d.ts.map +1 -0
  3. package/dist/constants/error-messages.js +86 -0
  4. package/dist/constants/error-messages.js.map +1 -0
  5. package/dist/constants/success-messages.d.ts +11 -0
  6. package/dist/constants/success-messages.d.ts.map +1 -0
  7. package/dist/constants/success-messages.js +14 -0
  8. package/dist/constants/success-messages.js.map +1 -0
  9. package/dist/index.d.ts +1 -0
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +3 -1
  12. package/dist/index.js.map +1 -1
  13. package/dist/services/ai-interaction.service.d.ts.map +1 -1
  14. package/dist/services/ai-interaction.service.js +4 -3
  15. package/dist/services/ai-interaction.service.js.map +1 -1
  16. package/dist/services/authentication.service.d.ts.map +1 -1
  17. package/dist/services/authentication.service.js +66 -64
  18. package/dist/services/authentication.service.js.map +1 -1
  19. package/dist/services/crud-helper.service.d.ts.map +1 -1
  20. package/dist/services/crud-helper.service.js +3 -2
  21. package/dist/services/crud-helper.service.js.map +1 -1
  22. package/dist/services/crud.service.d.ts.map +1 -1
  23. package/dist/services/crud.service.js +23 -21
  24. package/dist/services/crud.service.js.map +1 -1
  25. package/dist/services/csv.service.d.ts.map +1 -1
  26. package/dist/services/csv.service.js +3 -2
  27. package/dist/services/csv.service.js.map +1 -1
  28. package/dist/services/excel.service.d.ts.map +1 -1
  29. package/dist/services/excel.service.js +3 -2
  30. package/dist/services/excel.service.js.map +1 -1
  31. package/dist/services/export-transaction.service.d.ts.map +1 -1
  32. package/dist/services/export-transaction.service.js +2 -1
  33. package/dist/services/export-transaction.service.js.map +1 -1
  34. package/dist/services/field-metadata.service.d.ts.map +1 -1
  35. package/dist/services/field-metadata.service.js +9 -8
  36. package/dist/services/field-metadata.service.js.map +1 -1
  37. package/dist/services/file.service.d.ts.map +1 -1
  38. package/dist/services/file.service.js +5 -4
  39. package/dist/services/file.service.js.map +1 -1
  40. package/dist/services/import-transaction.service.d.ts.map +1 -1
  41. package/dist/services/import-transaction.service.js +10 -9
  42. package/dist/services/import-transaction.service.js.map +1 -1
  43. package/dist/services/media-storage-provider-metadata.service.d.ts.map +1 -1
  44. package/dist/services/media-storage-provider-metadata.service.js +4 -3
  45. package/dist/services/media-storage-provider-metadata.service.js.map +1 -1
  46. package/dist/services/media.service.d.ts.map +1 -1
  47. package/dist/services/media.service.js +2 -1
  48. package/dist/services/media.service.js.map +1 -1
  49. package/dist/services/model-metadata.service.d.ts.map +1 -1
  50. package/dist/services/model-metadata.service.js +10 -9
  51. package/dist/services/model-metadata.service.js.map +1 -1
  52. package/dist/services/module-metadata.service.d.ts.map +1 -1
  53. package/dist/services/module-metadata.service.js +11 -10
  54. package/dist/services/module-metadata.service.js.map +1 -1
  55. package/dist/services/role-metadata.service.d.ts.map +1 -1
  56. package/dist/services/role-metadata.service.js +3 -2
  57. package/dist/services/role-metadata.service.js.map +1 -1
  58. package/dist/services/sql-expression-resolver.service.d.ts.map +1 -1
  59. package/dist/services/sql-expression-resolver.service.js +2 -1
  60. package/dist/services/sql-expression-resolver.service.js.map +1 -1
  61. package/dist/services/user.service.d.ts.map +1 -1
  62. package/dist/services/user.service.js +11 -10
  63. package/dist/services/user.service.js.map +1 -1
  64. package/dist/tsconfig.tsbuildinfo +1 -1
  65. package/package.json +1 -1
  66. package/src/constants/error-messages.ts +123 -0
  67. package/src/constants/success-messages.ts +13 -0
  68. package/src/index.ts +3 -1
  69. package/src/services/ai-interaction.service.ts +4 -3
  70. package/src/services/authentication.service.ts +66 -64
  71. package/src/services/crud-helper.service.ts +3 -2
  72. package/src/services/crud.service.ts +23 -23
  73. package/src/services/csv.service.ts +3 -2
  74. package/src/services/excel.service.ts +3 -2
  75. package/src/services/export-transaction.service.ts +2 -1
  76. package/src/services/field-metadata.service.ts +9 -8
  77. package/src/services/file.service.ts +5 -4
  78. package/src/services/import-transaction.service.ts +10 -9
  79. package/src/services/media-storage-provider-metadata.service.ts +4 -3
  80. package/src/services/media.service.ts +2 -1
  81. package/src/services/model-metadata.service.ts +10 -9
  82. package/src/services/module-metadata.service.ts +11 -10
  83. package/src/services/role-metadata.service.ts +3 -2
  84. package/src/services/sql-expression-resolver.service.ts +2 -1
  85. package/src/services/user.service.ts +11 -10
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidstarters/solid-core",
3
- "version": "1.2.143",
3
+ "version": "1.2.144",
4
4
  "description": "This module is a NestJS module containing all the required core providers required by a Solid application",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -0,0 +1,123 @@
1
+ // backend/common/constants/error-messages.ts
2
+
3
+ export const ERROR_MESSAGES = {
4
+ //authentication errors
5
+ USER_NOT_FOUND: 'User does not exist.',
6
+ USER_NOT_ACTIVE: 'User profile is not activated.',
7
+ USER_INACTIVE: 'User is inactive.',
8
+ PASSWORD_INCORRECT: 'Password does not match.',
9
+ PUBLIC_REGISTRATION_DISABLED: 'Public registrations are disabled.',
10
+ UNIQUE_CONSTRAINT_VIOLATION: 'A unique constraint violation occurred.',
11
+ PASSWORDLESS_REGISTRATION_DISABLED: 'Passwordless registration is not enabled.',
12
+ REGISTRATION_REQUIRES_CONTACT: 'Either mobile or email is required for initiating registration.',
13
+ EMAIL_REQUIRED_FOR_VALIDATION: 'Email is required for email validation source.',
14
+ MOBILE_REQUIRED_FOR_VALIDATION: 'Mobile is required for mobile validation source.',
15
+ USER_ALREADY_EXISTS: 'User already exists. Please sign in.',
16
+ VALIDATION_SOURCE_REQUIRED: 'At least one validation source is required.',
17
+ INVALID_OTP: 'Invalid OTP.',
18
+ OTP_EXPIRED: 'OTP has expired.',
19
+ INVALID_VERIFICATION_TYPE: 'Invalid type. Must be either email or mobile.',
20
+ NON_LOCAL_PROVIDER: 'User seems to have used a passwordless mode to authenticate.',
21
+ USER_ID_MISMATCH: "User ID's do not match.",
22
+ USERNAME_MISMATCH: "User username's do not match.",
23
+ INCORRECT_CURRENT_PASSWORD: 'Incorrect current password specified.',
24
+ PASSWORD_REUSED: 'This password was previously used, please use a different password.',
25
+ INVALID_VERIFICATION_TOKEN: 'Invalid verification token',
26
+ ACCESS_DENIED: 'Access denied',
27
+ INVALID_USER_PROFILE: 'Invalid user profile',
28
+ GOOGLE_OAUTH_PROFILE_FETCH_FAILED: 'Failed to fetch user profile from Google OAuth service',
29
+ LOGOUT_FAILED: 'Logout failed due to an unexpected error.',
30
+
31
+ INVALID_CREDENTIALS: 'Invalid username or password specified.',
32
+ LOGIN_FAILED: 'Login Failed',
33
+ OLD_PASSWORD_INCORRECT: 'You have specified an incorrect old password.',
34
+ INVALID_NEW_PASSWORD: 'Invalid new password.',
35
+ PASSWORDS_DO_NOT_MATCH: 'New passwords are not matching.',
36
+
37
+ // user management errors
38
+ DELETE_SELF_NOT_ALLOWED: 'Deleting logged-in user is not allowed.',
39
+ DELETE_IDS_REQUIRED: 'At least one ID is required for deletion.',
40
+ USER_MISSING_ID: 'User must exist before initializing roles.',
41
+ ROLES_NOT_FOUND: (roles: string[]) => `The following roles were not found: ${roles.join(', ')}`,
42
+ USER_NOT_FOUND_BY_USERNAME: (username: string) => `User with username '${username}' not found.`,
43
+ ROLE_NOT_FOUND: (roleName: string) => `Role '${roleName}' not found.`,
44
+ PERMISSION_NOT_EXIST: (permission: string) => `Permission '${permission}' does not exist.`,
45
+
46
+ // session errors
47
+ SESSION_INVALID: 'Your session is no longer valid. Please log in again.',
48
+ SESSION_EXPIRED: 'Your session has expired. Please log in again.',
49
+
50
+ // filter errors
51
+ GROUP_BY_LIMIT: 'buildFilterQuery: Only 1 Group by field is supported currently.',
52
+ INVALID_GROUP_BY_COUNT: 'Exactly one groupBy field is required to count grouped records.',
53
+
54
+ // general errors
55
+ FORBIDDEN: 'Forbidden',
56
+
57
+
58
+ // database errors
59
+ DUPLICATE_ENTRY: 'Duplicate entry. A record with similar unique fields already exists.',
60
+
61
+ // validation errors
62
+ ID_REQUIRED_FOR_UPDATE: 'Id is required for update.',
63
+ ID_REQUIRED_FOR_DELETE: 'Id is required for deletion.',
64
+
65
+ // CRUD service errors
66
+ RELATION_TYPE_NOT_SUPPORTED: 'Relation type not supported in CRUD service.',
67
+ NO_SOFT_DELETED_RECORD_FOUND: 'No soft-deleted record found with the given ID.',
68
+ CONFLICTING_RECORD_ON_UNARCHIVE: 'Another record is conflicting with the record you are attempting to Un-Archive, either delete or change the other record so as to avoid this conflict.',
69
+ NO_SOFT_DELETED_RECORDS_FOUND: 'No matching soft-deleted records found.',
70
+ EMPTY_PATH_PARTS: 'Path parts cannot be empty',
71
+
72
+
73
+ // CSV/Excel service errors
74
+ MISSING_HEADERS_OR_FUNCTION: 'Either headers or data records function must be provided.',
75
+ INVALID_CHUNK_SIZE: 'Chunk size must be greater than 0 when data records function is provided.',
76
+ INVALID_FORMAT: (format: string) => `Invalid ${format} format`,
77
+
78
+
79
+ //field errors
80
+ INVALID_INVERSE_FIELD_TYPE: 'Only relation fields can have inverse fields.',
81
+ MODEL_AND_MODULE_REQUIRED_TO_UPDATE_INVERSE_FIELD: 'Model and module are required to update inverse field.',
82
+ MODEL_NAME_AND_MODULE_NAME_REQUIRED_TO_CREATE_INVERSE_FIELD: 'Model name and module name are required to create inverse field.',
83
+ FIELD_NOT_FOUND: (id: number | string) => `No field with id #${id} exists`,
84
+ PROVIDER_NOT_FOUND: (provider: string) => `Field incorrectly configured. No provider with name ${provider} registered in backend.`,
85
+ FILE_WRITE_FAILED: 'File creation failed, rolling back transaction',
86
+
87
+ // file service errors
88
+ FILE_NOT_FOUND: 'File not found',
89
+ FILE_COPY_ERROR: 'Error copying file',
90
+ S3_CLIENT_NOT_INITIALIZED: 'S3 Client not initialized. Please check the S3 configuration.',
91
+
92
+ // model errors
93
+ MODEL_METADATA_NOT_FOUND: (id: string | number) => `Model metadata with ID ${id} not found.`,
94
+ MODEL_SERVICE_NOT_FOUND: (model: string) => `Model service for ${model} not found.`,
95
+ RELATION_CO_MODEL_NOT_DEFINED_FOR_FIELD: (fieldName: string) => `Relation coModelSingularName is not defined for relation field ${fieldName}`,
96
+ MODEL_NOT_FOUND: (singularName?: string) => `Model${singularName ? ` with singular name "${singularName}"` : ''} not found.`,
97
+ MODEL_REQUIRED_FOR_CODE_GENERATION: 'Model ID or Model Name is required for generating code.',
98
+
99
+ //module errors
100
+ MODULE_NOT_FOUND: (moduleName: string) => `Module with name ${moduleName} not found.`,
101
+ MODULE_ID_NOT_FOUND: (id: string | number) => `Module with ID ${id} not found.`,
102
+
103
+ //entity errors
104
+ ENTITY_NOT_FOUND: (entity?: string | number) => `Entity${entity ? ' ' + entity : ''} not found.`,
105
+ ENTITY_NAME_REQUIRED: 'Entity name is required to find the entity.',
106
+ ENTITY_ID_REQUIRED: 'Entity ID is required to find the entity.',
107
+
108
+ // import errors
109
+ NO_ERROR_LOG_FOR_IMPORT: (id: string | number) => `No error log entries found for import transaction ID ${id}.`,
110
+ FILE_READ_FAILED_FROM_URL: (url: string) => `Failed to read file from URL: ${url}`,
111
+
112
+ // media storage provider errors
113
+ MEDIA_STORAGE_PROVIDER_ID_NOT_FOUND: (id: number | string) => `Media Storage Provider with #${id} not found.`,
114
+ MEDIA_STORAGE_PROVIDER_NOT_FOUND: 'Media Storage Provider not found',
115
+
116
+ // SQL errors
117
+ UNSUPPORTED_SQL_OPERATOR: (operator: string) => `Unsupported SQL operator: ${operator}`,
118
+
119
+ // AI interaction errors
120
+ PYTHON_EXECUTABLE_NOT_CONFIGURED: 'SolidX AI MCP python executable or client path not configured.',
121
+ UNABLE_TO_RESOLVE_SOLID_COMMAND: 'Unable to resolve a solid_ command that was used to come up with this response.',
122
+ UNABLE_TO_RESOLVE_MCP_HANDLER: 'Unable to resolve a mcp tool handler.',
123
+ };
@@ -0,0 +1,13 @@
1
+ export const SUCCESS_MESSAGES = {
2
+ OTP_SENT_SUCCESS_REGISTRATION: 'User registration initiated. OTP sent to the user.',
3
+ OTP_SENT_SUCCESS_LOGIN: 'User login initiated. OTP sent to the user.',
4
+ FORGOT_PASSWORD_TOKEN_SENT: 'Forgot password - token generated and sent.',
5
+ FORGOT_PASSWORD_CONFIRMED: 'Forgot password confirmed.',
6
+ LOGOUT_SUCCESS: 'Logged out successfully',
7
+ USER_REGISTERED: 'User registered successfully.',
8
+
9
+ // CRUD service messages
10
+ RECORD_RECOVERED: 'Record successfully recovered',
11
+ SELECTED_RECORDS_RECOVERED: 'Selected records successfully recovered',
12
+
13
+ };
package/src/index.ts CHANGED
@@ -282,4 +282,6 @@ export * from './interfaces'
282
282
  export * from './solid-core.module'
283
283
 
284
284
  export * from './winston.logger'
285
- export { default as datetimeTransformer } from './transformers/datetime-transformer'
285
+ export { default as datetimeTransformer } from './transformers/datetime-transformer'
286
+
287
+ export { ERROR_MESSAGES } from './constants/error-messages'
@@ -17,6 +17,7 @@ import { PublisherFactory } from './queues/publisher-factory.service';
17
17
  import { RequestContextService } from './request-context.service';
18
18
  import { ActiveUserData } from 'src/interfaces/active-user-data.interface';
19
19
  import { McpToolResponseHandlerFactory } from './mcp-tool-response-handlers/mcp-tool-response-handler-factory.service';
20
+ import { ERROR_MESSAGES } from 'src/constants/error-messages';
20
21
 
21
22
  @Injectable()
22
23
  export class AiInteractionService extends CRUDService<AiInteraction> {
@@ -78,7 +79,7 @@ export class AiInteractionService extends CRUDService<AiInteraction> {
78
79
 
79
80
  // TODO: We can return an error if the above env variables are not properly setup...
80
81
  if (!pythonExecutable || !mcpClient) {
81
- throw new BadRequestException('SolidX AI MCP python executable or client path not configured.');
82
+ throw new BadRequestException(ERROR_MESSAGES.PYTHON_EXECUTABLE_NOT_CONFIGURED);
82
83
  }
83
84
 
84
85
  // Check if both paths are valid and accessible
@@ -187,7 +188,7 @@ export class AiInteractionService extends CRUDService<AiInteraction> {
187
188
  const toolsInvoked = metadata['tools_invoked'];
188
189
  if (!toolsInvoked) {
189
190
  // TODO: RESPONSE SHAPE ALERT Check if we want to control the shape of the response....
190
- throw new Error('Unable to resolve a solid_ command that was used to come up with this response.');
191
+ throw new Error(ERROR_MESSAGES.UNABLE_TO_RESOLVE_SOLID_COMMAND);
191
192
  }
192
193
 
193
194
  // TODO: OPTIMISATION for chained tool invocation, for now we are assuming only 1 tool was used.
@@ -198,7 +199,7 @@ export class AiInteractionService extends CRUDService<AiInteraction> {
198
199
  const mcpToolHandler = this.mcpToolResponseHandlerFactory.getInstance(toolInvoked);
199
200
  if (!mcpToolHandler) {
200
201
  // TODO: RESPONSE SHAPE ALERT Check if we want to control the shape of the response....
201
- throw new Error('Unable to resolve a mcp tool handler.');
202
+ throw new Error(ERROR_MESSAGES.UNABLE_TO_RESOLVE_MCP_HANDLER);
202
203
  }
203
204
 
204
205
  const handlerApplicationResponse = await mcpToolHandler.apply(aiInteraction);
@@ -46,6 +46,8 @@ import { RoleMetadataService } from './role-metadata.service';
46
46
  import commonConfig from 'src/config/common.config';
47
47
  import { UserActivityHistoryService } from './user-activity-history.service';
48
48
  import { RequestContextService } from './request-context.service';
49
+ import { ERROR_MESSAGES } from 'src/constants/error-messages';
50
+ import { SUCCESS_MESSAGES } from 'src/constants/success-messages';
49
51
 
50
52
 
51
53
  enum LoginProvider {
@@ -111,17 +113,17 @@ export class AuthenticationService {
111
113
  const user = await this.resolveUser(signInDto.username, signInDto.email);
112
114
 
113
115
  if (!user) {
114
- throw new UnauthorizedException('User does not exists');
116
+ throw new UnauthorizedException(ERROR_MESSAGES.USER_NOT_FOUND);
115
117
  }
116
118
  if (!user.active) {
117
- throw new UnauthorizedException('User profile not activated');
119
+ throw new UnauthorizedException(ERROR_MESSAGES.USER_NOT_ACTIVE);
118
120
  }
119
121
  const isEqual = await this.hashingService.compare(
120
122
  signInDto.password,
121
123
  user.password,
122
124
  );
123
125
  if (!isEqual) {
124
- throw new UnauthorizedException('Password does not match');
126
+ throw new UnauthorizedException(ERROR_MESSAGES.PASSWORD_INCORRECT);
125
127
  }
126
128
 
127
129
  return user;
@@ -130,7 +132,7 @@ export class AuthenticationService {
130
132
  async signUp(signUpDto: SignUpDto, activeUser: ActiveUserData = null): Promise<User> {
131
133
  // If public registrations are disabled and no activeUser is present when invoking signUp then we throw an exception.
132
134
  if (!(await this.settingService.getConfigValue('allowPublicRegistration')) && !activeUser) {
133
- throw new BadRequestException('Public registrations are disabled.');
135
+ throw new BadRequestException(ERROR_MESSAGES.PUBLIC_REGISTRATION_DISABLED);
134
136
  }
135
137
 
136
138
  try {
@@ -150,7 +152,7 @@ export class AuthenticationService {
150
152
  } catch (err) {
151
153
  const pgUniqueViolationErrorCode = '23505';
152
154
  if (err.code === pgUniqueViolationErrorCode) {
153
- throw new ConflictException();
155
+ throw new ConflictException(ERROR_MESSAGES.USER_ALREADY_EXISTS);
154
156
  }
155
157
  throw err;
156
158
  }
@@ -172,7 +174,7 @@ export class AuthenticationService {
172
174
  catch (err) {
173
175
  const pgUniqueViolationErrorCode = '23505';
174
176
  if (err.code === pgUniqueViolationErrorCode) {
175
- throw new ConflictException(parseUniqueConstraintError(err.detail || 'A unique constraint violation occurred.'));
177
+ throw new ConflictException(parseUniqueConstraintError(err.detail || ERROR_MESSAGES.UNIQUE_CONSTRAINT_VIOLATION));
176
178
  }
177
179
  throw err;
178
180
  }
@@ -275,17 +277,17 @@ export class AuthenticationService {
275
277
  async otpInitiateRegistration(signUpDto: OTPSignUpDto) {
276
278
  try {
277
279
  if (!this.isPasswordlessRegistrationEnabled()) {
278
- throw new BadRequestException('Passwordless registration is not enabled');
280
+ throw new BadRequestException(ERROR_MESSAGES.PASSWORDLESS_REGISTRATION_DISABLED);
279
281
  }
280
282
  // Validate if either mobile or email is present.
281
283
  if (isEmpty(signUpDto.mobile) && isEmpty(signUpDto.email)) {
282
- throw new BadRequestException('Either mobile or email is required for initiating registration');
284
+ throw new BadRequestException(ERROR_MESSAGES.REGISTRATION_REQUIRES_CONTACT);
283
285
  }
284
286
  if (signUpDto.validationSources.includes(TransactionalRegistrationValidationSource.EMAIL) && isEmpty(signUpDto.email)) {
285
- throw new BadRequestException('Email is required for email validation source');
287
+ throw new BadRequestException(ERROR_MESSAGES.EMAIL_REQUIRED_FOR_VALIDATION);
286
288
  }
287
289
  if (signUpDto.validationSources.includes(TransactionalRegistrationValidationSource.MOBILE) && isEmpty(signUpDto.mobile)) {
288
- throw new BadRequestException('Mobile is required for mobile validation source');
290
+ throw new BadRequestException(ERROR_MESSAGES.MOBILE_REQUIRED_FOR_VALIDATION);
289
291
  }
290
292
 
291
293
  // Validate if user already exists.
@@ -297,7 +299,7 @@ export class AuthenticationService {
297
299
  ]
298
300
  });
299
301
  if (isNotEmpty(existingUser) && existingUser.active) {
300
- throw new ConflictException('User already exists. Please sign in');
302
+ throw new ConflictException(ERROR_MESSAGES.USER_ALREADY_EXISTS);
301
303
  }
302
304
  const finalRegistrationVerificationSources = this.calculateVerificationSources(this.iamConfiguration.passwordlessRegistrationValidateWhat, signUpDto);
303
305
  let user = existingUser
@@ -314,11 +316,11 @@ export class AuthenticationService {
314
316
 
315
317
  // Send OTP to the user through email or SMS, depending on the configuration.
316
318
  this.notifyUserOnOtpInitiateRegistration(user, finalRegistrationVerificationSources);
317
- return { message: 'User registration initiated. OTP sent to the user.' }
319
+ return { message: SUCCESS_MESSAGES.OTP_SENT_SUCCESS_REGISTRATION }
318
320
  } catch (err) {
319
321
  const pgUniqueViolationErrorCode = '23505';
320
322
  if (err.code === pgUniqueViolationErrorCode) {
321
- throw new ConflictException();
323
+ throw new ConflictException(ERROR_MESSAGES.USER_ALREADY_EXISTS);
322
324
  }
323
325
  throw err;
324
326
  }
@@ -346,7 +348,7 @@ export class AuthenticationService {
346
348
  // Generate the validation tokens for the user i.e (system configured + user provided)
347
349
  private populateVerificationTokens(finalRegistrationValidationSources: string[], user: User) {
348
350
  if (finalRegistrationValidationSources.length === 0) {
349
- throw new BadRequestException('At least one validation source is required');
351
+ throw new BadRequestException(ERROR_MESSAGES.VALIDATION_SOURCE_REQUIRED);
350
352
  }
351
353
  if (finalRegistrationValidationSources.includes(TransactionalRegistrationValidationSource.EMAIL)) {
352
354
  const { token, expiresAt } = this.otp();
@@ -407,7 +409,7 @@ export class AuthenticationService {
407
409
 
408
410
  async otpConfirmRegistration(confirmSignUpDto: OTPConfirmOTPDto) {
409
411
  if (!this.isPasswordlessRegistrationEnabled()) {
410
- throw new BadRequestException('Passwordless registration is not enabled');
412
+ throw new BadRequestException(ERROR_MESSAGES.PASSWORDLESS_REGISTRATION_DISABLED);
411
413
  }
412
414
 
413
415
  // Based on the identifier, validate by query the user table.
@@ -418,13 +420,13 @@ export class AuthenticationService {
418
420
  }
419
421
  });
420
422
  if (!user) {
421
- throw new UnauthorizedException('User does not exist');
423
+ throw new UnauthorizedException(ERROR_MESSAGES.USER_NOT_FOUND);
422
424
  }
423
425
  if (user.emailVerificationTokenOnRegistration !== confirmSignUpDto.otp) {
424
- throw new UnauthorizedException('Invalid OTP');
426
+ throw new UnauthorizedException(ERROR_MESSAGES.INVALID_OTP);
425
427
  }
426
428
  if (user.emailVerificationTokenOnRegistrationExpiresAt < new Date()) {
427
- throw new UnauthorizedException('OTP expired');
429
+ throw new UnauthorizedException(ERROR_MESSAGES.OTP_EXPIRED);
428
430
  }
429
431
  user.emailVerifiedOnRegistrationAt = new Date();
430
432
  user.emailVerificationTokenOnRegistration = null;
@@ -440,13 +442,13 @@ export class AuthenticationService {
440
442
  }
441
443
  });
442
444
  if (!user) {
443
- throw new UnauthorizedException('User does not exist');
445
+ throw new UnauthorizedException(ERROR_MESSAGES.USER_NOT_FOUND);
444
446
  }
445
447
  if (user.mobileVerificationTokenOnRegistration !== confirmSignUpDto.otp) {
446
- throw new UnauthorizedException('Invalid OTP');
448
+ throw new UnauthorizedException(ERROR_MESSAGES.INVALID_OTP);
447
449
  }
448
450
  if (user.mobileVerificationTokenOnRegistrationExpiresAt < new Date()) {
449
- throw new UnauthorizedException('Invalid OTP');
451
+ throw new UnauthorizedException(ERROR_MESSAGES.INVALID_OTP);
450
452
  }
451
453
  user.mobileVerifiedOnRegistrationAt = new Date();
452
454
  user.mobileVerificationTokenOnRegistration = null;
@@ -456,7 +458,7 @@ export class AuthenticationService {
456
458
  this.triggerRegistrationEvent(savedUser);
457
459
  return { active: savedUser.active, message: `User registration verified for ${confirmSignUpDto.type}` }
458
460
  }
459
- throw new BadRequestException('Invalid type. Must be either email or mobile');
461
+ throw new BadRequestException(ERROR_MESSAGES.INVALID_VERIFICATION_TYPE);
460
462
  }
461
463
 
462
464
  private triggerRegistrationEvent(savedUser: User) {
@@ -512,7 +514,7 @@ export class AuthenticationService {
512
514
 
513
515
  async otpInitiateLogin(signInDto: OTPSignInDto) {
514
516
  if (!this.isPasswordlessRegistrationEnabled()) {
515
- throw new BadRequestException('Passwordless registration is not enabled');
517
+ throw new BadRequestException(ERROR_MESSAGES.PASSWORDLESS_REGISTRATION_DISABLED);
516
518
  }
517
519
 
518
520
  // Validate & generate otp token for the user based on the identifier type.
@@ -523,10 +525,10 @@ export class AuthenticationService {
523
525
  }
524
526
  });
525
527
  if (!user) {
526
- throw new UnauthorizedException('User does not exist');
528
+ throw new UnauthorizedException(ERROR_MESSAGES.USER_NOT_FOUND);
527
529
  }
528
530
  if (!user.active) {
529
- throw new UnauthorizedException('User is inactive');
531
+ throw new UnauthorizedException(ERROR_MESSAGES.USER_INACTIVE);
530
532
  }
531
533
  const { token, expiresAt } = this.otp();
532
534
  user.emailVerificationTokenOnLogin = token;
@@ -540,7 +542,7 @@ export class AuthenticationService {
540
542
  }
541
543
  });
542
544
  if (!user) {
543
- throw new UnauthorizedException('User does not exist');
545
+ throw new UnauthorizedException(ERROR_MESSAGES.USER_NOT_FOUND);
544
546
  }
545
547
 
546
548
  const { token, expiresAt } = this.otp();
@@ -550,9 +552,9 @@ export class AuthenticationService {
550
552
  this.notifyUserOnOtpInititateLogin(user, RegistrationValidationSource.MOBILE);
551
553
  }
552
554
  else {
553
- throw new BadRequestException('Invalid type. Must be either email or mobile');
555
+ throw new BadRequestException(ERROR_MESSAGES.INVALID_VERIFICATION_TYPE);
554
556
  }
555
- return { message: 'User login initiated. OTP sent to the user.' };
557
+ return { message: SUCCESS_MESSAGES.OTP_SENT_SUCCESS_LOGIN };
556
558
  }
557
559
 
558
560
  private async notifyUserOnOtpInititateLogin(user: User, loginType: RegistrationValidationSource) {
@@ -595,7 +597,7 @@ export class AuthenticationService {
595
597
 
596
598
  async otpConfirmLogin(confirmSignInDto: OTPConfirmOTPDto) {
597
599
  if (!this.isPasswordlessRegistrationEnabled()) {
598
- throw new BadRequestException('Passwordless registration is not enabled');
600
+ throw new BadRequestException(ERROR_MESSAGES.PASSWORDLESS_REGISTRATION_DISABLED);
599
601
  }
600
602
  if (confirmSignInDto.type === RegistrationValidationSource.EMAIL) {
601
603
  const user = await this.userRepository.findOne({
@@ -605,16 +607,16 @@ export class AuthenticationService {
605
607
  relations: ['roles']
606
608
  });
607
609
  if (!user) {
608
- throw new UnauthorizedException('User does not exist');
610
+ throw new UnauthorizedException(ERROR_MESSAGES.USER_NOT_FOUND);
609
611
  }
610
612
  if (!user.active) {
611
- throw new UnauthorizedException('User is inactive');
613
+ throw new UnauthorizedException(ERROR_MESSAGES.USER_INACTIVE);
612
614
  }
613
615
  if (user.emailVerificationTokenOnLogin !== confirmSignInDto.otp) {
614
- throw new UnauthorizedException('Invalid OTP');
616
+ throw new UnauthorizedException(ERROR_MESSAGES.INVALID_OTP);
615
617
  }
616
618
  if (user.emailVerificationTokenOnLoginExpiresAt < new Date()) {
617
- throw new UnauthorizedException('Invalid OTP');
619
+ throw new UnauthorizedException(ERROR_MESSAGES.INVALID_OTP);
618
620
  }
619
621
  user.emailVerifiedOnLoginAt = new Date();
620
622
  user.emailVerificationTokenOnLogin = null;
@@ -632,16 +634,16 @@ export class AuthenticationService {
632
634
  relations: ['roles']
633
635
  });
634
636
  if (!user) {
635
- throw new UnauthorizedException('User does not exist');
637
+ throw new UnauthorizedException(ERROR_MESSAGES.USER_NOT_ACTIVE);
636
638
  }
637
639
  if (!user.active) {
638
- throw new UnauthorizedException('User is inactive');
640
+ throw new UnauthorizedException(ERROR_MESSAGES.USER_INACTIVE);
639
641
  }
640
642
  if (user.mobileVerificationTokenOnLogin !== confirmSignInDto.otp) {
641
- throw new UnauthorizedException('Invalid OTP');
643
+ throw new UnauthorizedException(ERROR_MESSAGES.INVALID_OTP);
642
644
  }
643
645
  if (user.mobileVerificationTokenOnLoginExpiresAt < new Date()) {
644
- throw new UnauthorizedException('Invalid OTP');
646
+ throw new UnauthorizedException(ERROR_MESSAGES.INVALID_OTP);
645
647
  }
646
648
  user.mobileVerifiedOnLoginAt = new Date();
647
649
  user.mobileVerificationTokenOnLogin = null;
@@ -653,7 +655,7 @@ export class AuthenticationService {
653
655
  return { accessToken, refreshToken, user: { id, username, email, mobile, lastLoginProvider, roles } };
654
656
 
655
657
  }
656
- throw new BadRequestException('Invalid type. Must be either email or mobile');
658
+ throw new BadRequestException(ERROR_MESSAGES.INVALID_VERIFICATION_TYPE);
657
659
  }
658
660
 
659
661
  async changePassword(changePasswordDto: ChangePasswordDto, activeUser: ActiveUserData) {
@@ -661,26 +663,26 @@ export class AuthenticationService {
661
663
  where: { id: changePasswordDto.id }
662
664
  });
663
665
  if (!user) {
664
- throw new NotFoundException('User does not exists');
666
+ throw new NotFoundException(ERROR_MESSAGES.USER_NOT_FOUND);
665
667
  }
666
668
 
667
669
  if (!user.active) {
668
- throw new UnauthorizedException('User is inactive');
670
+ throw new UnauthorizedException(ERROR_MESSAGES.USER_INACTIVE);
669
671
  }
670
672
 
671
673
  // 2. Validate if user has used a provider which is "local", only then it makes sense for us to initiate the forgot password routine.
672
674
  if (user.lastLoginProvider !== 'local') {
673
- throw new BadRequestException('User seems to have used a passwordless mode to authenticate.');
675
+ throw new BadRequestException(ERROR_MESSAGES.NON_LOCAL_PROVIDER);
674
676
  }
675
677
 
676
678
  // Check if ID's match
677
679
  if (!(user.id === activeUser.sub)) {
678
- throw new BadRequestException("User ID's do not match ");
680
+ throw new BadRequestException(ERROR_MESSAGES.USER_ID_MISMATCH);
679
681
  }
680
682
 
681
683
  // Check if username's match
682
684
  if (!(user.username === activeUser.username)) {
683
- throw new BadRequestException("User username's do not match");
685
+ throw new BadRequestException(ERROR_MESSAGES.USERNAME_MISMATCH);
684
686
  }
685
687
 
686
688
  // Check if old password is matching.
@@ -689,7 +691,7 @@ export class AuthenticationService {
689
691
  user.password,
690
692
  );
691
693
  if (!isEqual) {
692
- throw new UnauthorizedException('Incorrect current password specified...');
694
+ throw new UnauthorizedException(ERROR_MESSAGES.INCORRECT_CURRENT_PASSWORD);
693
695
  }
694
696
 
695
697
  // Update Password
@@ -700,7 +702,7 @@ export class AuthenticationService {
700
702
  user.forcePasswordChange = false;
701
703
 
702
704
  if (await this.isPasswordDuplicate(user)) {
703
- throw new BadRequestException('Previously used passwords cannot be used again.');
705
+ throw new BadRequestException(ERROR_MESSAGES.PASSWORD_REUSED);
704
706
  }
705
707
  await this.deleteOldPasswords(user);
706
708
 
@@ -724,15 +726,15 @@ export class AuthenticationService {
724
726
  const user = await this.resolveUser(initiateForgotPasswordDto.username, initiateForgotPasswordDto.email);
725
727
 
726
728
  if (!user) {
727
- throw new NotFoundException('User does not exists');
729
+ throw new NotFoundException(ERROR_MESSAGES.USER_NOT_FOUND);
728
730
  }
729
731
  if (!user.active) {
730
- throw new UnauthorizedException('User is inactive');
732
+ throw new UnauthorizedException(ERROR_MESSAGES.USER_INACTIVE);
731
733
  }
732
734
 
733
735
  // 2. Validate if user has used a provider which is "local", only then it makes sense for us to initiate the forgot password routine.
734
736
  if (user.lastLoginProvider !== 'local') {
735
- throw new BadRequestException('User seems to have used a passwordless mode to authenticate.');
737
+ throw new BadRequestException(ERROR_MESSAGES.NON_LOCAL_PROVIDER);
736
738
  }
737
739
 
738
740
  // 3. Generate a 6 digit validation token, we send this token to the user over their email & mobile number (controlled using configuration).
@@ -746,7 +748,7 @@ export class AuthenticationService {
746
748
  // 5. Return.
747
749
  return {
748
750
  status: 'success',
749
- message: 'Forgot password - token generated and sent',
751
+ message: SUCCESS_MESSAGES.FORGOT_PASSWORD_TOKEN_SENT,
750
752
  error: '',
751
753
  errorCode: '',
752
754
  data: {
@@ -807,23 +809,23 @@ export class AuthenticationService {
807
809
  const user = await this.resolveUser(confirmForgotPasswordDto.username, confirmForgotPasswordDto.email);
808
810
 
809
811
  if (!user) {
810
- throw new NotFoundException('User does not exists');
812
+ throw new NotFoundException(ERROR_MESSAGES.USER_NOT_FOUND);
811
813
  }
812
814
 
813
815
  // 2. Validate if user has used a provider which is "local", only then it makes sense for us to initiate the forgot password routine.
814
816
  if (user.lastLoginProvider !== 'local') {
815
- throw new BadRequestException('User seems to have used a passwordless mode to authenticate.');
817
+ throw new BadRequestException(ERROR_MESSAGES.NON_LOCAL_PROVIDER);
816
818
  }
817
819
  if (!user.active) {
818
- throw new UnauthorizedException('User is inactive');
820
+ throw new UnauthorizedException(ERROR_MESSAGES.USER_INACTIVE);
819
821
  }
820
822
 
821
823
  // 3. Validate the verification token is proper & update the user record.
822
824
  if (user.verificationTokenOnForgotPassword !== confirmForgotPasswordDto.verificationToken) {
823
- throw new UnauthorizedException('Invalid verification token');
825
+ throw new UnauthorizedException(ERROR_MESSAGES.INVALID_VERIFICATION_TOKEN);
824
826
  }
825
827
  if (user.verificationTokenOnForgotPasswordExpiresAt < new Date()) {
826
- throw new UnauthorizedException('Invalid verification token');
828
+ throw new UnauthorizedException(ERROR_MESSAGES.INVALID_VERIFICATION_TOKEN);
827
829
  }
828
830
  user.forgotPasswordConfirmedAt = new Date();
829
831
  user.verificationTokenOnForgotPassword = null;
@@ -834,7 +836,7 @@ export class AuthenticationService {
834
836
  user.password = confirmForgotPasswordDto.password
835
837
 
836
838
  if (await this.isPasswordDuplicate(user)) {
837
- throw new BadRequestException('Previously used passwords cannot be used again.');
839
+ throw new BadRequestException(ERROR_MESSAGES.PASSWORD_REUSED);
838
840
  }
839
841
  await this.deleteOldPasswords(user);
840
842
 
@@ -849,7 +851,7 @@ export class AuthenticationService {
849
851
 
850
852
  return {
851
853
  status: 'success',
852
- message: 'Forgot password confirmed',
854
+ message: SUCCESS_MESSAGES.FORGOT_PASSWORD_CONFIRMED,
853
855
  error: '',
854
856
  errorCode: '',
855
857
  data: {}
@@ -950,7 +952,7 @@ export class AuthenticationService {
950
952
  }
951
953
  });
952
954
  if (!user) {
953
- throw new UnauthorizedException();
955
+ throw new UnauthorizedException(ERROR_MESSAGES.SESSION_INVALID);
954
956
  }
955
957
 
956
958
  // TODO: Replace the if else condition below with a call to validateAndRotate - Done
@@ -973,10 +975,10 @@ export class AuthenticationService {
973
975
  } catch (err) {
974
976
  if (err instanceof InvalidatedRefreshTokenError) {
975
977
  // Take action: notify user that his refresh token might have been stolen?
976
- throw new UnauthorizedException('Access denied');
978
+ throw new UnauthorizedException(ERROR_MESSAGES.ACCESS_DENIED);
977
979
  }
978
980
 
979
- throw new UnauthorizedException();
981
+ throw new UnauthorizedException(ERROR_MESSAGES.SESSION_EXPIRED);
980
982
  }
981
983
  }
982
984
 
@@ -1007,10 +1009,10 @@ export class AuthenticationService {
1007
1009
  // TODO: remove the access code both from the database.
1008
1010
  return userProfile;
1009
1011
  } else {
1010
- throw new UnauthorizedException('Invalid user profile');
1012
+ throw new UnauthorizedException(ERROR_MESSAGES.INVALID_USER_PROFILE);
1011
1013
  }
1012
1014
  } catch (error) {
1013
- throw new UnauthorizedException('Failed to fetch user profile from Google OAuth service');
1015
+ throw new UnauthorizedException(ERROR_MESSAGES.GOOGLE_OAUTH_PROFILE_FETCH_FAILED);
1014
1016
  }
1015
1017
  }
1016
1018
 
@@ -1071,11 +1073,11 @@ export class AuthenticationService {
1071
1073
  await this.userActivityHistoryService.logEvent('logout', user);
1072
1074
 
1073
1075
 
1074
- return { message: 'Logged out successfully' };
1076
+ return { message: SUCCESS_MESSAGES.LOGOUT_SUCCESS};
1075
1077
  } catch (err) {
1076
1078
  throw err instanceof UnauthorizedException || err instanceof InternalServerErrorException
1077
1079
  ? err
1078
- : new InternalServerErrorException('Logout failed due to an unexpected error.');
1080
+ : new InternalServerErrorException(ERROR_MESSAGES.LOGOUT_FAILED);
1079
1081
  }
1080
1082
  }
1081
1083
 
@@ -1083,7 +1085,7 @@ export class AuthenticationService {
1083
1085
  async activateUser(userId: number) {
1084
1086
  const user = await this.userService.findOne(userId, {});
1085
1087
  if (!user) {
1086
- throw new NotFoundException('User not found');
1088
+ throw new NotFoundException(ERROR_MESSAGES.USER_NOT_FOUND);
1087
1089
  }
1088
1090
  user.active = true;
1089
1091
  await this.userRepository.save(user);
@@ -4,6 +4,7 @@ import { classify } from "@angular-devkit/core/src/utils/strings";
4
4
  import { ActiveUserData } from "src/interfaces/active-user-data.interface";
5
5
  import { SolidRegistry } from "src/helpers/solid-registry";
6
6
  import { Logger } from "@nestjs/common";
7
+ import { ERROR_MESSAGES } from "src/constants/error-messages";
7
8
 
8
9
 
9
10
  export class CrudHelperService {
@@ -174,7 +175,7 @@ export class CrudHelperService {
174
175
  const normalizedSort = this.normalize(sort);
175
176
  const normalizedGroupBy = this.normalize(groupBy);
176
177
  if (normalizedGroupBy.length > 1) {
177
- throw new Error('buildFilterQuery: Only 1 Group by field is supported currently');
178
+ throw new Error(ERROR_MESSAGES.GROUP_BY_LIMIT);
178
179
  }
179
180
 
180
181
  // Depending upon the populate option, apply the join clause
@@ -367,7 +368,7 @@ export class CrudHelperService {
367
368
  const groupByField = filteredDto.groupBy;
368
369
 
369
370
  if (!groupByField || (Array.isArray(groupByField) && groupByField.length !== 1)) {
370
- throw new Error('Exactly one groupBy field is required to count grouped records.');
371
+ throw new Error(ERROR_MESSAGES.INVALID_GROUP_BY_COUNT);
371
372
  }
372
373
 
373
374
  const field = Array.isArray(groupByField) ? groupByField[0] : groupByField;