From 76b1c9b3a0c24678bde865a951d211ecce822ef8 Mon Sep 17 00:00:00 2001 From: Ho Ngoc Hai Date: Sun, 4 Jan 2026 13:31:11 +0700 Subject: [PATCH] =?UTF-8?q?refactor:=20chu=E1=BA=A9n=20h=C3=B3a=20x?= =?UTF-8?q?=E1=BB=AD=20l=C3=BD=20l=E1=BB=97i=20b=E1=BA=B1ng=20c=C3=A1ch=20?= =?UTF-8?q?gi=E1=BB=9Bi=20thi=E1=BB=87u=20ti=E1=BB=87n=20=C3=ADch=20`getEr?= =?UTF-8?q?rorMessage`=20v=C3=A0=20c=E1=BA=ADp=20nh=E1=BA=ADt=20ki?= =?UTF-8?q?=E1=BB=83u=20`catch`=20th=C3=A0nh=20`unknown`.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/add-error-imports.py | 67 +++++++++++ scripts/add-error-imports.sh | 42 +++++++ .../src/middlewares/auth.middleware.ts | 9 +- .../access/analytics/analytics.controller.ts | 21 ++-- .../access/request/request.controller.ts | 29 ++--- .../access/review/review.controller.ts | 29 ++--- .../src/modules/auth/auth.controller.ts | 17 +-- .../auth/change-password.controller.ts | 5 +- .../src/modules/common/repository.ts | 45 ++++---- .../src/modules/feature/feature.controller.ts | 17 +-- .../src/modules/feature/feature.repository.ts | 11 +- .../src/modules/feature/feature.service.ts | 4 +- .../compliance/compliance.controller.ts | 21 ++-- .../policy/policy-governance.controller.ts | 17 +-- .../reporting/reporting.controller.ts | 21 ++-- .../governance/risk/risk.controller.ts | 17 +-- .../identity/group/group.controller.ts | 33 +++--- .../organization/organization.controller.ts | 25 ++-- .../identity/profile/profile.controller.ts | 17 +-- .../modules/identity/user/user.controller.ts | 33 +++--- .../src/modules/identity/user/user.service.ts | 5 +- .../verification/verification.controller.ts | 21 ++-- .../src/modules/mfa/mfa.controller.ts | 21 ++-- .../src/modules/oidc/oidc.controller.ts | 13 ++- .../src/modules/rbac/rbac.controller.ts | 21 ++-- .../modules/session/sessions.controller.ts | 13 ++- .../src/modules/social/social.controller.ts | 19 ++-- .../src/modules/token/jwt.service.ts | 4 +- services/iam-service/src/utils/error-utils.ts | 107 ++++++++++++++++++ 29 files changed, 472 insertions(+), 232 deletions(-) create mode 100644 scripts/add-error-imports.py create mode 100755 scripts/add-error-imports.sh create mode 100644 services/iam-service/src/utils/error-utils.ts diff --git a/scripts/add-error-imports.py b/scripts/add-error-imports.py new file mode 100644 index 00000000..76b95bf9 --- /dev/null +++ b/scripts/add-error-imports.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +import os +import re +from pathlib import Path + +# Base directory +base_dir = Path("/Users/velikho/Desktop/WORKING/Base/services/iam-service/src") + +# Find all files that use getErrorMessage +for root, dirs, files in os.walk(base_dir): + # Skip test directories + if '__tests__' in root or 'node_modules' in root: + continue + + for file in files: + if not (file.endswith('.controller.ts') or file.endswith('.middleware.ts') or file.endswith('.service.ts')): + continue + if file.endswith('.test.ts') or file.endswith('.e2e.ts'): + continue + + filepath = Path(root) / file + + # Read file content + with open(filepath, 'r', encoding='utf-8') as f: + content = f.read() + + # Check if file uses getErrorMessage + if 'getErrorMessage(' not in content: + continue + + # Check if import already exists + if re.search(r'import.*getErrorMessage.*from.*error-utils', content): + continue + + # Calculate relative path + rel_path = filepath.relative_to(base_dir) + depth = len(rel_path.parts) - 1 # -1 for the file itself + + # Build relative import path + if depth == 1: # src/middlewares/ + import_path = '../utils/error-utils' + elif depth == 2: # src/modules/xxx/ + import_path = '../../utils/error-utils' + elif depth == 3: # src/modules/xxx/yyy/ + import_path = '../../../utils/error-utils' + else: + import_path = '../../utils/error-utils' # default + + # Find the last import line + lines = content.split('\n') + last_import_idx = -1 + for i, line in enumerate(lines): + if line.strip().startswith('import '): + last_import_idx = i + + if last_import_idx >= 0: + # Insert new import after last import + import_statement = f"import {{ getErrorMessage }} from '{import_path}';" + lines.insert(last_import_idx + 1, import_statement) + + # Write back + with open(filepath, 'w', encoding='utf-8') as f: + f.write('\n'.join(lines)) + + print(f"Added import to {filepath}") + +print("Done!") diff --git a/scripts/add-error-imports.sh b/scripts/add-error-imports.sh new file mode 100755 index 00000000..4988fd20 --- /dev/null +++ b/scripts/add-error-imports.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# Script to add getErrorMessage import to files that use it + +cd /Users/velikho/Desktop/WORKING/Base/services/iam-service/src + +# Find all files that use getErrorMessage but don't have the import +for file in $(find . \( -name "*.controller.ts" -o -name "*.middleware.ts" -o -name "*.service.ts" \) -not -path "*/__tests__/*" -not -name "*.test.ts" -exec grep -l "getErrorMessage" {} \;); do + # Check if import already exists + if ! grep -q "getErrorMessage.*from.*error-utils" "$file"; then + # Calculate relative path to error-utils + depth=$(echo "$file" | grep -o "/" | wc -l) + if [ $depth -eq 2 ]; then + # File is in src/modules/xxx/ + relative_path="../utils/error-utils" + elif [ $depth -eq 3 ]; then + # File is in src/modules/xxx/yyy/ + relative_path="../../utils/error-utils" + elif [ $depth -eq 4 ]; then + # File is in src/modules/xxx/yyy/zzz/ + relative_path="../../../utils/error-utils" + else + # Default to ../../utils/error-utils + relative_path="../../utils/error-utils" + fi + + # Add import after the last import statement + awk -v path="$relative_path" ' + /^import/ { last_import=NR } + { lines[NR]=$0 } + END { + for(i=1; i<=NR; i++) { + print lines[i] + if(i==last_import) { + print "import { getErrorMessage } from \"" path "\";" + } + } + } + ' "$file" > "$file.tmp" && mv "$file.tmp" "$file" + + echo "Added import to $file" + fi +done diff --git a/services/iam-service/src/middlewares/auth.middleware.ts b/services/iam-service/src/middlewares/auth.middleware.ts index c0763164..93828f1c 100644 --- a/services/iam-service/src/middlewares/auth.middleware.ts +++ b/services/iam-service/src/middlewares/auth.middleware.ts @@ -3,6 +3,7 @@ import { ApiResponse } from '@goodgo/types'; import { Request, Response, NextFunction } from 'express'; import { jwtService } from '../modules/token/jwt.service'; +import { getErrorMessage } from '../utils/error-utils'; /** * EN: Extended Request interface with user information @@ -97,9 +98,9 @@ export const authenticate = (_options: { }); next(); - } catch (error: any) { + } catch (error: unknown) { logger.warn('Authentication failed / Xác thực thất bại', { - error: error.message, + error: getErrorMessage(error), path: req.path, method: req.method, }); @@ -239,11 +240,11 @@ export const optionalAuth = (_options: { } next(); - } catch (error: any) { + } catch (error: unknown) { // EN: For optional auth, just continue without user info // VI: Với optional auth, chỉ tiếp tục mà không có thông tin user logger.debug('Optional authentication skipped / Xác thực tùy chọn bị bỏ qua', { - reason: error.message, + reason: getErrorMessage(error), }); next(); } diff --git a/services/iam-service/src/modules/access/analytics/analytics.controller.ts b/services/iam-service/src/modules/access/analytics/analytics.controller.ts index 4596acbd..505daf31 100644 --- a/services/iam-service/src/modules/access/analytics/analytics.controller.ts +++ b/services/iam-service/src/modules/access/analytics/analytics.controller.ts @@ -4,6 +4,7 @@ import { z } from 'zod'; import { DateRangeDto, RiskFiltersDto } from '../access.dto'; import { accessAnalyticsService } from './analytics.service'; +import { getErrorMessage } from '../../../utils/error-utils'; /** * EN: Access Analytics Controller @@ -27,7 +28,7 @@ export class AccessAnalyticsController { success: true, data: stats, }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -44,7 +45,7 @@ export class AccessAnalyticsController { success: false, error: { code: 'GET_USAGE_STATS_FAILED', - message: error.message || 'Failed to get usage statistics', + message: getErrorMessage(error) || 'Failed to get usage statistics', }, }); } @@ -62,12 +63,12 @@ export class AccessAnalyticsController { success: true, data: distribution, }); - } catch (error: any) { + } catch (error: unknown) { res.status(500).json({ success: false, error: { code: 'GET_PERMISSION_DISTRIBUTION_FAILED', - message: error.message || 'Failed to get permission distribution', + message: getErrorMessage(error) || 'Failed to get permission distribution', }, }); } @@ -86,12 +87,12 @@ export class AccessAnalyticsController { success: true, data: summary, }); - } catch (error: any) { + } catch (error: unknown) { res.status(500).json({ success: false, error: { code: 'GET_USER_SUMMARY_FAILED', - message: error.message || 'Failed to get user access summary', + message: getErrorMessage(error) || 'Failed to get user access summary', }, }); } @@ -114,7 +115,7 @@ export class AccessAnalyticsController { success: true, data: trends, }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -131,7 +132,7 @@ export class AccessAnalyticsController { success: false, error: { code: 'GET_TRENDS_FAILED', - message: error.message || 'Failed to get access trends', + message: getErrorMessage(error) || 'Failed to get access trends', }, }); } @@ -156,7 +157,7 @@ export class AccessAnalyticsController { success: true, data: analysis, }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -173,7 +174,7 @@ export class AccessAnalyticsController { success: false, error: { code: 'GET_RISK_ANALYSIS_FAILED', - message: error.message || 'Failed to get risk analysis', + message: getErrorMessage(error) || 'Failed to get risk analysis', }, }); } diff --git a/services/iam-service/src/modules/access/request/request.controller.ts b/services/iam-service/src/modules/access/request/request.controller.ts index 4589aa44..bb3dd332 100644 --- a/services/iam-service/src/modules/access/request/request.controller.ts +++ b/services/iam-service/src/modules/access/request/request.controller.ts @@ -5,6 +5,7 @@ import { NotFoundError, BadRequestError } from '../../../errors/http-error'; import { CreateAccessRequestDto, ApproveAccessRequestDto, RejectAccessRequestDto } from '../access.dto'; import { accessRequestService } from './request.service'; +import { getErrorMessage } from '../../../utils/error-utils'; /** * EN: Access Request Controller @@ -36,12 +37,12 @@ export class AccessRequestController { success: true, data: requests, }); - } catch (error: any) { + } catch (error: unknown) { res.status(500).json({ success: false, error: { code: 'LIST_REQUESTS_FAILED', - message: error.message || 'Failed to list access requests', + message: getErrorMessage(error) || 'Failed to list access requests', }, }); } @@ -73,7 +74,7 @@ export class AccessRequestController { data: request, message: 'Access request created successfully / Yêu cầu truy cập đã được tạo thành công', }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -90,7 +91,7 @@ export class AccessRequestController { success: false, error: { code: 'CREATE_REQUEST_FAILED', - message: error.message || 'Failed to create access request', + message: getErrorMessage(error) || 'Failed to create access request', }, }); } @@ -109,7 +110,7 @@ export class AccessRequestController { success: true, data: request, }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof NotFoundError) { res.status(404).json(error.toApiResponse()); return; @@ -119,7 +120,7 @@ export class AccessRequestController { success: false, error: { code: 'GET_REQUEST_FAILED', - message: error.message || 'Failed to get access request', + message: getErrorMessage(error) || 'Failed to get access request', }, }); } @@ -152,7 +153,7 @@ export class AccessRequestController { data: request, message: 'Access request approved successfully / Yêu cầu truy cập đã được phê duyệt thành công', }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -174,7 +175,7 @@ export class AccessRequestController { success: false, error: { code: 'APPROVE_REQUEST_FAILED', - message: error.message || 'Failed to approve access request', + message: getErrorMessage(error) || 'Failed to approve access request', }, }); } @@ -207,7 +208,7 @@ export class AccessRequestController { data: request, message: 'Access request rejected / Yêu cầu truy cập đã bị từ chối', }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -229,7 +230,7 @@ export class AccessRequestController { success: false, error: { code: 'REJECT_REQUEST_FAILED', - message: error.message || 'Failed to reject access request', + message: getErrorMessage(error) || 'Failed to reject access request', }, }); } @@ -260,7 +261,7 @@ export class AccessRequestController { success: true, message: 'Access request cancelled successfully / Yêu cầu truy cập đã được hủy thành công', }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof NotFoundError || error instanceof BadRequestError) { res.status(error.statusCode).json(error.toApiResponse()); return; @@ -270,7 +271,7 @@ export class AccessRequestController { success: false, error: { code: 'CANCEL_REQUEST_FAILED', - message: error.message || 'Failed to cancel access request', + message: getErrorMessage(error) || 'Failed to cancel access request', }, }); } @@ -300,12 +301,12 @@ export class AccessRequestController { success: true, data: requests, }); - } catch (error: any) { + } catch (error: unknown) { res.status(500).json({ success: false, error: { code: 'GET_PENDING_APPROVALS_FAILED', - message: error.message || 'Failed to get pending approvals', + message: getErrorMessage(error) || 'Failed to get pending approvals', }, }); } diff --git a/services/iam-service/src/modules/access/review/review.controller.ts b/services/iam-service/src/modules/access/review/review.controller.ts index 7ff4fb0e..20c6d541 100644 --- a/services/iam-service/src/modules/access/review/review.controller.ts +++ b/services/iam-service/src/modules/access/review/review.controller.ts @@ -5,6 +5,7 @@ import { NotFoundError, BadRequestError } from '../../../errors/http-error'; import { CreateAccessReviewDto, ReviewAccessItemDto } from '../access.dto'; import { accessReviewService } from './review.service'; +import { getErrorMessage } from '../../../utils/error-utils'; /** * EN: Access Review Controller @@ -24,12 +25,12 @@ export class AccessReviewController { success: true, data: reviews, }); - } catch (error: any) { + } catch (error: unknown) { res.status(500).json({ success: false, error: { code: 'LIST_REVIEWS_FAILED', - message: error.message || 'Failed to list reviews', + message: getErrorMessage(error) || 'Failed to list reviews', }, }); } @@ -61,7 +62,7 @@ export class AccessReviewController { data: review, message: 'Access review created successfully / Đánh giá truy cập đã được tạo thành công', }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -83,7 +84,7 @@ export class AccessReviewController { success: false, error: { code: 'CREATE_REVIEW_FAILED', - message: error.message || 'Failed to create review', + message: getErrorMessage(error) || 'Failed to create review', }, }); } @@ -102,7 +103,7 @@ export class AccessReviewController { success: true, data: review, }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof NotFoundError) { res.status(404).json(error.toApiResponse()); return; @@ -112,7 +113,7 @@ export class AccessReviewController { success: false, error: { code: 'GET_REVIEW_FAILED', - message: error.message || 'Failed to get review', + message: getErrorMessage(error) || 'Failed to get review', }, }); } @@ -132,7 +133,7 @@ export class AccessReviewController { data: review, message: 'Access review started successfully / Đánh giá truy cập đã được bắt đầu thành công', }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof NotFoundError || error instanceof BadRequestError) { res.status(error.statusCode).json(error.toApiResponse()); return; @@ -142,7 +143,7 @@ export class AccessReviewController { success: false, error: { code: 'START_REVIEW_FAILED', - message: error.message || 'Failed to start review', + message: getErrorMessage(error) || 'Failed to start review', }, }); } @@ -162,7 +163,7 @@ export class AccessReviewController { data: review, message: 'Access review completed successfully / Đánh giá truy cập đã được hoàn thành thành công', }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof NotFoundError || error instanceof BadRequestError) { res.status(error.statusCode).json(error.toApiResponse()); return; @@ -172,7 +173,7 @@ export class AccessReviewController { success: false, error: { code: 'COMPLETE_REVIEW_FAILED', - message: error.message || 'Failed to complete review', + message: getErrorMessage(error) || 'Failed to complete review', }, }); } @@ -191,12 +192,12 @@ export class AccessReviewController { success: true, data: items, }); - } catch (error: any) { + } catch (error: unknown) { res.status(500).json({ success: false, error: { code: 'GET_REVIEW_ITEMS_FAILED', - message: error.message || 'Failed to get review items', + message: getErrorMessage(error) || 'Failed to get review items', }, }); } @@ -229,7 +230,7 @@ export class AccessReviewController { data: item, message: 'Review item updated successfully / Item đánh giá đã được cập nhật thành công', }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -251,7 +252,7 @@ export class AccessReviewController { success: false, error: { code: 'REVIEW_ITEM_FAILED', - message: error.message || 'Failed to review item', + message: getErrorMessage(error) || 'Failed to review item', }, }); } diff --git a/services/iam-service/src/modules/auth/auth.controller.ts b/services/iam-service/src/modules/auth/auth.controller.ts index 34de70e3..8281d9db 100644 --- a/services/iam-service/src/modules/auth/auth.controller.ts +++ b/services/iam-service/src/modules/auth/auth.controller.ts @@ -5,6 +5,7 @@ import { z } from 'zod'; import { RegisterDto, LoginDto } from './auth.dto'; import { authService } from './auth.service'; +import { getErrorMessage } from '../../utils/error-utils'; /** @@ -35,7 +36,7 @@ export class AuthController { tokens: result.tokens, }, }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -52,7 +53,7 @@ export class AuthController { success: false, error: { code: 'REGISTRATION_FAILED', - message: error.message || 'Registration failed', + message: getErrorMessage(error) || 'Registration failed', }, }); } @@ -92,7 +93,7 @@ export class AuthController { tokens: result.tokens, }, }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -109,7 +110,7 @@ export class AuthController { success: false, error: { code: 'LOGIN_FAILED', - message: error.message || 'Login failed', + message: getErrorMessage(error) || 'Login failed', }, }); } @@ -137,12 +138,12 @@ export class AuthController { success: true, data: { message: 'Logged out successfully' }, }); - } catch (error: any) { + } catch (error: unknown) { res.status(500).json({ success: false, error: { code: 'LOGOUT_FAILED', - message: error.message || 'Logout failed', + message: getErrorMessage(error) || 'Logout failed', }, }); } @@ -178,12 +179,12 @@ export class AuthController { success: true, data: result, }); - } catch (error: any) { + } catch (error: unknown) { res.status(401).json({ success: false, error: { code: 'REFRESH_FAILED', - message: error.message || 'Token refresh failed', + message: getErrorMessage(error) || 'Token refresh failed', }, }); } diff --git a/services/iam-service/src/modules/auth/change-password.controller.ts b/services/iam-service/src/modules/auth/change-password.controller.ts index db18a42f..6ae02ec5 100644 --- a/services/iam-service/src/modules/auth/change-password.controller.ts +++ b/services/iam-service/src/modules/auth/change-password.controller.ts @@ -3,6 +3,7 @@ import { z } from 'zod'; import { ChangePasswordDto } from './auth.dto'; import { changePasswordService } from './change-password.service'; +import { getErrorMessage } from '../../utils/error-utils'; /** * EN: Change Password Controller @@ -38,7 +39,7 @@ export class ChangePasswordController { success: true, data: { message: 'Password changed successfully' }, }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -55,7 +56,7 @@ export class ChangePasswordController { success: false, error: { code: 'CHANGE_PASSWORD_FAILED', - message: error.message || 'Failed to change password', + message: getErrorMessage(error) || 'Failed to change password', }, }); } diff --git a/services/iam-service/src/modules/common/repository.ts b/services/iam-service/src/modules/common/repository.ts index d83cfc99..35d7e821 100644 --- a/services/iam-service/src/modules/common/repository.ts +++ b/services/iam-service/src/modules/common/repository.ts @@ -2,6 +2,7 @@ import { logger } from '@goodgo/logger'; import { PrismaClient } from '@prisma/client'; import { DatabaseError } from '../../errors/http-error'; +import { formatErrorForLogging, hasCode } from '../../utils/error-utils'; /** * EN: Base repository class providing common database operations @@ -30,8 +31,8 @@ export abstract class BaseRepository { logger.debug(`${this.modelName} ${entity ? 'found' : 'not found'} / ${this.modelName} ${entity ? 'đã tìm thấy' : 'không tìm thấy'}`, { id }); return entity; - } catch (error: any) { - logger.error(`Failed to find ${this.modelName} by ID / Không thể tìm ${this.modelName} theo ID`, { error, id }); + } catch (error: unknown) { + logger.error(`Failed to find ${this.modelName} by ID / Không thể tìm ${this.modelName} theo ID`, { ...formatErrorForLogging(error), id }); throw new DatabaseError(`Failed to find ${this.modelName}`, { id, originalError: error }); } } @@ -40,7 +41,7 @@ export abstract class BaseRepository { * EN: Find entity by unique field * VI: Tìm entity theo field duy nhất */ - async findByUnique(field: string, value: any): Promise { + async findByUnique(field: string, value: unknown): Promise { try { logger.debug(`Finding ${this.modelName} by ${field} / Tìm ${this.modelName} theo ${field}`, { field, value }); @@ -50,8 +51,8 @@ export abstract class BaseRepository { logger.debug(`${this.modelName} ${entity ? 'found' : 'not found'} / ${this.modelName} ${entity ? 'đã tìm thấy' : 'không tìm thấy'}`, { field, value }); return entity; - } catch (error: any) { - logger.error(`Failed to find ${this.modelName} by ${field} / Không thể tìm ${this.modelName} theo ${field}`, { error, field, value }); + } catch (error: unknown) { + logger.error(`Failed to find ${this.modelName} by ${field} / Không thể tìm ${this.modelName} theo ${field}`, { ...formatErrorForLogging(error), field, value }); throw new DatabaseError(`Failed to find ${this.modelName}`, { field, value, originalError: error }); } } @@ -74,8 +75,8 @@ export abstract class BaseRepository { logger.debug(`Found ${entities.length} ${this.modelName} entities / Đã tìm thấy ${entities.length} ${this.modelName} entities`); return entities; - } catch (error: any) { - logger.error(`Failed to find all ${this.modelName} / Không thể tìm tất cả ${this.modelName}`, { error, options }); + } catch (error: unknown) { + logger.error(`Failed to find all ${this.modelName} / Không thể tìm tất cả ${this.modelName}`, { ...formatErrorForLogging(error), options }); throw new DatabaseError(`Failed to find ${this.modelName} entities`, { options, originalError: error }); } } @@ -94,8 +95,8 @@ export abstract class BaseRepository { logger.debug(`${this.modelName} created successfully / ${this.modelName} đã được tạo thành công`, { id: (entity as any).id }); return entity; - } catch (error: any) { - logger.error(`Failed to create ${this.modelName} / Không thể tạo ${this.modelName}`, { error, data }); + } catch (error: unknown) { + logger.error(`Failed to create ${this.modelName} / Không thể tạo ${this.modelName}`, { ...formatErrorForLogging(error), data }); throw new DatabaseError(`Failed to create ${this.modelName}`, { data, originalError: error }); } } @@ -115,12 +116,12 @@ export abstract class BaseRepository { logger.debug(`${this.modelName} updated successfully / ${this.modelName} đã được cập nhật thành công`, { id }); return entity; - } catch (error: any) { - if (error.code === 'P2025') { + } catch (error: unknown) { + if (hasCode(error) && error.code === 'P2025') { logger.warn(`${this.modelName} not found for update / ${this.modelName} không tìm thấy để cập nhật`, { id }); throw new DatabaseError(`${this.modelName} not found`, { id }); } - logger.error(`Failed to update ${this.modelName} / Không thể cập nhật ${this.modelName}`, { error, id, data }); + logger.error(`Failed to update ${this.modelName} / Không thể cập nhật ${this.modelName}`, { ...formatErrorForLogging(error), id, data }); throw new DatabaseError(`Failed to update ${this.modelName}`, { id, data, originalError: error }); } } @@ -139,12 +140,12 @@ export abstract class BaseRepository { logger.debug(`${this.modelName} deleted successfully / ${this.modelName} đã được xóa thành công`, { id }); return true; - } catch (error: any) { - if (error.code === 'P2025') { + } catch (error: unknown) { + if (hasCode(error) && error.code === 'P2025') { logger.warn(`${this.modelName} not found for deletion / ${this.modelName} không tìm thấy để xóa`, { id }); throw new DatabaseError(`${this.modelName} not found`, { id }); } - logger.error(`Failed to delete ${this.modelName} / Không thể xóa ${this.modelName}`, { error, id }); + logger.error(`Failed to delete ${this.modelName} / Không thể xóa ${this.modelName}`, { ...formatErrorForLogging(error), id }); throw new DatabaseError(`Failed to delete ${this.modelName}`, { id, originalError: error }); } } @@ -163,8 +164,8 @@ export abstract class BaseRepository { logger.debug(`Counted ${count} ${this.modelName} entities / Đã đếm ${count} ${this.modelName} entities`); return count; - } catch (error: any) { - logger.error(`Failed to count ${this.modelName} / Không thể đếm ${this.modelName}`, { error, where }); + } catch (error: unknown) { + logger.error(`Failed to count ${this.modelName} / Không thể đếm ${this.modelName}`, { ...formatErrorForLogging(error), where }); throw new DatabaseError(`Failed to count ${this.modelName}`, { where, originalError: error }); } } @@ -177,8 +178,8 @@ export abstract class BaseRepository { try { const count = await this.count({ id }); return count > 0; - } catch (error: any) { - logger.error(`Failed to check if ${this.modelName} exists / Không thể kiểm tra ${this.modelName} có tồn tại`, { error, id }); + } catch (error: unknown) { + logger.error(`Failed to check if ${this.modelName} exists / Không thể kiểm tra ${this.modelName} có tồn tại`, { ...formatErrorForLogging(error), id }); throw error; } } @@ -197,8 +198,8 @@ export abstract class BaseRepository { logger.debug(`${this.modelName} transaction completed successfully / Transaction ${this.modelName} đã hoàn thành thành công`); return result; - } catch (error: any) { - logger.error(`${this.modelName} transaction failed / Transaction ${this.modelName} thất bại`, { error }); + } catch (error: unknown) { + logger.error(`${this.modelName} transaction failed / Transaction ${this.modelName} thất bại`, formatErrorForLogging(error)); throw new DatabaseError(`${this.modelName} transaction failed`, { originalError: error }); } } @@ -210,7 +211,7 @@ export abstract class BaseRepository { */ export interface IRepository { findById(id: string): Promise; - findByUnique(field: string, value: any): Promise; + findByUnique(field: string, value: unknown): Promise; findAll(options?: any): Promise; create(data: CreateInput): Promise; update(id: string, data: UpdateInput): Promise; diff --git a/services/iam-service/src/modules/feature/feature.controller.ts b/services/iam-service/src/modules/feature/feature.controller.ts index 87110b75..d5beb458 100644 --- a/services/iam-service/src/modules/feature/feature.controller.ts +++ b/services/iam-service/src/modules/feature/feature.controller.ts @@ -4,6 +4,7 @@ import { Request, Response } from 'express'; import { asyncHandler } from '../../middlewares/error.middleware'; import { FeatureService } from './feature.service'; +import { getErrorMessage } from '../../utils/error-utils'; /** @@ -83,12 +84,12 @@ export class FeatureController { timestamp: new Date().toISOString(), }; res.json(response); - } catch (error: any) { + } catch (error: unknown) { res.status(500).json({ success: false, error: { code: 'FEATURE_004', - message: error.message || 'Failed to retrieve feature / Không thể lấy feature', + message: getErrorMessage(error) || 'Failed to retrieve feature / Không thể lấy feature', }, timestamp: new Date().toISOString(), }); @@ -112,12 +113,12 @@ export class FeatureController { timestamp: new Date().toISOString(), }; res.json(response); - } catch (error: any) { + } catch (error: unknown) { res.status(400).json({ success: false, error: { code: 'FEATURE_005', - message: error.message || 'Failed to update feature / Không thể cập nhật feature', + message: getErrorMessage(error) || 'Failed to update feature / Không thể cập nhật feature', }, timestamp: new Date().toISOString(), }); @@ -139,12 +140,12 @@ export class FeatureController { timestamp: new Date().toISOString(), }; res.json(response); - } catch (error: any) { + } catch (error: unknown) { res.status(400).json({ success: false, error: { code: 'FEATURE_006', - message: error.message || 'Failed to delete feature / Không thể xóa feature', + message: getErrorMessage(error) || 'Failed to delete feature / Không thể xóa feature', }, timestamp: new Date().toISOString(), }); @@ -167,12 +168,12 @@ export class FeatureController { timestamp: new Date().toISOString(), }; res.json(response); - } catch (error: any) { + } catch (error: unknown) { res.status(400).json({ success: false, error: { code: 'FEATURE_007', - message: error.message || 'Failed to toggle feature / Không thể chuyển đổi feature', + message: getErrorMessage(error) || 'Failed to toggle feature / Không thể chuyển đổi feature', }, timestamp: new Date().toISOString(), }); diff --git a/services/iam-service/src/modules/feature/feature.repository.ts b/services/iam-service/src/modules/feature/feature.repository.ts index 392e986e..b9497bb7 100644 --- a/services/iam-service/src/modules/feature/feature.repository.ts +++ b/services/iam-service/src/modules/feature/feature.repository.ts @@ -3,6 +3,7 @@ import { logger } from '@goodgo/logger'; import { prisma } from '../../config/database.config'; import { ConflictError } from '../../errors/http-error'; import { BaseRepository, IRepository } from '../common/repository'; +import { hasCode } from '../../utils/error-utils'; // EN: Feature entity type from Prisma // VI: Feature entity type từ Prisma @@ -11,7 +12,7 @@ type Feature = { name: string; title: string | null; description: string | null; - config: any; + config: Record; enabled: boolean; version: string | null; tags: string[]; @@ -25,14 +26,14 @@ type CreateFeatureInput = { name: string; title?: string; description?: string; - config?: any; + config?: Record; tags?: string[]; }; type UpdateFeatureInput = { title?: string; description?: string; - config?: any; + config?: Record; enabled?: boolean; tags?: string[]; }; @@ -229,8 +230,8 @@ export class FeatureRepository extends BaseRepository; tags?: string[] }) { logger.info('Creating feature / Tạo feature', { data }); const feature = await featureRepository.create(data); @@ -77,7 +77,7 @@ export class FeatureService { * EN: Update feature * VI: Cập nhật feature */ - async update(id: string, data: Partial<{ title?: string; description?: string; config?: any; enabled?: boolean; tags?: string[] }>) { + async update(id: string, data: Partial<{ title?: string; description?: string; config?: Record; enabled?: boolean; tags?: string[] }>) { logger.info('Updating feature / Cập nhật feature', { id, data }); const feature = await featureRepository.update(id, data); diff --git a/services/iam-service/src/modules/governance/compliance/compliance.controller.ts b/services/iam-service/src/modules/governance/compliance/compliance.controller.ts index 0bc6f95c..144c40b7 100644 --- a/services/iam-service/src/modules/governance/compliance/compliance.controller.ts +++ b/services/iam-service/src/modules/governance/compliance/compliance.controller.ts @@ -5,6 +5,7 @@ import { NotFoundError, BadRequestError } from '../../../errors/http-error'; import { GenerateComplianceReportDto, ReportFiltersDto } from '../governance.dto'; import { complianceService } from './compliance.service'; +import { getErrorMessage } from '../../../utils/error-utils'; /** * EN: Compliance Controller @@ -39,7 +40,7 @@ export class ComplianceController { }, }, }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -56,7 +57,7 @@ export class ComplianceController { success: false, error: { code: 'LIST_REPORTS_FAILED', - message: error.message || 'Failed to list reports', + message: getErrorMessage(error) || 'Failed to list reports', }, }); } @@ -97,7 +98,7 @@ export class ComplianceController { data: report, message: 'Compliance report generated successfully / Báo cáo tuân thủ đã được tạo thành công', }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -119,7 +120,7 @@ export class ComplianceController { success: false, error: { code: 'GENERATE_REPORT_FAILED', - message: error.message || 'Failed to generate report', + message: getErrorMessage(error) || 'Failed to generate report', }, }); } @@ -138,7 +139,7 @@ export class ComplianceController { success: true, data: report, }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof NotFoundError) { res.status(404).json(error.toApiResponse()); return; @@ -148,7 +149,7 @@ export class ComplianceController { success: false, error: { code: 'GET_REPORT_FAILED', - message: error.message || 'Failed to get report', + message: getErrorMessage(error) || 'Failed to get report', }, }); } @@ -182,7 +183,7 @@ export class ComplianceController { }, }); } - } catch (error: any) { + } catch (error: unknown) { if (error instanceof NotFoundError) { res.status(404).json(error.toApiResponse()); return; @@ -192,7 +193,7 @@ export class ComplianceController { success: false, error: { code: 'EXPORT_REPORT_FAILED', - message: error.message || 'Failed to export report', + message: getErrorMessage(error) || 'Failed to export report', }, }); } @@ -212,7 +213,7 @@ export class ComplianceController { data: report, message: 'Report published successfully / Báo cáo đã được xuất bản thành công', }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof NotFoundError) { res.status(404).json(error.toApiResponse()); return; @@ -222,7 +223,7 @@ export class ComplianceController { success: false, error: { code: 'PUBLISH_REPORT_FAILED', - message: error.message || 'Failed to publish report', + message: getErrorMessage(error) || 'Failed to publish report', }, }); } diff --git a/services/iam-service/src/modules/governance/policy/policy-governance.controller.ts b/services/iam-service/src/modules/governance/policy/policy-governance.controller.ts index 945247ac..994910d1 100644 --- a/services/iam-service/src/modules/governance/policy/policy-governance.controller.ts +++ b/services/iam-service/src/modules/governance/policy/policy-governance.controller.ts @@ -5,6 +5,7 @@ import { NotFoundError } from '../../../errors/http-error'; import { CreatePolicyTemplateDto, TestPolicyDto } from '../governance.dto'; import { policyGovernanceService } from './policy-governance.service'; +import { getErrorMessage } from '../../../utils/error-utils'; /** * EN: Policy Governance Controller @@ -24,12 +25,12 @@ export class PolicyGovernanceController { success: true, data: templates, }); - } catch (error: any) { + } catch (error: unknown) { res.status(500).json({ success: false, error: { code: 'GET_TEMPLATES_FAILED', - message: error.message || 'Failed to get templates', + message: getErrorMessage(error) || 'Failed to get templates', }, }); } @@ -49,7 +50,7 @@ export class PolicyGovernanceController { data: template, message: 'Policy template created successfully / Template policy đã được tạo thành công', }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -66,7 +67,7 @@ export class PolicyGovernanceController { success: false, error: { code: 'CREATE_TEMPLATE_FAILED', - message: error.message || 'Failed to create template', + message: getErrorMessage(error) || 'Failed to create template', }, }); } @@ -85,7 +86,7 @@ export class PolicyGovernanceController { success: true, data: versions, }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof NotFoundError) { res.status(404).json(error.toApiResponse()); return; @@ -95,7 +96,7 @@ export class PolicyGovernanceController { success: false, error: { code: 'GET_VERSIONS_FAILED', - message: error.message || 'Failed to get policy versions', + message: getErrorMessage(error) || 'Failed to get policy versions', }, }); } @@ -115,7 +116,7 @@ export class PolicyGovernanceController { success: true, data: result, }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -137,7 +138,7 @@ export class PolicyGovernanceController { success: false, error: { code: 'TEST_POLICY_FAILED', - message: error.message || 'Failed to test policy', + message: getErrorMessage(error) || 'Failed to test policy', }, }); } diff --git a/services/iam-service/src/modules/governance/reporting/reporting.controller.ts b/services/iam-service/src/modules/governance/reporting/reporting.controller.ts index 81c3f7c8..9e411609 100644 --- a/services/iam-service/src/modules/governance/reporting/reporting.controller.ts +++ b/services/iam-service/src/modules/governance/reporting/reporting.controller.ts @@ -4,6 +4,7 @@ import { z } from 'zod'; import { AccessSummaryFiltersDto, UserActivityFiltersDto, SecurityEventsFiltersDto } from '../governance.dto'; import { reportingService } from './reporting.service'; +import { getErrorMessage } from '../../../utils/error-utils'; /** * EN: Reporting Controller @@ -28,7 +29,7 @@ export class ReportingController { success: true, data: summary, }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -45,7 +46,7 @@ export class ReportingController { success: false, error: { code: 'GET_ACCESS_SUMMARY_FAILED', - message: error.message || 'Failed to get access summary', + message: getErrorMessage(error) || 'Failed to get access summary', }, }); } @@ -70,7 +71,7 @@ export class ReportingController { success: true, data: activity, }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -87,7 +88,7 @@ export class ReportingController { success: false, error: { code: 'GET_USER_ACTIVITY_FAILED', - message: error.message || 'Failed to get user activity', + message: getErrorMessage(error) || 'Failed to get user activity', }, }); } @@ -121,7 +122,7 @@ export class ReportingController { }, }, }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -138,7 +139,7 @@ export class ReportingController { success: false, error: { code: 'GET_SECURITY_EVENTS_FAILED', - message: error.message || 'Failed to get security events', + message: getErrorMessage(error) || 'Failed to get security events', }, }); } @@ -156,12 +157,12 @@ export class ReportingController { success: true, data: status, }); - } catch (error: any) { + } catch (error: unknown) { res.status(500).json({ success: false, error: { code: 'GET_COMPLIANCE_STATUS_FAILED', - message: error.message || 'Failed to get compliance status', + message: getErrorMessage(error) || 'Failed to get compliance status', }, }); } @@ -179,12 +180,12 @@ export class ReportingController { success: true, data: overview, }); - } catch (error: any) { + } catch (error: unknown) { res.status(500).json({ success: false, error: { code: 'GET_RISK_OVERVIEW_FAILED', - message: error.message || 'Failed to get risk overview', + message: getErrorMessage(error) || 'Failed to get risk overview', }, }); } diff --git a/services/iam-service/src/modules/governance/risk/risk.controller.ts b/services/iam-service/src/modules/governance/risk/risk.controller.ts index cd37d1ce..901336fb 100644 --- a/services/iam-service/src/modules/governance/risk/risk.controller.ts +++ b/services/iam-service/src/modules/governance/risk/risk.controller.ts @@ -6,6 +6,7 @@ import { NotFoundError } from '../../../errors/http-error'; import { CalculateRiskScoreDto, RiskFiltersDto } from '../governance.dto'; import { riskService } from './risk.service'; +import { getErrorMessage } from '../../../utils/error-utils'; /** * EN: Risk Management Controller @@ -41,7 +42,7 @@ export class RiskController { }, }, }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -58,7 +59,7 @@ export class RiskController { success: false, error: { code: 'LIST_RISK_SCORES_FAILED', - message: error.message || 'Failed to list risk scores', + message: getErrorMessage(error) || 'Failed to list risk scores', }, }); } @@ -77,7 +78,7 @@ export class RiskController { success: true, data: score, }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof NotFoundError) { res.status(404).json(error.toApiResponse()); return; @@ -87,7 +88,7 @@ export class RiskController { success: false, error: { code: 'GET_RISK_SCORE_FAILED', - message: error.message || 'Failed to get risk score', + message: getErrorMessage(error) || 'Failed to get risk score', }, }); } @@ -107,7 +108,7 @@ export class RiskController { data: score, message: 'Risk score calculated successfully / Điểm rủi ro đã được tính thành công', }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -129,7 +130,7 @@ export class RiskController { success: false, error: { code: 'CALCULATE_RISK_SCORE_FAILED', - message: error.message || 'Failed to calculate risk score', + message: getErrorMessage(error) || 'Failed to calculate risk score', }, }); } @@ -170,12 +171,12 @@ export class RiskController { totalUsers: allScores.length, }, }); - } catch (error: any) { + } catch (error: unknown) { res.status(500).json({ success: false, error: { code: 'GET_DASHBOARD_FAILED', - message: error.message || 'Failed to get risk dashboard', + message: getErrorMessage(error) || 'Failed to get risk dashboard', }, }); } diff --git a/services/iam-service/src/modules/identity/group/group.controller.ts b/services/iam-service/src/modules/identity/group/group.controller.ts index c7b9c4eb..20f1a709 100644 --- a/services/iam-service/src/modules/identity/group/group.controller.ts +++ b/services/iam-service/src/modules/identity/group/group.controller.ts @@ -5,6 +5,7 @@ import { NotFoundError, ConflictError } from '../../../errors/http-error'; import { CreateGroupDto, UpdateGroupDto, AddGroupMemberDto } from '../identity.dto'; import { groupService } from './group.service'; +import { getErrorMessage } from '../../../utils/error-utils'; /** * EN: Group Controller @@ -24,12 +25,12 @@ export class GroupController { success: true, data: groups, }); - } catch (error: any) { + } catch (error: unknown) { res.status(500).json({ success: false, error: { code: 'LIST_GROUPS_FAILED', - message: error.message || 'Failed to list groups', + message: getErrorMessage(error) || 'Failed to list groups', }, }); } @@ -50,7 +51,7 @@ export class GroupController { data: group, message: 'Group created successfully / Nhóm đã được tạo thành công', }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -72,7 +73,7 @@ export class GroupController { success: false, error: { code: 'CREATE_GROUP_FAILED', - message: error.message || 'Failed to create group', + message: getErrorMessage(error) || 'Failed to create group', }, }); } @@ -91,7 +92,7 @@ export class GroupController { success: true, data: group, }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof NotFoundError) { res.status(404).json(error.toApiResponse()); return; @@ -101,7 +102,7 @@ export class GroupController { success: false, error: { code: 'GET_GROUP_FAILED', - message: error.message || 'Failed to get group', + message: getErrorMessage(error) || 'Failed to get group', }, }); } @@ -122,7 +123,7 @@ export class GroupController { data: group, message: 'Group updated successfully / Nhóm đã được cập nhật thành công', }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -144,7 +145,7 @@ export class GroupController { success: false, error: { code: 'UPDATE_GROUP_FAILED', - message: error.message || 'Failed to update group', + message: getErrorMessage(error) || 'Failed to update group', }, }); } @@ -163,7 +164,7 @@ export class GroupController { success: true, message: 'Group deleted successfully / Nhóm đã được xóa thành công', }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof NotFoundError || error instanceof ConflictError) { res.status(error.statusCode).json(error.toApiResponse()); return; @@ -173,7 +174,7 @@ export class GroupController { success: false, error: { code: 'DELETE_GROUP_FAILED', - message: error.message || 'Failed to delete group', + message: getErrorMessage(error) || 'Failed to delete group', }, }); } @@ -192,12 +193,12 @@ export class GroupController { success: true, data: members, }); - } catch (error: any) { + } catch (error: unknown) { res.status(500).json({ success: false, error: { code: 'GET_GROUP_MEMBERS_FAILED', - message: error.message || 'Failed to get group members', + message: getErrorMessage(error) || 'Failed to get group members', }, }); } @@ -219,7 +220,7 @@ export class GroupController { success: true, message: 'Member added successfully / Thành viên đã được thêm thành công', }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -241,7 +242,7 @@ export class GroupController { success: false, error: { code: 'ADD_MEMBER_FAILED', - message: error.message || 'Failed to add member', + message: getErrorMessage(error) || 'Failed to add member', }, }); } @@ -260,7 +261,7 @@ export class GroupController { success: true, message: 'Member removed successfully / Thành viên đã được xóa thành công', }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof NotFoundError) { res.status(404).json(error.toApiResponse()); return; @@ -270,7 +271,7 @@ export class GroupController { success: false, error: { code: 'REMOVE_MEMBER_FAILED', - message: error.message || 'Failed to remove member', + message: getErrorMessage(error) || 'Failed to remove member', }, }); } diff --git a/services/iam-service/src/modules/identity/organization/organization.controller.ts b/services/iam-service/src/modules/identity/organization/organization.controller.ts index 78149e4e..fe6bb9bd 100644 --- a/services/iam-service/src/modules/identity/organization/organization.controller.ts +++ b/services/iam-service/src/modules/identity/organization/organization.controller.ts @@ -5,6 +5,7 @@ import { NotFoundError, ConflictError } from '../../../errors/http-error'; import { CreateOrganizationDto, UpdateOrganizationDto } from '../identity.dto'; import { organizationService } from './organization.service'; +import { getErrorMessage } from '../../../utils/error-utils'; /** * EN: Organization Controller @@ -33,12 +34,12 @@ export class OrganizationController { }, }, }); - } catch (error: any) { + } catch (error: unknown) { res.status(500).json({ success: false, error: { code: 'LIST_ORGANIZATIONS_FAILED', - message: error.message || 'Failed to list organizations', + message: getErrorMessage(error) || 'Failed to list organizations', }, }); } @@ -58,7 +59,7 @@ export class OrganizationController { data: organization, message: 'Organization created successfully / Tổ chức đã được tạo thành công', }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -80,7 +81,7 @@ export class OrganizationController { success: false, error: { code: 'CREATE_ORGANIZATION_FAILED', - message: error.message || 'Failed to create organization', + message: getErrorMessage(error) || 'Failed to create organization', }, }); } @@ -99,7 +100,7 @@ export class OrganizationController { success: true, data: organization, }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof NotFoundError) { res.status(404).json(error.toApiResponse()); return; @@ -109,7 +110,7 @@ export class OrganizationController { success: false, error: { code: 'GET_ORGANIZATION_FAILED', - message: error.message || 'Failed to get organization', + message: getErrorMessage(error) || 'Failed to get organization', }, }); } @@ -130,7 +131,7 @@ export class OrganizationController { data: organization, message: 'Organization updated successfully / Tổ chức đã được cập nhật thành công', }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -152,7 +153,7 @@ export class OrganizationController { success: false, error: { code: 'UPDATE_ORGANIZATION_FAILED', - message: error.message || 'Failed to update organization', + message: getErrorMessage(error) || 'Failed to update organization', }, }); } @@ -171,7 +172,7 @@ export class OrganizationController { success: true, message: 'Organization deleted successfully / Tổ chức đã được xóa thành công', }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof NotFoundError || error instanceof ConflictError) { res.status(error.statusCode).json(error.toApiResponse()); return; @@ -181,7 +182,7 @@ export class OrganizationController { success: false, error: { code: 'DELETE_ORGANIZATION_FAILED', - message: error.message || 'Failed to delete organization', + message: getErrorMessage(error) || 'Failed to delete organization', }, }); } @@ -210,7 +211,7 @@ export class OrganizationController { }, }, }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof NotFoundError) { res.status(404).json(error.toApiResponse()); return; @@ -220,7 +221,7 @@ export class OrganizationController { success: false, error: { code: 'GET_ORGANIZATION_USERS_FAILED', - message: error.message || 'Failed to get organization users', + message: getErrorMessage(error) || 'Failed to get organization users', }, }); } diff --git a/services/iam-service/src/modules/identity/profile/profile.controller.ts b/services/iam-service/src/modules/identity/profile/profile.controller.ts index 6beb818e..3fe3f32b 100644 --- a/services/iam-service/src/modules/identity/profile/profile.controller.ts +++ b/services/iam-service/src/modules/identity/profile/profile.controller.ts @@ -5,6 +5,7 @@ import { NotFoundError } from '../../../errors/http-error'; import { UpdateUserProfileDto } from '../identity.dto'; import { profileService } from './profile.service'; +import { getErrorMessage } from '../../../utils/error-utils'; /** * EN: Profile Management Controller @@ -35,12 +36,12 @@ export class ProfileController { success: true, data: profile, }); - } catch (error: any) { + } catch (error: unknown) { res.status(500).json({ success: false, error: { code: 'GET_PROFILE_FAILED', - message: error.message || 'Failed to get profile', + message: getErrorMessage(error) || 'Failed to get profile', }, }); } @@ -61,7 +62,7 @@ export class ProfileController { data: profile, message: 'Profile updated successfully / Profile đã được cập nhật thành công', }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -83,7 +84,7 @@ export class ProfileController { success: false, error: { code: 'UPDATE_PROFILE_FAILED', - message: error.message || 'Failed to update profile', + message: getErrorMessage(error) || 'Failed to update profile', }, }); } @@ -116,7 +117,7 @@ export class ProfileController { data: profile, message: 'Avatar uploaded successfully / Avatar đã được upload thành công', }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof NotFoundError) { res.status(404).json(error.toApiResponse()); return; @@ -126,7 +127,7 @@ export class ProfileController { success: false, error: { code: 'UPLOAD_AVATAR_FAILED', - message: error.message || 'Failed to upload avatar', + message: getErrorMessage(error) || 'Failed to upload avatar', }, }); } @@ -146,7 +147,7 @@ export class ProfileController { data: profile, message: 'Avatar deleted successfully / Avatar đã được xóa thành công', }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof NotFoundError) { res.status(404).json(error.toApiResponse()); return; @@ -156,7 +157,7 @@ export class ProfileController { success: false, error: { code: 'DELETE_AVATAR_FAILED', - message: error.message || 'Failed to delete avatar', + message: getErrorMessage(error) || 'Failed to delete avatar', }, }); } diff --git a/services/iam-service/src/modules/identity/user/user.controller.ts b/services/iam-service/src/modules/identity/user/user.controller.ts index e7ad7377..3e785324 100644 --- a/services/iam-service/src/modules/identity/user/user.controller.ts +++ b/services/iam-service/src/modules/identity/user/user.controller.ts @@ -5,6 +5,7 @@ import { NotFoundError } from '../../../errors/http-error'; import { UpdateUserDto, UserFiltersDto, BulkImportUsersDto } from '../identity.dto'; import { userManagementService } from './user.service'; +import { getErrorMessage } from '../../../utils/error-utils'; /** * EN: User Management Controller @@ -39,7 +40,7 @@ export class UserManagementController { }, }, }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -56,7 +57,7 @@ export class UserManagementController { success: false, error: { code: 'LIST_USERS_FAILED', - message: error.message || 'Failed to list users', + message: getErrorMessage(error) || 'Failed to list users', }, }); } @@ -75,7 +76,7 @@ export class UserManagementController { success: true, data: user, }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof NotFoundError) { res.status(404).json(error.toApiResponse()); return; @@ -85,7 +86,7 @@ export class UserManagementController { success: false, error: { code: 'GET_USER_FAILED', - message: error.message || 'Failed to get user', + message: getErrorMessage(error) || 'Failed to get user', }, }); } @@ -106,7 +107,7 @@ export class UserManagementController { data: user, message: 'User updated successfully / User đã được cập nhật thành công', }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -128,7 +129,7 @@ export class UserManagementController { success: false, error: { code: 'UPDATE_USER_FAILED', - message: error.message || 'Failed to update user', + message: getErrorMessage(error) || 'Failed to update user', }, }); } @@ -147,7 +148,7 @@ export class UserManagementController { success: true, message: 'User deleted successfully / User đã được xóa thành công', }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof NotFoundError) { res.status(404).json(error.toApiResponse()); return; @@ -157,7 +158,7 @@ export class UserManagementController { success: false, error: { code: 'DELETE_USER_FAILED', - message: error.message || 'Failed to delete user', + message: getErrorMessage(error) || 'Failed to delete user', }, }); } @@ -177,7 +178,7 @@ export class UserManagementController { data: user, message: 'User deactivated successfully / User đã được vô hiệu hóa thành công', }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof NotFoundError) { res.status(404).json(error.toApiResponse()); return; @@ -187,7 +188,7 @@ export class UserManagementController { success: false, error: { code: 'DEACTIVATE_USER_FAILED', - message: error.message || 'Failed to deactivate user', + message: getErrorMessage(error) || 'Failed to deactivate user', }, }); } @@ -207,7 +208,7 @@ export class UserManagementController { data: user, message: 'User reactivated successfully / User đã được kích hoạt lại thành công', }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof NotFoundError) { res.status(404).json(error.toApiResponse()); return; @@ -217,7 +218,7 @@ export class UserManagementController { success: false, error: { code: 'REACTIVATE_USER_FAILED', - message: error.message || 'Failed to reactivate user', + message: getErrorMessage(error) || 'Failed to reactivate user', }, }); } @@ -237,7 +238,7 @@ export class UserManagementController { data: result, message: `Imported ${result.created} users successfully / Đã import ${result.created} users thành công`, }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -254,7 +255,7 @@ export class UserManagementController { success: false, error: { code: 'BULK_IMPORT_FAILED', - message: error.message || 'Failed to import users', + message: getErrorMessage(error) || 'Failed to import users', }, }); } @@ -284,7 +285,7 @@ export class UserManagementController { exportedAt: new Date().toISOString(), total: users.length, }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -301,7 +302,7 @@ export class UserManagementController { success: false, error: { code: 'BULK_EXPORT_FAILED', - message: error.message || 'Failed to export users', + message: getErrorMessage(error) || 'Failed to export users', }, }); } diff --git a/services/iam-service/src/modules/identity/user/user.service.ts b/services/iam-service/src/modules/identity/user/user.service.ts index db2c16fc..1241ff32 100644 --- a/services/iam-service/src/modules/identity/user/user.service.ts +++ b/services/iam-service/src/modules/identity/user/user.service.ts @@ -8,6 +8,7 @@ import { NotFoundError, ConflictError } from '../../../errors/http-error'; import { UserProfileRepository } from '../../../repositories/user-profile.repository'; import { UserRepository } from '../../../repositories/user.repository'; import { UpdateUserDto, UserFiltersDto, BulkImportUsersDto } from '../identity.dto'; +import { getErrorMessage } from '../../../utils/error-utils'; /** * EN: User Management Service for user lifecycle operations @@ -246,8 +247,8 @@ export class UserManagementService { success: true, }); } - } catch (error: any) { - errors.push({ email: userData.email, error: error.message }); + } catch (error: unknown) { + errors.push({ email: userData.email, error: getErrorMessage(error) }); } } diff --git a/services/iam-service/src/modules/identity/verification/verification.controller.ts b/services/iam-service/src/modules/identity/verification/verification.controller.ts index d2300200..cf9c3654 100644 --- a/services/iam-service/src/modules/identity/verification/verification.controller.ts +++ b/services/iam-service/src/modules/identity/verification/verification.controller.ts @@ -5,6 +5,7 @@ import { BadRequestError, NotFoundError } from '../../../errors/http-error'; import { VerifyEmailDto, VerifyPhoneDto } from '../identity.dto'; import { verificationService } from './verification.service'; +import { getErrorMessage } from '../../../utils/error-utils'; /** * EN: Identity Verification Controller @@ -36,7 +37,7 @@ export class VerificationController { data: result, message: 'Verification email sent / Email xác thực đã được gửi', }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof NotFoundError || error instanceof BadRequestError) { res.status(error.statusCode).json(error.toApiResponse()); return; @@ -46,7 +47,7 @@ export class VerificationController { success: false, error: { code: 'REQUEST_VERIFICATION_FAILED', - message: error.message || 'Failed to request verification', + message: getErrorMessage(error) || 'Failed to request verification', }, }); } @@ -66,7 +67,7 @@ export class VerificationController { data: result, message: 'Email verified successfully / Email đã được xác thực thành công', }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -88,7 +89,7 @@ export class VerificationController { success: false, error: { code: 'VERIFY_EMAIL_FAILED', - message: error.message || 'Failed to verify email', + message: getErrorMessage(error) || 'Failed to verify email', }, }); } @@ -132,7 +133,7 @@ export class VerificationController { data: result, message: 'Verification code sent / Mã xác thực đã được gửi', }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof NotFoundError || error instanceof BadRequestError) { res.status(error.statusCode).json(error.toApiResponse()); return; @@ -142,7 +143,7 @@ export class VerificationController { success: false, error: { code: 'REQUEST_PHONE_VERIFICATION_FAILED', - message: error.message || 'Failed to request phone verification', + message: getErrorMessage(error) || 'Failed to request phone verification', }, }); } @@ -162,7 +163,7 @@ export class VerificationController { data: result, message: 'Phone verified successfully / Điện thoại đã được xác thực thành công', }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -184,7 +185,7 @@ export class VerificationController { success: false, error: { code: 'VERIFY_PHONE_FAILED', - message: error.message || 'Failed to verify phone', + message: getErrorMessage(error) || 'Failed to verify phone', }, }); } @@ -216,12 +217,12 @@ export class VerificationController { success: true, data: status, }); - } catch (error: any) { + } catch (error: unknown) { res.status(500).json({ success: false, error: { code: 'GET_VERIFICATION_STATUS_FAILED', - message: error.message || 'Failed to get verification status', + message: getErrorMessage(error) || 'Failed to get verification status', }, }); } diff --git a/services/iam-service/src/modules/mfa/mfa.controller.ts b/services/iam-service/src/modules/mfa/mfa.controller.ts index 4027a93a..2d3c5230 100644 --- a/services/iam-service/src/modules/mfa/mfa.controller.ts +++ b/services/iam-service/src/modules/mfa/mfa.controller.ts @@ -2,6 +2,7 @@ import { Request, Response } from 'express'; import { z } from 'zod'; import { mfaService } from './mfa.service'; +import { getErrorMessage } from '../../utils/error-utils'; const VerifyTOTPDto = z.object({ token: z.string().length(6), @@ -38,12 +39,12 @@ export class MFAController { message: 'Scan QR code with authenticator app and verify with token', }, }); - } catch (error: any) { + } catch (error: unknown) { res.status(500).json({ success: false, error: { code: 'ENABLE_TOTP_FAILED', - message: error.message || 'Failed to enable TOTP', + message: getErrorMessage(error) || 'Failed to enable TOTP', }, }); } @@ -80,7 +81,7 @@ export class MFAController { error: { code: 'INVALID_TOKEN', message: 'Invalid TOTP token' }, }); } - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -97,7 +98,7 @@ export class MFAController { success: false, error: { code: 'VERIFY_TOTP_FAILED', - message: error.message || 'Failed to verify TOTP', + message: getErrorMessage(error) || 'Failed to verify TOTP', }, }); } @@ -133,7 +134,7 @@ export class MFAController { error: { code: 'INVALID_TOKEN', message: 'Invalid TOTP token' }, }); } - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -150,7 +151,7 @@ export class MFAController { success: false, error: { code: 'VERIFY_TOTP_FAILED', - message: error.message || 'Failed to verify TOTP', + message: getErrorMessage(error) || 'Failed to verify TOTP', }, }); } @@ -178,12 +179,12 @@ export class MFAController { success: true, data: { message: 'MFA disabled successfully' }, }); - } catch (error: any) { + } catch (error: unknown) { res.status(500).json({ success: false, error: { code: 'DISABLE_MFA_FAILED', - message: error.message || 'Failed to disable MFA', + message: getErrorMessage(error) || 'Failed to disable MFA', }, }); } @@ -217,12 +218,12 @@ export class MFAController { createdAt: d.createdAt, })), }); - } catch (error: any) { + } catch (error: unknown) { res.status(500).json({ success: false, error: { code: 'GET_MFA_DEVICES_FAILED', - message: error.message || 'Failed to get MFA devices', + message: getErrorMessage(error) || 'Failed to get MFA devices', }, }); } diff --git a/services/iam-service/src/modules/oidc/oidc.controller.ts b/services/iam-service/src/modules/oidc/oidc.controller.ts index 18f7e71b..372bd678 100644 --- a/services/iam-service/src/modules/oidc/oidc.controller.ts +++ b/services/iam-service/src/modules/oidc/oidc.controller.ts @@ -2,6 +2,7 @@ import { logger } from '@goodgo/logger'; import { Request, Response } from 'express'; import { oidcProviderService } from './oidc-provider.service'; +import { getErrorMessage } from '../../utils/error-utils'; /** * EN: OIDC Controller @@ -16,7 +17,7 @@ export class OIDCController { try { const discovery = oidcProviderService.getDiscoveryDocument(); res.json(discovery); - } catch (error: any) { + } catch (error: unknown) { logger.error('OIDC discovery failed', { error }); res.status(500).json({ success: false, @@ -70,7 +71,7 @@ export class OIDCController { } res.redirect(redirectUrl.toString()); - } catch (error: any) { + } catch (error: unknown) { logger.error('OIDC authorization failed', { error }); res.status(500).json({ success: false, @@ -115,13 +116,13 @@ export class OIDCController { token_type: 'Bearer', expires_in: 900, // 15 minutes }); - } catch (error: any) { + } catch (error: unknown) { logger.error('OIDC token exchange failed', { error }); res.status(400).json({ success: false, error: { code: 'TOKEN_EXCHANGE_FAILED', - message: error.message || 'Token exchange failed', + message: getErrorMessage(error) || 'Token exchange failed', }, }); } @@ -170,7 +171,7 @@ export class OIDCController { name: user.username, updated_at: Math.floor(user.updatedAt.getTime() / 1000), }); - } catch (error: any) { + } catch (error: unknown) { logger.error('OIDC userinfo failed', { error }); res.status(500).json({ success: false, @@ -190,7 +191,7 @@ export class OIDCController { try { const jwks = oidcProviderService.getJWKS(); res.json(jwks); - } catch (error: any) { + } catch (error: unknown) { logger.error('OIDC JWKS failed', { error }); res.status(500).json({ success: false, diff --git a/services/iam-service/src/modules/rbac/rbac.controller.ts b/services/iam-service/src/modules/rbac/rbac.controller.ts index bd2355d8..f3e3d81d 100644 --- a/services/iam-service/src/modules/rbac/rbac.controller.ts +++ b/services/iam-service/src/modules/rbac/rbac.controller.ts @@ -2,6 +2,7 @@ import { Request, Response } from 'express'; import { z } from 'zod'; import { rbacService } from './rbac.service'; +import { getErrorMessage } from '../../utils/error-utils'; const AssignRoleDto = z.object({ userId: z.string(), @@ -46,12 +47,12 @@ export class RBACController { roles, }, }); - } catch (error: any) { + } catch (error: unknown) { res.status(500).json({ success: false, error: { code: 'GET_PERMISSIONS_FAILED', - message: error.message || 'Failed to get permissions', + message: getErrorMessage(error) || 'Failed to get permissions', }, }); } @@ -75,7 +76,7 @@ export class RBACController { success: true, data: { message: 'Role assigned successfully' }, }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -92,7 +93,7 @@ export class RBACController { success: false, error: { code: 'ASSIGN_ROLE_FAILED', - message: error.message || 'Failed to assign role', + message: getErrorMessage(error) || 'Failed to assign role', }, }); } @@ -120,12 +121,12 @@ export class RBACController { success: true, data: { message: 'Role revoked successfully' }, }); - } catch (error: any) { + } catch (error: unknown) { res.status(500).json({ success: false, error: { code: 'REVOKE_ROLE_FAILED', - message: error.message || 'Failed to revoke role', + message: getErrorMessage(error) || 'Failed to revoke role', }, }); } @@ -149,7 +150,7 @@ export class RBACController { success: true, data: { message: 'Permission granted successfully' }, }); - } catch (error: any) { + } catch (error: unknown) { if (error instanceof z.ZodError) { res.status(400).json({ success: false, @@ -166,7 +167,7 @@ export class RBACController { success: false, error: { code: 'GRANT_PERMISSION_FAILED', - message: error.message || 'Failed to grant permission', + message: getErrorMessage(error) || 'Failed to grant permission', }, }); } @@ -203,12 +204,12 @@ export class RBACController { success: true, data: { hasPermission }, }); - } catch (error: any) { + } catch (error: unknown) { res.status(500).json({ success: false, error: { code: 'CHECK_PERMISSION_FAILED', - message: error.message || 'Failed to check permission', + message: getErrorMessage(error) || 'Failed to check permission', }, }); } diff --git a/services/iam-service/src/modules/session/sessions.controller.ts b/services/iam-service/src/modules/session/sessions.controller.ts index a48a693c..1bbc3b63 100644 --- a/services/iam-service/src/modules/session/sessions.controller.ts +++ b/services/iam-service/src/modules/session/sessions.controller.ts @@ -1,6 +1,7 @@ import { Request, Response } from 'express'; import { sessionService } from './session.service'; +import { getErrorMessage } from '../../utils/error-utils'; /** * EN: Sessions Controller @@ -36,12 +37,12 @@ export class SessionsController { expiresAt: s.expiresAt, })), }); - } catch (error: any) { + } catch (error: unknown) { res.status(500).json({ success: false, error: { code: 'GET_SESSIONS_FAILED', - message: error.message || 'Failed to get sessions', + message: getErrorMessage(error) || 'Failed to get sessions', }, }); } @@ -70,12 +71,12 @@ export class SessionsController { success: true, data: { message: 'Session revoked successfully' }, }); - } catch (error: any) { + } catch (error: unknown) { res.status(500).json({ success: false, error: { code: 'REVOKE_SESSION_FAILED', - message: error.message || 'Failed to revoke session', + message: getErrorMessage(error) || 'Failed to revoke session', }, }); } @@ -103,12 +104,12 @@ export class SessionsController { success: true, data: { message: 'All sessions revoked successfully' }, }); - } catch (error: any) { + } catch (error: unknown) { res.status(500).json({ success: false, error: { code: 'REVOKE_ALL_SESSIONS_FAILED', - message: error.message || 'Failed to revoke all sessions', + message: getErrorMessage(error) || 'Failed to revoke all sessions', }, }); } diff --git a/services/iam-service/src/modules/social/social.controller.ts b/services/iam-service/src/modules/social/social.controller.ts index 3960d208..03ee47ac 100644 --- a/services/iam-service/src/modules/social/social.controller.ts +++ b/services/iam-service/src/modules/social/social.controller.ts @@ -8,6 +8,7 @@ import { cookieService } from '../token/cookie.service'; import { jwtService } from '../token/jwt.service'; import { socialAuthService } from './social.service'; +import { getErrorMessage } from '../../utils/error-utils'; /** * EN: Social Auth Controller @@ -24,7 +25,7 @@ export class SocialAuthController { const provider = new GoogleProvider(); const url = provider.getAuthorizationUrl(); res.redirect(url); - } catch (error: any) { + } catch (error: unknown) { logger.error('Google auth initiation failed', { error }); res.status(500).json({ success: false, @@ -84,9 +85,9 @@ export class SocialAuthController { // Redirect to frontend res.redirect(`${process.env.FRONTEND_URL || 'http://localhost:3000'}/auth/callback?token=${tokens.accessToken}`); - } catch (error: any) { + } catch (error: unknown) { logger.error('Google callback failed', { error }); - res.redirect(`${process.env.FRONTEND_URL || 'http://localhost:3000'}/auth/error?message=${encodeURIComponent(error.message)}`); + res.redirect(`${process.env.FRONTEND_URL || 'http://localhost:3000'}/auth/error?message=${encodeURIComponent(getErrorMessage(error))}`); } } @@ -100,7 +101,7 @@ export class SocialAuthController { const provider = new FacebookProvider(); const url = provider.getAuthorizationUrl(); res.redirect(url); - } catch (error: any) { + } catch (error: unknown) { logger.error('Facebook auth initiation failed', { error }); res.status(500).json({ success: false, @@ -154,9 +155,9 @@ export class SocialAuthController { }); res.redirect(`${process.env.FRONTEND_URL || 'http://localhost:3000'}/auth/callback?token=${tokens.accessToken}`); - } catch (error: any) { + } catch (error: unknown) { logger.error('Facebook callback failed', { error }); - res.redirect(`${process.env.FRONTEND_URL || 'http://localhost:3000'}/auth/error?message=${encodeURIComponent(error.message)}`); + res.redirect(`${process.env.FRONTEND_URL || 'http://localhost:3000'}/auth/error?message=${encodeURIComponent(getErrorMessage(error))}`); } } @@ -170,7 +171,7 @@ export class SocialAuthController { const provider = new GitHubProvider(); const url = provider.getAuthorizationUrl(); res.redirect(url); - } catch (error: any) { + } catch (error: unknown) { logger.error('GitHub auth initiation failed', { error }); res.status(500).json({ success: false, @@ -224,9 +225,9 @@ export class SocialAuthController { }); res.redirect(`${process.env.FRONTEND_URL || 'http://localhost:3000'}/auth/callback?token=${tokens.accessToken}`); - } catch (error: any) { + } catch (error: unknown) { logger.error('GitHub callback failed', { error }); - res.redirect(`${process.env.FRONTEND_URL || 'http://localhost:3000'}/auth/error?message=${encodeURIComponent(error.message)}`); + res.redirect(`${process.env.FRONTEND_URL || 'http://localhost:3000'}/auth/error?message=${encodeURIComponent(getErrorMessage(error))}`); } } } diff --git a/services/iam-service/src/modules/token/jwt.service.ts b/services/iam-service/src/modules/token/jwt.service.ts index 1a775622..28873d1f 100644 --- a/services/iam-service/src/modules/token/jwt.service.ts +++ b/services/iam-service/src/modules/token/jwt.service.ts @@ -208,7 +208,7 @@ export class JWTService { * EN: Verify ID token (OIDC) * VI: Xác thực ID token (OIDC) */ - verifyIdToken(token: string, expectedAudience: string): any { + verifyIdToken(token: string, expectedAudience: string): unknown { try { const decoded = verify(token, jwtConfig.idSecret, { issuer: jwtConfig.issuer, @@ -226,7 +226,7 @@ export class JWTService { * EN: Decode token without verification (for debugging) * VI: Giải mã token không xác thực (để debug) */ - decodeToken(token: string): any { + decodeToken(token: string): unknown { return decode(token); } diff --git a/services/iam-service/src/utils/error-utils.ts b/services/iam-service/src/utils/error-utils.ts new file mode 100644 index 00000000..94828e16 --- /dev/null +++ b/services/iam-service/src/utils/error-utils.ts @@ -0,0 +1,107 @@ +/** + * EN: Error handling utilities for type-safe error handling + * VI: Tiện ích xử lý lỗi cho xử lý lỗi type-safe + */ + +/** + * EN: Type guard to check if error is an Error instance + * VI: Type guard để kiểm tra xem error có phải là Error instance không + */ +export function isError(error: unknown): error is Error { + return error instanceof Error; +} + +/** + * EN: Type guard to check if error has a message property + * VI: Type guard để kiểm tra xem error có property message không + */ +export function hasMessage(error: unknown): error is { message: string } { + return ( + typeof error === 'object' && + error !== null && + 'message' in error && + typeof (error as { message: unknown }).message === 'string' + ); +} + +/** + * EN: Type guard to check if error has a code property + * VI: Type guard để kiểm tra xem error có property code không + */ +export function hasCode(error: unknown): error is { code: string } { + return ( + typeof error === 'object' && + error !== null && + 'code' in error && + typeof (error as { code: unknown }).code === 'string' + ); +} + +/** + * EN: Get error message from unknown error + * VI: Lấy error message từ unknown error + */ +export function getErrorMessage(error: unknown): string { + if (isError(error)) { + return error.message; + } + + if (hasMessage(error)) { + return error.message; + } + + if (typeof error === 'string') { + return error; + } + + return 'Unknown error occurred'; +} + +/** + * EN: Get error code from unknown error + * VI: Lấy error code từ unknown error + */ +export function getErrorCode(error: unknown): string | undefined { + if (hasCode(error)) { + return error.code; + } + + return undefined; +} + +/** + * EN: Format error for logging + * VI: Format error để logging + */ +export function formatErrorForLogging(error: unknown): { + message: string; + code?: string; + stack?: string; + details?: unknown; +} { + const message = getErrorMessage(error); + const code = getErrorCode(error); + + const formatted: { + message: string; + code?: string; + stack?: string; + details?: unknown; + } = { message }; + + if (code) { + formatted.code = code; + } + + if (isError(error) && error.stack) { + formatted.stack = error.stack; + } + + // EN: Include original error for debugging + // VI: Bao gồm error gốc để debug + if (typeof error === 'object' && error !== null) { + formatted.details = error; + } + + return formatted; +}