-
Notifications
You must be signed in to change notification settings - Fork 209
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: i18n support for backend #1647
base: develop
Are you sure you want to change the base?
Changes from 4 commits
54260e2
54e9c95
41a4087
c4de593
e7fb742
559783e
30b7bbd
8501f99
3f7911e
597c5bf
2dbad4f
69c62b1
a4713e0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,11 +16,12 @@ import { handleValidationError, handleError } from "./controllerUtils.js"; | |
const SERVICE_NAME = "authController"; | ||
|
||
class AuthController { | ||
constructor(db, settingsService, emailService, jobQueue) { | ||
constructor(db, settingsService, emailService, jobQueue, stringService) { | ||
this.db = db; | ||
this.settingsService = settingsService; | ||
this.emailService = emailService; | ||
this.jobQueue = jobQueue; | ||
this.stringService = stringService; | ||
} | ||
|
||
/** | ||
|
@@ -76,7 +77,7 @@ class AuthController { | |
// If superAdmin exists, a token should be attached to all further register requests | ||
const superAdminExists = await this.db.checkSuperadmin(req, res); | ||
if (superAdminExists) { | ||
await this.db.getInviteTokenAndDelete(inviteToken); | ||
await this.db.getInviteTokenAndDelete(inviteToken, req.language); | ||
} else { | ||
// This is the first account, create JWT secret to use if one is not supplied by env | ||
const jwtSecret = crypto.randomBytes(64).toString("hex"); | ||
|
@@ -85,7 +86,7 @@ class AuthController { | |
|
||
const newUser = await this.db.insertUser({ ...req.body }, req.file); | ||
logger.info({ | ||
message: successMessages.AUTH_CREATE_USER, | ||
message: successMessages.AUTH_CREATE_USER(req.language), | ||
service: SERVICE_NAME, | ||
details: newUser._id, | ||
}); | ||
|
@@ -116,7 +117,7 @@ class AuthController { | |
}); | ||
|
||
res.success({ | ||
msg: successMessages.AUTH_CREATE_USER, | ||
msg: successMessages.AUTH_CREATE_USER(req.language), | ||
data: { user: newUser, token: token, refreshToken: refreshToken }, | ||
}); | ||
} catch (error) { | ||
|
@@ -148,12 +149,12 @@ class AuthController { | |
const { email, password } = req.body; | ||
|
||
// Check if user exists | ||
const user = await this.db.getUserByEmail(email); | ||
const user = await this.db.getUserByEmail(email, req.language); | ||
|
||
// Compare password | ||
const match = await user.comparePassword(password); | ||
if (match !== true) { | ||
const error = new Error(errorMessages.AUTH_INCORRECT_PASSWORD); | ||
const error = new Error(this.stringService.authIncorrectPassword); | ||
error.status = 401; | ||
next(error); | ||
return; | ||
Comment on lines
+156
to
159
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Standardize error handling patterns across the controller. Error creation is scattered throughout the code with inconsistent patterns. Some errors include service and method information, while others don't. Consider creating a helper method in + /**
+ * Creates a standardized error with i18n support
+ * @param {string} message - The i18n message key
+ * @param {number} status - HTTP status code
+ * @param {string} service - Service name
+ * @param {string} method - Method name
+ * @returns {Error}
+ */
+ export const createError = (message, status, service, method) => {
+ const error = new Error(message);
+ error.status = status;
+ error.service = service;
+ error.method = method;
+ return error;
+ }; Then use it consistently: - const error = new Error(this.stringService.authIncorrectPassword);
- error.status = 401;
- next(error);
+ next(createError(
+ this.stringService.authIncorrectPassword,
+ 401,
+ SERVICE_NAME,
+ 'loginUser'
+ )); Also applies to: 210-215, 225-231, 281-286, 305-309 |
||
|
@@ -176,7 +177,7 @@ class AuthController { | |
userWithoutPassword.avatarImage = user.avatarImage; | ||
|
||
return res.success({ | ||
msg: successMessages.AUTH_LOGIN_USER, | ||
msg: successMessages.AUTH_LOGIN_USER(req.language), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same for these, these strings should now all be provided by the |
||
data: { | ||
user: userWithoutPassword, | ||
token: token, | ||
|
@@ -206,7 +207,7 @@ class AuthController { | |
|
||
if (!refreshToken) { | ||
// No refresh token provided | ||
const error = new Error(errorMessages.NO_REFRESH_TOKEN); | ||
const error = new Error(this.stringService.noRefreshToken); | ||
error.status = 401; | ||
error.service = SERVICE_NAME; | ||
error.method = "refreshAuthToken"; | ||
|
@@ -221,8 +222,8 @@ class AuthController { | |
// Invalid or expired refresh token, trigger logout | ||
const errorMessage = | ||
refreshErr.name === "TokenExpiredError" | ||
? errorMessages.EXPIRED_REFRESH_TOKEN | ||
: errorMessages.INVALID_REFRESH_TOKEN; | ||
? this.stringService.expiredAuthToken | ||
: this.stringService.invalidAuthToken; | ||
const error = new Error(errorMessage); | ||
error.status = 401; | ||
error.service = SERVICE_NAME; | ||
|
@@ -243,7 +244,7 @@ class AuthController { | |
); | ||
|
||
return res.success({ | ||
msg: successMessages.AUTH_TOKEN_REFRESHED, | ||
msg: successMessages.AUTH_TOKEN_REFRESHED(req.language), | ||
data: { user: payloadData, token: newAuthToken, refreshToken: refreshToken }, | ||
}); | ||
} catch (error) { | ||
|
@@ -276,7 +277,7 @@ class AuthController { | |
|
||
// TODO is this neccessary any longer? Verify ownership middleware should handle this | ||
if (req.params.userId !== req.user._id.toString()) { | ||
const error = new Error(errorMessages.AUTH_UNAUTHORIZED); | ||
const error = new Error(this.stringService.unauthorized); | ||
error.status = 401; | ||
error.service = SERVICE_NAME; | ||
next(error); | ||
|
@@ -294,13 +295,13 @@ class AuthController { | |
// Add user email to body for DB operation | ||
req.body.email = email; | ||
// Get user | ||
const user = await this.db.getUserByEmail(email); | ||
const user = await this.db.getUserByEmail(email, req.language); | ||
// Compare passwords | ||
const match = await user.comparePassword(req.body.password); | ||
// If not a match, throw a 403 | ||
// 403 instead of 401 to avoid triggering axios interceptor | ||
if (!match) { | ||
const error = new Error(errorMessages.AUTH_INCORRECT_PASSWORD); | ||
const error = new Error(this.stringService.authIncorrectPassword); | ||
error.status = 403; | ||
next(error); | ||
return; | ||
|
@@ -311,7 +312,7 @@ class AuthController { | |
|
||
const updatedUser = await this.db.updateUser(req, res); | ||
res.success({ | ||
msg: successMessages.AUTH_UPDATE_USER, | ||
msg: successMessages.AUTH_UPDATE_USER(req.language), | ||
data: updatedUser, | ||
}); | ||
} catch (error) { | ||
|
@@ -333,7 +334,7 @@ class AuthController { | |
const superAdminExists = await this.db.checkSuperadmin(req, res); | ||
|
||
return res.success({ | ||
msg: successMessages.AUTH_ADMIN_EXISTS, | ||
msg: successMessages.AUTH_ADMIN_EXISTS(req.language), | ||
data: superAdminExists, | ||
}); | ||
} catch (error) { | ||
|
@@ -362,7 +363,7 @@ class AuthController { | |
|
||
try { | ||
const { email } = req.body; | ||
const user = await this.db.getUserByEmail(email); | ||
const user = await this.db.getUserByEmail(email, req.language); | ||
const recoveryToken = await this.db.requestRecoveryToken(req, res); | ||
const name = user.firstName; | ||
const { clientHost } = this.settingsService.getSettings(); | ||
|
@@ -379,7 +380,7 @@ class AuthController { | |
); | ||
|
||
return res.success({ | ||
msg: successMessages.AUTH_CREATE_RECOVERY_TOKEN, | ||
msg: successMessages.AUTH_CREATE_RECOVERY_TOKEN(req.language), | ||
data: msgId, | ||
}); | ||
} catch (error) { | ||
|
@@ -410,7 +411,7 @@ class AuthController { | |
await this.db.validateRecoveryToken(req, res); | ||
|
||
return res.success({ | ||
msg: successMessages.AUTH_VERIFY_RECOVERY_TOKEN, | ||
msg: successMessages.AUTH_VERIFY_RECOVERY_TOKEN(req.language), | ||
}); | ||
} catch (error) { | ||
next(handleError(error, SERVICE_NAME, "validateRecoveryTokenController")); | ||
|
@@ -443,7 +444,7 @@ class AuthController { | |
const token = this.issueToken(user._doc, tokenType.ACCESS_TOKEN, appSettings); | ||
|
||
return res.success({ | ||
msg: successMessages.AUTH_RESET_PASSWORD, | ||
msg: successMessages.AUTH_RESET_PASSWORD(req.language), | ||
data: { user, token }, | ||
}); | ||
} catch (error) { | ||
|
@@ -467,7 +468,7 @@ class AuthController { | |
const { email } = decodedToken; | ||
|
||
// Check if the user exists | ||
const user = await this.db.getUserByEmail(email); | ||
const user = await this.db.getUserByEmail(email, req.language); | ||
// 1. Find all the monitors associated with the team ID if superadmin | ||
|
||
const result = await this.db.getMonitorsByTeamId({ | ||
|
@@ -494,10 +495,10 @@ class AuthController { | |
await this.db.deleteMonitorsByUserId(user._id); | ||
} | ||
// 6. Delete the user by id | ||
await this.db.deleteUser(user._id); | ||
await this.db.deleteUser(user._id, req.language); | ||
|
||
return res.success({ | ||
msg: successMessages.AUTH_DELETE_USER, | ||
msg: successMessages.AUTH_DELETE_USER(req.language), | ||
}); | ||
} catch (error) { | ||
next(handleError(error, SERVICE_NAME, "deleteUserController")); | ||
|
@@ -509,7 +510,7 @@ class AuthController { | |
const allUsers = await this.db.getAllUsers(req, res); | ||
|
||
return res.success({ | ||
msg: successMessages.AUTH_GET_ALL_USERS, | ||
msg: successMessages.AUTH_GET_ALL_USERS(req.language), | ||
data: allUsers, | ||
}); | ||
} catch (error) { | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -45,7 +45,7 @@ class MaintenanceWindowController { | |||||
await Promise.all(dbTransactions); | ||||||
|
||||||
return res.success({ | ||||||
msg: successMessages.MAINTENANCE_WINDOW_CREATE, | ||||||
msg: successMessages.MAINTENANCE_WINDOW_CREATE(req.language), | ||||||
}); | ||||||
} catch (error) { | ||||||
next(handleError(error, SERVICE_NAME, "createMaintenanceWindow")); | ||||||
|
@@ -63,7 +63,7 @@ class MaintenanceWindowController { | |||||
const maintenanceWindow = await this.db.getMaintenanceWindowById(req.params.id); | ||||||
|
||||||
return res.success({ | ||||||
msg: successMessages.MAINTENANCE_WINDOW_GET_BY_ID, | ||||||
msg: successMessages.MAINTENANCE_WINDOW_GET_BY_ID(req.language), | ||||||
data: maintenanceWindow, | ||||||
}); | ||||||
} catch (error) { | ||||||
|
@@ -89,7 +89,7 @@ class MaintenanceWindowController { | |||||
); | ||||||
|
||||||
return res.success({ | ||||||
msg: successMessages.MAINTENANCE_WINDOW_GET_BY_TEAM, | ||||||
msg: successMessages.MAINTENANCE_WINDOW_GET_BY_TEAM(req.language), | ||||||
data: maintenanceWindows, | ||||||
}); | ||||||
} catch (error) { | ||||||
|
@@ -111,7 +111,7 @@ class MaintenanceWindowController { | |||||
); | ||||||
|
||||||
return res.success({ | ||||||
msg: successMessages.MAINTENANCE_WINDOW_GET_BY_USER, | ||||||
msg: successMessages.MAINTENANCE_WINDOW_GET_BY_USER(req.language), | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Fix inconsistent message key. The message key - msg: successMessages.MAINTENANCE_WINDOW_GET_BY_USER(req.language),
+ msg: successMessages.MAINTENANCE_WINDOW_GET_BY_MONITOR(req.language), 📝 Committable suggestion
Suggested change
|
||||||
data: maintenanceWindows, | ||||||
}); | ||||||
} catch (error) { | ||||||
|
@@ -129,7 +129,7 @@ class MaintenanceWindowController { | |||||
try { | ||||||
await this.db.deleteMaintenanceWindowById(req.params.id); | ||||||
return res.success({ | ||||||
msg: successMessages.MAINTENANCE_WINDOW_DELETE, | ||||||
msg: successMessages.MAINTENANCE_WINDOW_DELETE(req.language), | ||||||
}); | ||||||
} catch (error) { | ||||||
next(handleError(error, SERVICE_NAME, "deleteMaintenanceWindow")); | ||||||
|
@@ -150,7 +150,7 @@ class MaintenanceWindowController { | |||||
req.body | ||||||
); | ||||||
return res.success({ | ||||||
msg: successMessages.MAINTENANCE_WINDOW_EDIT, | ||||||
msg: successMessages.MAINTENANCE_WINDOW_EDIT(req.language), | ||||||
data: editedMaintenanceWindow, | ||||||
}); | ||||||
} catch (error) { | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't need req.language anymore, you can pass a reference to
StringService
toMongoDB
when it is instantiated