From 17a7f76462c375f32489ea783b9e19de08e0915f Mon Sep 17 00:00:00 2001 From: Marshall Sorenson Date: Fri, 18 Oct 2024 19:03:04 -0400 Subject: [PATCH] feat: bring more exceptions up to runtime exception standards --- .../exceptions/auth-apple-decode.exception.ts | 11 +++++++--- ...auth-apple-email-not-verified.exception.ts | 11 +++++++--- .../auth-apple-invalid-audience.exception.ts | 11 +++++++--- .../auth-apple-invalid-issuer.exception.ts | 11 +++++++--- .../auth-apple-missing-email.exception.ts | 11 +++++++--- .../auth-apple-missing-id.exception.ts | 11 +++++++--- .../auth-apple-public-key.exception.ts | 11 +++++++--- .../auth-apple-token-expired.exception.ts | 11 +++++++--- .../auth-github-missing-email.exception.ts | 13 +++++++----- .../auth-github-missing-id.exception.ts | 11 +++++++--- .../auth-google-missing-email.exception.ts | 13 +++++++----- .../auth-google-missing-id.exception.ts | 11 +++++++--- .../federated-user-lookup.exception.ts | 12 ++++++++--- .../federated-user-relationship.exception.ts | 13 ++++++------ .../src/services/federated-oauth.service.ts | 5 +---- .../exceptions/file-duplicated.exception.ts | 12 ++++++----- .../exceptions/file-id-missing.exception.ts | 10 +++++++--- ...ile-storage-service-not-found.exception.ts | 13 ++++++------ .../logger-sentry.transport.spec.ts | 1 + .../src/exceptions/org-member.exception.ts | 10 ++-------- .../src/exceptions/org-not-found.exception.ts | 1 + .../listeners/invitation-accepted-listener.ts | 13 ++++++------ .../src/services/org-member.service.ts | 10 ++++++---- .../assignment-not-found.exception.ts | 11 ++++++++-- .../exceptions/entity-not-found.exception.ts | 12 +++++++++-- .../role-assignment-conflict.exception.ts | 16 ++++++++++++--- .../nestjs-role/src/services/role.service.ts | 8 ++++++-- .../src/exceptions/user-exception.ts | 13 ++++++------ .../exceptions/user-not-found-exception.ts | 1 + .../listeners/invitation-accepted-listener.ts | 7 ++++--- .../services/user-password-history.service.ts | 18 +++++++++-------- .../src/services/user-password.service.ts | 20 ++++++++++++------- .../reference-validation.exception.ts | 5 +++-- 33 files changed, 226 insertions(+), 121 deletions(-) diff --git a/packages/nestjs-auth-apple/src/exceptions/auth-apple-decode.exception.ts b/packages/nestjs-auth-apple/src/exceptions/auth-apple-decode.exception.ts index b0f2e4cd3..5e542d2da 100644 --- a/packages/nestjs-auth-apple/src/exceptions/auth-apple-decode.exception.ts +++ b/packages/nestjs-auth-apple/src/exceptions/auth-apple-decode.exception.ts @@ -1,10 +1,15 @@ -import { RuntimeException } from '@concepta/nestjs-exception'; +import { + RuntimeException, + RuntimeExceptionOptions, +} from '@concepta/nestjs-exception'; export class AuthAppleDecodeException extends RuntimeException { - constructor(message = 'Apple token was not able to be decoded.') { + constructor(options?: RuntimeExceptionOptions) { super({ - safeMessage: message, + safeMessage: 'Apple token was not able to be decoded.', + ...options, }); + this.errorCode = 'AUTH_APPLE_DECODE_ERROR'; } } diff --git a/packages/nestjs-auth-apple/src/exceptions/auth-apple-email-not-verified.exception.ts b/packages/nestjs-auth-apple/src/exceptions/auth-apple-email-not-verified.exception.ts index 56f57edb0..9e95b768b 100644 --- a/packages/nestjs-auth-apple/src/exceptions/auth-apple-email-not-verified.exception.ts +++ b/packages/nestjs-auth-apple/src/exceptions/auth-apple-email-not-verified.exception.ts @@ -1,10 +1,15 @@ -import { RuntimeException } from '@concepta/nestjs-exception'; +import { + RuntimeException, + RuntimeExceptionOptions, +} from '@concepta/nestjs-exception'; export class AuthAppleEmailNotVerifiedException extends RuntimeException { - constructor(message = 'Apple email not is verified.') { + constructor(options?: RuntimeExceptionOptions) { super({ - safeMessage: message, + safeMessage: 'Apple email not is verified.', + ...options, }); + this.errorCode = 'AUTH_APPLE_EMAIL_NOT_VERIFIED'; } } diff --git a/packages/nestjs-auth-apple/src/exceptions/auth-apple-invalid-audience.exception.ts b/packages/nestjs-auth-apple/src/exceptions/auth-apple-invalid-audience.exception.ts index 1839835c8..d95a85bdf 100644 --- a/packages/nestjs-auth-apple/src/exceptions/auth-apple-invalid-audience.exception.ts +++ b/packages/nestjs-auth-apple/src/exceptions/auth-apple-invalid-audience.exception.ts @@ -1,10 +1,15 @@ -import { RuntimeException } from '@concepta/nestjs-exception'; +import { + RuntimeException, + RuntimeExceptionOptions, +} from '@concepta/nestjs-exception'; export class AuthAppleInvalidAudienceException extends RuntimeException { - constructor(message = 'Apple audience is not valid.') { + constructor(options?: RuntimeExceptionOptions) { super({ - safeMessage: message, + safeMessage: 'Apple audience is not valid.', + ...options, }); + this.errorCode = 'AUTH_APPLE_INVALID_AUDIENCE'; } } diff --git a/packages/nestjs-auth-apple/src/exceptions/auth-apple-invalid-issuer.exception.ts b/packages/nestjs-auth-apple/src/exceptions/auth-apple-invalid-issuer.exception.ts index efd47f506..b3f4fe54b 100644 --- a/packages/nestjs-auth-apple/src/exceptions/auth-apple-invalid-issuer.exception.ts +++ b/packages/nestjs-auth-apple/src/exceptions/auth-apple-invalid-issuer.exception.ts @@ -1,10 +1,15 @@ -import { RuntimeException } from '@concepta/nestjs-exception'; +import { + RuntimeException, + RuntimeExceptionOptions, +} from '@concepta/nestjs-exception'; export class AuthAppleInvalidIssuerException extends RuntimeException { - constructor(message = 'Apple token issuer is not valid.') { + constructor(options?: RuntimeExceptionOptions) { super({ - safeMessage: message, + safeMessage: 'Apple token issuer is not valid.', + ...options, }); + this.errorCode = 'AUTH_APPLE_INVALID_ISSUER'; } } diff --git a/packages/nestjs-auth-apple/src/exceptions/auth-apple-missing-email.exception.ts b/packages/nestjs-auth-apple/src/exceptions/auth-apple-missing-email.exception.ts index 1a6f73f3d..75fae2ad2 100644 --- a/packages/nestjs-auth-apple/src/exceptions/auth-apple-missing-email.exception.ts +++ b/packages/nestjs-auth-apple/src/exceptions/auth-apple-missing-email.exception.ts @@ -1,10 +1,15 @@ -import { RuntimeException } from '@concepta/nestjs-exception'; +import { + RuntimeException, + RuntimeExceptionOptions, +} from '@concepta/nestjs-exception'; export class AuthAppleMissingEmailException extends RuntimeException { - constructor(message = 'Apple did not return an email address for the user.') { + constructor(options?: RuntimeExceptionOptions) { super({ - safeMessage: message, + safeMessage: 'Apple did not return an email address for the user.', + ...options, }); + this.errorCode = 'AUTH_APPLE_MISSING_PROFILE_EMAIL_ERROR'; } } diff --git a/packages/nestjs-auth-apple/src/exceptions/auth-apple-missing-id.exception.ts b/packages/nestjs-auth-apple/src/exceptions/auth-apple-missing-id.exception.ts index 6a6e8d335..a779c349e 100644 --- a/packages/nestjs-auth-apple/src/exceptions/auth-apple-missing-id.exception.ts +++ b/packages/nestjs-auth-apple/src/exceptions/auth-apple-missing-id.exception.ts @@ -1,10 +1,15 @@ -import { RuntimeException } from '@concepta/nestjs-exception'; +import { + RuntimeException, + RuntimeExceptionOptions, +} from '@concepta/nestjs-exception'; export class AuthAppleMissingIdException extends RuntimeException { - constructor(message = 'Apple did not return an id for the user.') { + constructor(options?: RuntimeExceptionOptions) { super({ - safeMessage: message, + safeMessage: 'Apple did not return an id for the user.', + ...options, }); + this.errorCode = 'AUTH_APPLE_MISSING_PROFILE_ID_ERROR'; } } diff --git a/packages/nestjs-auth-apple/src/exceptions/auth-apple-public-key.exception.ts b/packages/nestjs-auth-apple/src/exceptions/auth-apple-public-key.exception.ts index 9110c6c5f..4c6e1c27f 100644 --- a/packages/nestjs-auth-apple/src/exceptions/auth-apple-public-key.exception.ts +++ b/packages/nestjs-auth-apple/src/exceptions/auth-apple-public-key.exception.ts @@ -1,10 +1,15 @@ -import { RuntimeException } from '@concepta/nestjs-exception'; +import { + RuntimeException, + RuntimeExceptionOptions, +} from '@concepta/nestjs-exception'; export class AuthApplePublicKeyException extends RuntimeException { - constructor(message = 'Apple public key was not able to be retrieved.') { + constructor(options?: RuntimeExceptionOptions) { super({ - safeMessage: message, + safeMessage: 'Apple public key was not able to be retrieved.', + ...options, }); + this.errorCode = 'AUTH_APPLE_PUBLIC_KEY_ERROR'; } } diff --git a/packages/nestjs-auth-apple/src/exceptions/auth-apple-token-expired.exception.ts b/packages/nestjs-auth-apple/src/exceptions/auth-apple-token-expired.exception.ts index d6d78b865..4caf99f22 100644 --- a/packages/nestjs-auth-apple/src/exceptions/auth-apple-token-expired.exception.ts +++ b/packages/nestjs-auth-apple/src/exceptions/auth-apple-token-expired.exception.ts @@ -1,10 +1,15 @@ -import { RuntimeException } from '@concepta/nestjs-exception'; +import { + RuntimeException, + RuntimeExceptionOptions, +} from '@concepta/nestjs-exception'; export class AuthAppleTokenExpiredException extends RuntimeException { - constructor(message = 'Apple oauth token has expired.') { + constructor(options?: RuntimeExceptionOptions) { super({ - safeMessage: message, + safeMessage: 'Apple oauth token has expired.', + ...options, }); + this.errorCode = 'AUTH_APPLE_OAUTH_TOKEN_EXPIRED'; } } diff --git a/packages/nestjs-auth-github/src/exceptions/auth-github-missing-email.exception.ts b/packages/nestjs-auth-github/src/exceptions/auth-github-missing-email.exception.ts index 7101b1958..c481d118c 100644 --- a/packages/nestjs-auth-github/src/exceptions/auth-github-missing-email.exception.ts +++ b/packages/nestjs-auth-github/src/exceptions/auth-github-missing-email.exception.ts @@ -1,12 +1,15 @@ -import { RuntimeException } from '@concepta/nestjs-exception'; +import { + RuntimeException, + RuntimeExceptionOptions, +} from '@concepta/nestjs-exception'; export class AuthGithubMissingEmailException extends RuntimeException { - constructor( - message = 'GitHub did not return an email address for the user.', - ) { + constructor(options?: RuntimeExceptionOptions) { super({ - safeMessage: message, + safeMessage: 'GitHub did not return an email address for the user.', + ...options, }); + this.errorCode = 'AUTH_GITHUB_MISSING_PROFILE_EMAIL_ERROR'; } } diff --git a/packages/nestjs-auth-github/src/exceptions/auth-github-missing-id.exception.ts b/packages/nestjs-auth-github/src/exceptions/auth-github-missing-id.exception.ts index 3919f8e97..85cbf1b3e 100644 --- a/packages/nestjs-auth-github/src/exceptions/auth-github-missing-id.exception.ts +++ b/packages/nestjs-auth-github/src/exceptions/auth-github-missing-id.exception.ts @@ -1,10 +1,15 @@ -import { RuntimeException } from '@concepta/nestjs-exception'; +import { + RuntimeException, + RuntimeExceptionOptions, +} from '@concepta/nestjs-exception'; export class AuthGithubMissingIdException extends RuntimeException { - constructor(message = 'GitHub did not return an id for the user.') { + constructor(options?: RuntimeExceptionOptions) { super({ - safeMessage: message, + safeMessage: 'GitHub did not return an id for the user.', + ...options, }); + this.errorCode = 'AUTH_GITHUB_MISSING_PROFILE_ID_ERROR'; } } diff --git a/packages/nestjs-auth-google/src/exceptions/auth-google-missing-email.exception.ts b/packages/nestjs-auth-google/src/exceptions/auth-google-missing-email.exception.ts index 5e436a99a..a59530020 100644 --- a/packages/nestjs-auth-google/src/exceptions/auth-google-missing-email.exception.ts +++ b/packages/nestjs-auth-google/src/exceptions/auth-google-missing-email.exception.ts @@ -1,12 +1,15 @@ -import { RuntimeException } from '@concepta/nestjs-exception'; +import { + RuntimeException, + RuntimeExceptionOptions, +} from '@concepta/nestjs-exception'; export class AuthGoogleMissingEmailException extends RuntimeException { - constructor( - message = 'Google did not return an email address for the user.', - ) { + constructor(options?: RuntimeExceptionOptions) { super({ - safeMessage: message, + safeMessage: 'Google did not return an email address for the user.', + ...options, }); + this.errorCode = 'AUTH_GOOGLE_MISSING_PROFILE_EMAIL_ERROR'; } } diff --git a/packages/nestjs-auth-google/src/exceptions/auth-google-missing-id.exception.ts b/packages/nestjs-auth-google/src/exceptions/auth-google-missing-id.exception.ts index 8cf9388ae..e14f03f4d 100644 --- a/packages/nestjs-auth-google/src/exceptions/auth-google-missing-id.exception.ts +++ b/packages/nestjs-auth-google/src/exceptions/auth-google-missing-id.exception.ts @@ -1,10 +1,15 @@ -import { RuntimeException } from '@concepta/nestjs-exception'; +import { + RuntimeException, + RuntimeExceptionOptions, +} from '@concepta/nestjs-exception'; export class AuthGoogleMissingIdException extends RuntimeException { - constructor(message = 'Google did not return an id for the user.') { + constructor(options?: RuntimeExceptionOptions) { super({ - safeMessage: message, + safeMessage: 'Google did not return an id for the user.', + ...options, }); + this.errorCode = 'AUTH_GOOGLE_MISSING_PROFILE_ID_ERROR'; } } diff --git a/packages/nestjs-federated/src/exceptions/federated-user-lookup.exception.ts b/packages/nestjs-federated/src/exceptions/federated-user-lookup.exception.ts index 7582dcda1..7f4a9bcd7 100644 --- a/packages/nestjs-federated/src/exceptions/federated-user-lookup.exception.ts +++ b/packages/nestjs-federated/src/exceptions/federated-user-lookup.exception.ts @@ -1,5 +1,8 @@ import { ReferenceIdInterface } from '@concepta/ts-core'; -import { RuntimeException } from '@concepta/nestjs-exception'; +import { + RuntimeException, + RuntimeExceptionOptions, +} from '@concepta/nestjs-exception'; import { HttpStatus } from '@nestjs/common'; export class FederatedUserLookupException extends RuntimeException { @@ -11,14 +14,17 @@ export class FederatedUserLookupException extends RuntimeException { constructor( entityName: string, user: ReferenceIdInterface, - message = 'Error while trying find user %s', + options?: RuntimeExceptionOptions, ) { super({ - message, + message: 'Error while trying find user %s', messageParams: [user.id], httpStatus: HttpStatus.NOT_FOUND, + ...options, }); + this.errorCode = 'FEDERATED_USER_LOOKUP_ERROR'; + this.context = { ...super.context, entityName, diff --git a/packages/nestjs-federated/src/exceptions/federated-user-relationship.exception.ts b/packages/nestjs-federated/src/exceptions/federated-user-relationship.exception.ts index cb89b773b..a29243db0 100644 --- a/packages/nestjs-federated/src/exceptions/federated-user-relationship.exception.ts +++ b/packages/nestjs-federated/src/exceptions/federated-user-relationship.exception.ts @@ -1,18 +1,19 @@ -import { RuntimeException } from '@concepta/nestjs-exception'; +import { + RuntimeException, + RuntimeExceptionOptions, +} from '@concepta/nestjs-exception'; import { HttpStatus } from '@nestjs/common'; export class FederatedUserRelationshipException extends RuntimeException { context: RuntimeException['context'] & { federatedId: string; }; - constructor( - federatedId: string, - message = 'Error while trying to load user relationship from federated %s', - ) { + constructor(federatedId: string, options?: RuntimeExceptionOptions) { super({ - message, + message: 'Error while trying to load user relationship from federated %s', messageParams: [federatedId], httpStatus: HttpStatus.NOT_FOUND, + ...options, }); this.errorCode = 'FEDERATED_USER_RELATIONSHIP_ERROR'; diff --git a/packages/nestjs-federated/src/services/federated-oauth.service.ts b/packages/nestjs-federated/src/services/federated-oauth.service.ts index c29278671..418a053ba 100644 --- a/packages/nestjs-federated/src/services/federated-oauth.service.ts +++ b/packages/nestjs-federated/src/services/federated-oauth.service.ts @@ -61,10 +61,7 @@ export class FederatedOAuthService implements FederatedOAuthServiceInterface { ); } else { if (!federated.user?.id) { - throw new FederatedUserRelationshipException( - this.constructor.name, - federated.id, - ); + throw new FederatedUserRelationshipException(federated.id); } const user = await this.userLookupService.byId( diff --git a/packages/nestjs-file/src/exceptions/file-duplicated.exception.ts b/packages/nestjs-file/src/exceptions/file-duplicated.exception.ts index b988f126b..a0f7d07f8 100644 --- a/packages/nestjs-file/src/exceptions/file-duplicated.exception.ts +++ b/packages/nestjs-file/src/exceptions/file-duplicated.exception.ts @@ -1,5 +1,8 @@ import { HttpStatus } from '@nestjs/common'; -import { RuntimeException } from '@concepta/nestjs-exception'; +import { + RuntimeException, + RuntimeExceptionOptions, +} from '@concepta/nestjs-exception'; export class FileDuplicateEntryException extends RuntimeException { context: RuntimeException['context'] & { @@ -10,14 +13,13 @@ export class FileDuplicateEntryException extends RuntimeException { constructor( serviceKey: string, fileName: string, - originalError?: unknown, - message = 'Duplicate entry detected for service %s with file %s', + options?: RuntimeExceptionOptions, ) { super({ - message, + message: 'Duplicate entry detected for service %s with file %s', messageParams: [serviceKey, fileName], httpStatus: HttpStatus.CONFLICT, - originalError, + ...options, }); this.errorCode = 'FILE_DUPLICATE_ENTRY_ERROR'; diff --git a/packages/nestjs-file/src/exceptions/file-id-missing.exception.ts b/packages/nestjs-file/src/exceptions/file-id-missing.exception.ts index 22e30cbea..cf6f8f63b 100644 --- a/packages/nestjs-file/src/exceptions/file-id-missing.exception.ts +++ b/packages/nestjs-file/src/exceptions/file-id-missing.exception.ts @@ -1,11 +1,15 @@ import { HttpStatus } from '@nestjs/common'; -import { RuntimeException } from '@concepta/nestjs-exception'; +import { + RuntimeException, + RuntimeExceptionOptions, +} from '@concepta/nestjs-exception'; export class FileIdMissingException extends RuntimeException { - constructor(message = 'File id is missing.') { + constructor(options?: RuntimeExceptionOptions) { super({ - message, + message: 'File id is missing.', httpStatus: HttpStatus.BAD_REQUEST, + ...options, }); this.errorCode = 'FILE_ID_MISSING_ERROR'; diff --git a/packages/nestjs-file/src/exceptions/file-storage-service-not-found.exception.ts b/packages/nestjs-file/src/exceptions/file-storage-service-not-found.exception.ts index ad5fa1ac7..d5fa73f26 100644 --- a/packages/nestjs-file/src/exceptions/file-storage-service-not-found.exception.ts +++ b/packages/nestjs-file/src/exceptions/file-storage-service-not-found.exception.ts @@ -1,19 +1,20 @@ import { HttpStatus } from '@nestjs/common'; -import { RuntimeException } from '@concepta/nestjs-exception'; +import { + RuntimeException, + RuntimeExceptionOptions, +} from '@concepta/nestjs-exception'; export class FileStorageServiceNotFoundException extends RuntimeException { context: RuntimeException['context'] & { storageServiceName: string; }; - constructor( - assignmentName: string, - message = 'Storage Service %s was not registered to be used.', - ) { + constructor(assignmentName: string, options?: RuntimeExceptionOptions) { super({ - message, + message: 'Storage Service %s was not registered to be used.', messageParams: [assignmentName], httpStatus: HttpStatus.NOT_FOUND, + ...options, }); this.errorCode = 'FILE_STORAGE_SERVICE_NOT_FOUND_ERROR'; diff --git a/packages/nestjs-logger-sentry/src/transports/logger-sentry.transport.spec.ts b/packages/nestjs-logger-sentry/src/transports/logger-sentry.transport.spec.ts index a88532cc4..682a815a6 100644 --- a/packages/nestjs-logger-sentry/src/transports/logger-sentry.transport.spec.ts +++ b/packages/nestjs-logger-sentry/src/transports/logger-sentry.transport.spec.ts @@ -165,6 +165,7 @@ describe('loggerSentryTransport', () => { httpStatus: HttpStatus.BAD_REQUEST, ...options, }); + this.errorCode = 'INVALID_LOGIN_DATA_ERROR'; } } diff --git a/packages/nestjs-org/src/exceptions/org-member.exception.ts b/packages/nestjs-org/src/exceptions/org-member.exception.ts index d3effe37a..ede96cae4 100644 --- a/packages/nestjs-org/src/exceptions/org-member.exception.ts +++ b/packages/nestjs-org/src/exceptions/org-member.exception.ts @@ -4,14 +4,8 @@ import { } from '@concepta/nestjs-exception'; export class OrgMemberException extends RuntimeException { - constructor( - message: string, - options?: Omit, - ) { - super({ - message, - ...options, - }); + constructor(options?: RuntimeExceptionOptions) { + super(options); this.errorCode = 'ORG_MEMBER_ERROR'; } } diff --git a/packages/nestjs-org/src/exceptions/org-not-found.exception.ts b/packages/nestjs-org/src/exceptions/org-not-found.exception.ts index 9c7f8e747..899d43dce 100644 --- a/packages/nestjs-org/src/exceptions/org-not-found.exception.ts +++ b/packages/nestjs-org/src/exceptions/org-not-found.exception.ts @@ -9,6 +9,7 @@ export class OrgNotFoundException extends RuntimeException { message: 'The org was not found', ...options, }); + this.errorCode = 'ORG_NOT_FOUND_ERROR'; } } diff --git a/packages/nestjs-org/src/listeners/invitation-accepted-listener.ts b/packages/nestjs-org/src/listeners/invitation-accepted-listener.ts index 8e7055c89..e48bb37e9 100644 --- a/packages/nestjs-org/src/listeners/invitation-accepted-listener.ts +++ b/packages/nestjs-org/src/listeners/invitation-accepted-listener.ts @@ -53,15 +53,16 @@ export class InvitationAcceptedListener const { orgId } = event?.payload?.invitation?.constraints ?? {}; if (typeof userId !== 'string') { - throw new OrgMemberException( - 'The invitation accepted event payload received has invalid content. The payload must have the "userId" property.', - ); + throw new OrgMemberException({ + message: + 'The invitation accepted event payload received has invalid content. The payload must have the "userId" property.', + }); } if (typeof orgId !== 'string') { - throw new OrgMemberException( - 'The org of invitation does not have orgId in constraints', - ); + throw new OrgMemberException({ + message: 'The org of invitation does not have orgId in constraints', + }); } await this.orgMemberService.add( diff --git a/packages/nestjs-org/src/services/org-member.service.ts b/packages/nestjs-org/src/services/org-member.service.ts index 4e39afcf0..345ef012f 100644 --- a/packages/nestjs-org/src/services/org-member.service.ts +++ b/packages/nestjs-org/src/services/org-member.service.ts @@ -1,5 +1,5 @@ import { Repository } from 'typeorm'; -import { Injectable } from '@nestjs/common'; +import { HttpStatus, Injectable } from '@nestjs/common'; import { InjectDynamicRepository } from '@concepta/nestjs-typeorm-ext'; import { BaseService, QueryOptionsInterface } from '@concepta/typeorm-common'; @@ -38,9 +38,11 @@ export class OrgMemberService if (orgMemberFound) { const { userId, orgId } = orgMember; - throw new OrgMemberException( - `Can't create OrgMember, the the combination of userid: ${userId} and orgId: ${orgId} already exists`, - ); + throw new OrgMemberException({ + message: `Can't create OrgMember, the the combination of userid: %s and orgId: %s already exists`, + messageParams: [userId, orgId], + httpStatus: HttpStatus.BAD_REQUEST, + }); } return await this.orgMemberMutateService.create(orgMember, queryOptions); diff --git a/packages/nestjs-role/src/exceptions/assignment-not-found.exception.ts b/packages/nestjs-role/src/exceptions/assignment-not-found.exception.ts index f834ddd7f..3987978c8 100644 --- a/packages/nestjs-role/src/exceptions/assignment-not-found.exception.ts +++ b/packages/nestjs-role/src/exceptions/assignment-not-found.exception.ts @@ -1,17 +1,24 @@ -import { RuntimeException } from '@concepta/nestjs-exception'; +import { + RuntimeException, + RuntimeExceptionOptions, +} from '@concepta/nestjs-exception'; import { HttpStatus } from '@nestjs/common'; export class AssignmentNotFoundException extends RuntimeException { - constructor(assignmentName: string) { + context: RuntimeException['context'] & { assignmentName: string }; + + constructor(assignmentName: string, options?: RuntimeExceptionOptions) { super({ message: 'Assignment %s was not registered to be used.', messageParams: [assignmentName], httpStatus: HttpStatus.NOT_FOUND, + ...options, }); this.errorCode = 'ROLE_ASSIGNMENT_NOT_FOUND_ERROR'; this.context = { + ...super.context, assignmentName, }; } diff --git a/packages/nestjs-role/src/exceptions/entity-not-found.exception.ts b/packages/nestjs-role/src/exceptions/entity-not-found.exception.ts index 2b0a880d2..a552a4353 100644 --- a/packages/nestjs-role/src/exceptions/entity-not-found.exception.ts +++ b/packages/nestjs-role/src/exceptions/entity-not-found.exception.ts @@ -1,16 +1,24 @@ import { HttpStatus } from '@nestjs/common'; -import { RuntimeException } from '@concepta/nestjs-exception'; +import { + RuntimeException, + RuntimeExceptionOptions, +} from '@concepta/nestjs-exception'; export class EntityNotFoundException extends RuntimeException { - constructor(entityName: string) { + context: RuntimeException['context'] & { entityName: string }; + + constructor(entityName: string, options?: RuntimeExceptionOptions) { super({ message: 'Entity %s was not registered to be used.', messageParams: [entityName], httpStatus: HttpStatus.NOT_FOUND, + ...options, }); this.errorCode = 'ROLE_ENTITY_NOT_FOUND_ERROR'; + this.context = { + ...super.context, entityName, }; } diff --git a/packages/nestjs-role/src/exceptions/role-assignment-conflict.exception.ts b/packages/nestjs-role/src/exceptions/role-assignment-conflict.exception.ts index f1a23963c..7eee9ee63 100644 --- a/packages/nestjs-role/src/exceptions/role-assignment-conflict.exception.ts +++ b/packages/nestjs-role/src/exceptions/role-assignment-conflict.exception.ts @@ -1,5 +1,8 @@ import { HttpStatus } from '@nestjs/common'; -import { RuntimeException } from '@concepta/nestjs-exception'; +import { + RuntimeException, + RuntimeExceptionOptions, +} from '@concepta/nestjs-exception'; export class RoleAssignmentConflictException extends RuntimeException { context: RuntimeException['context'] & { @@ -8,16 +11,23 @@ export class RoleAssignmentConflictException extends RuntimeException { assigneeId: string; }; - constructor(assignmentName: string, roleId: string, assigneeId: string) { + constructor( + assignmentName: string, + roleId: string, + assigneeId: string, + options?: RuntimeExceptionOptions, + ) { super({ message: 'Role %s is already assigned to assignee %s for assignment %s.', messageParams: [roleId, assigneeId, assignmentName], - httpStatus: HttpStatus.CONFLICT, + httpStatus: HttpStatus.BAD_REQUEST, + ...options, }); this.errorCode = 'ROLE_ASSIGNMENT_CONFLICT_ERROR'; this.context = { + ...super.context, assignmentName, roleId, assigneeId, diff --git a/packages/nestjs-role/src/services/role.service.ts b/packages/nestjs-role/src/services/role.service.ts index c767e38e5..452fac346 100644 --- a/packages/nestjs-role/src/services/role.service.ts +++ b/packages/nestjs-role/src/services/role.service.ts @@ -62,7 +62,9 @@ export class RoleService implements RoleServiceInterface { // return the roles return assignments.map((assignment) => assignment.role); } catch (e) { - throw new ReferenceLookupException(assignmentRepo.metadata.targetName, e); + throw new ReferenceLookupException(assignmentRepo.metadata.targetName, { + originalError: e, + }); } } @@ -100,7 +102,9 @@ export class RoleService implements RoleServiceInterface { // return true if we found an assignment return assignment ? true : false; } catch (e) { - throw new ReferenceLookupException(assignmentRepo.metadata.targetName, e); + throw new ReferenceLookupException(assignmentRepo.metadata.targetName, { + originalError: e, + }); } } diff --git a/packages/nestjs-user/src/exceptions/user-exception.ts b/packages/nestjs-user/src/exceptions/user-exception.ts index b10324373..5aed14e11 100644 --- a/packages/nestjs-user/src/exceptions/user-exception.ts +++ b/packages/nestjs-user/src/exceptions/user-exception.ts @@ -1,14 +1,13 @@ -import { mapNonErrorToException } from '@concepta/ts-core'; -import { RuntimeException } from '@concepta/nestjs-exception'; +import { + RuntimeException, + RuntimeExceptionOptions, +} from '@concepta/nestjs-exception'; /** * Generic user exception. */ export class UserException extends RuntimeException { - constructor(message: string, originalError?: unknown) { - super({ - message, - originalError: mapNonErrorToException(originalError), - }); + constructor(options?: RuntimeExceptionOptions) { + super(options); this.errorCode = 'USER_ERROR'; } } diff --git a/packages/nestjs-user/src/exceptions/user-not-found-exception.ts b/packages/nestjs-user/src/exceptions/user-not-found-exception.ts index c857d2300..ddbc72af7 100644 --- a/packages/nestjs-user/src/exceptions/user-not-found-exception.ts +++ b/packages/nestjs-user/src/exceptions/user-not-found-exception.ts @@ -11,6 +11,7 @@ export class UserNotFoundException extends RuntimeException { httpStatus: HttpStatus.NOT_FOUND, ...options, }); + this.errorCode = 'USER_NOT_FOUND_ERROR'; } } diff --git a/packages/nestjs-user/src/listeners/invitation-accepted-listener.ts b/packages/nestjs-user/src/listeners/invitation-accepted-listener.ts index 988cda419..a334ca305 100644 --- a/packages/nestjs-user/src/listeners/invitation-accepted-listener.ts +++ b/packages/nestjs-user/src/listeners/invitation-accepted-listener.ts @@ -55,9 +55,10 @@ export class InvitationAcceptedListener const { userId, newPassword } = event?.payload?.data ?? {}; if (typeof userId !== 'string' || typeof newPassword !== 'string') { - throw new UserException( - 'The invitation accepted event payload received has invalid content. The payload must have the "userId" and "newPassword" properties.', - ); + throw new UserException({ + message: + 'The invitation accepted event payload received has invalid content. The payload must have the "userId" and "newPassword" properties.', + }); } const user = await this.userLookupService.byId( diff --git a/packages/nestjs-user/src/services/user-password-history.service.ts b/packages/nestjs-user/src/services/user-password-history.service.ts index a94860a0e..5d70cb918 100644 --- a/packages/nestjs-user/src/services/user-password-history.service.ts +++ b/packages/nestjs-user/src/services/user-password-history.service.ts @@ -39,10 +39,11 @@ export class UserPasswordHistoryService queryOptions, ); } catch (e: unknown) { - throw new UserException( - 'Cannot update password, error while getting password history by user id', - e, - ); + throw new UserException({ + message: + 'Cannot update password, error while getting password history by user id', + originalError: e, + }); } // return history if found or empty array @@ -63,10 +64,11 @@ export class UserPasswordHistoryService queryOptions, ); } catch (e: unknown) { - throw new UserException( - 'Cannot update password, error while pushing password history by user id', - e, - ); + throw new UserException({ + message: + 'Cannot update password, error while pushing password history by user id', + originalError: e, + }); } } diff --git a/packages/nestjs-user/src/services/user-password.service.ts b/packages/nestjs-user/src/services/user-password.service.ts index d143c8a1c..6e3fd60ef 100644 --- a/packages/nestjs-user/src/services/user-password.service.ts +++ b/packages/nestjs-user/src/services/user-password.service.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable, Optional } from '@nestjs/common'; +import { HttpStatus, Inject, Injectable, Optional } from '@nestjs/common'; import { ReferenceId, ReferenceIdInterface } from '@concepta/ts-core'; import { AuthenticatedUserInterface, @@ -112,10 +112,10 @@ export class UserPasswordService implements UserPasswordServiceInterface { // try to lookup the user user = await this.userLookupService.byId(userId); } catch (e: unknown) { - throw new UserException( - 'Cannot update password, error while getting user by id', - e, - ); + throw new UserException({ + message: 'Cannot update password, error while getting user by id', + originalError: e, + }); } // did we get a user? @@ -155,7 +155,10 @@ export class UserPasswordService implements UserPasswordServiceInterface { if (currentIsValid) { return true; } else { - throw new UserException(`Current password is not valid`); + throw new UserException({ + message: `Current password is not valid`, + httpStatus: HttpStatus.BAD_REQUEST, + }); } } @@ -181,7 +184,10 @@ export class UserPasswordService implements UserPasswordServiceInterface { }); if (!isValid) { - throw new UserException(`Password has been used too recently.`); + throw new UserException({ + message: `Password has been used too recently.`, + httpStatus: HttpStatus.BAD_REQUEST, + }); } } diff --git a/packages/typeorm-common/src/exceptions/reference-validation.exception.ts b/packages/typeorm-common/src/exceptions/reference-validation.exception.ts index 6eeb89195..0e3e5b1ed 100644 --- a/packages/typeorm-common/src/exceptions/reference-validation.exception.ts +++ b/packages/typeorm-common/src/exceptions/reference-validation.exception.ts @@ -13,19 +13,20 @@ export class ReferenceValidationException extends RuntimeException { constructor( entityName: string, validationErrors: ValidationError[], - message = 'Data for the %s reference is not valid', options?: RuntimeExceptionOptions, ) { super({ - message, + message: 'Data for the %s reference is not valid', messageParams: [entityName], ...options, }); + this.context = { ...super.context, entityName, validationErrors, }; + this.errorCode = 'REFERENCE_VALIDATION_ERROR'; } }