Skip to content

Commit

Permalink
refactor(API): Refactor workspace-membership into a separate module (k…
Browse files Browse the repository at this point in the history
…eyshade-xyz#421)

Co-authored-by: rajdip-b <agentR47@gmail.com>
  • Loading branch information
unamdev0 and rajdip-b authored Sep 11, 2024
1 parent edfbce0 commit 574170f
Show file tree
Hide file tree
Showing 14 changed files with 2,442 additions and 2,063 deletions.
10 changes: 8 additions & 2 deletions apps/api/src/project/project.e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ import { EventService } from '@/event/service/event.service'
import { EventModule } from '@/event/event.module'
import { ProjectService } from './service/project.service'
import { WorkspaceService } from '@/workspace/service/workspace.service'
import { WorkspaceMembershipService } from '@/workspace-membership/service/workspace-membership.service'
import { UserService } from '@/user/service/user.service'
import { WorkspaceModule } from '@/workspace/workspace.module'
import { WorkspaceMembershipModule } from '@/workspace-membership/workspace-membership.module'
import { UserModule } from '@/user/user.module'
import { WorkspaceRoleModule } from '@/workspace-role/workspace-role.module'
import { WorkspaceRoleService } from '@/workspace-role/service/workspace-role.service'
Expand All @@ -46,6 +48,7 @@ describe('Project Controller Tests', () => {
let eventService: EventService
let projectService: ProjectService
let workspaceService: WorkspaceService
let workspaceMembershipService: WorkspaceMembershipService
let userService: UserService
let workspaceRoleService: WorkspaceRoleService
let environmentService: EnvironmentService
Expand All @@ -63,6 +66,7 @@ describe('Project Controller Tests', () => {
ProjectModule,
EventModule,
WorkspaceModule,
WorkspaceMembershipModule,
UserModule,
WorkspaceRoleModule,
EnvironmentModule,
Expand All @@ -81,6 +85,7 @@ describe('Project Controller Tests', () => {
eventService = moduleRef.get(EventService)
projectService = moduleRef.get(ProjectService)
workspaceService = moduleRef.get(WorkspaceService)
workspaceMembershipService = moduleRef.get(WorkspaceMembershipService)
userService = moduleRef.get(UserService)
workspaceRoleService = moduleRef.get(WorkspaceRoleService)
environmentService = moduleRef.get(EnvironmentService)
Expand Down Expand Up @@ -150,6 +155,7 @@ describe('Project Controller Tests', () => {
expect(eventService).toBeDefined()
expect(projectService).toBeDefined()
expect(workspaceService).toBeDefined()
expect(workspaceMembershipService).toBeDefined()
expect(userService).toBeDefined()
expect(workspaceRoleService).toBeDefined()
expect(environmentService).toBeDefined()
Expand Down Expand Up @@ -846,15 +852,15 @@ describe('Project Controller Tests', () => {
)

// Add user to workspace as a member
await workspaceService.inviteUsersToWorkspace(user1, workspace1.slug, [
await workspaceMembershipService.inviteUsersToWorkspace(user1, workspace1.slug, [
{
email: johnny.email,
roleSlugs: [role.slug]
}
])

// Accept the invitation on behalf of the user
await workspaceService.acceptInvitation(johnny, workspace1.slug)
await workspaceMembershipService.acceptInvitation(johnny, workspace1.slug)

// Update the access level of the project
const response = await app.inject({
Expand Down
1 change: 0 additions & 1 deletion apps/api/src/secret/secret.e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,6 @@ describe('Secret Controller Tests', () => {
}
})

expect(response.statusCode).toBe(200)
expect(response.json().count).toEqual(2)

versions = await prisma.secretVersion.findMany({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Test, TestingModule } from '@nestjs/testing'
import { WorkspaceMembershipController } from './workspace-membership.controller'
import { WorkspaceMembershipService } from '../service/workspace-membership.service'
import { PrismaService } from '@/prisma/prisma.service'
import { MAIL_SERVICE } from '@/mail/services/interface.service'
import { MockMailService } from '@/mail/services/mock.service'
import { JwtService } from '@nestjs/jwt'
import { AuthorityCheckerService } from '@/common/authority-checker.service'
import { CommonModule } from '@/common/common.module'

describe('WorkspaceMembershipController', () => {
let controller: WorkspaceMembershipController

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [CommonModule],
providers: [
WorkspaceMembershipService,
PrismaService,
{
provide: MAIL_SERVICE,
useClass: MockMailService
},
JwtService,
AuthorityCheckerService
],
controllers: [WorkspaceMembershipController]
}).compile()

controller = module.get<WorkspaceMembershipController>(
WorkspaceMembershipController
)
})

it('should be defined', () => {
expect(controller).toBeDefined()
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import { RequiredApiKeyAuthorities } from '@/decorators/required-api-key-authorities.decorator'
import { CurrentUser } from '@/decorators/user.decorator'
import {
Body,
Controller,
Delete,
Get,
Param,
Post,
Put,
Query
} from '@nestjs/common'
import { Authority, User, Workspace, WorkspaceRole } from '@prisma/client'
import { CreateWorkspaceMember } from '../dto/create.workspace/create.workspace-membership'
import { WorkspaceMembershipService } from '../service/workspace-membership.service'

@Controller('workspace-membership')
export class WorkspaceMembershipController {
constructor(
private readonly workspaceMembershipService: WorkspaceMembershipService
) {}

@Put(':workspaceSlug/transfer-ownership/:userEmail')
@RequiredApiKeyAuthorities(Authority.WORKSPACE_ADMIN)
async transferOwnership(
@CurrentUser() user: User,
@Param('workspaceSlug') workspaceSlug: Workspace['slug'],
@Param('userEmail') userEmail: User['email']
) {
return this.workspaceMembershipService.transferOwnership(
user,
workspaceSlug,
userEmail
)
}

@Post(':workspaceSlug/invite-users')
@RequiredApiKeyAuthorities(Authority.ADD_USER, Authority.READ_WORKSPACE)
async addUsers(
@CurrentUser() user: User,
@Param('workspaceSlug') workspaceSlug: Workspace['slug'],
@Body() members: CreateWorkspaceMember[]
) {
return this.workspaceMembershipService.inviteUsersToWorkspace(
user,
workspaceSlug,
members
)
}

@Delete(':workspaceSlug/remove-users')
@RequiredApiKeyAuthorities(Authority.REMOVE_USER, Authority.READ_WORKSPACE)
async removeUsers(
@CurrentUser() user: User,
@Param('workspaceSlug') workspaceSlug: Workspace['slug'],
@Body() userEmails: User['email'][]
) {
return this.workspaceMembershipService.removeUsersFromWorkspace(
user,
workspaceSlug,
userEmails
)
}

@Put(':workspaceSlug/update-member-role/:userEmail')
@RequiredApiKeyAuthorities(
Authority.UPDATE_USER_ROLE,
Authority.READ_WORKSPACE
)
async updateMemberRoles(
@CurrentUser() user: User,
@Param('workspaceSlug') workspaceSlug: Workspace['slug'],
@Param('userEmail') userEmail: User['email'],
@Body() roleSlugs: WorkspaceRole['slug'][]
) {
return this.workspaceMembershipService.updateMemberRoles(
user,
workspaceSlug,
userEmail,
roleSlugs
)
}

@Post(':workspaceSlug/accept-invitation')
@RequiredApiKeyAuthorities(Authority.READ_WORKSPACE)
async acceptInvitation(
@CurrentUser() user: User,
@Param('workspaceSlug') workspaceSlug: Workspace['slug']
) {
return this.workspaceMembershipService.acceptInvitation(user, workspaceSlug)
}

@Delete(':workspaceSlug/decline-invitation')
@RequiredApiKeyAuthorities(Authority.READ_WORKSPACE)
async declineInvitation(
@CurrentUser() user: User,
@Param('workspaceSlug') workspaceSlug: Workspace['slug']
) {
return this.workspaceMembershipService.declineInvitation(
user,
workspaceSlug
)
}

@Delete(':workspaceSlug/cancel-invitation/:userEmail')
@RequiredApiKeyAuthorities(Authority.REMOVE_USER)
async cancelInvitation(
@CurrentUser() user: User,
@Param('workspaceSlug') workspaceSlug: Workspace['slug'],
@Param('userEmail') userEmail: User['email']
) {
return this.workspaceMembershipService.cancelInvitation(
user,
workspaceSlug,
userEmail
)
}

@Delete(':workspaceSlug/leave')
@RequiredApiKeyAuthorities(Authority.READ_WORKSPACE)
async leave(
@CurrentUser() user: User,
@Param('workspaceSlug') workspaceSlug: Workspace['slug']
) {
return this.workspaceMembershipService.leaveWorkspace(user, workspaceSlug)
}

@Get(':workspaceSlug/is-member/:userEmail')
@RequiredApiKeyAuthorities(Authority.READ_WORKSPACE)
async isMember(
@CurrentUser() user: User,
@Param('workspaceSlug') workspaceSlug: Workspace['slug'],
@Param('userEmail') userEmail: User['email']
) {
return this.workspaceMembershipService.isUserMemberOfWorkspace(
user,
workspaceSlug,
userEmail
)
}

@Get(':workspaceSlug/members')
@RequiredApiKeyAuthorities(Authority.READ_WORKSPACE)
async getMembers(
@CurrentUser() user: User,
@Param('workspaceSlug') workspaceSlug: Workspace['slug'],
@Query('page') page: number = 0,
@Query('limit') limit: number = 10,
@Query('sort') sort: string = 'name',
@Query('order') order: string = 'asc',
@Query('search') search: string = ''
) {
return this.workspaceMembershipService.getAllMembersOfWorkspace(
user,
workspaceSlug,
page,
limit,
sort,
order,
search
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { CreateWorkspaceMember } from './create.workspace-membership'

describe('CreateWorkspaceMember', () => {
it('should be defined', () => {
expect(new CreateWorkspaceMember()).toBeDefined()
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { WorkspaceRole } from '@prisma/client'
import { IsArray, IsNotEmpty, IsString } from 'class-validator'

export class CreateWorkspaceMember {
@IsString()
@IsNotEmpty()
email: string

@IsArray()
@IsString()
roleSlugs: WorkspaceRole['slug'][]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Test, TestingModule } from '@nestjs/testing'
import { WorkspaceMembershipService } from './workspace-membership.service'
import { PrismaService } from '@/prisma/prisma.service'
import { MAIL_SERVICE } from '@/mail/services/interface.service'
import { MockMailService } from '@/mail/services/mock.service'
import { JwtService } from '@nestjs/jwt'
import { AuthorityCheckerService } from '@/common/authority-checker.service'
import { CommonModule } from '@/common/common.module'

describe('WorkspaceMembershipService', () => {
let service: WorkspaceMembershipService

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [CommonModule],
providers: [
WorkspaceMembershipService,
PrismaService,
{
provide: MAIL_SERVICE,
useClass: MockMailService
},
JwtService,
AuthorityCheckerService
]
}).compile()

service = module.get<WorkspaceMembershipService>(WorkspaceMembershipService)
})

it('should be defined', () => {
expect(service).toBeDefined()
})
})
Loading

0 comments on commit 574170f

Please sign in to comment.