Skip to content

Commit

Permalink
Merge pull request #2 from xgeekshq/main
Browse files Browse the repository at this point in the history
feat: create, update and delete card (xgeekshq#74)
  • Loading branch information
nunocaseiro authored Jan 26, 2022
2 parents c073d6e + 84645a8 commit 860850b
Show file tree
Hide file tree
Showing 19 changed files with 19,931 additions and 81 deletions.
19,671 changes: 19,671 additions & 0 deletions backend/package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion backend/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import DatabaseModule from './database/database.module';
import UsersModule from './models/users/users.module';
import AuthModule from './auth/auth.module';
import BoardsModule from './models/boards/boards.module';
import ActionsModule from './actions/actions.module';
import ActionsModule from './socket/socket.module';

@Module({
imports: [
Expand Down
2 changes: 0 additions & 2 deletions backend/src/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ export default class AuthService {
if (!user.password)
throw new HttpException(INVALID_CREDENTIALS, HttpStatus.BAD_REQUEST);
await this.verifyPassword(plainTextPassword, user.password);
user.password = undefined;
return user;
}

Expand All @@ -49,7 +48,6 @@ export default class AuthService {
...registrationData,
password: hashedPassword,
});
createdUser.password = undefined;
return createdUser;
} catch (error) {
if (error?.code === Errors.UniqueViolation) {
Expand Down
91 changes: 76 additions & 15 deletions backend/src/models/boards/boards.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,17 @@ import BoardsService from './boards.service';
import BoardDto from './dto/board.dto';
import JwtAuthenticationGuard from '../../guards/jwtAuth.guard';
import RequestWithUser from '../../interfaces/requestWithUser.interface';
import ActionsGateway from '../../actions/actions.gateway';
import ActionsGateway from '../../socket/socket.gateway';
import { UpdateCardPositionDto } from './dto/card/updateCardPosition.dto';
import { AddCardDto } from './dto/card/addCard.dto';
import DeleteCardDto from './dto/card/deleteCard.dto';
import UpdateCardDto from './dto/card/updateCard.dto';

@Controller('boards')
export default class BoardsController {
constructor(
private readonly boardService: BoardsService,
private readonly actionsService: ActionsGateway,
private readonly socketService: ActionsGateway,
) {}

// #region BOARD
Expand All @@ -39,44 +42,102 @@ export default class BoardsController {
}

@UseGuards(JwtAuthenticationGuard)
@Get(':id')
@Get(':boardId')
getBoard(@Req() request: RequestWithUser) {
const { id: boardId } = request.params;
const { _id: userId } = request.user;
const {
user: { _id: userId },
params: { boardId },
} = request;
return this.boardService.getBoardWithEmail(boardId, userId);
}

@UseGuards(JwtAuthenticationGuard)
@Put(':id')
@Put(':boardId')
updateBoard(@Req() request, @Body() boardData: BoardDto) {
const { _id: userId } = request.user;
return this.boardService.updateBoard(userId, boardData);
const {
user: { _id: userId },
params: { boardId },
} = request;
return this.boardService.updateBoard(userId, boardId, boardData);
}

@UseGuards(JwtAuthenticationGuard)
@Delete(':id')
@Delete(':boardId')
deleteBoard(@Req() request: RequestWithUser) {
const { id: boardId } = request.params;
const { _id: userId } = request.user;
const {
user: { _id: userId },
params: { boardId },
} = request;
return this.boardService.deleteBoard(boardId, userId);
}

// #endregion

// #region CARD

@Put(':id/card/:cardId/updateCardPosition')
@UseGuards(JwtAuthenticationGuard)
@Post(':boardId/card')
async addCard(@Req() request, @Body() createCardDto: AddCardDto) {
const {
user: { _id: userId },
params: { boardId },
} = request;
const { card, colIdToAdd, socketId } = createCardDto;
const board = await this.boardService.addCardToBoard(
boardId,
userId,
card,
colIdToAdd,
);
this.socketService.sendUpdatedBoard(board, socketId);
return board;
}

@UseGuards(JwtAuthenticationGuard)
@Delete(':boardId/card/:cardId')
async deleteCard(@Req() request, @Body() deleteCardDto: DeleteCardDto) {
const {
params: { boardId, cardId },
user: { _id: userId },
} = request;
const board = await this.boardService.deleteCard(boardId, cardId, userId);
this.socketService.sendUpdatedBoard(board, deleteCardDto.socketId);
return board;
}

@UseGuards(JwtAuthenticationGuard)
@Put(':boardId/card/:cardId/items/:cardItemId')
async updateCardText(@Req() request, @Body() updateCardDto: UpdateCardDto) {
const {
params: { boardId, cardId, cardItemId },
user: { _id: userId },
} = request;
const { text, socketId } = updateCardDto;
const board = await this.boardService.updateCardText(
boardId,
cardId,
cardItemId,
userId,
text,
);
this.socketService.sendUpdatedBoard(board, socketId);
return board;
}

@Put(':boardId/card/:cardId/updateCardPosition')
async updateCardPosition(
@Req() request,
@Body() boardData: UpdateCardPositionDto,
) {
const { id: boardId, cardId } = request.params;
const { boardId, cardId } = request.params;
const { targetColumnId, newPosition, socketId } = boardData;
const board = await this.boardService.updateCardPosition(
boardId,
cardId,
boardData,
targetColumnId,
newPosition,
);
this.actionsService.sendUpdatedBoard(board, boardData.socketId);
this.socketService.sendUpdatedBoard(board, socketId);
return board;
}

Expand Down
2 changes: 1 addition & 1 deletion backend/src/models/boards/boards.module.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { forwardRef, Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import ActionsModule from '../../actions/actions.module';
import ActionsModule from '../../socket/socket.module';
import BoardsService from './boards.service';
import BoardsController from './boards.controller';
import Board, { BoardSchema } from './schemas/board.schema';
Expand Down
97 changes: 89 additions & 8 deletions backend/src/models/boards/boards.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import Board, { BoardDocument } from './schemas/board.schema';
import BoardDto from './dto/board.dto';
import { encrypt } from '../../utils/bcrypt';
import Card from './schemas/card.schema';
import { UpdateCardPositionDto } from './dto/card/updateCardPosition.dto';
import CardDto from './dto/card/card.dto';

@Injectable()
export default class BoardsService {
Expand Down Expand Up @@ -60,10 +60,10 @@ export default class BoardsService {
throw new HttpException(BOARD_NOT_FOUND, HttpStatus.NOT_FOUND);
}

async updateBoard(userId: string, boardData: BoardDto) {
async updateBoard(userId: string, boardId: string, boardData: BoardDto) {
const result = await this.boardModel.findOneAndUpdate(
{
_id: boardData._id,
_id: boardId,
createdBy: userId,
},
boardData,
Expand Down Expand Up @@ -134,10 +134,9 @@ export default class BoardsService {
async updateCardPosition(
boardId: string,
cardId: string,
updateCardPositionDto: UpdateCardPositionDto,
targetColumnId: string,
newPosition: number,
) {
const { columnId, position } = updateCardPositionDto;

const cardToMove = await this.getCardFromBoard(boardId, cardId);

if (cardToMove) {
Expand All @@ -163,13 +162,13 @@ export default class BoardsService {
.findOneAndUpdate(
{
_id: boardId,
'columns._id': columnId,
'columns._id': targetColumnId,
},
{
$push: {
'columns.$.cards': {
$each: [cardToMove],
$position: position,
$position: newPosition,
},
},
},
Expand All @@ -184,5 +183,87 @@ export default class BoardsService {
throw new HttpException(UPDATE_FAILED, HttpStatus.BAD_REQUEST);
}

async addCardToBoard(
id: number,
userId: string,
card: CardDto,
colIdToAdd: string,
) {
card.createdBy = userId;
card.items[0].createdBy = userId;
const result = await this.boardModel
.findOneAndUpdate(
{
_id: id,
'columns._id': colIdToAdd,
},
{
$push: {
'columns.$.cards': { ...card },
},
},
{ new: true, rawResult: true },
)
.exec();
if (result.value && result.lastErrorObject?.updatedExisting)
return result.value;
throw new HttpException(INSERT_FAILED, HttpStatus.BAD_REQUEST);
}

async updateCardText(
boardId: string,
cardId: string,
cardItemId: string,
userId: string,
text: string,
) {
const result = await this.boardModel
.findOneAndUpdate(
{
_id: boardId,
'columns.cards._id': cardId,
'columns.cards.createdBy': userId,
},
{
$set: {
'columns.$.cards.$[c].text': text,
'columns.$.cards.$[c].items.$[item].text': text,
},
},
{
arrayFilters: [{ 'c._id': cardId }, { 'item._id': cardItemId }],
new: true,
rawResult: true,
},
)
.exec();
if (result.value && result.lastErrorObject?.updatedExisting)
return result.value;
throw new HttpException(UPDATE_FAILED, HttpStatus.BAD_REQUEST);
}

async deleteCard(boardId: string, cardId: string, userId: string) {
const result = await this.boardModel
.findOneAndUpdate(
{
_id: boardId,
'columns.cards._id': cardId,
'columns.cards.createdBy': userId,
},
{
$pull: {
'columns.$[].cards': { _id: cardId },
},
},
{ new: true, rawResult: true },
)
.exec();

if (result.value && result.lastErrorObject?.updatedExisting)
return result.value;

throw new HttpException(UPDATE_FAILED, HttpStatus.BAD_REQUEST);
}

// #endregion
}
17 changes: 17 additions & 0 deletions backend/src/models/boards/dto/card/addCard.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Type } from 'class-transformer';
import { IsNotEmpty, IsString } from 'class-validator';
import CardDto from './card.dto';

export class AddCardDto {
@IsNotEmpty()
@IsString()
colIdToAdd!: string;

@IsNotEmpty()
@Type(() => CardDto)
card!: CardDto;

@IsNotEmpty()
@IsString()
socketId!: string;
}
25 changes: 4 additions & 21 deletions backend/src/models/boards/dto/card/card.dto.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,8 @@
import { IsNotEmpty, IsString, ValidateNested } from 'class-validator';
import { Transform, TransformFnParams } from 'class-transformer';
import CardItem from '../../schemas/card.item.schema';

export default class CardDto {
@IsNotEmpty()
@IsString()
_id!: string;

@IsNotEmpty()
@IsString()
@Transform(({ value }: TransformFnParams) => value.trim())
text!: string;
import { IsNotEmpty, ValidateNested } from 'class-validator';
import CardItemDto from './card.item.dto';

export default class CardDto extends CardItemDto {
@IsNotEmpty()
@ValidateNested({ each: true })
items!: CardItem[];

// @ValidateNested({ each: true })
// @Type(() => CommentDto)
// comments!: CommentDto[];

// @IsNotEmpty()
// votes!: string[];
items!: CardItemDto[];
}
21 changes: 14 additions & 7 deletions backend/src/models/boards/dto/card/card.item.dto.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { IsNotEmpty, IsString } from 'class-validator';
import { Transform, TransformFnParams } from 'class-transformer';
import { IsNotEmpty, IsString, ValidateNested } from 'class-validator';
import { Transform, TransformFnParams, Type } from 'class-transformer';
import CommentDto from '../comment/comment.dto';

export default class CardItemDto {
@IsNotEmpty()
Expand All @@ -11,10 +12,16 @@ export default class CardItemDto {
@Transform(({ value }: TransformFnParams) => value.trim())
text!: string;

// @ValidateNested({ each: true })
// @Type(() => CommentDto)
// comments!: CommentDto[];
@IsNotEmpty()
@IsString()
createdBy!: string;

// @IsNotEmpty()
// votes!: string[];
@IsNotEmpty()
@ValidateNested({ each: true })
@Type(() => CommentDto)
comments!: CommentDto[];

@IsNotEmpty()
@ValidateNested({ each: true })
votes!: string[];
}
7 changes: 7 additions & 0 deletions backend/src/models/boards/dto/card/deleteCard.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { IsNotEmpty, IsString } from 'class-validator';

export default class DeleteCardDto {
@IsNotEmpty()
@IsString()
socketId!: string;
}
Loading

0 comments on commit 860850b

Please sign in to comment.