Skip to content

Commit

Permalink
feat(api): Add feature to export data of a workspace (#152)
Browse files Browse the repository at this point in the history
  • Loading branch information
rajdip-b authored Feb 22, 2024
1 parent 2e62351 commit 46833aa
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 4 deletions.
4 changes: 2 additions & 2 deletions apps/api/src/secret/dto/create.secret/create.secret.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IsNumber, IsOptional, IsString, Length } from 'class-validator'
import { IsOptional, IsString, Length } from 'class-validator'

export class CreateSecret {
@IsString()
Expand All @@ -12,8 +12,8 @@ export class CreateSecret {
@Length(0, 100)
note: string

@IsNumber()
@IsOptional()
@IsString()
environmentId: string

@IsString()
Expand Down
4 changes: 2 additions & 2 deletions apps/api/src/variable/dto/create.variable/create.variable.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IsNumber, IsOptional, IsString, Length } from 'class-validator'
import { IsOptional, IsString, Length } from 'class-validator'

export class CreateVariable {
@IsString()
Expand All @@ -12,7 +12,7 @@ export class CreateVariable {
@Length(0, 100)
note: string

@IsNumber()
@IsString()
@IsOptional()
environmentId: string
}
9 changes: 9 additions & 0 deletions apps/api/src/workspace/controller/workspace.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,15 @@ export class WorkspaceController {
return this.workspaceService.getWorkspaceById(user, workspaceId)
}

@Get(':workspaceId/export-data')
@RequiredApiKeyAuthorities(Authority.WORKSPACE_ADMIN)
async exportData(
@CurrentUser() user: User,
@Param('workspaceId') workspaceId: Workspace['id']
) {
return this.workspaceService.exportData(user, workspaceId)
}

@Get('/all')
@RequiredApiKeyAuthorities(Authority.READ_WORKSPACE)
async getAllWorkspacesOfUser(
Expand Down
83 changes: 83 additions & 0 deletions apps/api/src/workspace/service/workspace.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,89 @@ export class WorkspaceService {
})
}

async exportData(user: User, workspaceId: Workspace['id']) {
const workspace = await getWorkspaceWithAuthority(
user.id,
workspaceId,
Authority.WORKSPACE_ADMIN,
this.prisma
)

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const data: any = {}

data.name = workspace.name
data.description = workspace.description

// Get all the roles of the workspace
data.workspaceRoles = await this.prisma.workspaceRole.findMany({
where: {
workspaceId
},
select: {
name: true,
description: true,
colorCode: true,
hasAdminAuthority: true,
authorities: true,
projects: {
select: {
id: true
}
}
}
})

// Get all projects, environments, variables and secrets of the workspace
data.projects = await this.prisma.project.findMany({
where: {
workspaceId
},
select: {
name: true,
description: true,
publicKey: true,
privateKey: true,
storePrivateKey: true,
isPublic: true,
environments: {
select: {
name: true,
description: true,
isDefault: true,
secrets: {
select: {
name: true,
rotateAt: true,
note: true,
versions: {
select: {
value: true,
version: true
}
}
}
},
variables: {
select: {
name: true,
note: true,
versions: {
select: {
value: true,
version: true
}
}
}
}
}
}
}
})

return data
}

private async existsByName(
name: string,
userId: User['id']
Expand Down
53 changes: 53 additions & 0 deletions apps/api/src/workspace/workspace.e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1131,6 +1131,59 @@ describe('Workspace Controller Tests', () => {
expect(response.json()).toEqual(expect.arrayContaining([event]))
})

it('should not be able to export data of a non-existing workspace', async () => {
const response = await app.inject({
method: 'GET',
headers: {
'x-e2e-user-email': user1.email
},
url: `/workspace/abc/export-data`
})

expect(response.statusCode).toBe(404)
expect(response.json()).toEqual({
statusCode: 404,
error: 'Not Found',
message: `Workspace with id abc not found`
})
})

it('should not be able to export data of a workspace it is not a member of', async () => {
const response = await app.inject({
method: 'GET',
headers: {
'x-e2e-user-email': user1.email
},
url: `/workspace/${workspace1.id}/export-data`
})

expect(response.statusCode).toBe(401)
expect(response.json()).toEqual({
statusCode: 401,
error: 'Unauthorized',
message: `User ${user1.id} does not have the required authorities to perform the action`
})
})

it('should be able to export data of the workspace', async () => {
const response = await app.inject({
method: 'GET',
headers: {
'x-e2e-user-email': user2.email
},
url: `/workspace/${workspace1.id}/export-data`
})

expect(response.statusCode).toBe(200)

const body = response.json()

expect(body.name).toEqual(workspace1.name)
expect(body.description).toEqual(workspace1.description)
expect(body.workspaceRoles).toBeInstanceOf(Array)
expect(body.projects).toBeInstanceOf(Array)
})

it('should be able to delete the workspace', async () => {
const response = await app.inject({
method: 'DELETE',
Expand Down

0 comments on commit 46833aa

Please sign in to comment.