Skip to content

Commit

Permalink
feat: regular board public private (#1093)
Browse files Browse the repository at this point in the history
Co-authored-by: Cátia Antunes <c.antunes@kigroup.de>
  • Loading branch information
2 people authored and GoncaloCanteiro committed Feb 22, 2023
1 parent 33b747d commit 5168513
Show file tree
Hide file tree
Showing 26 changed files with 322 additions and 15 deletions.
4 changes: 4 additions & 0 deletions backend/src/libs/dto/response/login-guest-user.response.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export class LoginGuestUserResponse {
board: string;
user: string;
}
3 changes: 3 additions & 0 deletions backend/src/libs/exceptions/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ const EMAIL_DONT_MATCH = 'EMAIL_DONT_MATCH';
const BOARD_NOT_FOUND = 'BOARD_NOT_FOUND';
const BOARDS_NOT_FOUND = 'BOARDS_NOT_FOUND';

const BOARD_USER_EXISTS = 'BOARD_USER_EXISTS';

const COLUMN_NOT_FOUND = 'COLUMN_NOT_FOUND';

const TOKENS_NOT_MATCHING = 'TOKENS_NOT_MATCHING';
Expand All @@ -32,6 +34,7 @@ const PHASE_NOT_EXISTS = 'PHASE_NOT_EXISTS';
export {
BOARD_NOT_FOUND,
BOARDS_NOT_FOUND,
BOARD_USER_EXISTS,
CARD_NOT_FOUND,
CARD_NOT_INSERTED,
CARD_NOT_REMOVED,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import CreateGuestUserDto from 'src/modules/users/dto/create.guest.user.dto';
import { Inject, Injectable } from '@nestjs/common';
import CreateUserDto from 'src/modules/users/dto/create.user.dto';
import { RegisterAuthApplication } from '../interfaces/applications/register.auth.application.interface';
Expand All @@ -14,4 +15,10 @@ export class RegisterAuthApplicationImpl implements RegisterAuthApplication {
register(registrationData: CreateUserDto) {
return this.registerAuthService.register(registrationData);
}

createGuestUser(guestUserData: CreateGuestUserDto) {
if (guestUserData.user) return this.registerAuthService.loginGuest(guestUserData);

return this.registerAuthService.createGuest(guestUserData);
}
}
4 changes: 3 additions & 1 deletion backend/src/modules/auth/auth.module.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { mongooseBoardUserModule } from './../../infrastructure/database/mongoose.module';
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { PassportModule } from '@nestjs/passport';
Expand Down Expand Up @@ -32,7 +33,8 @@ import JwtRefreshTokenStrategy from './strategy/refresh.strategy';
PassportModule,
ConfigModule,
mongooseResetModule,
mongooseUserModule
mongooseUserModule,
mongooseBoardUserModule,
],
providers: [
getTokenAuthService,
Expand Down
29 changes: 29 additions & 0 deletions backend/src/modules/auth/controller/auth.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
import AuthController from 'src/modules/auth/controller/auth.controller';
import {
boardRepository,
createBoardService,
getBoardApplication,
getBoardService
} from 'src/modules/boards/boards.providers';
Expand All @@ -39,6 +40,12 @@ import {
updateUserService,
userRepository
} from 'src/modules/users/users.providers';
import {
createSchedulesService,
deleteSchedulesService
} from 'src/modules/schedules/schedules.providers';
import * as CommunicationsType from 'src/modules/communication/interfaces/types';
import { SchedulerRegistry } from '@nestjs/schedule';

describe('AuthController', () => {
let app: INestApplication;
Expand Down Expand Up @@ -74,7 +81,29 @@ describe('AuthController', () => {
teamUserRepository,
updateTeamService,
boardRepository,
createBoardService,
createSchedulesService,
deleteSchedulesService,
SchedulerRegistry,
ConfigService,
{
provide: CommunicationsType.TYPES.services.SlackCommunicationService,
useValue: {
execute: jest.fn()
}
},
{
provide: getModelToken('Schedules'),
useValue: {
find: jest.fn().mockResolvedValue([])
}
},
{
provide: CommunicationsType.TYPES.services.SlackArchiveChannelService,
useValue: {
execute: jest.fn()
}
},
{
provide: ConfigService,
useValue: configService
Expand Down
16 changes: 16 additions & 0 deletions backend/src/modules/auth/controller/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import { RegisterAuthApplication } from '../interfaces/applications/register.aut
import { TYPES } from '../interfaces/types';
import { signIn } from '../shared/login.auth';
import { LoginResponse } from '../swagger/login.swagger';
import CreateGuestUserDto from 'src/modules/users/dto/create.guest.user.dto';

@ApiTags('Authentication')
@Controller('auth')
Expand Down Expand Up @@ -318,4 +319,19 @@ export default class AuthController {

return { usersCount, teamsCount, boardsCount };
}

@ApiOperation({ summary: 'Create new guest user' })
@ApiCreatedResponse({ type: UserDto, description: 'Guest user successfully created!' })
@ApiBadRequestResponse({
description: 'Bad Request',
type: BadRequestResponse
})
@ApiInternalServerErrorResponse({
description: 'Internal Server Error',
type: InternalServerErrorResponse
})
@Post('loginGuest')
async loginGuest(@Body() guestUserData: CreateGuestUserDto) {
return await this.registerAuthApp.createGuestUser(guestUserData);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { LoginGuestUserResponse } from './../../../../libs/dto/response/login-guest-user.response';
import CreateGuestUserDto from 'src/modules/users/dto/create.guest.user.dto';
import CreateUserDto from 'src/modules/users/dto/create.user.dto';
import User from 'src/modules/users/entities/user.schema';

export interface RegisterAuthApplication {
register(registrationData: CreateUserDto): Promise<User>;
createGuestUser(guestUserData: CreateGuestUserDto): Promise<LoginGuestUserResponse>;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { LoginGuestUserResponse } from './../../../../libs/dto/response/login-guest-user.response';
import CreateGuestUserDto from 'src/modules/users/dto/create.guest.user.dto';
import CreateUserDto from 'src/modules/users/dto/create.user.dto';
import User from 'src/modules/users/entities/user.schema';

export interface RegisterAuthService {
register(registrationData: CreateUserDto): Promise<User>;
createGuest(guestUserData: CreateGuestUserDto): Promise<LoginGuestUserResponse>;
loginGuest(guestUserData: CreateGuestUserDto): Promise<LoginGuestUserResponse>;
}
51 changes: 49 additions & 2 deletions backend/src/modules/auth/services/register.auth.service.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
import { Inject, Injectable } from '@nestjs/common';
import { BOARD_USER_EXISTS, INSERT_FAILED } from 'src/libs/exceptions/messages';
import { BadRequestException, Inject, Injectable } from '@nestjs/common';
import { encrypt } from 'src/libs/utils/bcrypt';
import CreateUserDto from 'src/modules/users/dto/create.user.dto';
import { CreateUserService } from 'src/modules/users/interfaces/services/create.user.service.interface';
import { TYPES } from 'src/modules/users/interfaces/types';
import { RegisterAuthService } from '../interfaces/services/register.auth.service.interface';
import CreateGuestUserDto from 'src/modules/users/dto/create.guest.user.dto';
import { BoardRoles } from 'src/libs/enum/board.roles';
import { InjectModel } from '@nestjs/mongoose';
import BoardUser, { BoardUserDocument } from 'src/modules/boards/entities/board.user.schema';
import { Model } from 'mongoose';

@Injectable()
export default class RegisterAuthServiceImpl implements RegisterAuthService {
constructor(
@Inject(TYPES.services.CreateUserService)
private createUserService: CreateUserService
private createUserService: CreateUserService,
@InjectModel(BoardUser.name)
private boardUserModel: Model<BoardUserDocument>
) {}

public async register(registrationData: CreateUserDto) {
Expand All @@ -20,4 +28,43 @@ export default class RegisterAuthServiceImpl implements RegisterAuthService {
password: hashedPassword
});
}

public async createGuest(guestUserData: CreateGuestUserDto) {
const { board } = guestUserData;
const guestUserCreated = await this.createUserService.createGuest(guestUserData);

if (!guestUserCreated) throw new BadRequestException(INSERT_FAILED);

const { _id: user } = guestUserCreated;

await this.createGuestBoardUser(board, user);

return { board, user };
}

public async loginGuest(guestUserData: CreateGuestUserDto) {
const { board, user } = guestUserData;

await this.createGuestBoardUser(board, user);

return { board, user };
}

private async createGuestBoardUser(board: string, user: string) {
const boardUserFound = await this.boardUserModel.findOne({ board, user });

if (boardUserFound) throw new BadRequestException(BOARD_USER_EXISTS);

const boardUser = {
role: BoardRoles.MEMBER,
board,
user,
votesCount: 0
};
const boardUserCreated = await this.boardUserModel.create(boardUser);

if (!boardUserCreated) throw new BadRequestException(INSERT_FAILED);

return boardUserCreated;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,8 @@ export class GetBoardApplication implements GetBoardApplicationInterface {
getAllBoardIdsAndTeamIdsOfUser(userId: string) {
return this.getBoardService.getAllBoardIdsAndTeamIdsOfUser(userId);
}

isBoardPublic(boardId: string) {
return this.getBoardService.isBoardPublic(boardId);
}
}
13 changes: 9 additions & 4 deletions backend/src/modules/boards/boards.module.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { userRepository } from 'src/modules/users/users.providers';
import { Module, forwardRef } from '@nestjs/common';
import {
mongooseBoardModule,
mongooseBoardUserModule
mongooseBoardUserModule,
mongooseUserModule
} from 'src/infrastructure/database/mongoose.module';
import { CommunicationModule } from 'src/modules/communication/communication.module';
import { SchedulesModule } from 'src/modules/schedules/schedules.module';
Expand Down Expand Up @@ -32,6 +34,7 @@ import {
updateBoardTimerDurationService
} from './boards.providers';
import BoardsController from './controller/boards.controller';
import PublicBoardsController from './controller/public.boards.controller';

@Module({
imports: [
Expand All @@ -41,7 +44,8 @@ import BoardsController from './controller/boards.controller';
CommunicationModule,
CardsModule,
mongooseBoardModule,
mongooseBoardUserModule
mongooseBoardUserModule,
mongooseUserModule
],
providers: [
createBoardService,
Expand All @@ -64,9 +68,10 @@ import BoardsController from './controller/boards.controller';
afterUserStoppedTimerSubscriber,
afterUserUpdatedDurationSubscriber,
afterUserRequestedTimerStateSubscriber,
boardRepository
boardRepository,
userRepository
],
controllers: [BoardsController],
controllers: [BoardsController, PublicBoardsController],
exports: [
getBoardApplication,
createBoardService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
teamUserRepository,
updateTeamService
} from 'src/modules/teams/providers';
import { userRepository } from 'src/modules/users/users.providers';
import { deleteVoteService } from 'src/modules/votes/votes.providers';

describe('BoardsController', () => {
Expand Down Expand Up @@ -61,6 +62,8 @@ describe('BoardsController', () => {
deleteCardService,
deleteVoteService,
boardRepository,
userRepository,
updateTeamService,
{
provide: getModelToken('User'),
useValue: {}
Expand Down
69 changes: 69 additions & 0 deletions backend/src/modules/boards/controller/public.boards.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { UserParams } from './../../../libs/dto/param/user.param';
import { Controller, Get, Inject, Param, Query } from '@nestjs/common';
import {
ApiBadRequestResponse,
ApiInternalServerErrorResponse,
ApiNotFoundResponse,
ApiOkResponse,
ApiOperation,
ApiParam,
ApiQuery,
ApiTags
} from '@nestjs/swagger';
import { BaseParam } from 'src/libs/dto/param/base.param';
import BoardDto from '../dto/board.dto';
import { GetBoardApplicationInterface } from '../interfaces/applications/get.board.application.interface';
import { TYPES } from '../interfaces/types';
import { BadRequestResponse } from 'src/libs/swagger/errors/bad-request.swagger';
import { InternalServerErrorResponse } from 'src/libs/swagger/errors/internal-server-error.swagger';
import { NotFoundResponse } from 'src/libs/swagger/errors/not-found.swagger';

@ApiTags('Public Boards')
@Controller('publicBoards')
export default class PublicBoardsController {
constructor(
@Inject(TYPES.applications.GetBoardApplication)
private getBoardApp: GetBoardApplicationInterface
) {}

@ApiOperation({ summary: 'Retrieve a boolean that checks if board is public' })
@ApiParam({ type: String, name: 'boardId', required: true })
@ApiOkResponse({ type: BoardDto, description: 'Public status retrieved successfully!' })
@ApiBadRequestResponse({
description: 'Bad Request',
type: BadRequestResponse
})
@ApiNotFoundResponse({
type: NotFoundResponse,
description: 'Board not found!'
})
@ApiInternalServerErrorResponse({
description: 'Internal Server Error',
type: InternalServerErrorResponse
})
@Get(':boardId/publicStatus')
async getPublicStatus(@Param() { boardId }: BaseParam) {
return await this.getBoardApp.isBoardPublic(boardId);
}

@ApiOperation({ summary: 'Retrieve one public board by id' })
@ApiParam({ type: String, name: 'boardId', required: true })
@ApiQuery({ type: String, name: 'userId', required: true })
@ApiOkResponse({ type: BoardDto, description: 'Board retrieved successfully!' })
@ApiBadRequestResponse({
description: 'Bad Request',
type: BadRequestResponse
})
@ApiNotFoundResponse({
type: NotFoundResponse,
description: 'Board not found!'
})
@ApiInternalServerErrorResponse({
description: 'Internal Server Error',
type: InternalServerErrorResponse
})
@Get(':boardId')
async getBoard(@Param() { boardId }: BaseParam, @Query() { userId }: UserParams) {
return await this.getBoardApp.getBoard(boardId, userId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,6 @@ export interface GetBoardApplicationInterface {
getAllBoardIdsAndTeamIdsOfUser(
userId: string
): Promise<{ boardIds: LeanDocument<unknown>[]; teamIds: unknown[] }>;

isBoardPublic(boardId: string): Promise<boolean>;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { BoardUserDocument } from 'src/modules/boards/entities/board.user.schema';
import BoardDto from '../../dto/board.dto';
import BoardUserDto from '../../dto/board.user.dto';
import { BoardDocument } from '../../entities/board.schema';

export interface Configs {
Expand All @@ -16,4 +18,6 @@ export interface CreateBoardService {
create(boardData: BoardDto, userId: string): Promise<BoardDocument>;

splitBoardByTeam(ownerId: string, teamId: string, configs: Configs): Promise<string | null>;

saveBoardUsers(newUsers: BoardUserDto[], newBoardId: string): Promise<BoardUserDocument[]>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,6 @@ export interface GetBoardServiceInterface {
): Promise<{ boardIds: LeanDocument<any>[]; teamIds: any[] }>;

getAllBoardsByTeamId(teamId: string): Promise<LeanDocument<BoardDocument>[]>;

isBoardPublic(boardId: string): Promise<boolean>;
}
Loading

0 comments on commit 5168513

Please sign in to comment.