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

feat: add getGroupsByGroupIds and addMemberToGroups #643

Open
wants to merge 6 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 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
9 changes: 9 additions & 0 deletions apps/api/src/app/groups/dto/add-member-to-groups.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { ApiProperty } from "@nestjs/swagger"
import { ArrayNotEmpty, IsArray } from "class-validator"

export class AddMemberToGroupsDto {
@IsArray()
@ArrayNotEmpty()
@ApiProperty()
readonly groupIds: string[]
}
66 changes: 62 additions & 4 deletions apps/api/src/app/groups/groups.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { UpdateGroupsDto } from "./dto/update-groups.dto"
import { GroupsService } from "./groups.service"
import { mapGroupToResponseDTO } from "./groups.utils"
import { RemoveGroupsDto } from "./dto/remove-groups.dto"
import { AddMemberToGroupsDto } from "./dto/add-member-to-groups.dto"

@ApiTags("groups")
@Controller("groups")
Expand All @@ -40,15 +41,26 @@ export class GroupsController {
@Get()
@ApiQuery({ name: "adminId", required: false, type: String })
@ApiQuery({ name: "memberId", required: false, type: String })
@ApiQuery({
name: "groupIds",
required: false,
type: String,
isArray: true
})
@ApiOperation({ description: "Returns the list of groups." })
@ApiCreatedResponse({ type: Group, isArray: true })
async getGroups(
@Query("adminId") adminId: string,
@Query("memberId") memberId: string
@Query("memberId") memberId: string,
@Query("groupIds") groupIds: string[]
) {
const groups = await this.groupsService.getGroups({ adminId, memberId })
const groupIds = groups.map((group) => group.id)
const fingerprints = await this.groupsService.getFingerprints(groupIds)
const groups = await this.groupsService.getGroups({
adminId,
memberId,
groupIds
})
const groupsIds = groups.map((group) => group.id)
const fingerprints = await this.groupsService.getFingerprints(groupsIds)

return groups.map((group, index) =>
mapGroupToResponseDTO(group, fingerprints[index])
Expand Down Expand Up @@ -365,6 +377,52 @@ export class GroupsController {
throw new NotImplementedException()
}

@Post("/member/:member")
waddaboo marked this conversation as resolved.
Show resolved Hide resolved
@ApiBody({ type: AddMemberToGroupsDto })
@ApiHeader({ name: "x-api-key", required: true })
@ApiCreatedResponse({ isArray: true, type: Group })
@ApiOperation({
description:
"Adds a member to multiple groups. Requires an API Key in the headers or a valid session."
})
async addMemberToGroups(
@Param("member") memberId: string,
@Body() dto: AddMemberToGroupsDto,
@Headers() headers: Headers,
@Req() req: Request
) {
waddaboo marked this conversation as resolved.
Show resolved Hide resolved
let groups = []
const groupsToResponseDTO = []

const apiKey = headers["x-api-key"] as string

if (apiKey) {
groups = await this.groupsService.addMemberToGroupsWithAPIKey(
dto.groupIds,
memberId,
apiKey
)
} else if (req.session.adminId) {
groups = await this.groupsService.addMemberToGroupsManually(
dto.groupIds,
memberId,
req.session.adminId
)
} else {
throw new NotImplementedException()
}

for await (const group of groups) {
const fingerprint = await this.groupsService.getFingerprint(
group.id
)

groupsToResponseDTO.push(mapGroupToResponseDTO(group, fingerprint))
}

return groupsToResponseDTO
}

@Delete(":group/members/:member")
@ApiHeader({ name: "x-api-key", required: true })
@ApiOperation({
Expand Down
234 changes: 234 additions & 0 deletions apps/api/src/app/groups/groups.service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,34 @@ describe("GroupsService", () => {

expect(result).toHaveLength(1)
})

it("Should return a list of groups by group ids", async () => {
const group1 = await groupsService.createGroup(
{
name: "Group Id 1",
description: "This is a description",
treeDepth: 16,
fingerprintDuration: 3600
},
"admin"
)

const group2 = await groupsService.createGroup(
{
name: "Group Id 2",
description: "This is a description",
treeDepth: 16,
fingerprintDuration: 3600
},
"admin"
)

const result = await groupsService.getGroups({
groupIds: [group1.id, group2.id]
})

expect(result).toHaveLength(2)
})
})

describe("# getGroup", () => {
Expand Down Expand Up @@ -1487,6 +1515,212 @@ describe("GroupsService", () => {
})
})

describe("# addMemberToGroupsManually", () => {
let groups: Array<Group>
let admin: Admin

beforeAll(async () => {
admin = await adminsService.create({
id: "admin",
address: "0x"
})

groups = await groupsService.createGroupsManually(
[
{
name: "Multiple Group 1",
description: "This is a new group",
treeDepth: 16,
fingerprintDuration: 3600
},
{
name: "Multiple Group 2",
description: "This is a new group",
treeDepth: 16,
fingerprintDuration: 3600
}
],
admin.id
)
})

it("Should add a member to multiple groups manually", async () => {
const multipleGroups =
await groupsService.addMemberToGroupsManually(
groups.map((g) => g.id),
"123123",
admin.id
)

expect(multipleGroups).toHaveLength(2)
})

it("Should not add a member to the groups if the group is a credential group", async () => {
const _group = await groupsService.createGroup(
{
name: "Multiple Group Credential Group",
description: "This is a new group",
treeDepth: 16,
fingerprintDuration: 3600,
credentials: {
id: "GITHUB_FOLLOWERS",
criteria: {
minFollowers: 5
}
}
},
admin.id
)

const fun = groupsService.addMemberToGroupsManually(
[groups[0].id, _group.id],
"456456",
admin.id
)

await expect(fun).rejects.toThrow(
`The group '${_group.name}' is a credential group. You cannot manually add members to a credential group.`
)
})

it("Should not add a member to multiple groups if the member already exists", async () => {
const fun = groupsService.addMemberToGroupsManually(
groups.map((g) => g.id),
"123123",
admin.id
)

await expect(fun).rejects.toThrow(
`Member '123123' already exists in the group '${groups[0].id}'`
)
})

it("Should not add a member to multiple groups if the admin is the wrong admin", async () => {
const fun = groupsService.addMemberToGroupsManually(
groups.map((g) => g.id),
"123123",
"wrong-admin"
)

await expect(fun).rejects.toThrow(
`You are not the admin of the group '${groups[0].id}'`
)
})
})

describe("# addMembersToGroupsWithAPIKey", () => {
let groups: Array<Group>
let admin: Admin
let apiKey: string

beforeAll(async () => {
admin = await adminsService.create({
id: "admin",
address: "0x"
})

apiKey = await adminsService.updateApiKey(
admin.id,
ApiKeyActions.Generate
)

groups = await groupsService.createGroupsManually(
[
{
name: "Multiple Group API 1",
description: "This is a new group",
treeDepth: 16,
fingerprintDuration: 3600
},
{
name: "Multiple Group API 2",
description: "This is a new group",
treeDepth: 16,
fingerprintDuration: 3600
}
],
admin.id
)
})

it("Should add a member to multiple groups via API", async () => {
const multipleGroups =
await groupsService.addMemberToGroupsWithAPIKey(
groups.map((g) => g.id),
"123123",
apiKey
)

expect(multipleGroups).toHaveLength(2)
})

it("Should not add a member to the groups if the group is a credential group", async () => {
const _group = await groupsService.createGroup(
{
name: "Multiple Group Credential Group API",
description: "This is a new group",
treeDepth: 16,
fingerprintDuration: 3600,
credentials: {
id: "GITHUB_FOLLOWERS",
criteria: {
minFollowers: 5
}
}
},
admin.id
)

const fun = groupsService.addMemberToGroupsWithAPIKey(
[groups[0].id, _group.id],
"456456",
apiKey
)

await expect(fun).rejects.toThrow(
`The group '${_group.name}' is a credential group. You cannot add members to a credential group using an API Key.`
)
})

it("Should not add a member to multiple groups if the member already exists", async () => {
const fun = groupsService.addMemberToGroupsWithAPIKey(
groups.map((g) => g.id),
"123123",
apiKey
)

await expect(fun).rejects.toThrow(
`Member '123123' already exists in the group '${groups[0].id}'`
)
})

it("Should not add a member to multiple groups if the API key is invalid", async () => {
const fun = groupsService.addMemberToGroupsWithAPIKey(
groups.map((g) => g.id),
"123123",
"invalid-apikey"
)

await expect(fun).rejects.toThrow(
`Invalid API key or API access not enabled for admin '${admin.id}'`
)
})

it("Should not add a member to multiple groups if the API key is disabled", async () => {
await adminsService.updateApiKey(admin.id, ApiKeyActions.Disable)

const fun = groupsService.addMemberToGroupsWithAPIKey(
groups.map((g) => g.id),
"123123",
apiKey
)

await expect(fun).rejects.toThrow(
`Invalid API key or API access not enabled for admin '${admin.id}'`
)
})
})

describe("# createGroupManually", () => {
const groupDto: CreateGroupDto = {
id: "1",
Expand Down
Loading
Loading