diff --git a/firebase.firestore.indexes.json b/firebase.firestore.indexes.json index bad9250..56c142b 100644 --- a/firebase.firestore.indexes.json +++ b/firebase.firestore.indexes.json @@ -1,5 +1,19 @@ { "indexes": [ + { + "collectionGroup": "admins", + "queryScope": "COLLECTION", + "fields": [ + { + "fieldPath": "accessControlList", + "arrayConfig": "CONTAINS" + }, + { + "fieldPath": "email", + "order": "ASCENDING" + } + ] + }, { "collectionGroup": "prefectures", "queryScope": "COLLECTION", diff --git a/src/admins/admins.controller.ts b/src/admins/admins.controller.ts index e88dd80..7e7b321 100644 --- a/src/admins/admins.controller.ts +++ b/src/admins/admins.controller.ts @@ -11,6 +11,7 @@ import { HttpCode, Param, Delete, + Query, } from '@nestjs/common' import { ApiOperation, @@ -29,6 +30,7 @@ import { Admin } from './classes/admin.class' import { NoResponseBodyInterceptor } from '../shared/interceptors/no-response-body.interceptor' import { NoResponseBody } from '../shared/classes/no-response-body.class' import { RequestAdminUser } from '../shared/interfaces' +import { PaginationParamsDto } from '../shared/classes/pagination-params.class' @ApiTags('admin') @ApiBearerAuth() @@ -40,11 +42,13 @@ export class AdminsController { constructor(private adminsService: AdminsService) {} // TODO @yashmurty : Investigate pagination for this later. + @UsePipes(new ValidationPipe(VALIDATION_PIPE_OPTIONS)) @ApiOperation({ summary: 'Get all admin users' }) @ApiOkResponse({ type: [Admin] }) @Get('/users') - async getAdminUsers(): Promise { - return this.adminsService.findAllAdminUsers() + async getAdminUsers(@Request() req, @Query() query: PaginationParamsDto): Promise { + const requestAdminUser: RequestAdminUser = req.user + return this.adminsService.findAllAdminUsers(requestAdminUser, query.limit, query.offset) } @UsePipes(new ValidationPipe(VALIDATION_PIPE_OPTIONS)) diff --git a/src/admins/admins.repository.ts b/src/admins/admins.repository.ts index a85f5e6..f46f4b5 100644 --- a/src/admins/admins.repository.ts +++ b/src/admins/admins.repository.ts @@ -63,12 +63,19 @@ export class AdminsRepository { return admin } - async findAll(): Promise { + async findAll( + userAccessKey: string, + limit: number, + offset: number + ): Promise { const adminsArray: Admin[] = [] const adminsRef = (await this.firestoreDB).collection('admins') await adminsRef - .limit(100) + .orderBy('email') + .where('accessControlList', 'array-contains', userAccessKey) + .limit(limit) + .offset(offset) .get() .then((snapshot) => { if (snapshot.empty) { diff --git a/src/admins/admins.service.ts b/src/admins/admins.service.ts index 62448aa..e0a3866 100644 --- a/src/admins/admins.service.ts +++ b/src/admins/admins.service.ts @@ -134,15 +134,16 @@ export class AdminsService { return this.adminsRepository.findOneById(adminId) } - async findAllAdminUsers(): Promise { - // TODO @yashmurty : - // Fetch resource and perform ACL check. - - return this.adminsRepository.findAll() + async findAllAdminUsers( + requestAdminUser: RequestAdminUser, + limit: number, + offset: number + ): Promise { + // ACL check is automatically performed in the repository function. + return this.adminsRepository.findAll(requestAdminUser.userAccessKey, limit, offset) } async deleteOneAdminById(requestAdminUser: RequestAdminUser, adminId: string): Promise { - // TODO @yashmurty : // Fetch resource and perform ACL check. Check performed within the called function. await this.getOneAdminById(requestAdminUser, adminId) diff --git a/src/shared/classes/pagination-params.class.ts b/src/shared/classes/pagination-params.class.ts new file mode 100644 index 0000000..5251dc6 --- /dev/null +++ b/src/shared/classes/pagination-params.class.ts @@ -0,0 +1,23 @@ +import { IsNumber, IsOptional } from 'class-validator' +import { Transform } from 'class-transformer' +import { ApiPropertyOptional } from '@nestjs/swagger' + +export class PaginationParamsDto { + @ApiPropertyOptional({ + description: 'Optional, defaults to 100', + type: Number, + }) + @IsNumber() + @IsOptional() + @Transform((value) => parseInt(value, 10), { toClassOnly: true }) + limit = 100 + + @ApiPropertyOptional({ + description: 'Optional, defaults to 0', + type: Number, + }) + @IsNumber() + @IsOptional() + @Transform((value) => parseInt(value, 10), { toClassOnly: true }) + offset = 0 +}