mirror of
https://github.com/docmost/docmost.git
synced 2025-11-12 19:22:39 +10:00
pagination - wip
This commit is contained in:
@ -1,11 +1,14 @@
|
|||||||
import {
|
import {
|
||||||
Body,
|
Body,
|
||||||
Controller,
|
Controller,
|
||||||
|
DefaultValuePipe,
|
||||||
Delete,
|
Delete,
|
||||||
Get,
|
Get,
|
||||||
HttpCode,
|
HttpCode,
|
||||||
HttpStatus,
|
HttpStatus,
|
||||||
|
ParseIntPipe,
|
||||||
Post,
|
Post,
|
||||||
|
Query,
|
||||||
UseGuards,
|
UseGuards,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { WorkspaceService } from '../services/workspace.service';
|
import { WorkspaceService } from '../services/workspace.service';
|
||||||
@ -20,9 +23,10 @@ import { AuthUser } from '../../../decorators/auth-user.decorator';
|
|||||||
import { User } from '../../user/entities/user.entity';
|
import { User } from '../../user/entities/user.entity';
|
||||||
import { CurrentWorkspace } from '../../../decorators/current-workspace.decorator';
|
import { CurrentWorkspace } from '../../../decorators/current-workspace.decorator';
|
||||||
import { Workspace } from '../entities/workspace.entity';
|
import { Workspace } from '../entities/workspace.entity';
|
||||||
|
import { PaginationOptions } from '../../../helpers/pagination/pagination-options';
|
||||||
|
|
||||||
@UseGuards(JwtGuard)
|
@UseGuards(JwtGuard)
|
||||||
@Controller('workspace')
|
@Controller('workspaces')
|
||||||
export class WorkspaceController {
|
export class WorkspaceController {
|
||||||
constructor(private readonly workspaceService: WorkspaceService) {}
|
constructor(private readonly workspaceService: WorkspaceService) {}
|
||||||
|
|
||||||
@ -51,9 +55,13 @@ export class WorkspaceController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
@Get('members')
|
@Post('members')
|
||||||
async getWorkspaceMembers(@CurrentWorkspace() workspace: Workspace) {
|
async getWorkspaceMembers(
|
||||||
return this.workspaceService.getWorkspaceUsers(workspace.id);
|
@Body()
|
||||||
|
pagination: PaginationOptions,
|
||||||
|
@CurrentWorkspace() workspace: Workspace,
|
||||||
|
) {
|
||||||
|
return this.workspaceService.getWorkspaceUsers(workspace.id, pagination);
|
||||||
}
|
}
|
||||||
|
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
|
|||||||
@ -15,6 +15,10 @@ import { UpdateWorkspaceDto } from '../dto/update-workspace.dto';
|
|||||||
import { DeleteWorkspaceDto } from '../dto/delete-workspace.dto';
|
import { DeleteWorkspaceDto } from '../dto/delete-workspace.dto';
|
||||||
import { UpdateWorkspaceUserRoleDto } from '../dto/update-workspace-user-role.dto';
|
import { UpdateWorkspaceUserRoleDto } from '../dto/update-workspace-user-role.dto';
|
||||||
import { SpaceService } from '../../space/space.service';
|
import { SpaceService } from '../../space/space.service';
|
||||||
|
import { UserWithRole } from '../../user/entities/user.entity';
|
||||||
|
import { PaginationOptions } from '../../../helpers/pagination/pagination-options';
|
||||||
|
import { PaginationMetaDto } from '../../../helpers/pagination/pagination-meta-dto';
|
||||||
|
import { PaginatedResult } from '../../../helpers/pagination/paginated-result';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class WorkspaceService {
|
export class WorkspaceService {
|
||||||
@ -209,25 +213,32 @@ export class WorkspaceService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getWorkspaceUsers(workspaceId: string) {
|
async getWorkspaceUsers(
|
||||||
const workspace = await this.workspaceRepository.findOne({
|
workspaceId: string,
|
||||||
where: { id: workspaceId },
|
paginationOptions: PaginationOptions,
|
||||||
relations: ['workspaceUsers', 'workspaceUsers.user'],
|
): Promise<PaginatedResult<any>> {
|
||||||
});
|
const [workspaceUsers, count] =
|
||||||
|
await this.workspaceUserRepository.findAndCount({
|
||||||
|
relations: ['user'],
|
||||||
|
where: {
|
||||||
|
workspace: {
|
||||||
|
id: workspaceId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
take: paginationOptions.limit,
|
||||||
|
skip: paginationOptions.skip,
|
||||||
|
});
|
||||||
|
|
||||||
if (!workspace) {
|
const users = workspaceUsers.map((workspaceUser) => {
|
||||||
throw new BadRequestException('Invalid workspace');
|
|
||||||
}
|
|
||||||
|
|
||||||
const users = workspace.workspaceUsers.map((workspaceUser) => {
|
|
||||||
workspaceUser.user.password = '';
|
workspaceUser.user.password = '';
|
||||||
return {
|
return {
|
||||||
...workspaceUser.user,
|
...workspaceUser.user,
|
||||||
workspaceRole: workspaceUser.role,
|
role: workspaceUser.role,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
return { users };
|
const paginationMeta = new PaginationMetaDto({ count, paginationOptions });
|
||||||
|
return new PaginatedResult(users, paginationMeta);
|
||||||
}
|
}
|
||||||
|
|
||||||
async validateWorkspaceMember(
|
async validateWorkspaceMember(
|
||||||
|
|||||||
14
apps/server/src/helpers/pagination/paginated-result.ts
Normal file
14
apps/server/src/helpers/pagination/paginated-result.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { IsArray } from 'class-validator';
|
||||||
|
import { PaginationMetaDto } from './pagination-meta-dto';
|
||||||
|
|
||||||
|
export class PaginatedResult<T> {
|
||||||
|
@IsArray()
|
||||||
|
readonly items: T[];
|
||||||
|
|
||||||
|
readonly pagination: PaginationMetaDto;
|
||||||
|
|
||||||
|
constructor(items: T[], pagination: PaginationMetaDto) {
|
||||||
|
this.items = items;
|
||||||
|
this.pagination = pagination;
|
||||||
|
}
|
||||||
|
}
|
||||||
29
apps/server/src/helpers/pagination/pagination-meta-dto.ts
Normal file
29
apps/server/src/helpers/pagination/pagination-meta-dto.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { PaginationOptions } from './pagination-options';
|
||||||
|
|
||||||
|
export class PaginationMetaDto {
|
||||||
|
readonly page: number;
|
||||||
|
|
||||||
|
readonly limit: number;
|
||||||
|
|
||||||
|
readonly total: number;
|
||||||
|
|
||||||
|
readonly pageCount: number;
|
||||||
|
|
||||||
|
readonly hasPreviousPage: boolean;
|
||||||
|
|
||||||
|
readonly hasNextPage: boolean;
|
||||||
|
|
||||||
|
constructor({ count, paginationOptions }: PageMetaDtoParameters) {
|
||||||
|
this.page = paginationOptions.page;
|
||||||
|
this.limit = paginationOptions.limit;
|
||||||
|
this.total = count;
|
||||||
|
this.pageCount = Math.ceil(this.total / this.limit);
|
||||||
|
this.hasPreviousPage = this.page > 1;
|
||||||
|
this.hasNextPage = this.page < this.pageCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PageMetaDtoParameters {
|
||||||
|
count: number;
|
||||||
|
paginationOptions: PaginationOptions;
|
||||||
|
}
|
||||||
23
apps/server/src/helpers/pagination/pagination-options.ts
Normal file
23
apps/server/src/helpers/pagination/pagination-options.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { IsNumber, IsOptional, IsPositive, Max, Min } from 'class-validator';
|
||||||
|
|
||||||
|
export class PaginationOptions {
|
||||||
|
@IsOptional()
|
||||||
|
@IsNumber()
|
||||||
|
@Min(1)
|
||||||
|
page = 1;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsNumber()
|
||||||
|
@IsPositive()
|
||||||
|
@Min(1)
|
||||||
|
@Max(100)
|
||||||
|
limit = 25;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsNumber()
|
||||||
|
offset = 0;
|
||||||
|
|
||||||
|
get skip(): number {
|
||||||
|
return (this.page - 1) * this.limit;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -25,6 +25,7 @@ async function bootstrap() {
|
|||||||
new ValidationPipe({
|
new ValidationPipe({
|
||||||
whitelist: true,
|
whitelist: true,
|
||||||
stopAtFirstError: true,
|
stopAtFirstError: true,
|
||||||
|
transform: true,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
app.enableCors();
|
app.enableCors();
|
||||||
|
|||||||
Reference in New Issue
Block a user