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

Improving validation #62

Merged
merged 6 commits into from
Oct 6, 2024
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
8 changes: 8 additions & 0 deletions api/src/main/java/com/backend/backend/config/Constants.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.backend.backend.config;

public class Constants {
public static final Integer MAX_KANBAN_TITLE_LENGTH = 25;
public static final Integer MAX_TASK_TITLE_LENGTH = 25;
public static final Integer MAX_TASK_DESCRIPTION_LENGTH = 255;
public static final Integer MAX_COMMENT_LENGTH = 255;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import com.backend.backend.dto.BoardResponse;
import com.backend.backend.dto.UpdateBoardRequest;
import com.backend.backend.exceptions.CharacterLimitException;
import com.backend.backend.model.User;
import com.backend.backend.service.BoardService;
import com.backend.backend.service.UserBoardService;
Expand Down Expand Up @@ -67,7 +68,7 @@ public ResponseEntity<?> updateBoardById(@PathVariable Long id, @RequestBody Upd
BoardResponse boardResponse;
try {
boardResponse = userBoardService.updateBoardForUser(currentUser, id, request);
} catch (BoardEditException e) {
} catch (BoardEditException | CharacterLimitException e) {
log.error("User {} is updating board {} FAILED", currentUser.getUserTag(), id);
return ResponseEntity.badRequest().body(e.getMessage());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import com.backend.backend.dto.CommentRequest;
import com.backend.backend.dto.TaskResponse;
import com.backend.backend.dto.UpdateTaskRequest;
import com.backend.backend.exceptions.CharacterLimitException;
import com.backend.backend.exceptions.TaskEditException;
import com.backend.backend.model.Task;
import com.backend.backend.model.User;
import com.backend.backend.service.TaskService;
Expand Down Expand Up @@ -34,16 +36,20 @@ public ResponseEntity<Task> createTaskForBoard(@PathVariable Long boardId) {
}

@PostMapping("/{boardId}/tasks/{taskId}")
public ResponseEntity<Task> updateTaskForBoard(@PathVariable Long boardId, @PathVariable Long taskId,
public ResponseEntity<?> updateTaskForBoard(@PathVariable Long boardId, @PathVariable Long taskId,
@RequestBody UpdateTaskRequest request) {

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
User currentUser = (User) authentication.getPrincipal();
log.info("User {} is updating task {} on board {} START", currentUser.getUserTag(), taskId, boardId);
Task task = taskService.updateTaskForBoard(currentUser, boardId, taskId, request);
log.info("User {} is updating task {} on board {} SUCCESS", currentUser.getUserTag(), taskId, boardId);
return ResponseEntity.ok(task);

try {
Task task = taskService.updateTaskForBoard(currentUser, boardId, taskId, request);
log.info("User {} is updating task {} on board {} SUCCESS", currentUser.getUserTag(), taskId, boardId);
return ResponseEntity.ok(task);
} catch (TaskEditException | CharacterLimitException e) {
log.error("User {} is updating task {} on board {} FAILED", currentUser.getUserTag(), taskId, boardId);
return ResponseEntity.badRequest().body(e.getMessage());
}
}

@DeleteMapping("/{boardId}/tasks/{taskId}")
Expand All @@ -57,14 +63,19 @@ public ResponseEntity<Void> deleteTask(@PathVariable Long boardId, @PathVariable
}

@PostMapping("/{boardId}/tasks/{taskId}/comment")
public ResponseEntity<TaskResponse> commentOnTask(@PathVariable Long boardId, @PathVariable Long taskId,
public ResponseEntity<?> commentOnTask(@PathVariable Long boardId, @PathVariable Long taskId,
@RequestBody CommentRequest request) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
User currentUser = (User) authentication.getPrincipal();
log.info("User {} is commenting on task {} on board {} START", currentUser.getUserTag(), taskId, boardId);
Task task = taskService.commentOnTask(currentUser, boardId, taskId, request);
log.info("User {} is commenting on task {} on board {} SUCCESS", currentUser.getUserTag(), taskId, boardId);
return ResponseEntity.ok(new TaskResponse(task));
try {
Task task = taskService.commentOnTask(currentUser, boardId, taskId, request);
log.info("User {} is commenting on task {} on board {} SUCCESS", currentUser.getUserTag(), taskId, boardId);
return ResponseEntity.ok(new TaskResponse(task));
} catch (CharacterLimitException e) {
log.error("User {} is commenting on task {} on board {} FAILED", currentUser.getUserTag(), taskId, boardId);
return ResponseEntity.badRequest().body(e.getMessage());
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.backend.backend.exceptions;

public class CharacterLimitException extends RuntimeException {
public CharacterLimitException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.backend.backend.exceptions;

public class TaskEditException extends RuntimeException {
public TaskEditException(String message) {
super(message);
}
}
15 changes: 15 additions & 0 deletions api/src/main/java/com/backend/backend/service/TaskService.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package com.backend.backend.service;

import com.backend.backend.config.Constants;
import com.backend.backend.dto.CommentRequest;
import com.backend.backend.dto.ShortUserRequest;
import com.backend.backend.dto.TaskResponse;
import com.backend.backend.dto.UpdateTaskRequest;
import com.backend.backend.exceptions.CharacterLimitException;
import com.backend.backend.exceptions.TaskEditException;
import com.backend.backend.model.*;
import com.backend.backend.repository.BoardRepository;
import com.backend.backend.repository.CommentsRepository;
Expand Down Expand Up @@ -51,12 +54,21 @@ public Task updateTaskForBoard(User user, Long boardId, Long taskId, UpdateTaskR
" with board id " + boardId.toString() + " and user id " + user.getId().toString()));

if (request.getName() != null) {
if (request.getName().length() > Constants.MAX_TASK_TITLE_LENGTH) {
throw new CharacterLimitException("Task name is too long (max " + Constants.MAX_TASK_TITLE_LENGTH + " characters)");
}
task.setName(request.getName());
}
if (request.getDescription() != null) {
if (request.getDescription().length() > Constants.MAX_TASK_DESCRIPTION_LENGTH) {
throw new CharacterLimitException("Task description is too long (max " + Constants.MAX_TASK_DESCRIPTION_LENGTH + " characters)");
}
task.setDescription(request.getDescription());
}
if (request.getDueDate() != null) {
if (task.getBoard().getStartDate().isAfter(request.getDueDate())) {
throw new TaskEditException("Start date must be before due date");
}
task.setDueDate(request.getDueDate());
}
if (request.getUrgency() != null) {
Expand Down Expand Up @@ -87,6 +99,9 @@ public Task commentOnTask(User user, Long boardId, Long taskId, CommentRequest r
" with board id " + boardId.toString() + " and user id " + user.getId().toString()));

Comment comment = new Comment();
if (request.getComment().length() > Constants.MAX_COMMENT_LENGTH) {
throw new CharacterLimitException("Comment is too long (max " + Constants.MAX_COMMENT_LENGTH + " characters)");
}
comment.setComment(request.getComment());
comment.setUser(user);
comment.setTask(task);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import java.util.ArrayList;
import java.util.List;

import com.backend.backend.config.Constants;
import com.backend.backend.dto.ShortUserRequest;
import com.backend.backend.exceptions.CharacterLimitException;
import com.backend.backend.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
Expand Down Expand Up @@ -51,6 +53,9 @@ public BoardResponse updateBoardForUser(User user, Long boardId, UpdateBoardRequ
}

if (request.getName() != null) {
if (request.getName().length() > Constants.MAX_KANBAN_TITLE_LENGTH) {
throw new CharacterLimitException("Board name is too long (max " + Constants.MAX_KANBAN_TITLE_LENGTH + " characters)");
}
board.setName(request.getName());
}
if (request.getDescription() != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.backend.backend.dto.CommentRequest;
import com.backend.backend.dto.TaskResponse;
import com.backend.backend.dto.UpdateTaskRequest;
import com.backend.backend.exceptions.CharacterLimitException;
import com.backend.backend.model.Task;
import com.backend.backend.model.User;
import com.backend.backend.service.TaskService;
Expand Down Expand Up @@ -71,7 +72,7 @@ void testUpdateTaskForBoard() {
when(taskService.updateTaskForBoard(currentUser, boardId, taskId, request)).thenReturn(mockTask);

// Act
ResponseEntity<Task> response = taskController.updateTaskForBoard(boardId, taskId, request);
ResponseEntity<?> response = taskController.updateTaskForBoard(boardId, taskId, request);

// Assert
assertEquals(HttpStatus.OK, response.getStatusCode());
Expand Down Expand Up @@ -103,11 +104,28 @@ void testCommentOnTask() {
when(taskService.commentOnTask(currentUser, boardId, taskId, commentRequest)).thenReturn(mockTask);

// Act
ResponseEntity<TaskResponse> response = taskController.commentOnTask(boardId, taskId, commentRequest);
ResponseEntity<?> response = taskController.commentOnTask(boardId, taskId, commentRequest);

// Assert
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals(new TaskResponse(mockTask), response.getBody());
verify(taskService).commentOnTask(currentUser, boardId, taskId, commentRequest);
}

@Test
void testCreateTaskLongTitle() {
// Arrange
Long boardId = 1L;
Long taskId = 1L;
UpdateTaskRequest request = new UpdateTaskRequest();
Task mockTask = new Task();
when(taskService.updateTaskForBoard(currentUser, boardId, taskId, request)).thenThrow(new CharacterLimitException("Title is too long"));

// Act
ResponseEntity<?> response = taskController.updateTaskForBoard(boardId, taskId, new UpdateTaskRequest());

// Assert
assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
assertEquals("Title is too long", response.getBody());
}
}
3 changes: 3 additions & 0 deletions frontend/src/components/forms/add-task-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ const AddTaskForm = ({
onClose,
onSubmit,
board,
errors,
}: {
onClose: () => void;
onSubmit: (taskData: any) => void;
board: KanbanBoard;
errors: string | null;
}) => {
const [name, setName] = useState("");
const [description, setDescription] = useState("");
Expand Down Expand Up @@ -204,6 +206,7 @@ const AddTaskForm = ({
Cancel
</button>
</div>
{errors && <p className="text-red-500">{errors}</p>}
</form>
</div>
</div>
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/components/forms/user-board-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,9 @@ export default function UserBoardForm({
</button>
</div>
<div>
<h2 className="text-xl font-bold mb-5">Board Name: {board.name}</h2>
<h2 className="text-xl font-bold mb-5 break-words max-w-full">
Board Name: {board.name}
</h2>

<h3 className="text-lg font-bold mb-2">Users</h3>
<ul>
Expand Down
20 changes: 7 additions & 13 deletions frontend/src/components/kanbans/kanban-display.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export default function KanbanDisplay({
const [currentUser, setCurrentUser] = useState<UserInfo | null>(null);
const [isConfirmModalOpen, setIsConfirmModalOpen] = useState(false);
const [taskToDelete, setTaskToDelete] = useState<number | null>(null);
const [addTaskError, setAddTaskError] = useState<string | null>(null);

useEffect(() => {
const subscription = UserAPI.getUserObservable().subscribe({
Expand Down Expand Up @@ -106,22 +107,13 @@ export default function KanbanDisplay({
setIsTaskModalOpen(false);
},
error: (error) => {
setAddTaskError(error.error.response.data);
TaskAPI.deleteTask(kanban.id, error.task.id);
console.error("Error creating task:", error);
},
});
};

const addComment = (comment: string, taskId: number) => {
TaskAPI.addCommentObservable(kanban.id, taskId, { comment }).subscribe({
next: (comment) => {
console.log("Comment added:", comment);
},
error: (error) => {
console.error("Error adding comment:", error);
},
});
};

const onDragEnd = (result: any) => {
const { destination, source, draggableId } = result;

Expand Down Expand Up @@ -156,7 +148,9 @@ export default function KanbanDisplay({
return (
<div style={{ padding: "0 20px" }}>
<header className="flex flex-col items-start mb-6 w-full">
<h1 className="text-4xl font-bold">{kanban.name}</h1>
<h1 className="text-4xl font-bold break-words sm:max-w-full max-w-64">
{kanban.name}
</h1>
<div className="flex justify-between text-sm mb-2 w-full space-x-4 mt-4">
<span className="font-semibold">
START DATE:{" "}
Expand Down Expand Up @@ -211,7 +205,6 @@ export default function KanbanDisplay({
<DetailedTaskView
task={kanban.tasks.find((task) => task.id === selectedTask)!}
onClose={handleTaskClose}
addComment={addComment}
board={kanban}
onDeleteTask={handleDeleteTask}
/>
Expand All @@ -223,6 +216,7 @@ export default function KanbanDisplay({
onClose={() => setIsTaskModalOpen(false)}
onSubmit={handleAddTask}
board={kanban}
errors={addTaskError}
/>
)}

Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/kanbans/kanban-list-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ const BoardCard = ({
onClick={() => handleCardClick(id)}
>
<div className="flex">
<h3 className="font-bold text-lg">{title}</h3>
<h3 className="font-bold text-lg break-words max-w-9xl">{title}</h3>

<button
className="text-black ml-auto mr-2"
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/components/kanbans/kanban-task-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ export default function KanbanCard({
task.urgency
)}`}
></span>
<h3 className="text-lg font-semibold">{task.name}</h3>
<h3 className="text-lg font-semibold max-w-full break-words">
{task.name}
</h3>
<p className="text-sm text-gray-400">Due Date: {task.dueDate}</p>
{task.users.some((user) => user.id === currentUser?.id) && (
<p className="text-sm text-gray-400">Assigned to you</p>
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/components/kanbans/kanban-task-comment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ const KanbanTaskComment = ({ comment }: { comment: Comment }) => {
</div>
</div>
</div>
<p className="mt-3 text-gray-700">{comment.comment}</p>
<p className="mt-3 text-gray-700 break-words max-w-full">
{comment.comment}
</p>
</div>
);
};
Expand Down
Loading
Loading