-
Notifications
You must be signed in to change notification settings - Fork 14
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
021 oct 20 auth pages navigation #132
021 oct 20 auth pages navigation #132
Conversation
WalkthroughThe pull request includes modifications to several files across the client and server components. Key changes involve formatting adjustments to the Changes
Possibly related PRs
Suggested labels
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 11
🧹 Outside diff range and nitpick comments (9)
Clients/src/infrastructure/api/customAxios.ts (4)
28-28
: LGTM! Consider adding a type assertion for better type safety.The change to use
import.meta.env.BASE_URL
is appropriate and aligns with modern build systems like Vite. To improve type safety, consider adding a type assertion:baseURL: (import.meta.env.BASE_URL as string) || BASE_URL,This ensures that
BASE_URL
is always treated as a string, preventing potential type-related issues.
Line range hint
9-9
: Consider environment-specific fallback URLsInstead of hardcoding "http://localhost:3000" as the fallback URL, consider using environment-specific fallbacks. This approach ensures that the appropriate URL is used in different environments (development, staging, production).
You could modify the
BASE_URL
declaration as follows:const BASE_URL = import.meta.env.NODE_ENV === 'production' ? 'https://api.yourproductionurl.com' : 'http://localhost:3000';This ensures that even if
import.meta.env.BASE_URL
is not set, you'll have an appropriate fallback for each environment.
Line range hint
54-67
: Enhance error logging for production environmentsThe current error handling uses
console.error
for all cases, which might not be ideal for production environments. Consider implementing a more robust logging mechanism that can be easily configured for different environments.You could create a separate logging utility that can be configured based on the environment. For example:
import { logger } from '../utils/logger'; // In the error handling section: logger.error('Unauthorized access - possibly invalid token');This approach allows you to easily switch between console logging, file logging, or even sending logs to a monitoring service based on the environment.
Line range hint
17-17
: Consider optimizing Redux store importImporting the entire Redux store to access the auth token might be inefficient. Consider using a more targeted approach to access the auth state.
You could use Redux hooks in a custom hook to access just the auth token:
// In a separate file, e.g., useAuthToken.ts import { useSelector } from 'react-redux'; import { RootState } from '../path/to/rootState'; export const useAuthToken = () => useSelector((state: RootState) => state.auth.token); // In customAxios.ts import { useAuthToken } from '../path/to/useAuthToken'; // In the request interceptor const token = useAuthToken();This approach is more efficient and follows React best practices for accessing Redux state.
Clients/src/infrastructure/api/networkServices.ts (1)
47-47
: Improved logging withconsole.table
, consider handling non-tabular data.The change from
console.log
toconsole.table
is a good improvement for logging API responses, as it provides a more structured and readable output for complex objects. However, consider handling cases where the response might not be suitable for tabular display.Consider adding a check for the response type before using
console.table
. Here's a suggested improvement:const logResponse = (method: string, endpoint: string, response: any) => { if (typeof response === 'object' && response !== null) { console.table(`[API Response] ${method.toUpperCase()} ${endpoint}`, response); } else { console.log(`[API Response] ${method.toUpperCase()} ${endpoint}`, response); } };This modification ensures that
console.table
is used for object responses, while falling back toconsole.log
for other types of data.Clients/src/presentation/pages/Authentication/RegisterAdmin/index.tsx (1)
Line range hint
1-280
: Consider adding loading state and more granular error handling.The changes integrate well with the existing component structure, enhancing its functionality with user creation. However, there are opportunities for further improvements:
- Add a loading state to disable the submit button and show a spinner while the registration is in progress.
- Implement more granular error handling to provide specific error messages based on the API response.
- Consider using a form library like Formik or react-hook-form for more robust form management.
Here's a basic example of how you might implement a loading state:
const [isLoading, setIsLoading] = useState(false); const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => { event.preventDefault(); if (validateForm()) { setIsLoading(true); try { // ... existing code ... } catch (error) { // ... existing code ... } finally { setIsLoading(false); } } }; // In the JSX: <Button type="submit" disableRipple variant="contained" sx={singleTheme.buttons.primary} disabled={isLoading} > {isLoading ? 'Registering...' : 'Get started'} </Button>This change would provide better user feedback during the registration process.
Servers/controllers/user.ctrl.ts (3)
124-132
: Approve changes with a minor suggestion for error handlingThe changes to the
createNewUser
function are well-implemented:
- Proper password hashing is now in place, enhancing security.
- The function correctly uses
createNewUserQuery
for non-mock operations.- Code structure and readability have been improved.
Consider adding specific error handling for the password hashing operation:
+ try { const password_hash = await bcrypt.hash(password, 10); + } catch (hashError) { + return res.status(500).json(STATUS_CODE[500]('Error hashing password')); + }This will provide more precise error feedback if the hashing process fails.
162-163
: Approve changes with a minor consistency suggestionThe changes to the
loginUser
function are good:
- Improved code formatting enhances readability.
- The core logic remains correct and unchanged.
For consistency, consider using
user.id
instead ofuser!.id
in both mock and non-mock sections:- id: user!.id, + id: user.id,This change assumes that the
user
object is guaranteed to exist at this point in the code, which seems to be the case given the surrounding checks.Also applies to: 166-166, 185-186
Line range hint
1-300
: Overall assessment: Positive changes with security improvementsThe modifications to this file, particularly in the
createNewUser
andloginUser
functions, represent a significant improvement:
- Enhanced security through proper password hashing in
createNewUser
.- Improved code structure and readability in both functions.
- Consistent error handling and response structures maintained throughout.
These changes align well with the PR objectives of implementing network requests for Admin Create Account and Login functionalities. The code now provides a more secure and robust foundation for user authentication.
As the application grows, consider implementing a middleware for handling the
MOCK_DATA_ON
logic to reduce repetition across controller functions. This could simplify the code and make it easier to maintain in the future.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (11)
- Clients/.env (1 hunks)
- Clients/src/application/repository/entity.repository.ts (3 hunks)
- Clients/src/infrastructure/api/customAxios.ts (1 hunks)
- Clients/src/infrastructure/api/networkServices.ts (1 hunks)
- Clients/src/presentation/pages/Authentication/Login/index.tsx (2 hunks)
- Clients/src/presentation/pages/Authentication/RegisterAdmin/index.tsx (2 hunks)
- Servers/.example.env (0 hunks)
- Servers/controllers/user.ctrl.ts (3 hunks)
- Servers/index.ts (0 hunks)
- Servers/utils/jwt.util.ts (1 hunks)
- Servers/utils/user.utils.ts (2 hunks)
💤 Files with no reviewable changes (2)
- Servers/.example.env
- Servers/index.ts
✅ Files skipped from review due to trivial changes (1)
- Clients/.env
🧰 Additional context used
🔇 Additional comments (3)
Clients/src/presentation/pages/Authentication/RegisterAdmin/index.tsx (1)
9-9
: LGTM: Import statement forcreateNewUser
added.The new import statement is correctly placed and aligns with the changes in the
handleSubmit
function.Clients/src/presentation/pages/Authentication/Login/index.tsx (2)
8-8
: 🛠️ Refactor suggestionConsider using absolute imports or path aliases for better maintainability.
Using relative paths with multiple directory traversals like
"../../../../application/repository/entity.repository"
can be error-prone and harder to maintain. Consider configuring your project to use absolute imports or path aliases to simplify import statements.⛔ Skipped due to learnings
Learnt from: sankettank66 PR: bluewave-labs/verifywise#94 File: Clients/src/presentation/pages/Authentication/Login/index.tsx:91-108 Timestamp: 2024-10-16T16:18:22.983Z Learning: As per project requirements, client-side validation should not be added to the authentication views, including `Clients/src/presentation/pages/Authentication/Login/index.tsx` and similar components.
49-51
: Verify that the correct HTTP status code is used for a successful login.You're checking if
response.status === 202
to navigate to the home page. Typically, successful login requests return a status code like200 OK
. Please verify that the server returns a202
status code upon successful login, or adjust the condition to match the actual status code received.Run the following script to check the server's login endpoint for the returned status code:
const generateToken = (payload: { id: number; email: string }) => { | ||
try { | ||
return Jwt.sign( | ||
{ | ||
...payload, | ||
expire: Date.now() + 1 * 3600 * 1000, | ||
}, | ||
process.env.JWT_SECRET as string | ||
); | ||
} catch (error) { | ||
return console.error(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.
💡 Codebase verification
Handle potential null return values from generateToken
The verification confirms that there are instances where generateToken
is called without handling the possibility of a null
return value:
Servers/controllers/user.ctrl.ts
- Line 160:
const token = generateToken({ id: user!.id, email: email, });
- Line 183:
const token = generateToken({ id: user!.id, email: email, });
- Line 160:
Recommended Actions:
-
Update these calls to handle
null
returns appropriately. For example:const token = generateToken({ id: user!.id, email: email }); if (!token) { // Handle the error, e.g., return an error response return res.status(500).json({ message: 'Token generation failed.' }); }
-
Ensure consistent error handling across all usages of
generateToken
.
🔗 Analysis chain
Improve error handling and maintain consistent return types
The changes to the generateToken
function have improved error handling, but there are some concerns:
- The function now implicitly returns
undefined
on error, which is inconsistent with the previous behavior and may break existing code. - Logging to the console is insufficient for production environments.
- The error is not propagated to the caller, limiting error handling options.
Consider the following improvements:
const generateToken = (payload: { id: number; email: string }): string | null => {
try {
return Jwt.sign(
{
...payload,
expire: Date.now() + 1 * 3600 * 1000,
},
process.env.JWT_SECRET as string
);
} catch (error) {
console.error('Error generating token:', error);
// Consider using a proper logging mechanism here
return null;
}
}
This implementation:
- Maintains the previous return type (
string | null
). - Improves the error logging message.
- Allows for easy integration with a proper logging mechanism.
To ensure consistent usage across the codebase, run the following script:
Review the results to ensure that all calls to generateToken
properly handle the possibility of a null return value.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify the usage of generateToken function
# Expected: All calls to generateToken should handle potential null returns
rg -p 'generateToken\(' -A 5 -g '!{Servers/utils/jwt.util.ts}'
Length of output: 488
/** | ||
* Logs in a user by sending a POST request to the specified route URL with the provided credentials. | ||
* | ||
* @param {Object} params - The parameters for the login request. | ||
* @param {string} [params.routeUrl] - The route URL to which the POST request will be sent. | ||
* @param {any} params.body - The body of the POST request containing login credentials. | ||
* @returns {Promise<any>} A promise that resolves to the response data of the logged-in user. | ||
* @throws Will throw an error if the login fails. | ||
*/ | ||
export async function loginUser({ | ||
routeUrl, | ||
body, | ||
}: { | ||
routeUrl?: string; | ||
body: any; | ||
}): Promise<any> { | ||
try { | ||
const response = await apiServices.post(routeAddress + routeUrl, body); | ||
console.log(`User logged in with the following details: ${response}`); | ||
return response; | ||
} catch (error) { | ||
console.error("Error logging in user:", error); | ||
throw 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.
Enhance security in loginUser
function
While the new loginUser
function is well-structured and includes error handling, there are a few security considerations to address:
- The function returns the entire response object, which might include sensitive information.
- The console.log statement in the success case could potentially log sensitive user data.
Consider the following improvements:
- Return only necessary data from the response:
- return response;
+ return {
+ success: true,
+ user: response.data.user, // Adjust based on your API response structure
+ };
- Remove or sanitize the console.log statement:
- console.log(`User logged in with the following details: ${response}`);
+ console.log(`User logged in successfully`);
- Implement proper logging that doesn't expose sensitive data:
import { logger } from '../path/to/your/logger';
// In the try block
logger.info('User logged in successfully', { userId: response.data.user.id });
// In the catch block
logger.error('Error logging in user', { error: error.message });
These changes will enhance the security of the login process and prevent potential exposure of sensitive information.
@@ -1,6 +1,6 @@ | |||
import { apiServices } from "../../infrastructure/api/networkServices"; | |||
|
|||
const routeAddress = process.env.BASE_URL || "http://localhost:3000"; | |||
const routeAddress = "http://localhost:3000"; |
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.
Consider using an environment variable for routeAddress
Hardcoding the URL "http://localhost:3000"
reduces flexibility and makes the code less maintainable. It's generally better to use environment variables for such configuration values, especially when dealing with different deployment environments (e.g., development, staging, production).
Consider replacing the hardcoded value with an environment variable:
-const routeAddress = "http://localhost:3000";
+const routeAddress = import.meta.env.VITE_API_BASE_URL || "http://localhost:3000";
This change allows for easy configuration across different environments while still providing a default value for local development.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const routeAddress = "http://localhost:3000"; | |
const routeAddress = import.meta.env.VITE_API_BASE_URL || "http://localhost:3000"; |
@@ -19,6 +19,7 @@ export async function createNewUser({ | |||
body: any; | |||
}): Promise<any> { | |||
try { | |||
console.log("routeAddress => ", routeAddress); |
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.
Remove or replace console.log with proper logging
While console.log statements are useful for debugging, they should not be left in production code. They can potentially expose sensitive information and impact performance.
Consider removing this console.log statement or replacing it with a proper logging mechanism that can be controlled based on the environment:
- console.log("routeAddress => ", routeAddress);
+ if (import.meta.env.DEV) {
+ console.log("routeAddress => ", routeAddress);
+ }
Alternatively, implement a proper logging library that can be configured based on the environment.
Committable suggestion was skipped due to low confidence.
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => { | ||
event.preventDefault(); | ||
if (validateForm()) { | ||
console.log("Form submitted:", values); | ||
// Reset form after successful submission | ||
setValues(initialState); | ||
setErrors({}); | ||
setPasswordChecks({ length: false, specialChar: false }); | ||
navigate("/login"); | ||
try { | ||
const response = await createNewUser({ | ||
routeUrl: "/users/register", | ||
body: values, | ||
}); | ||
console.log("Form submitted:", response); | ||
// Reset form after successful submission | ||
setValues(initialState); | ||
setErrors({}); | ||
setPasswordChecks({ length: false, specialChar: false }); | ||
navigate("/login"); | ||
} 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.
Improve error handling and user feedback in handleSubmit
.
The async function and try-catch block are good additions. However, there are a few areas for improvement:
- The catch block is empty, which silently ignores errors. Consider logging the error and providing user feedback.
- There's no user feedback for successful registration or errors. Add appropriate notifications or alerts.
Here's a suggested improvement:
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
if (validateForm()) {
try {
const response = await createNewUser({
routeUrl: "/users/register",
body: values,
});
console.log("Form submitted:", response);
// Reset form after successful submission
setValues(initialState);
setErrors({});
setPasswordChecks({ length: false, specialChar: false });
// Add user feedback for successful registration
alert("Registration successful!"); // Consider using a more user-friendly notification system
navigate("/login");
} catch (error) {
console.error("Registration error:", error);
// Add user feedback for registration error
alert("Registration failed. Please try again."); // Consider using a more user-friendly notification system
}
}
};
This implementation provides better error handling and user feedback.
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => { | ||
event.preventDefault(); | ||
console.log("Form submitted:", values); | ||
// Reset form after successful submission | ||
setValues(initialState); | ||
navigate("/"); | ||
|
||
await loginUser({ | ||
routeUrl: "/users/login", | ||
body: values, | ||
}) | ||
.then((response) => { | ||
console.log("Login Form submitted:", response); | ||
console.log("response.status:", response.status); | ||
// Reset form after successful submission | ||
setValues(initialState); | ||
if (response.status === 202) { | ||
navigate("/"); | ||
} | ||
}) | ||
.catch((error) => { | ||
console.error("Error submitting form:", 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.
🛠️ Refactor suggestion
Simplify the handleSubmit
function by using async/await
consistently.
Currently, you're mixing async/await
with .then()
and .catch()
. This can be simplified for better readability and error handling by using a try...catch
block.
Apply this diff to refactor the function:
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
- await loginUser({
+ try {
+ const response = await loginUser({
routeUrl: "/users/login",
body: values,
- })
- .then((response) => {
console.log("Login Form submitted:", response);
console.log("response.status:", response.status);
// Reset form after successful submission
setValues(initialState);
if (response.status === 202) {
navigate("/");
}
- })
- .catch((error) => {
- console.error("Error submitting form:", error);
- });
+ } catch (error) {
+ console.error("Error submitting form:", error);
+ }
};
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => { | |
event.preventDefault(); | |
console.log("Form submitted:", values); | |
// Reset form after successful submission | |
setValues(initialState); | |
navigate("/"); | |
await loginUser({ | |
routeUrl: "/users/login", | |
body: values, | |
}) | |
.then((response) => { | |
console.log("Login Form submitted:", response); | |
console.log("response.status:", response.status); | |
// Reset form after successful submission | |
setValues(initialState); | |
if (response.status === 202) { | |
navigate("/"); | |
} | |
}) | |
.catch((error) => { | |
console.error("Error submitting form:", error); | |
}); | |
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => { | |
event.preventDefault(); | |
try { | |
const response = await loginUser({ | |
routeUrl: "/users/login", | |
body: values, | |
}); | |
console.log("Login Form submitted:", response); | |
console.log("response.status:", response.status); | |
// Reset form after successful submission | |
setValues(initialState); | |
if (response.status === 202) { | |
navigate("/"); | |
} | |
} catch (error) { | |
console.error("Error submitting form:", error); | |
} | |
}; |
try { | ||
const user = await pool.query("SELECT * FROM users WHERE email = $1", [ | ||
email, | ||
]); | ||
return user.rows[0]; | ||
} catch (error) { | ||
console.error("Error getting user by email:", error); | ||
throw 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.
🛠️ Refactor suggestion
Use a logging library instead of console.error
for error handling
Logging errors directly to the console is not recommended for production environments. Consider using a logging library like winston
or pino
to handle error logging with appropriate log levels and outputs.
); | ||
return result.rows[0]; | ||
const { name, email, password_hash } = user; | ||
const role = 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Avoid hard-coding role values; use enums or constants for roles
The role
is hard-coded as 1
. Using enums or constants to represent role values improves code readability and maintainability.
try { | ||
const result = await pool.query( | ||
`INSERT INTO users (name, email, password_hash, role, created_at, last_login) | ||
VALUES ($1, $2, $3, $4, $5, $6) RETURNING *`, | ||
[name, email, password_hash, role, created_at, last_login] | ||
); | ||
|
||
return result.rows[0]; | ||
} catch (error) { | ||
console.error("Error creating new user:", error); | ||
throw 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.
🛠️ Refactor suggestion
Implement consistent error handling across utility functions
The try-catch block is a good addition for error handling. However, consider creating a centralized error handling mechanism or middleware to handle errors uniformly across all utility functions.
const created_at = new Date(); | ||
const last_login = new Date(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Set timestamp fields in the database to ensure consistency
Assigning created_at
and last_login
using new Date()
may lead to inconsistencies due to server time variations. It's preferable to use database functions like NOW()
to set these fields.
Apply this diff to modify the SQL query and remove the timestamp fields from the values array:
const result = await pool.query(
`INSERT INTO users (name, email, password_hash, role, created_at, last_login)
- VALUES ($1, $2, $3, $4, $5, $6) RETURNING *`,
- [name, email, password_hash, role, created_at, last_login]
+ VALUES ($1, $2, $3, $4, NOW(), NOW()) RETURNING *`,
+ [name, email, password_hash, role]
);
Committable suggestion was skipped due to low confidence.
Now, the network requests for
Admin Create Account and Login
is working
Summary by CodeRabbit
Release Notes
New Features
Improvements
Bug Fixes
Chores