Closed unamdev0 closed 2 months ago
Do fill up the description about with the pointers whenever you can
โฑ๏ธ Estimated effort to review: 4 ๐ต๐ต๐ต๐ตโช |
๐งช PR contains tests |
๐ No security concerns identified |
โก Key issues to review Code Removal Large portions of code related to workspace membership functionality have been removed from this file. Ensure all removed functionality is properly implemented in the new workspace-membership module. New Service Implementation This new service file contains a lot of complex logic related to workspace membership. Carefully review all methods for correctness, especially around invitation handling, role updates, and ownership transfers. Test Coverage This new end-to-end test file is quite extensive. Ensure it covers all critical paths and edge cases for the new workspace membership functionality. |
Category | Suggestion | Score |
Best practice |
Use a transaction for workspace deletion to ensure atomicity___ **Consider using a transaction for the delete operation to ensure atomicity. This canprevent partial deletions if an error occurs during the process.** [apps/api/src/workspace/service/workspace.service.ts [157-162]](https://github.com/keyshade-xyz/keyshade/pull/421/files#diff-a92613f23cf2834d52eaedb87c4e8c460d48b6fca8df4ccc968b2a8af19a9c3fR157-R162) ```diff // Delete the workspace -await this.prisma.workspace.delete({ - where: { - id: workspace.id - } -}) +await this.prisma.$transaction(async (prisma) => { + // Delete related entities first (if any) + await prisma.workspaceMember.deleteMany({ where: { workspaceId: workspace.id } }); + // Delete the workspace + await prisma.workspace.delete({ + where: { + id: workspace.id + } + }); +}); ``` - [ ] **Apply this suggestion** Suggestion importance[1-10]: 9Why: Using a transaction for deletion ensures atomicity and prevents partial deletions, which is crucial for maintaining data consistency. This is a significant improvement, hence a high score. | 9 |
Use a more descriptive variable name for workspace roles to improve readability___ **In the 'beforeEach' function, consider using a more descriptive variable name forthe workspace roles, such as memberWorkspaceRole instead of memberRole , to improve code readability.** [apps/api/src/workspace-membership/workspace-membership.e2e.spec.ts [150-157]](https://github.com/keyshade-xyz/keyshade/pull/421/files#diff-3d2af810cbc31b6ae710d387ba6e8d72d9aaf5e8021ce6266fe5b438c6115c1aR150-R157) ```diff -memberRole = await prisma.workspaceRole.create({ +memberWorkspaceRole = await prisma.workspaceRole.create({ data: { name: 'Member', slug: 'member', workspaceId: workspace1.id, authorities: [Authority.READ_WORKSPACE] } }) ``` - [ ] **Apply this suggestion** Suggestion importance[1-10]: 5Why: Using a more descriptive variable name can improve code readability, but the current name is already fairly descriptive, so the improvement is minor. | 5 | |
Enhancement |
Add an assertion to verify the removal of the old role after updating a member's role___ **In the 'should be able to update the role of a member' test, consider adding anassertion to check that the old role (adminRole) is no longer associated with the user after the update.** [apps/api/src/workspace-membership/workspace-membership.e2e.spec.ts [595-599]](https://github.com/keyshade-xyz/keyshade/pull/421/files#diff-3d2af810cbc31b6ae710d387ba6e8d72d9aaf5e8021ce6266fe5b438c6115c1aR595-R599) ```diff expect(membership.roles).toEqual([ { roleId: memberRole.id } ]) +expect(membership.roles).not.toContainEqual({ + roleId: adminRole.id +}) ``` - [ ] **Apply this suggestion** Suggestion importance[1-10]: 8Why: Adding an assertion to verify the removal of the old role after updating a member's role is a valuable enhancement, as it ensures that the role update process is functioning correctly and completely. | 8 |
Provide a more informative error message for BadRequestException___ **Consider using a more specific error message in the BadRequestException. Instead ofusing an empty string, provide a clear explanation of why the request is invalid.** [apps/api/src/workspace/service/workspace.service.ts [152-153]](https://github.com/keyshade-xyz/keyshade/pull/421/files#diff-a92613f23cf2834d52eaedb87c4e8c460d48b6fca8df4ccc968b2a8af19a9c3fR152-R153) ```diff throw new BadRequestException( + 'Invalid request: Unable to perform the requested action on the workspace.' ) ``` - [ ] **Apply this suggestion** Suggestion importance[1-10]: 7Why: The suggestion improves the clarity of error messages, which enhances user experience and debugging. However, it does not address a critical issue, so it receives a moderate score. | 7 | |
Add assertions to check the structure of returned member objects in the test___ **In the 'should be able to get all the members of the workspace' test, consideradding an assertion to check the structure of the returned member object, ensuring it contains expected properties like id, email, or name.** [apps/api/src/workspace-membership/workspace-membership.e2e.spec.ts [1014-1016]](https://github.com/keyshade-xyz/keyshade/pull/421/files#diff-3d2af810cbc31b6ae710d387ba6e8d72d9aaf5e8021ce6266fe5b438c6115c1aR1014-R1016) ```diff expect(response.statusCode).toBe(200) expect(response.json().items).toBeInstanceOf(Array) expect(response.json().items).toHaveLength(1) +expect(response.json().items[0]).toHaveProperty('id') +expect(response.json().items[0]).toHaveProperty('email') +expect(response.json().items[0]).toHaveProperty('name') ``` - [ ] **Apply this suggestion** Suggestion importance[1-10]: 7Why: Adding assertions to check the structure of the returned member object enhances the test by ensuring that the response contains the expected properties, improving test robustness and reliability. | 7 | |
Add a method to resend invitation emails for pending invitations___ **Consider adding a method to resend invitation emails for pending invitations, whichcould be useful if the original invitation email was not received or expired.** [apps/api/src/workspace-membership/service/workspace-membership.service.ts [1011]](https://github.com/keyshade-xyz/keyshade/pull/421/files#diff-510c8dfb0963173c1ce7e47b2433e04050f9e999e298ba59d3fd771ceceb7419R1011-R1011) ```diff } +async resendInvitation( + user: User, + workspaceSlug: Workspace['slug'], + inviteeEmail: User['email'] +): Promise Suggestion importance[1-10]: 6Why: Adding a method to resend invitations is a useful enhancement for user experience, but it is not critical to the current functionality and could be implemented later as an additional feature. | 6 | |
Possible issue |
Add a check for workspace existence before updating___ **Consider adding a check for the existence of the workspace before attempting toupdate it. This can prevent potential errors if the workspace doesn't exist.** [apps/api/src/workspace/service/workspace.service.ts [94-110]](https://github.com/keyshade-xyz/keyshade/pull/421/files#diff-a92613f23cf2834d52eaedb87c4e8c460d48b6fca8df4ccc968b2a8af19a9c3fR94-R110) ```diff +const existingWorkspace = await this.prisma.workspace.findUnique({ + where: { id: workspace.id } +}); +if (!existingWorkspace) { + throw new NotFoundException(`Workspace with ID ${workspace.id} not found`); +} const updatedWorkspace = await this.prisma.workspace.update({ where: { id: workspace.id }, data: { name: dto.name, slug: dto.name ? await generateEntitySlug(dto.name, 'WORKSPACE', this.prisma) : undefined, description: dto.description, lastUpdatedBy: { connect: { id: user.id } } } }) ``` - [ ] **Apply this suggestion** Suggestion importance[1-10]: 8Why: Adding a check for workspace existence before updating is a good practice to prevent errors and ensure data integrity. This suggestion addresses a potential issue, making it valuable. | 8 |
Security |
Add input validation for the update workspace method___ **Consider adding input validation for thedto parameter in the updateWorkspace method. This can help prevent potential issues with invalid or unexpected input.** [apps/api/src/workspace/service/workspace.service.ts [71-75]](https://github.com/keyshade-xyz/keyshade/pull/421/files#diff-a92613f23cf2834d52eaedb87c4e8c460d48b6fca8df4ccc968b2a8af19a9c3fR71-R75) ```diff async updateWorkspace( user: User, workspaceSlug: Workspace['slug'], dto: UpdateWorkspace ) { + if (!dto || (typeof dto.name !== 'undefined' && dto.name.trim() === '')) { + throw new BadRequestException('Invalid workspace update data'); + } ``` - [ ] **Apply this suggestion** Suggestion importance[1-10]: 8Why: Input validation is essential for preventing invalid data from causing errors or security issues. This suggestion enhances the robustness of the code, making it an important improvement. | 8 |
Implement rate limiting for the invitation system___ **Consider implementing rate limiting for theinviteUsersToWorkspace method to prevent potential abuse of the invitation system.** [apps/api/src/workspace-membership/service/workspace-membership.service.ts [186-190]](https://github.com/keyshade-xyz/keyshade/pull/421/files#diff-510c8dfb0963173c1ce7e47b2433e04050f9e999e298ba59d3fd771ceceb7419R186-R190) ```diff +@RateLimit({ points: 10, duration: 60 }) // Example rate limit: 10 invitations per minute async inviteUsersToWorkspace( user: User, workspaceSlug: Workspace['slug'], members: CreateWorkspaceMember[] ): Promise Suggestion importance[1-10]: 7Why: Implementing rate limiting can prevent abuse and enhance security, but the suggestion lacks details on how to integrate it with the existing system, which limits its immediate applicability. | 7 | |
Input validation |
Add input validation for pagination and sorting parameters___ **Consider adding input validation for thepage , limit , sort , order , and search parameters in the getAllMembersOfWorkspace method to ensure they are within acceptable ranges or formats.** [apps/api/src/workspace-membership/service/workspace-membership.service.ts [436-444]](https://github.com/keyshade-xyz/keyshade/pull/421/files#diff-510c8dfb0963173c1ce7e47b2433e04050f9e999e298ba59d3fd771ceceb7419R436-R444) ```diff async getAllMembersOfWorkspace( user: User, workspaceSlug: Workspace['slug'], page: number, limit: number, sort: string, order: string, search: string ) { + if (page < 0) throw new BadRequestException('Page must be non-negative') + if (limit < 1 || limit > 100) throw new BadRequestException('Limit must be between 1 and 100') + if (!['asc', 'desc'].includes(order.toLowerCase())) throw new BadRequestException('Order must be "asc" or "desc"') + // Add more validations as needed ``` - [ ] **Apply this suggestion** Suggestion importance[1-10]: 8Why: Adding input validation for pagination and sorting parameters is a good practice to prevent invalid inputs and potential errors, enhancing the robustness of the method. | 8 |
Error handling |
Improve error handling by using a more specific error type___ **Consider using a more specific error type instead ofInternalServerErrorException in the transferOwnership method. This could provide more meaningful error information to the client.** [apps/api/src/workspace-membership/service/workspace-membership.service.ts [149-153]](https://github.com/keyshade-xyz/keyshade/pull/421/files#diff-510c8dfb0963173c1ce7e47b2433e04050f9e999e298ba59d3fd771ceceb7419R149-R153) ```diff } catch (e) { this.log.error('Error in transaction', e) - throw new InternalServerErrorException('Error in transaction') + throw new Error('Failed to transfer ownership: ' + e.message) } ``` - [ ] **Apply this suggestion** Suggestion importance[1-10]: 4Why: The suggestion to use a more specific error type could improve error clarity, but replacing `InternalServerErrorException` with a generic `Error` does not provide a more specific error type. The suggestion does not enhance the specificity of the error handling. | 4 |
:tada: This PR is included in version 2.5.0 :tada:
The release is available on GitHub release
Your semantic-release bot :package::rocket:
User description
Description
Created seperate modulr for workspace membership
Fixes #319
Documentation Update
PR Type
enhancement, tests
Description
workspace-membership
module.WorkspaceMembershipService
for managing workspace memberships, including transferring ownership, inviting users, and updating roles.WorkspaceMembershipController
to handle HTTP requests related to workspace memberships.Changes walkthrough ๐
6 files
workspace.service.ts
Refactor workspace service to separate membership logic
apps/api/src/workspace/service/workspace.service.ts
updates.
workspace-membership.service.ts
Implement workspace membership management service
apps/api/src/workspace-membership/service/workspace-membership.service.ts
workspace-membership.controller.ts
Create controller for workspace membership operations
apps/api/src/workspace-membership/controller/workspace-membership.controller.ts
create.workspace-membership.ts
Define DTO for workspace member creation
apps/api/src/workspace-membership/dto/create.workspace/create.workspace-membership.ts
workspace-membership.module.ts
Create module for workspace membership management
apps/api/src/workspace-membership/workspace-membership.module.ts
create.workspace.ts
Simplify workspace DTO by removing membership details
apps/api/src/workspace/dto/create.workspace/create.workspace.ts
5 files
workspace-membership.e2e.spec.ts
Add end-to-end tests for workspace membership
apps/api/src/workspace-membership/workspace-membership.e2e.spec.ts
project.e2e.spec.ts
Integrate workspace membership service in project tests
apps/api/src/project/project.e2e.spec.ts
workspace-membership.controller.spec.ts
Add unit tests for workspace membership controller
apps/api/src/workspace-membership/controller/workspace-membership.controller.spec.ts
workspace-membership.service.spec.ts
Add unit tests for workspace membership service
apps/api/src/workspace-membership/service/workspace-membership.service.spec.ts
create.workspace-membership.spec.ts
Add test for CreateWorkspaceMember DTO
apps/api/src/workspace-membership/dto/create.workspace/create.workspace-membership.spec.ts