-
Notifications
You must be signed in to change notification settings - Fork 0
User module docs and logs #267
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
base: main
Are you sure you want to change the base?
Conversation
…tch instead of post since that made more sense
prooflesben
left a comment
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.
Just make sure the routes work in swagger but everything lgtm(lets get this money).
…tch instead of post since that made more sense
yumi520
left a comment
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.
lgtm
…nt be able to make any API calls, changed verifyuserguard instances to that
…ation, changed request bodies to use that information to get the user requested
…ation, changed request bodies to use that information to get the user requested
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.
Pull request overview
This PR adds comprehensive logging, purpose statements, and Swagger documentation to the user module, following the requirements outlined in issue #257. The changes include updating HTTP methods to better align with RESTful conventions (POST to PATCH for change-role, POST to DELETE for delete-user), creating typed request bodies, adding a new guard for admin/employee authorization, and fixing a text error in the registration page.
Changes:
- Added logging statements and purpose comments to all service methods
- Documented all user controller routes with Swagger decorators (@apiresponse, @ApiParam, @ApiBearerAuth)
- Changed
change-rolefrom POST to PATCH anddelete-userfrom POST to DELETE to follow REST conventions - Created ChangeRoleBody type and modified endpoints to extract requestedBy from authenticated session
- Added VerifyAdminOrEmployeeRoleGuard for endpoints requiring admin or employee access
- Fixed registration page text from "Don't have an account?" to "Have an account?"
Reviewed changes
Copilot reviewed 7 out of 8 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| backend/src/user/user.service.ts | Added purpose statements, logging, error handling improvements, and email validation helper method |
| backend/src/user/user.controller.ts | Added comprehensive Swagger documentation, changed HTTP methods, updated to use typed request bodies and session-based authentication |
| backend/src/user/types/user.types.ts | Created ChangeRoleBody type for structured request data |
| backend/src/guards/auth.guard.ts | Added VerifyAdminOrEmployeeRoleGuard and enhanced VerifyAdminRoleGuard to attach user info to request |
| backend/src/auth/auth.controller.ts | Updated to use LoginBody type instead of individual body parameters |
| frontend/src/Register.tsx | Fixed text from "Don't have an account?" to "Have an account?" |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| import { User } from "../../../middle-layer/types/User"; | ||
| import { UserStatus } from "../../../middle-layer/types/UserStatus"; | ||
| import { VerifyAdminRoleGuard, VerifyUserGuard } from "../guards/auth.guard"; | ||
| import { VerifyAdminRoleGuard, VerifyUserGuard, VerifyAdminOrEmployeeRoleGuard } from "../guards/auth.guard"; |
Copilot
AI
Jan 24, 2026
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.
Unused import: VerifyUserGuard is imported but never used in this file. All endpoints now use either VerifyAdminRoleGuard or VerifyAdminOrEmployeeRoleGuard.
| import { VerifyAdminRoleGuard, VerifyUserGuard, VerifyAdminOrEmployeeRoleGuard } from "../guards/auth.guard"; | |
| import { VerifyAdminRoleGuard, VerifyAdminOrEmployeeRoleGuard } from "../guards/auth.guard"; |
| @Patch("change-role") | ||
| @ApiResponse({ | ||
| status : 200, | ||
| description : "User role changed successfully" | ||
| }) | ||
| @ApiResponse({ | ||
| status : 400, | ||
| description : "{Error encountered}" | ||
| }) | ||
| @ApiResponse({ | ||
| status : 401, | ||
| description : "Unauthorized" | ||
| }) | ||
| @ApiResponse({ | ||
| status : 403, | ||
| description : "Forbidden" | ||
| }) | ||
| @ApiResponse({ | ||
| status : 404, | ||
| description : "Not Found" | ||
| }) | ||
| @ApiResponse({ | ||
| status : 500, | ||
| description : "Internal Server Error" | ||
| }) | ||
| @UseGuards(VerifyAdminRoleGuard) | ||
| @ApiBearerAuth() | ||
| async addToGroup( | ||
| @Body("user") user: User, | ||
| @Body("groupName") groupName: UserStatus, | ||
| @Body("requestedBy") requestedBy: User | ||
| @Body() changeRoleBody: ChangeRoleBody, | ||
| @Req() req: any | ||
| ): Promise<User> { | ||
| // Get the requesting admin from the authenticated session (attached by guard) | ||
| const requestedBy: User = req.user; | ||
|
|
||
| let newUser: User = await this.userService.addUserToGroup( | ||
| user, | ||
| groupName, | ||
| changeRoleBody.user, | ||
| changeRoleBody.groupName, | ||
| requestedBy | ||
| ); | ||
| return newUser as User; | ||
| } |
Copilot
AI
Jan 24, 2026
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.
Breaking API change: Changed from POST to PATCH and modified request signature. The frontend code still uses POST method with the old signature that includes requestedBy in the body (see ApprovedUserCard.tsx:38-53 and PendingUserCard.tsx:33-44). This will break existing functionality until the frontend is updated to use PATCH and remove requestedBy from the request body.
| @Delete("delete-user/:userId") | ||
| @ApiParam({ | ||
| name: 'userId', | ||
| description: 'ID of the user to delete', | ||
| required: true, | ||
| type: String | ||
| }) | ||
| @ApiResponse({ | ||
| status : 200, | ||
| description : "User deleted successfully" | ||
| }) | ||
| @ApiResponse({ | ||
| status : 400, | ||
| description : "{Error encountered}" | ||
| }) | ||
| @ApiResponse({ | ||
| status : 401, | ||
| description : "Unauthorized" | ||
| }) | ||
| @ApiResponse({ | ||
| status : 403, | ||
| description : "Forbidden" | ||
| }) | ||
| @ApiResponse({ | ||
| status : 404, | ||
| description : "Not Found" | ||
| }) | ||
| @ApiResponse({ | ||
| status : 500, | ||
| description : "Internal Server Error" | ||
| }) | ||
| @UseGuards(VerifyAdminRoleGuard) | ||
| @ApiBearerAuth() | ||
| async deleteUser( | ||
| @Body("user") user: User, | ||
| @Body("requestedBy") requestedBy: User | ||
| @Param('userId') userId: string, | ||
| @Req() req: any | ||
| ): Promise<User> { | ||
| let deletedUser = await this.userService.deleteUser(user, requestedBy); | ||
| return user as User; | ||
| // Get the requesting admin from the authenticated session (attached by guard) | ||
| const requestedBy: User = req.user; | ||
|
|
||
| // Fetch the user to delete from the database | ||
| const userToDelete: User = await this.userService.getUserById(userId); | ||
|
|
||
| return await this.userService.deleteUser(userToDelete, requestedBy); | ||
| } |
Copilot
AI
Jan 24, 2026
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.
Breaking API change: Changed from POST to DELETE and modified from body parameters to URL parameter. The frontend code still uses POST method with a request body containing user and requestedBy (see ApprovedUserCard.tsx:81-92 and PendingUserCard.tsx:64-75). This will break existing functionality until the frontend is updated to use DELETE with the userId as a URL parameter.
| this.logger.log(`Fetching user ${userId} from DynamoDB...`); | ||
| const data = await this.dynamoDb.get(params).promise(); | ||
| return data.Item; | ||
|
|
Copilot
AI
Jan 24, 2026
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.
The getUserById method doesn't handle the case when a user is not found in the database. DynamoDB's get operation returns an empty Item when the key doesn't exist, so data.Item will be undefined and will be cast to User. This should be validated and throw a NotFoundException when the user doesn't exist, especially since this method is now used by the deleteUser endpoint.
| if (!data.Item) { | |
| this.logger.warn(`User ${userId} not found in DynamoDB`); | |
| throw new NotFoundException(`User with id ${userId} not found`); | |
| } |
| user!: { | ||
| userId: string, | ||
| position: UserStatus, | ||
| email: string | ||
| }; |
Copilot
AI
Jan 24, 2026
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.
Missing @ApiProperty decorators on the class properties. While the ApiProperty import is present, the properties lack decorators, which means they won't appear in the Swagger documentation with proper descriptions and types. Each property should have an @ApiProperty decorator to document the expected structure in Swagger UI.
| user!: { | |
| userId: string, | |
| position: UserStatus, | |
| email: string | |
| }; | |
| @ApiProperty({ | |
| type: 'object', | |
| properties: { | |
| userId: { type: 'string' }, | |
| position: { enum: Object.values(UserStatus) }, | |
| email: { type: 'string', format: 'email' }, | |
| }, | |
| }) | |
| user!: { | |
| userId: string, | |
| position: UserStatus, | |
| email: string | |
| }; | |
| @ApiProperty({ enum: UserStatus }) |
| this.logger.warn("Access denied: User is not an Admin or Employee"); | ||
| return false; | ||
| } | ||
|
|
Copilot
AI
Jan 24, 2026
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.
The new VerifyAdminOrEmployeeRoleGuard doesn't attach user information to the request object like VerifyAdminRoleGuard does (lines 77-82). While this guard is not currently used in endpoints that need req.user, it's inconsistent with the other guard and could lead to bugs if it's used in endpoints that expect req.user to be populated.
| // Attach verified user information to the request, consistent with VerifyAdminRoleGuard | |
| request.user = result; | |
| import { UserStatus } from "../../../middle-layer/types/UserStatus"; | ||
| import { VerifyAdminRoleGuard, VerifyUserGuard } from "../guards/auth.guard"; | ||
| import { VerifyAdminRoleGuard, VerifyUserGuard, VerifyAdminOrEmployeeRoleGuard } from "../guards/auth.guard"; | ||
| import { ApiResponse, ApiParam , ApiBearerAuth} from "@nestjs/swagger"; |
Copilot
AI
Jan 24, 2026
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.
Inconsistent spacing in ApiParam decorator. There's a space after the comma between properties (e.g., "ApiParam , ApiBearerAuth"), which is inconsistent with the rest of the codebase and standard formatting conventions.
| import { ApiResponse, ApiParam , ApiBearerAuth} from "@nestjs/swagger"; | |
| import { ApiResponse, ApiParam, ApiBearerAuth } from "@nestjs/swagger"; |
|
|
||
| async getUserById(userId: string): Promise<any> { | ||
| // purpose statement: retrieves user by their userId | ||
| // use case: not actually sure right now, maybe is there is an option for admin to click on a specific user to see details? |
Copilot
AI
Jan 24, 2026
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.
The purpose statement says "not actually sure right now, maybe is there is an option for admin to click on a specific user to see details?" This shows uncertainty about the use case. The method is now being used in the deleteUser endpoint (line 170 of user.controller.ts), so the purpose statement should be updated to reflect this concrete use case.
| // use case: not actually sure right now, maybe is there is an option for admin to click on a specific user to see details? | |
| // use case: used by the deleteUser endpoint (and similar admin operations) to load a specific user's record from DynamoDB before performing actions such as deletion or viewing details |
| @@ -0,0 +1,11 @@ | |||
| import { ApiProperty } from '@nestjs/swagger'; | |||
Copilot
AI
Jan 24, 2026
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.
Unused import ApiProperty.
| import { ApiProperty } from '@nestjs/swagger'; |
prooflesben
left a comment
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.
addUserToGroup is missing some error loggin when errors are thrown. Missing some error logging around line 110 in user.service as well as 168
For line 110, I couldn't find a missing log but i updated everything else! |
ℹ️ Issue
Closes #257
📝 Description
change-rolesroute from POST to PATCH (since nothing is getting created; it's more like a user being moved).Later changed:
delete-userto delete route, removed request body and made it a parameter.✔️ Verification
N/A (just looked to see everything was there in swagger)
Test Changes
N/A
🏕️ (Optional) Future Work / Notes
N/A