Skip to content
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

refactor(API): Refactor workspace-membership into a separate module #421

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading