Skip to content

Commit

Permalink
(BE) Add API for Retrieving Workspace Members (#60)
Browse files Browse the repository at this point in the history
* Add base codes for workspace user

* Fix formatting

* Add service for retrieve workspace members

* Add controller for retrieving workspace members
  • Loading branch information
devleejb authored Jan 18, 2024
1 parent 448327b commit 7bbeee8
Show file tree
Hide file tree
Showing 10 changed files with 193 additions and 17 deletions.
18 changes: 9 additions & 9 deletions backend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 7 additions & 7 deletions backend/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ datasource db {
}

model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
socialProvider String @map("social_provider")
socialUid String @unique @map("social_uid")
nickname String
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
UserWorkspace UserWorkspace[]
id String @id @default(auto()) @map("_id") @db.ObjectId
socialProvider String @map("social_provider")
socialUid String @unique @map("social_uid")
nickname String
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
userWorkspaceList UserWorkspace[]
@@map("users")
}
Expand Down
9 changes: 8 additions & 1 deletion backend/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,16 @@ import { ConfigModule } from "@nestjs/config";
import { APP_GUARD } from "@nestjs/core/constants";
import { JwtAuthGuard } from "./auth/jwt.guard";
import { WorkspacesModule } from "./workspaces/workspaces.module";
import { WorkspaceUsersModule } from "./workspace-users/workspace-users.module";

@Module({
imports: [ConfigModule.forRoot({ isGlobal: true }), UsersModule, AuthModule, WorkspacesModule],
imports: [
ConfigModule.forRoot({ isGlobal: true }),
UsersModule,
AuthModule,
WorkspacesModule,
WorkspaceUsersModule,
],
controllers: [],
providers: [
PrismaService,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { ApiProperty } from "@nestjs/swagger";
import { WorkspaceUserDomain } from "./workspace-user.domain";

export class FindWorkspaceUsersResponse {
@ApiProperty({ type: [WorkspaceUserDomain], description: "List of found workspace users" })
workspaceUsers: Array<WorkspaceUserDomain>;

@ApiProperty({ type: String, description: "The ID of last workspace user" })
cursor: string | null;
}
12 changes: 12 additions & 0 deletions backend/src/workspace-users/types/workspace-user.domain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { ApiProperty } from "@nestjs/swagger";

export class WorkspaceUserDomain {
@ApiProperty({ type: String, description: "ID of the user" })
id: string;
@ApiProperty({ type: String, description: "Nickname of the user" })
nickname: string;
@ApiProperty({ type: Date, description: "Created date of the user" })
createdAt: Date;
@ApiProperty({ type: Date, description: "Updated date of the user" })
updatedAt: Date;
}
18 changes: 18 additions & 0 deletions backend/src/workspace-users/workspace-users.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Test, TestingModule } from "@nestjs/testing";
import { WorkspaceUsersController } from "./workspace-users.controller";

describe("WorkspaceUsersController", () => {
let controller: WorkspaceUsersController;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [WorkspaceUsersController],
}).compile();

controller = module.get<WorkspaceUsersController>(WorkspaceUsersController);
});

it("should be defined", () => {
expect(controller).toBeDefined();
});
});
40 changes: 40 additions & 0 deletions backend/src/workspace-users/workspace-users.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Controller, DefaultValuePipe, Get, Param, ParseIntPipe, Query, Req } from "@nestjs/common";
import { ApiBearerAuth, ApiFoundResponse, ApiOperation, ApiQuery, ApiTags } from "@nestjs/swagger";
import { FindWorkspaceUsersResponse } from "./types/find-workspace-users-response.type";
import { AuthroizedRequest } from "src/utils/types/req.type";
import { WorkspaceUsersService } from "./workspace-users.service";

@ApiTags("Workspace.Users")
@ApiBearerAuth()
@Controller("workspaces/:workspace_id/users")
export class WorkspaceUsersController {
constructor(private workspaceUsersService: WorkspaceUsersService) {}

@Get("")
@ApiOperation({
summary: "Retrieve the Users in Workspace",
description: "Return the users in the workspace. This API supports KeySet pagination.",
})
@ApiFoundResponse({ type: FindWorkspaceUsersResponse })
@ApiQuery({
name: "page_size",
type: Number,
description: "Page size to fetch (Default to 10)",
required: false,
})
@ApiQuery({
name: "cursor",
type: String,
description:
"API returns a limited set of results after a given cursor. If no value is provided, it returns the first page.",
required: false,
})
async findMany(
@Req() req: AuthroizedRequest,
@Param("workspace_id") workspaceId: string,
@Query("page_size", new DefaultValuePipe(10), ParseIntPipe) pageSize: number,
@Query("cursor", new DefaultValuePipe(undefined)) cursor?: string
): Promise<FindWorkspaceUsersResponse> {
return this.workspaceUsersService.findMany(req.user.id, workspaceId, pageSize, cursor);
}
}
10 changes: 10 additions & 0 deletions backend/src/workspace-users/workspace-users.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Module } from "@nestjs/common";
import { WorkspaceUsersController } from "./workspace-users.controller";
import { WorkspaceUsersService } from "./workspace-users.service";
import { PrismaService } from "src/db/prisma.service";

@Module({
controllers: [WorkspaceUsersController],
providers: [WorkspaceUsersService, PrismaService],
})
export class WorkspaceUsersModule {}
18 changes: 18 additions & 0 deletions backend/src/workspace-users/workspace-users.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Test, TestingModule } from "@nestjs/testing";
import { WorkspaceUsersService } from "./workspace-users.service";

describe("WorkspaceUsersService", () => {
let service: WorkspaceUsersService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [WorkspaceUsersService],
}).compile();

service = module.get<WorkspaceUsersService>(WorkspaceUsersService);
});

it("should be defined", () => {
expect(service).toBeDefined();
});
});
61 changes: 61 additions & 0 deletions backend/src/workspace-users/workspace-users.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { Injectable, NotFoundException } from "@nestjs/common";
import { Prisma } from "@prisma/client";
import { PrismaService } from "src/db/prisma.service";
import { FindWorkspaceUsersResponse } from "./types/find-workspace-users-response.type";

@Injectable()
export class WorkspaceUsersService {
constructor(private prismaService: PrismaService) {}

async findMany(
userId: string,
workspaceId: string,
pageSize: number,
cursor?: string
): Promise<FindWorkspaceUsersResponse> {
try {
await this.prismaService.userWorkspace.findFirstOrThrow({
where: {
userId,
workspaceId,
},
});
} catch (e) {
throw new NotFoundException();
}

const additionalOptions: Prisma.UserFindManyArgs = {};

if (cursor) {
additionalOptions.cursor = { id: cursor };
}

const workspaceUserList = await this.prismaService.user.findMany({
take: pageSize + 1,
select: {
id: true,
nickname: true,
updatedAt: true,
createdAt: true,
},
where: {
userWorkspaceList: {
some: {
workspaceId: {
equals: workspaceId,
},
},
},
},
orderBy: {
id: "desc",
},
...additionalOptions,
});

return {
workspaceUsers: workspaceUserList.slice(0, pageSize),
cursor: workspaceUserList.length > pageSize ? workspaceUserList[pageSize].id : null,
};
}
}

0 comments on commit 7bbeee8

Please sign in to comment.