diff --git a/backend/src/infrastructure/config/jwt.register.ts b/backend/src/infrastructure/config/jwt.register.ts new file mode 100644 index 000000000..b4e5f8393 --- /dev/null +++ b/backend/src/infrastructure/config/jwt.register.ts @@ -0,0 +1,17 @@ +import { ConfigModule, ConfigService } from '@nestjs/config'; +import { JwtModule } from '@nestjs/jwt'; +import { + JWT_ACCESS_TOKEN_SECRET, + JWT_ACCESS_TOKEN_EXPIRATION_TIME, +} from '../../libs/constants/jwt'; + +export const JwtRegister = JwtModule.registerAsync({ + imports: [ConfigModule], + inject: [ConfigService], + useFactory: (configService: ConfigService) => ({ + secret: configService.get(JWT_ACCESS_TOKEN_SECRET), + signOptions: { + expiresIn: `${configService.get(JWT_ACCESS_TOKEN_EXPIRATION_TIME)}s`, + }, + }), +}); diff --git a/backend/src/libs/dto/param/pagination.params.ts b/backend/src/libs/dto/param/pagination.params.ts new file mode 100644 index 000000000..0782bbe78 --- /dev/null +++ b/backend/src/libs/dto/param/pagination.params.ts @@ -0,0 +1,16 @@ +import { IsNumber, Min, IsOptional } from 'class-validator'; +import { Type } from 'class-transformer'; + +export class PaginationParams { + @IsOptional() + @Type(() => Number) + @IsNumber() + @Min(0) + page?: number; + + @IsOptional() + @Type(() => Number) + @IsNumber() + @Min(1) + size?: number; +} diff --git a/backend/src/modules/auth/auth.module.ts b/backend/src/modules/auth/auth.module.ts index 51ac6326e..a65d9bbdf 100644 --- a/backend/src/modules/auth/auth.module.ts +++ b/backend/src/modules/auth/auth.module.ts @@ -1,8 +1,6 @@ import { Module } from '@nestjs/common'; -import { ConfigModule, ConfigService } from '@nestjs/config'; +import { ConfigModule } from '@nestjs/config'; import { PassportModule } from '@nestjs/passport'; -import { JwtModule } from '@nestjs/jwt'; - import AuthController from './controller/auth.controller'; import UsersModule from '../users/users.module'; import LocalStrategy from './strategy/local.strategy'; @@ -15,22 +13,18 @@ import { getTokenAuthApplication, registerAuthApplication, } from './auth.providers'; +import TeamsModule from '../teams/teams.module'; +import BoardsModule from '../boards/boards.module'; +import { JwtRegister } from '../../infrastructure/config/jwt.register'; @Module({ imports: [ UsersModule, + TeamsModule, + JwtRegister, + BoardsModule, PassportModule, ConfigModule, - JwtModule.registerAsync({ - imports: [ConfigModule], - inject: [ConfigService], - useFactory: async (configService: ConfigService) => ({ - secret: configService.get('jwt.accessToken.secret'), - signOptions: { - expiresIn: `${configService.get('jwt.accessToken.expirationTime')}s`, - }, - }), - }), ], providers: [ getTokenAuthService, diff --git a/backend/src/modules/auth/controller/auth.controller.ts b/backend/src/modules/auth/controller/auth.controller.ts index 77a504063..24bc00643 100644 --- a/backend/src/modules/auth/controller/auth.controller.ts +++ b/backend/src/modules/auth/controller/auth.controller.ts @@ -11,7 +11,6 @@ import { BadRequestException, Param, } from '@nestjs/common'; -import { EmailParam } from '../../../libs/dto/param/email.param'; import LocalAuthGuard from '../../../libs/guards/localAuth.guard'; import RequestWithUser from '../../../libs/interfaces/requestWithUser.interface'; import JwtRefreshGuard from '../../../libs/guards/jwtRefreshAuth.guard'; @@ -26,7 +25,13 @@ import CreateUserDto from '../../users/dto/create.user.dto'; import { uniqueViolation } from '../../../infrastructure/database/errors/unique.user'; import { signIn } from '../shared/login.auth'; import * as User from '../../users/interfaces/types'; +import * as Teams from '../../teams/interfaces/types'; +import * as Boards from '../../boards/interfaces/types'; +import { EmailParam } from '../../../libs/dto/param/email.param'; import { GetUserApplication } from '../../users/interfaces/applications/get.user.application.interface'; +import JwtAuthenticationGuard from '../../../libs/guards/jwtAuth.guard'; +import { GetBoardApplicationInterface } from '../../boards/interfaces/applications/get.board.application.interface'; +import { GetTeamApplicationInterface } from '../../teams/interfaces/applications/get.team.application.interface'; @Controller('auth') export default class AuthController { @@ -37,6 +42,10 @@ export default class AuthController { private getTokenAuthApp: GetTokenAuthApplication, @Inject(User.TYPES.applications.GetUserApplication) private getUserApp: GetUserApplication, + @Inject(Teams.TYPES.applications.GetTeamApplication) + private getTeamsApp: GetTeamApplicationInterface, + @Inject(Boards.TYPES.applications.GetBoardApplication) + private getBoardApp: GetBoardApplicationInterface, ) {} @Post('register') @@ -78,4 +87,16 @@ export default class AuthController { checkEmail(@Param() { email }: EmailParam): Promise { return this.getUserApp.getByEmail(email).then((user) => !!user); } + + @UseGuards(JwtAuthenticationGuard) + @Get('/dashboardStatistics') + async getDashboardHeaderInfo(@Req() request: RequestWithUser) { + const { _id: userId } = request.user; + const [usersCount, teamsCount, boardsCount] = await Promise.all([ + this.getUserApp.countUsers(), + this.getTeamsApp.countTeams(userId), + this.getBoardApp.countBoards(userId), + ]); + return { usersCount, teamsCount, boardsCount }; + } } diff --git a/backend/src/modules/azure/services/auth.azure.service.ts b/backend/src/modules/azure/services/auth.azure.service.ts index aa3d76d58..b728d3f9f 100644 --- a/backend/src/modules/azure/services/auth.azure.service.ts +++ b/backend/src/modules/azure/services/auth.azure.service.ts @@ -42,6 +42,8 @@ export default class AuthAzureServiceImpl implements AuthAzureService { const { unique_name, email, given_name, family_name } = ( jwt_decode(azureToken) ); + const userExists = await this.checkUserExistsInActiveDirectory(email); + if (!userExists) return null; const emailOrUniqueName = email ?? unique_name; const user = await this.getUserService.getByEmail(emailOrUniqueName); diff --git a/backend/src/modules/boards/applications/get.board.application.ts b/backend/src/modules/boards/applications/get.board.application.ts index fa7843d53..ac49d13ac 100644 --- a/backend/src/modules/boards/applications/get.board.application.ts +++ b/backend/src/modules/boards/applications/get.board.application.ts @@ -1,20 +1,45 @@ import { Inject, Injectable } from '@nestjs/common'; import { GetBoardApplicationInterface } from '../interfaces/applications/get.board.application.interface'; -import { GetBoardService } from '../interfaces/services/get.board.service.interface'; +import { BoardsAndPage } from '../interfaces/boards-page.interface'; +import { GetBoardServiceInterface } from '../interfaces/services/get.board.service.interface'; import { TYPES } from '../interfaces/types'; @Injectable() export class GetBoardApplication implements GetBoardApplicationInterface { constructor( @Inject(TYPES.services.GetBoardService) - private getBoardService: GetBoardService, + private getBoardService: GetBoardServiceInterface, ) {} - getAllBoards(userId: string) { - return this.getBoardService.getAllBoards(userId); + getUserBoardsOfLast3Months( + userId: string, + page?: number, + size?: number, + ): Promise { + return this.getBoardService.getUserBoardsOfLast3Months(userId, page, size); + } + + getSuperAdminBoards( + userId: string, + page?: number, + size?: number, + ): Promise { + return this.getBoardService.getSuperAdminBoards(userId, page, size); + } + + getUsersBoards( + userId: string, + page?: number, + size?: number, + ): Promise { + return this.getBoardService.getUsersBoards(userId, page, size); } getBoard(boardId: string, userId: string) { return this.getBoardService.getBoard(boardId, userId); } + + countBoards(userId: string) { + return this.getBoardService.countBoards(userId); + } } diff --git a/backend/src/modules/boards/boards.module.ts b/backend/src/modules/boards/boards.module.ts index 3403bb11f..e3023400f 100644 --- a/backend/src/modules/boards/boards.module.ts +++ b/backend/src/modules/boards/boards.module.ts @@ -15,9 +15,15 @@ import { mongooseBoardModule, mongooseBoardUserModule, } from '../../infrastructure/database/mongoose.module'; +import TeamsModule from '../teams/teams.module'; @Module({ - imports: [UsersModule, mongooseBoardModule, mongooseBoardUserModule], + imports: [ + UsersModule, + TeamsModule, + mongooseBoardModule, + mongooseBoardUserModule, + ], providers: [ createBoardService, updateBoardService, @@ -29,6 +35,6 @@ import { getBoardApplication, ], controllers: [BoardsController], - exports: [], + exports: [getBoardApplication], }) export default class BoardsModule {} diff --git a/backend/src/modules/boards/controller/boards.controller.ts b/backend/src/modules/boards/controller/boards.controller.ts index d655bd3ef..233b2af54 100644 --- a/backend/src/modules/boards/controller/boards.controller.ts +++ b/backend/src/modules/boards/controller/boards.controller.ts @@ -9,10 +9,10 @@ import { Param, Post, Put, + Query, Req, UseGuards, } from '@nestjs/common'; -import { BaseParam } from '../../../libs/dto/param/base.param'; import BoardDto from '../dto/board.dto'; import JwtAuthenticationGuard from '../../../libs/guards/jwtAuth.guard'; import RequestWithUser from '../../../libs/interfaces/requestWithUser.interface'; @@ -27,6 +27,8 @@ import { INSERT_FAILED, UPDATE_FAILED, } from '../../../libs/exceptions/messages'; +import { BaseParam } from '../../../libs/dto/param/base.param'; +import { PaginationParams } from '../../../libs/dto/param/pagination.params'; @Controller('boards') export default class BoardsController { @@ -53,10 +55,30 @@ export default class BoardsController { return board; } + @UseGuards(JwtAuthenticationGuard) + @Get('/dashboard') + getDashboardBoards( + @Req() request: RequestWithUser, + @Query() { page, size }: PaginationParams, + ) { + return this.getBoardApp.getUserBoardsOfLast3Months( + request.user._id, + page, + size, + ); + } + @UseGuards(JwtAuthenticationGuard) @Get() - boards(@Req() request: RequestWithUser) { - return this.getBoardApp.getAllBoards(request.user._id); + getAllBoards( + @Req() request: RequestWithUser, + @Query() { page, size }: PaginationParams, + ) { + const { _id: userId, isSAdmin } = request.user; + if (isSAdmin) { + return this.getBoardApp.getSuperAdminBoards(userId, page, size); + } + return this.getBoardApp.getUsersBoards(userId, page, size); } @UseGuards(JwtAuthenticationGuard) diff --git a/backend/src/modules/boards/interfaces/applications/get.board.application.interface.ts b/backend/src/modules/boards/interfaces/applications/get.board.application.interface.ts index fadcf959f..ba53bc7de 100644 --- a/backend/src/modules/boards/interfaces/applications/get.board.application.interface.ts +++ b/backend/src/modules/boards/interfaces/applications/get.board.application.interface.ts @@ -1,10 +1,26 @@ import { LeanDocument } from 'mongoose'; import { BoardDocument } from '../../schemas/board.schema'; +import { BoardsAndPage } from '../boards-page.interface'; export interface GetBoardApplicationInterface { - getAllBoards(userId: string): Promise[] | null>; + getUserBoardsOfLast3Months( + userId: string, + page?: number, + size?: number, + ): Promise; + getSuperAdminBoards( + userId: string, + page?: number, + size?: number, + ): Promise; + getUsersBoards( + userId: string, + page?: number, + size?: number, + ): Promise; getBoard( boardId: string, userId: string, ): Promise | null>; + countBoards(userId: string): Promise; } diff --git a/backend/src/modules/boards/interfaces/boards-page.interface.ts b/backend/src/modules/boards/interfaces/boards-page.interface.ts new file mode 100644 index 000000000..7c5735a80 --- /dev/null +++ b/backend/src/modules/boards/interfaces/boards-page.interface.ts @@ -0,0 +1,8 @@ +import { LeanDocument } from 'mongoose'; +import { BoardDocument } from '../schemas/board.schema'; + +export interface BoardsAndPage { + boards: LeanDocument[]; + hasNextPage: boolean; + page: number; +} diff --git a/backend/src/modules/boards/interfaces/findQuery.ts b/backend/src/modules/boards/interfaces/findQuery.ts new file mode 100644 index 000000000..32f8b08d3 --- /dev/null +++ b/backend/src/modules/boards/interfaces/findQuery.ts @@ -0,0 +1,33 @@ +import { LeanDocument } from 'mongoose'; +import { TeamUserDocument } from '../../teams/schemas/team.user.schema'; + +export type QueryType = { + $and: ( + | { + isSubBoard: boolean; + updatedAt?: { + $gte: number; + }; + $or?: undefined; + } + | { + $or: ( + | { + _id: { + $in: LeanDocument[]; + }; + team?: undefined; + } + | { + team: { + $in?: LeanDocument[]; + $ne?: undefined | null; + }; + _id?: undefined; + } + )[]; + isSubBoard?: undefined; + updatedAt?: undefined; + } + )[]; +}; diff --git a/backend/src/modules/boards/interfaces/services/get.board.service.interface.ts b/backend/src/modules/boards/interfaces/services/get.board.service.interface.ts index 08f221870..ff1a53944 100644 --- a/backend/src/modules/boards/interfaces/services/get.board.service.interface.ts +++ b/backend/src/modules/boards/interfaces/services/get.board.service.interface.ts @@ -1,8 +1,23 @@ import { LeanDocument } from 'mongoose'; import { BoardDocument } from '../../schemas/board.schema'; +import { BoardsAndPage } from '../boards-page.interface'; -export interface GetBoardService { - getAllBoards(userId: string): Promise[] | null>; +export interface GetBoardServiceInterface { + getUserBoardsOfLast3Months( + userId: string, + page?: number, + size?: number, + ): Promise; + getSuperAdminBoards( + userId: string, + page?: number, + size?: number, + ): Promise; + getUsersBoards( + userId: string, + page?: number, + size?: number, + ): Promise; getBoardFromRepo( boardId: string, ): Promise | null>; @@ -10,4 +25,5 @@ export interface GetBoardService { boardId: string, userId: string, ): Promise | null>; + countBoards(userId: string): Promise; } diff --git a/backend/src/modules/boards/schemas/board.schema.ts b/backend/src/modules/boards/schemas/board.schema.ts index 9a40ff617..c6e9dbb96 100644 --- a/backend/src/modules/boards/schemas/board.schema.ts +++ b/backend/src/modules/boards/schemas/board.schema.ts @@ -9,9 +9,6 @@ export type BoardDocument = Board & Document; @Schema({ timestamps: true, - toJSON: { - virtuals: true, - }, }) export default class Board { @Prop({ nullable: false }) diff --git a/backend/src/modules/boards/services/create.board.service.ts b/backend/src/modules/boards/services/create.board.service.ts index 948a631cb..6557a057b 100644 --- a/backend/src/modules/boards/services/create.board.service.ts +++ b/backend/src/modules/boards/services/create.board.service.ts @@ -52,6 +52,7 @@ export default class CreateBoardServiceImpl implements CreateBoardService { ...boardData, createdBy: userId, dividedBoards: await this.createDividedBoards(dividedBoards, userId), + isSubBoard: isEmpty(dividedBoards), }); } diff --git a/backend/src/modules/boards/services/get.board.service.ts b/backend/src/modules/boards/services/get.board.service.ts index f282b6ab9..bcb7ec8b3 100644 --- a/backend/src/modules/boards/services/get.board.service.ts +++ b/backend/src/modules/boards/services/get.board.service.ts @@ -1,35 +1,171 @@ -import { Injectable } from '@nestjs/common'; +import { Inject, Injectable } from '@nestjs/common'; import { InjectModel } from '@nestjs/mongoose'; import { Model } from 'mongoose'; -import { GetBoardService } from '../interfaces/services/get.board.service.interface'; +import { GetTeamService } from '../../teams/interfaces/services/get.team.service.interface'; +import * as Team from '../../teams/interfaces/types'; +import { QueryType } from '../interfaces/findQuery'; +import { GetBoardServiceInterface } from '../interfaces/services/get.board.service.interface'; import Board, { BoardDocument } from '../schemas/board.schema'; +import BoardUser, { BoardUserDocument } from '../schemas/board.user.schema'; @Injectable() -export default class GetBoardServiceImpl implements GetBoardService { +export default class GetBoardServiceImpl implements GetBoardServiceInterface { constructor( @InjectModel(Board.name) private boardModel: Model, + @InjectModel(BoardUser.name) + private boardUserModel: Model, + @Inject(Team.TYPES.services.GetTeamService) + private getTeamService: GetTeamService, ) {} - getAllBoards(userId: string) { - return this.boardModel - .find({ - createdBy: userId, - }) + getAllBoardsIdsOfUser(userId: string) { + return this.boardUserModel + .find({ user: userId }) + .select('board') + .distinct('board') .lean() .exec(); } + async getAllBoardIdsAndTeamIdsOfUser(userId: string) { + const [boardIds, teamIds] = await Promise.all([ + this.getAllBoardsIdsOfUser(userId), + this.getTeamService.getTeamsOfUser(userId), + ]); + return { boardIds, teamIds }; + } + + async getUserBoardsOfLast3Months( + userId: string, + page: number, + size?: number, + ) { + const { boardIds, teamIds } = await this.getAllBoardIdsAndTeamIdsOfUser( + userId, + ); + + const now = new Date(); + const last3Months = new Date().setMonth(now.getMonth() - 3); + const query = { + $and: [ + { isSubBoard: false, updatedAt: { $gte: last3Months } }, + { $or: [{ _id: { $in: boardIds } }, { team: { $in: teamIds } }] }, + ], + }; + + return this.getBoards(false, query, page, size); + } + + async getSuperAdminBoards(userId: string, page: number, size?: number) { + const { boardIds } = await this.getAllBoardIdsAndTeamIdsOfUser(userId); + + const query = { + $and: [ + { isSubBoard: false }, + { $or: [{ _id: { $in: boardIds } }, { team: { $ne: null } }] }, + ], + }; + + return this.getBoards(true, query, page, size); + } + + async getUsersBoards(userId: string, page: number, size?: number) { + const { boardIds, teamIds } = await this.getAllBoardIdsAndTeamIdsOfUser( + userId, + ); + const query = { + $and: [ + { isSubBoard: false }, + { $or: [{ _id: { $in: boardIds } }, { team: { $in: teamIds } }] }, + ], + }; + return this.getBoards(false, query, page, size); + } + + async getBoards(allBoards: boolean, query: QueryType, page = 0, size = 10) { + const count = await this.boardModel.find(query).countDocuments().exec(); + const hasNextPage = + page + 1 < Math.ceil(count / (allBoards ? count : size)); + const boards = await this.boardModel + .find(query) + .sort({ updatedAt: 'desc' }) + .skip(allBoards ? 0 : page * size) + .limit(allBoards ? count : size) + .select('-__v -createdAt -id') + .populate({ path: 'createdBy', select: 'firstName lastName' }) + .populate({ + path: 'team', + select: 'name users _id', + populate: { + path: 'users', + select: 'user role', + populate: { + path: 'user', + select: 'firstName lastName', + }, + }, + }) + .populate({ + path: 'dividedBoards', + select: '-__v -createdAt -id', + populate: { + path: 'users', + select: 'role user', + populate: { + path: 'user', + model: 'User', + select: 'firstName lastName', + }, + }, + }) + .populate({ + path: 'users', + select: 'user role -board', + populate: { + path: 'user', + select: 'firstName lastName', + }, + }) + .lean({ virtuals: true }) + .exec(); + + return { boards, hasNextPage, page }; + } + getBoardFromRepo(boardId: string) { return this.boardModel.findById(boardId).lean().exec(); } - async getBoard(boardId: string, userId: string) { - const board = await this.getBoardFromRepo(boardId); - - if (board?.isPublic || board?.createdBy?.toString() === userId) { - return board; - } + async getBoard(boardId: string) { + const board = await this.boardModel + .findById(boardId) + .populate({ + path: 'users', + select: 'user role -board', + }) + .populate({ + path: 'team', + select: 'name users -_id', + populate: { + path: 'users', + select: 'user role', + }, + }) + .lean({ virtuals: true }) + .exec(); + if (!board) return null; + return board; + } - return null; + async countBoards(userId: string) { + const { boardIds, teamIds } = await this.getAllBoardIdsAndTeamIdsOfUser( + userId, + ); + return this.boardModel.countDocuments({ + $and: [ + { isSubBoard: false }, + { $or: [{ _id: { $in: boardIds } }, { team: { $in: teamIds } }] }, + ], + }); } } diff --git a/backend/src/modules/teams/applications/get.team.application.ts b/backend/src/modules/teams/applications/get.team.application.ts index 62cc539b7..d98d91486 100644 --- a/backend/src/modules/teams/applications/get.team.application.ts +++ b/backend/src/modules/teams/applications/get.team.application.ts @@ -1,10 +1,10 @@ import { Inject, Injectable } from '@nestjs/common'; -import { GetTeamApplication } from '../interfaces/applications/get.team.application.interface'; +import { GetTeamApplicationInterface } from '../interfaces/applications/get.team.application.interface'; import { GetTeamService } from '../interfaces/services/get.team.service.interface'; import { TYPES } from '../interfaces/types'; @Injectable() -export class GetTeamApplicationImpl implements GetTeamApplication { +export class GetTeamApplicationImpl implements GetTeamApplicationInterface { constructor( @Inject(TYPES.services.GetTeamService) private getTeamService: GetTeamService, diff --git a/backend/src/modules/teams/interfaces/applications/get.team.application.interface.ts b/backend/src/modules/teams/interfaces/applications/get.team.application.interface.ts index b444948af..0a4928100 100644 --- a/backend/src/modules/teams/interfaces/applications/get.team.application.interface.ts +++ b/backend/src/modules/teams/interfaces/applications/get.team.application.interface.ts @@ -1,3 +1,3 @@ -export interface GetTeamApplication { +export interface GetTeamApplicationInterface { countTeams(userId: string): Promise; } diff --git a/backend/src/modules/teams/services/get.team.service.ts b/backend/src/modules/teams/services/get.team.service.ts index 3fee97d0b..6be36d052 100644 --- a/backend/src/modules/teams/services/get.team.service.ts +++ b/backend/src/modules/teams/services/get.team.service.ts @@ -21,7 +21,11 @@ export default class GetTeamServiceImpl implements GetTeamService { } getTeamsOfUser(userId: string) { - return this.teamUserModel.find({ user: userId }).lean().exec(); + return this.teamUserModel + .find({ user: userId }) + .distinct('team') + .lean() + .exec(); } getTeamUser(userId: string, teamId: string) { diff --git a/backend/src/modules/users/dto/user.dto.ts b/backend/src/modules/users/dto/user.dto.ts index 78b5f9829..ed0d26eab 100644 --- a/backend/src/modules/users/dto/user.dto.ts +++ b/backend/src/modules/users/dto/user.dto.ts @@ -1,4 +1,4 @@ -import { IsMongoId, IsNotEmpty, IsString } from 'class-validator'; +import { IsMongoId, IsNotEmpty, IsOptional, IsString } from 'class-validator'; export default class UserDto { @IsNotEmpty() @@ -17,4 +17,11 @@ export default class UserDto { @IsNotEmpty() @IsString() email!: string; + + @IsNotEmpty() + @IsString() + strategy!: string; + + @IsOptional() + isSAdmin?: boolean; } diff --git a/backend/test/auth/auth.controller.spec.ts b/backend/test/auth/auth.controller.spec.ts index b69434e67..928075e5b 100644 --- a/backend/test/auth/auth.controller.spec.ts +++ b/backend/test/auth/auth.controller.spec.ts @@ -20,6 +20,14 @@ import { getUserService, updateUserService, } from '../../src/modules/users/users.providers'; +import { + getTeamApplication, + getTeamService, +} from '../../src/modules/teams/providers'; +import { + getBoardApplication, + getBoardService, +} from '../../src/modules/boards/boards.providers'; describe('AuthController', () => { let app: INestApplication; @@ -36,6 +44,10 @@ describe('AuthController', () => { registerAuthApplication, getTokenAuthApplication, getTokenAuthService, + getTeamService, + getTeamApplication, + getBoardApplication, + getBoardService, registerAuthService, updateUserService, createUserService, @@ -50,10 +62,26 @@ describe('AuthController', () => { provide: JwtService, useValue: jwtService, }, + { + provide: getModelToken('Board'), + useValue: {}, + }, + { + provide: getModelToken('BoardUser'), + useValue: {}, + }, { provide: getModelToken('User'), useValue: usersRepository, }, + { + provide: getModelToken('Team'), + useValue: {}, + }, + { + provide: getModelToken('TeamUser'), + useValue: {}, + }, ], }).compile(); diff --git a/backend/test/boards/boards.controller.spec.ts b/backend/test/boards/boards.controller.spec.ts index acdd57939..f366c01a5 100644 --- a/backend/test/boards/boards.controller.spec.ts +++ b/backend/test/boards/boards.controller.spec.ts @@ -12,6 +12,10 @@ import { updateBoardApplication, updateBoardService, } from '../../src/modules/boards/boards.providers'; +import { + getTeamApplication, + getTeamService, +} from '../../src/modules/teams/providers'; describe('BoardsController', () => { let controller: BoardsController; @@ -25,6 +29,8 @@ describe('BoardsController', () => { createBoardService, getBoardApplication, getBoardService, + getTeamService, + getTeamApplication, updateBoardApplication, updateBoardService, deleteBoardApplication, @@ -41,6 +47,14 @@ describe('BoardsController', () => { provide: getModelToken('BoardUser'), useValue: {}, }, + { + provide: getModelToken('Team'), + useValue: {}, + }, + { + provide: getModelToken('TeamUser'), + useValue: {}, + }, ], }).compile();