Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: redirect guest user on public board #1304

Merged
merged 2 commits into from
Mar 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,8 @@ export class GetBoardApplication implements GetBoardApplicationInterface {
getAllBoardIdsAndTeamIdsOfUser(userId: string) {
return this.getBoardService.getAllBoardIdsAndTeamIdsOfUser(userId);
}

isBoardPublic(boardId: string) {
return this.getBoardService.isBoardPublic(boardId);
}
}
3 changes: 2 additions & 1 deletion backend/src/modules/boards/boards.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
} from './boards.providers';
import BoardsController from './controller/boards.controller';
import TeamUsersModule from 'src/modules/teamUsers/teamusers.module';
import PublicBoardsController from './controller/publicBoards.controller';

@Module({
imports: [
Expand Down Expand Up @@ -76,7 +77,7 @@ import TeamUsersModule from 'src/modules/teamUsers/teamusers.module';
afterUserRequestedTimerStateSubscriber,
boardRepository
],
controllers: [BoardsController],
controllers: [BoardsController, PublicBoardsController],
exports: [
getBoardApplication,
createBoardService,
Expand Down
43 changes: 43 additions & 0 deletions backend/src/modules/boards/controller/publicBoards.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { BaseParam } from 'src/libs/dto/param/base.param';
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';
import { Controller, Get, Inject, Param } from '@nestjs/common';
import {
ApiBadRequestResponse,
ApiInternalServerErrorResponse,
ApiNotFoundResponse,
ApiOperation,
ApiParam,
ApiTags
} from '@nestjs/swagger';
import { GetBoardApplicationInterface } from '../interfaces/applications/get.board.application.interface';
import { TYPES } from '../interfaces/types';

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

@ApiOperation({ summary: 'Check if board is public' })
@ApiParam({ type: String, name: 'boardId', required: true })
@ApiBadRequestResponse({
description: 'Bad Request',
type: BadRequestResponse
})
@ApiNotFoundResponse({
type: NotFoundResponse,
description: 'Board not found!'
})
@ApiInternalServerErrorResponse({
description: 'Internal Server Error',
type: InternalServerErrorResponse
})
@Get(':boardId/isPublic')
getBoard(@Param() { boardId }: BaseParam) {
return this.getBoardApp.isBoardPublic(boardId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,6 @@ export interface GetBoardApplicationInterface {
getAllBoardIdsAndTeamIdsOfUser(
userId: string
): Promise<{ boardIds: LeanDocument<unknown>[]; teamIds: unknown[] }>;

isBoardPublic(boardId: string);
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,6 @@ export interface GetBoardServiceInterface {
getBoardUser(board: string, user: string): Promise<BoardUser>;

getAllMainBoards(): Promise<Board[]>;

isBoardPublic(boardId: string);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { DeleteResult } from 'mongodb';

export interface BoardRepositoryInterface extends BaseInterfaceRepository<Board> {
getBoard(boardId: string): Promise<Board>;
isBoardPublic(boardId: string): Promise<Board>;
getBoardsByBoardIdsList(boardIds: string[]): Promise<Board[]>;
getBoardPopulated(boardId: string): Promise<Board>;
getMainBoard(boardId: string): Promise<Board>;
Expand Down
4 changes: 4 additions & 0 deletions backend/src/modules/boards/repositories/board.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ export class BoardRepository
return this.findOneById(boardId);
}

isBoardPublic(boardId: string): Promise<Board> {
return this.findOneById(boardId, 'isPublic');
}

getBoardsByBoardIdsList(boardIds: string[]): Promise<Board[]> {
return this.findAllWithQuery({
_id: { $in: boardIds }
Expand Down
23 changes: 23 additions & 0 deletions backend/src/modules/boards/services/get.board.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import Column from 'src/modules/columns/entities/column.schema';
import { UserDtoFactory } from 'src/libs/test-utils/mocks/factories/dto/userDto-factory.mock';
import { BadRequestException, NotFoundException } from '@nestjs/common';

const board = BoardFactory.create();

const hideVotesFromColumns = (columns: Column[], userId: string) => {
return columns.map((column) => {
column.cards.forEach((card) => {
Expand Down Expand Up @@ -558,4 +560,25 @@ describe('GetBoardService', () => {
expect(result).toEqual(countResult);
});
});

describe('isBoardPublic', () => {
it('should return the isPublic status of a board', async () => {
board.isPublic = true;

boardRepositoryMock.isBoardPublic.mockResolvedValue(board);

const result = await boardService.isBoardPublic(board._id);

expect(boardRepositoryMock.isBoardPublic).toBeCalledTimes(1);
expect(result).toEqual(true);
});

it('should throw an error if board is not found', async () => {
boardRepositoryMock.isBoardPublic.mockResolvedValue(null);

expect(async () => await boardService.isBoardPublic(board._id)).rejects.toThrow(
NotFoundException
);
});
});
});
12 changes: 11 additions & 1 deletion backend/src/modules/boards/services/get.board.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
NotFoundException,
forwardRef
} from '@nestjs/common';
import { BOARD_USER_NOT_FOUND, NOT_FOUND } from 'src/libs/exceptions/messages';
import { BOARD_NOT_FOUND, BOARD_USER_NOT_FOUND, NOT_FOUND } from 'src/libs/exceptions/messages';
import { GetTeamServiceInterface } from 'src/modules/teams/interfaces/services/get.team.service.interface';
import * as Teams from 'src/modules/teams/interfaces/types';
import * as Users from 'src/modules/users/interfaces/types';
Expand Down Expand Up @@ -159,6 +159,16 @@ export default class GetBoardService implements GetBoardServiceInterface {
return this.boardRepository.getAllMainBoards();
}

async isBoardPublic(boardId: string) {
const board = await this.boardRepository.isBoardPublic(boardId);

if (!board) {
throw new NotFoundException(BOARD_NOT_FOUND);
}

return board.isPublic;
}

/* --------------- HELPERS --------------- */

private async getBoards(allBoards: boolean, query: QueryType, page = 0, size = 10) {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/api/boardService.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export const getPublicStatusRequest = (
boardId: string,
context?: GetServerSidePropsContext,
): Promise<boolean> =>
fetchData<boolean>(`/publicBoards/${boardId}/publicStatus`, {
fetchData<boolean>(`/publicBoards/${boardId}/isPublic`, {
context,
serverSide: !!context,
isPublicRequest: true,
Expand Down
8 changes: 5 additions & 3 deletions frontend/src/pages/boards/[boardId].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { getSession, useSession } from 'next-auth/react';
import { useRouter } from 'next/router';
import { useEffect, useMemo, useState } from 'react';
import { useRecoilState, useSetRecoilState } from 'recoil';
import { getBoardRequest } from '@/api/boardService';
import { getBoardRequest, getPublicStatusRequest } from '@/api/boardService';
import DragDropArea from '@/components/Board/DragDropArea';
import RegularBoard from '@/components/Board/RegularBoard';
import { BoardSettings } from '@/components/Board/Settings';
Expand Down Expand Up @@ -49,8 +49,10 @@ export const getServerSideProps: GetServerSideProps = async (context) => {
props: {},
};

// if board is public and no session
if (!session) {
const boardIsPublic = await getPublicStatusRequest(boardId, context);

// if board is public and user has no session
if (boardIsPublic && !session) {
// check if there are guest user cookies
const cookiesGuestUser: GuestUser | { user: string } = getGuestUserCookies({ req, res }, true);
// if there isn´t cookies, the guest user is not registered
Expand Down