From a377098a9199042fbcef74ee3fb99fe1e70df22f Mon Sep 17 00:00:00 2001 From: furknbulbul Date: Tue, 21 Nov 2023 14:20:59 +0300 Subject: [PATCH 01/12] Task and Action services enhanced --- resq/backend/resq/pom.xml | 5 + .../resq/controller/ActionController.java | 42 ++++++ .../resq/controller/TaskController.java | 51 ++++++++ .../java/com/groupa1/resq/entity/Action.java | 11 +- .../java/com/groupa1/resq/entity/Comment.java | 30 +++++ .../groupa1/resq/entity/enums/EStatus.java | 6 +- .../resq/request/CreateActionRequest.java | 2 +- .../resq/request/CreateCommentRequest.java | 10 ++ .../resq/request/CreateFeedbackRequest.java | 10 ++ .../groupa1/resq/service/ActionService.java | 123 +++++++++++++++++- .../com/groupa1/resq/service/TaskService.java | 106 ++++++++++++++- .../resq/utils/NullAwareBeanUtilsBean.java | 19 +++ 12 files changed, 402 insertions(+), 13 deletions(-) create mode 100644 resq/backend/resq/src/main/java/com/groupa1/resq/entity/Comment.java create mode 100644 resq/backend/resq/src/main/java/com/groupa1/resq/request/CreateCommentRequest.java create mode 100644 resq/backend/resq/src/main/java/com/groupa1/resq/request/CreateFeedbackRequest.java create mode 100644 resq/backend/resq/src/main/java/com/groupa1/resq/utils/NullAwareBeanUtilsBean.java diff --git a/resq/backend/resq/pom.xml b/resq/backend/resq/pom.xml index dd2bae06..7eebeb48 100644 --- a/resq/backend/resq/pom.xml +++ b/resq/backend/resq/pom.xml @@ -77,6 +77,11 @@ 0.12.3 runtime + + commons-beanutils + commons-beanutils + 1.9.4 + diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/controller/ActionController.java b/resq/backend/resq/src/main/java/com/groupa1/resq/controller/ActionController.java index 14f8eae1..5a36eee4 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/controller/ActionController.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/controller/ActionController.java @@ -1,5 +1,6 @@ package com.groupa1.resq.controller; +import com.groupa1.resq.request.CreateCommentRequest; import com.groupa1.resq.request.CreateActionRequest; import com.groupa1.resq.response.ActionResponse; import com.groupa1.resq.service.ActionService; @@ -35,5 +36,46 @@ public ResponseEntity> viewActions(@RequestParam Long taskI return actionService.viewActions( taskId); } + @PreAuthorize("hasRole('COORDINATOR')") + @PostMapping("/deleteAction") + public ResponseEntity deleteAction(@RequestParam Long actionId) { + return actionService.deleteAction(actionId); + } + + @PreAuthorize("hasRole('COORDINATOR')") + @PostMapping("/updateAction") + public ResponseEntity updateAction(@RequestBody CreateActionRequest createActionRequest, @RequestParam Long actionId) { + return actionService.updateAction(createActionRequest, actionId); + } + + + + @PreAuthorize("hasRole('RESPONDER')") + @PostMapping("/completeAction") + public ResponseEntity completeAction(@RequestParam Long actionId, @RequestParam Long userId) { + return actionService.completeAction(actionId, userId); + } + @PreAuthorize("hasRole('FACILITATOR')") + @PostMapping("/verifyAction") + public ResponseEntity verifyAction(@RequestParam Long actionId, @RequestParam Long userId){ + return actionService.verifyAction(actionId, userId); + } + + @PreAuthorize("hasRole('FACILITATOR')") + @PostMapping("/commentAction") + public ResponseEntity verifyAction(@RequestBody + CreateCommentRequest commentActionRequest){ + return actionService.commentAction(commentActionRequest); + } + + //TODO +// @PreAuthorize("hasRole('FACILITATOR')") +// @PostMapping("/notifyCoordinator") +// public ResponseEntity notifyCoordinator(@RequestParam Long actionId){ +// return actionService.notifyCoordinator(actionId); +// } + + + } diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/controller/TaskController.java b/resq/backend/resq/src/main/java/com/groupa1/resq/controller/TaskController.java index c3ce5295..e47c1d9a 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/controller/TaskController.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/controller/TaskController.java @@ -1,5 +1,7 @@ package com.groupa1.resq.controller; +import com.groupa1.resq.request.CreateActionRequest; +import com.groupa1.resq.request.CreateFeedbackRequest; import com.groupa1.resq.request.CreateTaskRequest; import com.groupa1.resq.response.TaskResponse; import com.groupa1.resq.service.TaskService; @@ -8,13 +10,16 @@ import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import java.lang.reflect.InvocationTargetException; import java.util.List; +import java.util.Map; @RestController @Slf4j @@ -37,6 +42,13 @@ public ResponseEntity acceptTask(@RequestParam Long taskId, @RequestPara return taskService.acceptTask(taskId, userId); } + @PreAuthorize("hasRole('RESPONDER')") + @PostMapping("/declineTask") + public ResponseEntity declineTask(@RequestParam Long taskId, @RequestParam Long userId) { + return taskService.declineTask(taskId, userId); + } + + @PreAuthorize("hasRole('RESPONDER') or hasRole('COORDINATOR')") @GetMapping("/viewTasks") @@ -44,6 +56,45 @@ public ResponseEntity> viewAllTasks(@RequestParam Long userId return taskService.viewAllTasks(userId); } + @PreAuthorize("hasRole('COORDINATOR')") + @PostMapping("/deleteTask") + public ResponseEntity deleteTask(@RequestParam Long taskId) { + return taskService.deleteTask(taskId); + } + + @PreAuthorize("hasRole('COORDINATOR')") + @PatchMapping("/updateTask") + public ResponseEntity updateTask(@RequestBody + Map fields, @RequestParam Long taskId) + throws InvocationTargetException, IllegalAccessException { + return taskService.updateTask(fields, taskId); + } + + @PreAuthorize("hasRole('COORDINATOR')") + @PostMapping("/assignTask") + public ResponseEntity assignTask(@RequestParam Long taskId, @RequestParam Long userId) { + return taskService.assignTask(taskId, userId); + } + + @PreAuthorize("hasRole('COORDINATOR')") + @PostMapping("/unassignTask") + public ResponseEntity unassignTask(@RequestParam Long taskId, @RequestParam Long userId) { + return taskService.unassignTask(taskId); + } + + + @PreAuthorize("hasRole('RESPPONDER')") + @PostMapping("/completeTask") + public ResponseEntity completeTask(@RequestParam Long taskId, @RequestParam Long userId) { + return taskService.completeTask(taskId, userId); + } + + @PreAuthorize("hasRole('RESPONDER')") + @PostMapping("/giveFeedback") + public ResponseEntity giveFeedback(CreateFeedbackRequest feedback) { + return taskService.giveFeedback(feedback); + } + diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/entity/Action.java b/resq/backend/resq/src/main/java/com/groupa1/resq/entity/Action.java index 737a2edb..3975262e 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/entity/Action.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/entity/Action.java @@ -6,6 +6,7 @@ import java.math.BigDecimal; import java.time.LocalDateTime; +import java.util.Set; @NoArgsConstructor @Entity @@ -26,13 +27,21 @@ public class Action extends BaseEntity { private LocalDateTime dueDate; + // for responder private boolean isCompleted; - + // for facilitator + private boolean isVerified; private BigDecimal startLatitude; private BigDecimal startLongitude; private BigDecimal endLatitude; private BigDecimal endLongitude; + @OneToMany(fetch = FetchType.LAZY, mappedBy="action") + private Set comments; + + + + } diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/entity/Comment.java b/resq/backend/resq/src/main/java/com/groupa1/resq/entity/Comment.java new file mode 100644 index 00000000..b66e43d4 --- /dev/null +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/entity/Comment.java @@ -0,0 +1,30 @@ +package com.groupa1.resq.entity; + + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.Lob; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Entity +@NoArgsConstructor +@Table(name = "COMMENT") +@Data +public class Comment extends BaseEntity{ + + @ManyToOne + @JoinColumn(name = "action_id") + private Action action; + + @ManyToOne + @JoinColumn(name = "creator_id") + private User verifier; + + @Lob + @Column(length = 3000) + private String comment; +} diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/entity/enums/EStatus.java b/resq/backend/resq/src/main/java/com/groupa1/resq/entity/enums/EStatus.java index 96045304..2a54f069 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/entity/enums/EStatus.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/entity/enums/EStatus.java @@ -1,8 +1,10 @@ package com.groupa1.resq.entity.enums; public enum EStatus { - TODO, + TODO, // accepted IN_PROGRESS, DONE, - PENDING + PENDING, //responder assigned, but not yet accepted + DECLINED, + FREE // no responder assigned } diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/request/CreateActionRequest.java b/resq/backend/resq/src/main/java/com/groupa1/resq/request/CreateActionRequest.java index 6b8157d6..f2f2a6e4 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/request/CreateActionRequest.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/request/CreateActionRequest.java @@ -14,6 +14,7 @@ public class CreateActionRequest { private Long verifierId; private String description; private boolean isCompleted; + private boolean isVerified; private BigDecimal startLatitude; private BigDecimal startLongitude; @@ -22,5 +23,4 @@ public class CreateActionRequest { private LocalDateTime dueDate; - } diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/request/CreateCommentRequest.java b/resq/backend/resq/src/main/java/com/groupa1/resq/request/CreateCommentRequest.java new file mode 100644 index 00000000..0a551fb8 --- /dev/null +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/request/CreateCommentRequest.java @@ -0,0 +1,10 @@ +package com.groupa1.resq.request; + +import lombok.Data; + +@Data +public class CreateCommentRequest { + private Long userId; + private Long actionId; + private String comment; +} diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/request/CreateFeedbackRequest.java b/resq/backend/resq/src/main/java/com/groupa1/resq/request/CreateFeedbackRequest.java new file mode 100644 index 00000000..011626f3 --- /dev/null +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/request/CreateFeedbackRequest.java @@ -0,0 +1,10 @@ +package com.groupa1.resq.request; + +import lombok.Data; + +@Data +public class CreateFeedbackRequest { + private Long userId; + private Long taskId; + private String message; +} diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/service/ActionService.java b/resq/backend/resq/src/main/java/com/groupa1/resq/service/ActionService.java index 14fd2bba..fa14118f 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/service/ActionService.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/service/ActionService.java @@ -1,22 +1,22 @@ package com.groupa1.resq.service; -import com.fasterxml.jackson.databind.deser.std.NumberDeserializers; import com.groupa1.resq.entity.Action; +import com.groupa1.resq.entity.Comment; import com.groupa1.resq.entity.Task; import com.groupa1.resq.entity.User; import com.groupa1.resq.exception.EntityNotFoundException; +import com.groupa1.resq.exception.NotOwnerException; import com.groupa1.resq.repository.ActionRepository; import com.groupa1.resq.repository.TaskRepository; import com.groupa1.resq.repository.UserRepository; +import com.groupa1.resq.request.CreateCommentRequest; import com.groupa1.resq.request.CreateActionRequest; import com.groupa1.resq.response.ActionResponse; +import jakarta.transaction.Transactional; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; -import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Service; -import org.springframework.web.bind.annotation.RequestBody; - import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.ArrayList; @@ -65,13 +65,39 @@ public ResponseEntity createAction(CreateActionRequest createActionReque Task task = taskRepository.findById(createActionRequest.getTaskId()).orElseThrow(()-> new EntityNotFoundException("No task found")); task.getActions().add(actionEntity); actionEntity.setTask(task); - - - actionRepository.save(actionEntity); return ResponseEntity.ok("Action saved successfully!"); + } + @Transactional + public ResponseEntity deleteAction(Long actionId){ + Action action = actionRepository.findById(actionId).orElse(null); + if (action == null){ + log.error("No action found with id: {}", actionId); + throw new EntityNotFoundException("No action found"); + } + actionRepository.delete(action); + return ResponseEntity.ok("Action deleted successfully"); + } + + @Transactional + public ResponseEntity updateAction(CreateActionRequest createActionRequest, Long actionId){ + Action action = actionRepository.findById(actionId).orElseThrow(()-> new EntityNotFoundException("No action found")); + User verifier = userRepository.findById(createActionRequest.getVerifierId()).orElseThrow(()-> new EntityNotFoundException("No user found")); + action.setTask(taskRepository.findById(createActionRequest.getTaskId()).orElseThrow(()-> new EntityNotFoundException("No task found"))); + action.setVerifier(verifier); + action.setDescription(createActionRequest.getDescription()); + action.setCompleted(createActionRequest.isCompleted()); + action.setVerified(createActionRequest.isVerified()); + action.setStartLatitude(createActionRequest.getStartLatitude()); + action.setStartLongitude(createActionRequest.getStartLongitude()); + action.setEndLatitude(createActionRequest.getEndLatitude()); + action.setEndLongitude(createActionRequest.getEndLongitude()); + action.setDueDate(createActionRequest.getDueDate()); + + actionRepository.save(action); + return ResponseEntity.ok("Action updated successfully"); } @@ -101,6 +127,89 @@ public ResponseEntity> viewActions(Long taskId){ } } + @Transactional + public ResponseEntity completeAction(Long actionId, Long userId){ + Action action = actionRepository.findById(actionId).orElse(null); + User user = userRepository.findById(userId).orElse(null); + if (action == null){ + log.error("No action found with id: {}", actionId); + throw new EntityNotFoundException("No action found"); + } + if (user == null){ + log.error("No user found with id: {}", userId); + throw new EntityNotFoundException("No user found"); + } + if (action.getTask().getAssignee().getId() != userId) { + log.error( + "User with id: {} is not the assignee for action with id: {}", + userId, actionId); + throw new NotOwnerException("User is not the assignee for action"); + } + action.setCompleted(true); + actionRepository.save(action); + return ResponseEntity.ok("Action completed by responder"); + + + + } + + @Transactional + public ResponseEntity verifyAction(Long actionId, Long userId) { + Action action = actionRepository.findById(actionId).orElse(null); + User user = userRepository.findById(userId).orElse(null); + + if (action == null) { + log.error("No action found with id: {}", actionId); + throw new EntityNotFoundException("No action found"); + } + if (user == null) { + log.error("No user found with id: {}", userId); + throw new EntityNotFoundException("No user found"); + } + if (action.getVerifier() == null) { + log.error("No verifier found for action with id: {}", actionId); + throw new EntityNotFoundException("No verifier found for action"); + } + if (action.getVerifier().getId() != userId) { + log.error( + "User with id: {} is not the verifier for action with id: {}", + userId, actionId); + throw new NotOwnerException("User is not the verifier for action"); + } + action.setVerified(true); + actionRepository.save(action); + return ResponseEntity.ok("Action verified by facilitator"); + } + + + public ResponseEntity commentAction( + CreateCommentRequest commentActionRequest) { + User user = userRepository.findById(commentActionRequest.getUserId()).orElse(null); + Action action = actionRepository.findById(commentActionRequest.getActionId()).orElse(null); + User verifier = action.getVerifier(); + if(action == null || user == null || verifier == null){ + log.error("Action, user, or action verifier is not found"); + throw new EntityNotFoundException("No action found"); + } + if (user.getId() != verifier.getId()){ + log.error("User with id: {} is not the verifier for action with id: {}", + user.getId(), action.getId()); + throw new NotOwnerException("User is not the verifier for action"); + } + Comment comment = new Comment(); + comment.setVerifier(user); + comment.setAction(action); + comment.setComment(commentActionRequest.getComment()); + action.getComments().add(comment); + return ResponseEntity.ok("Comment added successfully"); + +} + + + + + + diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/service/TaskService.java b/resq/backend/resq/src/main/java/com/groupa1/resq/service/TaskService.java index 95c461bc..41e27b26 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/service/TaskService.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/service/TaskService.java @@ -1,30 +1,39 @@ package com.groupa1.resq.service; +import com.fasterxml.jackson.databind.ObjectMapper; import com.groupa1.resq.entity.Action; +import com.groupa1.resq.entity.Feedback; import com.groupa1.resq.entity.Resource; import com.groupa1.resq.entity.Task; import com.groupa1.resq.entity.User; import com.groupa1.resq.entity.enums.EGender; import com.groupa1.resq.entity.enums.EStatus; import com.groupa1.resq.entity.enums.EUrgency; +import com.groupa1.resq.exception.EntityNotFoundException; import com.groupa1.resq.repository.TaskRepository; import com.groupa1.resq.repository.UserRepository; +import com.groupa1.resq.request.CreateFeedbackRequest; import com.groupa1.resq.request.CreateTaskRequest; import com.groupa1.resq.response.ActionResponse; import com.groupa1.resq.response.FeedbackResponse; import com.groupa1.resq.response.ResourceResponse; import com.groupa1.resq.response.TaskResponse; +import com.groupa1.resq.utils.NullAwareBeanUtilsBean; import jakarta.transaction.Transactional; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; +import org.springframework.web.bind.annotation.RequestParam; +import java.lang.reflect.InvocationTargetException; import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; @@ -42,6 +51,12 @@ public class TaskService { @Autowired private UserRepository userRepository; + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private NullAwareBeanUtilsBean beanUtils; + @Transactional @@ -54,7 +69,7 @@ public ResponseEntity createTask(CreateTaskRequest createTaskRequest) { List actionEntities = new ArrayList<>(); List resourceEntities = new ArrayList<>(); EUrgency urgency = createTaskRequest.getUrgency(); - EStatus status = EStatus.PENDING; // thought the default should be like pending + EStatus status = EStatus.PENDING; String description = createTaskRequest.getDescription(); @@ -114,7 +129,6 @@ public ResponseEntity createTask(CreateTaskRequest createTaskRequest) { } - public ResponseEntity acceptTask(Long taskId, Long userId) { Optional task = taskRepository.findById(taskId); if (task.isPresent()) { @@ -135,6 +149,21 @@ public ResponseEntity acceptTask(Long taskId, Long userId) { } } + public ResponseEntity declineTask(Long taskId, Long userId){ + Task task = taskRepository.findById(taskId).orElseThrow(()-> new EntityNotFoundException("No task found")); + User user = userRepository.findById(userId).orElseThrow(()-> new EntityNotFoundException("No user found")); + if (task.getAssignee().getId() != user.getId()){ + log.error("User is not the assignee of the task"); + return ResponseEntity.badRequest().body("User is not the assignee of the task"); + } + task.setStatus(EStatus.DECLINED); + taskRepository.save(task); + return ResponseEntity.ok("Task declined"); + } + + + + public ResponseEntity> viewAllTasks(Long userId) { Optional> tasks = taskRepository.findByAssignee(userId); List taskResponses = new ArrayList<>(); @@ -200,6 +229,79 @@ public ResponseEntity> viewAllTasks(Long userId) { } } + @Transactional + public ResponseEntity deleteTask(@RequestParam Long taskId){ + Task task = taskRepository.findById(taskId).orElseThrow(()-> new EntityNotFoundException("No task found")); + taskRepository.delete(task); + return ResponseEntity.ok("Task deleted successfully"); + } + + @Transactional + public ResponseEntity updateTask(Map fields, Long taskId) + + throws InvocationTargetException, IllegalAccessException { + //TODO: implement other update methods to update specific fields + Task task = taskRepository.findById(taskId).orElseThrow(()-> new EntityNotFoundException("No task found")); + Task updatedTask = objectMapper.convertValue(fields, Task.class); + beanUtils.copyProperties(task, updatedTask); // copy fields of updatedTask to task ignoring null values + taskRepository.save(task); + return ResponseEntity.ok("Task updated successfully"); + } + public ResponseEntity assignTask(Long taskId, Long userId){ + Task task = taskRepository.findById(taskId).orElseThrow(()-> new EntityNotFoundException("No task found")); + User user = userRepository.findById(userId).orElseThrow(()-> new EntityNotFoundException("No user found")); + task.setAssignee(user); + task.setStatus(EStatus.PENDING); + taskRepository.save(task); + // send notification to responder + return ResponseEntity.ok("Task assigned successfully"); + } + + public ResponseEntity unassignTask(Long taskId){ + Task task = taskRepository.findById(taskId).orElseThrow(()-> new EntityNotFoundException("No task found")); + task.setAssignee(null); + task.setStatus(EStatus.FREE); + taskRepository.save(task); + // send notification to responder + return ResponseEntity.ok("Task unassigned successfully"); + } + + public ResponseEntity completeTask(Long taskId, Long userId){ + Task task = taskRepository.findById(taskId).orElseThrow(()-> new EntityNotFoundException("No task found")); + User user = userRepository.findById(userId).orElseThrow(()-> new EntityNotFoundException("No user found")); + if (task.getAssignee().getId() != user.getId()){ + log.error("User is not the assignee of the task"); + return ResponseEntity.badRequest().body("User is not the assignee of the task"); + } + if (task.getStatus() != EStatus.TODO){ + log.error("Task is not in progress"); + return ResponseEntity.badRequest().body("Task is not in progress"); + } + Set actions = task.getActions(); + actions.stream().filter(action -> !action.isCompleted()); + if (actions.size() > 0){ + log.error("Task is not completed, there are actions not completed"); + return ResponseEntity.badRequest().body("Actions are not done"); + } + + task.setStatus(EStatus.DONE); + taskRepository.save(task); + // send notification to coordinator + return ResponseEntity.ok("Task completed"); + } + + public ResponseEntity giveFeedback(CreateFeedbackRequest feedbackRequest){ + Task task = taskRepository.findById(feedbackRequest.getTaskId()).orElseThrow(()-> new EntityNotFoundException("No task found")); + User user = userRepository.findById(feedbackRequest.getUserId()).orElseThrow(()-> new EntityNotFoundException("No user found")); + Feedback feedback = new Feedback(); + feedback.setCreator(user); + feedback.setMessage(feedbackRequest.getMessage()); + feedback.setTask(task); + task.getFeedbacks().add(feedback); + // send notification to coordinator + taskRepository.save(task); + return ResponseEntity.ok("Feedback saved successfully"); + } diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/utils/NullAwareBeanUtilsBean.java b/resq/backend/resq/src/main/java/com/groupa1/resq/utils/NullAwareBeanUtilsBean.java new file mode 100644 index 00000000..9a7afa76 --- /dev/null +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/utils/NullAwareBeanUtilsBean.java @@ -0,0 +1,19 @@ +package com.groupa1.resq.utils; + +import org.apache.commons.beanutils.BeanUtilsBean; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Component; + +import java.lang.reflect.InvocationTargetException; + +@Component +public class NullAwareBeanUtilsBean extends BeanUtilsBean { + + @Override + public void copyProperty(Object dest, String name, Object value) + throws IllegalAccessException, InvocationTargetException { + if (value == null) + return; + super.copyProperty(dest, name, value); + } +} From 88fc133e5f4076287f57e95d389e668e0e4d3a5b Mon Sep 17 00:00:00 2001 From: furknbulbul Date: Tue, 21 Nov 2023 14:23:12 +0300 Subject: [PATCH 02/12] fix --- .../java/com/groupa1/resq/controller/ActionController.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/controller/ActionController.java b/resq/backend/resq/src/main/java/com/groupa1/resq/controller/ActionController.java index 5a36eee4..daf8ea27 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/controller/ActionController.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/controller/ActionController.java @@ -68,12 +68,7 @@ public ResponseEntity verifyAction(@RequestBody return actionService.commentAction(commentActionRequest); } - //TODO -// @PreAuthorize("hasRole('FACILITATOR')") -// @PostMapping("/notifyCoordinator") -// public ResponseEntity notifyCoordinator(@RequestParam Long actionId){ -// return actionService.notifyCoordinator(actionId); -// } + From fb24fa9298e1ca13087912bb230b9b408f4cf3d9 Mon Sep 17 00:00:00 2001 From: furknbulbul Date: Tue, 21 Nov 2023 14:23:20 +0300 Subject: [PATCH 03/12] fix --- .../main/java/com/groupa1/resq/utils/NullAwareBeanUtilsBean.java | 1 - 1 file changed, 1 deletion(-) diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/utils/NullAwareBeanUtilsBean.java b/resq/backend/resq/src/main/java/com/groupa1/resq/utils/NullAwareBeanUtilsBean.java index 9a7afa76..ba92aa25 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/utils/NullAwareBeanUtilsBean.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/utils/NullAwareBeanUtilsBean.java @@ -1,7 +1,6 @@ package com.groupa1.resq.utils; import org.apache.commons.beanutils.BeanUtilsBean; -import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import java.lang.reflect.InvocationTargetException; From 3edf1b22c3437b2cda3a53a0a900f03749e2b26b Mon Sep 17 00:00:00 2001 From: furknbulbul Date: Tue, 21 Nov 2023 16:29:09 +0300 Subject: [PATCH 04/12] make resource response use senderId --- .../main/java/com/groupa1/resq/response/ResourceResponse.java | 2 +- .../src/main/java/com/groupa1/resq/service/TaskService.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/response/ResourceResponse.java b/resq/backend/resq/src/main/java/com/groupa1/resq/response/ResourceResponse.java index 1f9e98e3..d5089de7 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/response/ResourceResponse.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/response/ResourceResponse.java @@ -11,7 +11,7 @@ @Accessors(chain = true) public class ResourceResponse { private long id; - private User sender; + private Long senderId; private int quantity; private EGender gender; private String categoryId; diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/service/TaskService.java b/resq/backend/resq/src/main/java/com/groupa1/resq/service/TaskService.java index cbe6fd7a..a3cf17dd 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/service/TaskService.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/service/TaskService.java @@ -211,7 +211,7 @@ public ResponseEntity> viewAllTasks(Long userId) { task.getResources().forEach(resource -> { resourceResponse.setId(resource.getId()) - .setSender(resource.getSender()) + .setSenderId(resource.getSender().getId()) .setQuantity(resource.getQuantity()) .setGender(resource.getGender()) .setCategoryId(resource.getCategoryTreeId()) From c37c04a5a43f7af9ee89980a14c695fc5f97703a Mon Sep 17 00:00:00 2001 From: furknbulbul Date: Sat, 25 Nov 2023 14:35:35 +0300 Subject: [PATCH 05/12] utils directory fix --- .../src/main/java/com/groupa1/resq/service/TaskService.java | 2 +- .../groupa1/resq/{utils => util}/NullAwareBeanUtilsBean.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename resq/backend/resq/src/main/java/com/groupa1/resq/{utils => util}/NullAwareBeanUtilsBean.java (93%) diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/service/TaskService.java b/resq/backend/resq/src/main/java/com/groupa1/resq/service/TaskService.java index a3cf17dd..35364a3e 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/service/TaskService.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/service/TaskService.java @@ -20,7 +20,7 @@ import com.groupa1.resq.response.FeedbackResponse; import com.groupa1.resq.response.ResourceResponse; import com.groupa1.resq.response.TaskResponse; -import com.groupa1.resq.utils.NullAwareBeanUtilsBean; +import com.groupa1.resq.util.NullAwareBeanUtilsBean; import com.groupa1.resq.util.NotificationMessages; import jakarta.transaction.Transactional; import lombok.extern.slf4j.Slf4j; diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/utils/NullAwareBeanUtilsBean.java b/resq/backend/resq/src/main/java/com/groupa1/resq/util/NullAwareBeanUtilsBean.java similarity index 93% rename from resq/backend/resq/src/main/java/com/groupa1/resq/utils/NullAwareBeanUtilsBean.java rename to resq/backend/resq/src/main/java/com/groupa1/resq/util/NullAwareBeanUtilsBean.java index ba92aa25..6a03da5b 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/utils/NullAwareBeanUtilsBean.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/util/NullAwareBeanUtilsBean.java @@ -1,4 +1,4 @@ -package com.groupa1.resq.utils; +package com.groupa1.resq.util; import org.apache.commons.beanutils.BeanUtilsBean; import org.springframework.stereotype.Component; From 89375a84165a1be6231326feab5717bc6708cd75 Mon Sep 17 00:00:00 2001 From: furknbulbul Date: Sat, 25 Nov 2023 17:51:18 +0300 Subject: [PATCH 06/12] convert map to object --- .../java/com/groupa1/resq/controller/TaskController.java | 7 +++---- .../main/java/com/groupa1/resq/service/TaskService.java | 5 ++--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/controller/TaskController.java b/resq/backend/resq/src/main/java/com/groupa1/resq/controller/TaskController.java index e47c1d9a..e67c7d5f 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/controller/TaskController.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/controller/TaskController.java @@ -1,6 +1,6 @@ package com.groupa1.resq.controller; -import com.groupa1.resq.request.CreateActionRequest; +import com.groupa1.resq.entity.Task; import com.groupa1.resq.request.CreateFeedbackRequest; import com.groupa1.resq.request.CreateTaskRequest; import com.groupa1.resq.response.TaskResponse; @@ -19,7 +19,6 @@ import java.lang.reflect.InvocationTargetException; import java.util.List; -import java.util.Map; @RestController @Slf4j @@ -65,9 +64,9 @@ public ResponseEntity deleteTask(@RequestParam Long taskId) { @PreAuthorize("hasRole('COORDINATOR')") @PatchMapping("/updateTask") public ResponseEntity updateTask(@RequestBody - Map fields, @RequestParam Long taskId) + Task newTask, @RequestParam Long taskId) throws InvocationTargetException, IllegalAccessException { - return taskService.updateTask(fields, taskId); + return taskService.updateTask(newTask, taskId); } @PreAuthorize("hasRole('COORDINATOR')") diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/service/TaskService.java b/resq/backend/resq/src/main/java/com/groupa1/resq/service/TaskService.java index 35364a3e..9f9cb71c 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/service/TaskService.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/service/TaskService.java @@ -249,13 +249,12 @@ public ResponseEntity deleteTask(@RequestParam Long taskId){ } @Transactional - public ResponseEntity updateTask(Map fields, Long taskId) + public ResponseEntity updateTask(Task newTask, Long taskId) throws InvocationTargetException, IllegalAccessException { //TODO: implement other update methods to update specific fields Task task = taskRepository.findById(taskId).orElseThrow(()-> new EntityNotFoundException("No task found")); - Task updatedTask = objectMapper.convertValue(fields, Task.class); - beanUtils.copyProperties(task, updatedTask); // copy fields of updatedTask to task ignoring null values + beanUtils.copyProperties(task, newTask); // copy fields of updatedTask to task ignoring null values taskRepository.save(task); return ResponseEntity.ok("Task updated successfully"); } From a9b8a1b7af3a5f9fa804999a7a898bfc73d79a00 Mon Sep 17 00:00:00 2001 From: furknbulbul Date: Mon, 18 Dec 2023 16:39:51 +0300 Subject: [PATCH 07/12] implement actionDto, specifications, --- .../resq/controller/ActionController.java | 17 ++++++-- .../resq/converter/ActionConverter.java | 28 +++++++++++++ .../ActionDto.java} | 8 ++-- .../resq/repository/ActionRepository.java | 6 +++ .../groupa1/resq/service/ActionService.java | 41 ++++++++++++++----- .../specification/ActionSpecifications.java | 31 ++++++++++++++ 6 files changed, 114 insertions(+), 17 deletions(-) create mode 100644 resq/backend/resq/src/main/java/com/groupa1/resq/converter/ActionConverter.java rename resq/backend/resq/src/main/java/com/groupa1/resq/{response/ActionResponse.java => dto/ActionDto.java} (81%) create mode 100644 resq/backend/resq/src/main/java/com/groupa1/resq/specification/ActionSpecifications.java diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/controller/ActionController.java b/resq/backend/resq/src/main/java/com/groupa1/resq/controller/ActionController.java index daf8ea27..ed378562 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/controller/ActionController.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/controller/ActionController.java @@ -2,7 +2,7 @@ import com.groupa1.resq.request.CreateCommentRequest; import com.groupa1.resq.request.CreateActionRequest; -import com.groupa1.resq.response.ActionResponse; +import com.groupa1.resq.dto.ActionDto; import com.groupa1.resq.service.ActionService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; @@ -14,6 +14,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import java.time.LocalDateTime; import java.util.List; @RestController @@ -26,13 +27,13 @@ public class ActionController { @PreAuthorize("hasRole('COORDINATOR')") @PostMapping("/createAction") - public ResponseEntity createAction(@RequestBody CreateActionRequest createActionRequest){ + public ResponseEntity createAction(@RequestBody CreateActionRequest createActionRequest){ return actionService.createAction(createActionRequest); } @PreAuthorize("hasRole('RESPONDER') or hasRole('COORDINATOR')") @GetMapping("/viewActions") - public ResponseEntity> viewActions(@RequestParam Long taskId) { + public ResponseEntity> viewActions(@RequestParam Long taskId) { return actionService.viewActions( taskId); } @@ -68,6 +69,16 @@ public ResponseEntity verifyAction(@RequestBody return actionService.commentAction(commentActionRequest); } + @PreAuthorize("hasRole('COORDINATOR') or hasRole('FACILITATOR')") + @GetMapping("/filterAction") + public ResponseEntity> viewActionsByFilter(@RequestParam(required = false) Long verifierId, + @RequestParam(required = false) Boolean isCompleted, + @RequestParam(required = false) LocalDateTime latestDueDate, + @RequestParam(required = false) LocalDateTime earliestDueDate){ + + return actionService.viewActionsByFilter(verifierId, isCompleted, latestDueDate, earliestDueDate); + } + diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/converter/ActionConverter.java b/resq/backend/resq/src/main/java/com/groupa1/resq/converter/ActionConverter.java new file mode 100644 index 00000000..5a441a72 --- /dev/null +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/converter/ActionConverter.java @@ -0,0 +1,28 @@ +package com.groupa1.resq.converter; + +import com.groupa1.resq.dto.ActionDto; +import com.groupa1.resq.entity.Action; +import org.springframework.stereotype.Service; + +@Service +public class ActionConverter { + + public ActionDto convertToDto(Action action){ + ActionDto actionDto = new ActionDto(); + actionDto.setId(action.getId()); + actionDto.setTaskId(action.getTask().getId()); + if (action.getVerifier() != null) { + actionDto.setVerifierId(action.getVerifier().getId()); + } + actionDto.setDescription(action.getDescription()); + actionDto.setCompleted(action.isCompleted()); + actionDto.setStartLatitude(action.getStartLatitude()); + actionDto.setStartLongitude(action.getStartLongitude()); + actionDto.setEndLatitude(action.getEndLatitude()); + actionDto.setEndLongitude(action.getEndLongitude()); + actionDto.setDueDate(action.getDueDate()); + actionDto.setCreatedDate(action.getCreatedAt()); + return actionDto; + + } +} diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/response/ActionResponse.java b/resq/backend/resq/src/main/java/com/groupa1/resq/dto/ActionDto.java similarity index 81% rename from resq/backend/resq/src/main/java/com/groupa1/resq/response/ActionResponse.java rename to resq/backend/resq/src/main/java/com/groupa1/resq/dto/ActionDto.java index e7061f3a..fea75201 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/response/ActionResponse.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/dto/ActionDto.java @@ -1,4 +1,4 @@ -package com.groupa1.resq.response; +package com.groupa1.resq.dto; import lombok.Data; import lombok.experimental.Accessors; @@ -8,9 +8,9 @@ @Data @Accessors(chain = true) -public class ActionResponse { - private long id; - private long taskId; +public class ActionDto { + private Long id; + private Long taskId; private long verifierId; private String description; private boolean isCompleted; diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/repository/ActionRepository.java b/resq/backend/resq/src/main/java/com/groupa1/resq/repository/ActionRepository.java index fad19f0a..05585882 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/repository/ActionRepository.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/repository/ActionRepository.java @@ -1,7 +1,13 @@ package com.groupa1.resq.repository; import com.groupa1.resq.entity.Action; +import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.List; + public interface ActionRepository extends JpaRepository { + + List findAll(Specification specification); + } diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/service/ActionService.java b/resq/backend/resq/src/main/java/com/groupa1/resq/service/ActionService.java index 9ab166c1..93481b20 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/service/ActionService.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/service/ActionService.java @@ -1,6 +1,7 @@ package com.groupa1.resq.service; +import com.groupa1.resq.converter.ActionConverter; import com.groupa1.resq.entity.Action; import com.groupa1.resq.entity.Comment; import com.groupa1.resq.entity.Task; @@ -13,11 +14,13 @@ import com.groupa1.resq.repository.UserRepository; import com.groupa1.resq.request.CreateCommentRequest; import com.groupa1.resq.request.CreateActionRequest; -import com.groupa1.resq.response.ActionResponse; +import com.groupa1.resq.dto.ActionDto; +import com.groupa1.resq.specification.ActionSpecifications; import com.groupa1.resq.util.NotificationMessages; import jakarta.transaction.Transactional; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.jpa.domain.Specification; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import java.math.BigDecimal; @@ -43,8 +46,13 @@ public class ActionService { @Autowired private NotificationService notificationService; + @Autowired + private ActionConverter actionConverter; + + - public ResponseEntity createAction(CreateActionRequest createActionRequest) { + + public ResponseEntity createAction(CreateActionRequest createActionRequest) { if (!taskRepository.existsById(createActionRequest.getTaskId())){ return ResponseEntity.badRequest().body("No task found"); } @@ -71,8 +79,7 @@ public ResponseEntity createAction(CreateActionRequest createActionReque Task task = taskRepository.findById(createActionRequest.getTaskId()).orElseThrow(()-> new EntityNotFoundException("No task found")); task.getActions().add(actionEntity); actionEntity.setTask(task); - actionRepository.save(actionEntity); - return ResponseEntity.ok("Action saved successfully!"); + return ResponseEntity.ok(actionRepository.save(actionEntity).getId()); } @@ -91,7 +98,6 @@ public ResponseEntity deleteAction(Long actionId){ public ResponseEntity updateAction(CreateActionRequest createActionRequest, Long actionId){ Action action = actionRepository.findById(actionId).orElseThrow(()-> new EntityNotFoundException("No action found")); User verifier = userRepository.findById(createActionRequest.getVerifierId()).orElseThrow(()-> new EntityNotFoundException("No user found")); - action.setTask(taskRepository.findById(createActionRequest.getTaskId()).orElseThrow(()-> new EntityNotFoundException("No task found"))); action.setVerifier(verifier); action.setDescription(createActionRequest.getDescription()); action.setCompleted(createActionRequest.isCompleted()); @@ -107,13 +113,13 @@ public ResponseEntity updateAction(CreateActionRequest createActionReque } - public ResponseEntity> viewActions(Long taskId){ + public ResponseEntity> viewActions(Long taskId){ Optional task = taskRepository.findById(taskId); - List actionResponses = new ArrayList<>(); + List actionResponses = new ArrayList<>(); if (task.isPresent()) { Set actions = task.get().getActions(); actions.forEach(action -> { - ActionResponse actionResponse = new ActionResponse(); + ActionDto actionResponse = new ActionDto(); actionResponse.setId(action.getId()) .setTaskId(action.getTask().getId()) .setVerifierId(action.getVerifier().getId()) @@ -217,14 +223,29 @@ public ResponseEntity commentAction( action.getComments().add(comment); return ResponseEntity.ok("Comment added successfully"); -} - + } + public ResponseEntity> viewActionsByFilter(Long verifierId, Boolean isCompleted, LocalDateTime latestDueDate, LocalDateTime earliestDueDate) { + Specification spec = Specification.where(null); + if (verifierId != null) { + spec = spec.and(ActionSpecifications.hasVerifier(verifierId)); + } + if (isCompleted != null) { + spec = spec.and(ActionSpecifications.hasCompleted(isCompleted)); + } + if (latestDueDate != null) { + spec = spec.and(ActionSpecifications.hasLatestDueDate(latestDueDate)); + } + if (earliestDueDate != null) { + spec = spec.and(ActionSpecifications.hasEarliestDueDate(earliestDueDate)); + } + return ResponseEntity.ok(actionRepository.findAll(spec).stream().map(action -> actionConverter.convertToDto(action)).toList()); + } } diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/specification/ActionSpecifications.java b/resq/backend/resq/src/main/java/com/groupa1/resq/specification/ActionSpecifications.java new file mode 100644 index 00000000..ebb084d5 --- /dev/null +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/specification/ActionSpecifications.java @@ -0,0 +1,31 @@ +package com.groupa1.resq.specification; + +import com.groupa1.resq.entity.Action; +import org.springframework.data.jpa.domain.Specification; + +import java.time.LocalDateTime; + +public class ActionSpecifications { + public static Specification hasVerifier(Long verifierId) { + return (root, query, criteriaBuilder) -> + criteriaBuilder.equal(root.get("verifier").get("id"), verifierId); + } + + public static Specification hasCompleted(Boolean completed) { + return (root, query, criteriaBuilder) -> + criteriaBuilder.equal(root.get("isCompleted"), completed); + } + + public static Specification hasRequest(Long requestId) { + return (root, query, criteriaBuilder) -> + criteriaBuilder.equal(root.get("request").get("id"), requestId); + } + public static Specification hasLatestDueDate(LocalDateTime dueDate) { + return (root, query, criteriaBuilder) -> + criteriaBuilder.lessThanOrEqualTo(root.get("dueDate"), dueDate); + } + public static Specification hasEarliestDueDate(LocalDateTime dueDate) { + return (root, query, criteriaBuilder) -> + criteriaBuilder.greaterThanOrEqualTo(root.get("dueDate"), dueDate); + } +} From 7f9a90d652515ab33c9120d94e914b5639cfc561 Mon Sep 17 00:00:00 2001 From: furknbulbul Date: Mon, 18 Dec 2023 16:41:10 +0300 Subject: [PATCH 08/12] implement taskDto --- .../resq/controller/TaskController.java | 52 ++-- .../groupa1/resq/converter/TaskConverter.java | 48 ++++ .../TaskResponse.java => dto/TaskDto.java} | 12 +- .../java/com/groupa1/resq/entity/Task.java | 4 +- .../resq/repository/TaskRepository.java | 2 + .../resq/request/CreateActionRequest.java | 1 + .../resq/request/CreateTaskRequest.java | 27 +- .../resq/request/UpdateTaskRequest.java | 12 + .../com/groupa1/resq/service/TaskService.java | 230 ++++++++---------- .../specification/TaskSpecifications.java | 26 ++ .../resq/service/ActionServiceTest.java | 29 +-- .../groupa1/resq/service/TaskServiceTest.java | 64 ----- 12 files changed, 240 insertions(+), 267 deletions(-) create mode 100644 resq/backend/resq/src/main/java/com/groupa1/resq/converter/TaskConverter.java rename resq/backend/resq/src/main/java/com/groupa1/resq/{response/TaskResponse.java => dto/TaskDto.java} (60%) create mode 100644 resq/backend/resq/src/main/java/com/groupa1/resq/request/UpdateTaskRequest.java create mode 100644 resq/backend/resq/src/main/java/com/groupa1/resq/specification/TaskSpecifications.java diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/controller/TaskController.java b/resq/backend/resq/src/main/java/com/groupa1/resq/controller/TaskController.java index e67c7d5f..9a5bd44a 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/controller/TaskController.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/controller/TaskController.java @@ -1,14 +1,17 @@ package com.groupa1.resq.controller; -import com.groupa1.resq.entity.Task; -import com.groupa1.resq.request.CreateFeedbackRequest; +import com.groupa1.resq.auth.UserDetailsImpl; +import com.groupa1.resq.entity.enums.EStatus; +import com.groupa1.resq.request.AddResourceToTaskRequest; import com.groupa1.resq.request.CreateTaskRequest; -import com.groupa1.resq.response.TaskResponse; +import com.groupa1.resq.dto.TaskDto; +import com.groupa1.resq.request.UpdateTaskRequest; import com.groupa1.resq.service.TaskService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.Authentication; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PostMapping; @@ -16,8 +19,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; - -import java.lang.reflect.InvocationTargetException; import java.util.List; @RestController @@ -30,7 +31,7 @@ public class TaskController { @PreAuthorize("hasRole('COORDINATOR')") @PostMapping("/createTask") - public ResponseEntity createTask(@RequestBody CreateTaskRequest createTaskRequest) { + public ResponseEntity createTask(@RequestBody CreateTaskRequest createTaskRequest) { return taskService.createTask(createTaskRequest); } @@ -51,8 +52,8 @@ public ResponseEntity declineTask(@RequestParam Long taskId, @RequestPar @PreAuthorize("hasRole('RESPONDER') or hasRole('COORDINATOR')") @GetMapping("/viewTasks") - public ResponseEntity> viewAllTasks(@RequestParam Long userId) { - return taskService.viewAllTasks(userId); + public ResponseEntity> viewTasks(@RequestParam Long userId) { + return taskService.viewTasks(userId); } @PreAuthorize("hasRole('COORDINATOR')") @@ -64,9 +65,8 @@ public ResponseEntity deleteTask(@RequestParam Long taskId) { @PreAuthorize("hasRole('COORDINATOR')") @PatchMapping("/updateTask") public ResponseEntity updateTask(@RequestBody - Task newTask, @RequestParam Long taskId) - throws InvocationTargetException, IllegalAccessException { - return taskService.updateTask(newTask, taskId); + UpdateTaskRequest updateTaskRequest, @RequestParam Long taskId){ + return taskService.updateTask(updateTaskRequest, taskId); } @PreAuthorize("hasRole('COORDINATOR')") @@ -82,19 +82,37 @@ public ResponseEntity unassignTask(@RequestParam Long taskId, @RequestPa } - @PreAuthorize("hasRole('RESPPONDER')") + @PreAuthorize("hasRole('RESPONDER')") @PostMapping("/completeTask") - public ResponseEntity completeTask(@RequestParam Long taskId, @RequestParam Long userId) { + public ResponseEntity completeTask(@RequestParam Long taskId, Authentication authentication) { + UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal(); + Long userId = userDetails.getId(); return taskService.completeTask(taskId, userId); } - @PreAuthorize("hasRole('RESPONDER')") - @PostMapping("/giveFeedback") - public ResponseEntity giveFeedback(CreateFeedbackRequest feedback) { - return taskService.giveFeedback(feedback); + @PreAuthorize("hasRole('COORDINATOR')") + @PostMapping("/addResources") + public ResponseEntity addResources(@RequestBody AddResourceToTaskRequest addResourceToTaskRequest) { + return taskService.addResources(addResourceToTaskRequest); } + @PreAuthorize("hasRole('COORDINATOR')") + @PostMapping("/removeResources") + public ResponseEntity removeResources(AddResourceToTaskRequest addResourceToTaskRequest) { + return taskService.removeResources(addResourceToTaskRequest); + } + + + @PreAuthorize("hasRole('COORDINATOR') or hasRole('RESPONDER')") + @GetMapping("/viewTaskByFilter") + public ResponseEntity> viewTaskByFilter( @RequestParam(required = false) EStatus status, @RequestParam(required=false) Long assignerId, @RequestParam(required=false) Long assigneeId) { + return taskService.viewTasksByFilter(assignerId,assigneeId, status); + } + + + + diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/converter/TaskConverter.java b/resq/backend/resq/src/main/java/com/groupa1/resq/converter/TaskConverter.java new file mode 100644 index 00000000..13c64c47 --- /dev/null +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/converter/TaskConverter.java @@ -0,0 +1,48 @@ +package com.groupa1.resq.converter; + +import com.groupa1.resq.dto.ActionDto; +import com.groupa1.resq.dto.FeedbackDto; +import com.groupa1.resq.dto.ResourceDto; +import com.groupa1.resq.dto.TaskDto; +import com.groupa1.resq.entity.Task; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.HashSet; +import java.util.Set; + +@Service +public class TaskConverter { + + @Autowired + private ActionConverter actionConverter; + + @Autowired + private ResourceConverter resourceConverter; + + @Autowired + private FeedbackConverter feedbackConverter; + + + public TaskDto convertToDto(Task task){ + TaskDto taskDto = new TaskDto(); + taskDto.setId(task.getId()); + taskDto.setAssignee(task.getAssignee().getId()); + taskDto.setAssigner(task.getAssigner().getId()); + taskDto.setStatus(task.getStatus()); + Set taskActions = new HashSet<>(task.getActions().stream() + .map(action -> actionConverter.convertToDto(action)).toList()); + taskDto.setActions(taskActions); + taskDto.setDescription(task.getDescription()); + Set taskResources = new HashSet<>(task.getResources().stream() + .map(resource ->resourceConverter.convertToDto(resource)).toList()); + taskDto.setResources(taskResources); + Set taskFeedbacks = new HashSet<>(task.getFeedbacks().stream() + .map(feedback ->feedbackConverter.convertToDto(feedback)).toList()); + taskDto.setFeedbacks(taskFeedbacks); + taskDto.setUrgency(task.getUrgency()); + taskDto.setCreatedDate(task.getCreatedAt()); + return taskDto; + + } +} diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/response/TaskResponse.java b/resq/backend/resq/src/main/java/com/groupa1/resq/dto/TaskDto.java similarity index 60% rename from resq/backend/resq/src/main/java/com/groupa1/resq/response/TaskResponse.java rename to resq/backend/resq/src/main/java/com/groupa1/resq/dto/TaskDto.java index a7a91608..5c62d1da 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/response/TaskResponse.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/dto/TaskDto.java @@ -1,23 +1,25 @@ -package com.groupa1.resq.response; +package com.groupa1.resq.dto; import com.groupa1.resq.entity.enums.EStatus; import com.groupa1.resq.entity.enums.EUrgency; import lombok.Data; import lombok.experimental.Accessors; +import java.time.LocalDateTime; import java.util.Set; @Data @Accessors(chain = true) -public class TaskResponse { +public class TaskDto { private long id; private long assignee; private long assigner; - private Set actions; + private Set actions; private String description; - private Set resources; - private Set feedbacks; + private Set resources; + private Set feedbacks; private EUrgency urgency; private EStatus status; + private LocalDateTime createdDate; } diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/entity/Task.java b/resq/backend/resq/src/main/java/com/groupa1/resq/entity/Task.java index 3c762b35..9a30b83e 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/entity/Task.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/entity/Task.java @@ -25,10 +25,10 @@ public class Task extends BaseEntity { @JoinColumn(name = "assigner_id") private User assigner; - @OneToMany(fetch = FetchType.LAZY, mappedBy="task") + @OneToMany(fetch = FetchType.LAZY, mappedBy="task", cascade = CascadeType.ALL) private Set actions; - @OneToMany(fetch = FetchType.LAZY) + @OneToMany(fetch = FetchType.LAZY, mappedBy = "task", cascade = CascadeType.ALL) private Set resources; @OneToMany(fetch = FetchType.LAZY, mappedBy="task") diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/repository/TaskRepository.java b/resq/backend/resq/src/main/java/com/groupa1/resq/repository/TaskRepository.java index cbabddb0..2055482a 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/repository/TaskRepository.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/repository/TaskRepository.java @@ -1,6 +1,7 @@ package com.groupa1.resq.repository; import com.groupa1.resq.entity.Task; +import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; @@ -14,4 +15,5 @@ public interface TaskRepository extends JpaRepository{ @Query("SELECT t FROM Task t WHERE t.assignee.id = ?1") Optional> findByAssignee(Long userId); + List findAll(Specification specifications); } diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/request/CreateActionRequest.java b/resq/backend/resq/src/main/java/com/groupa1/resq/request/CreateActionRequest.java index f2f2a6e4..408a7c1c 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/request/CreateActionRequest.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/request/CreateActionRequest.java @@ -5,6 +5,7 @@ import java.math.BigDecimal; import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; @Data diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/request/CreateTaskRequest.java b/resq/backend/resq/src/main/java/com/groupa1/resq/request/CreateTaskRequest.java index 14d89ecc..306493c4 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/request/CreateTaskRequest.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/request/CreateTaskRequest.java @@ -8,6 +8,7 @@ import lombok.Data; import java.math.BigDecimal; +import java.time.LocalDateTime; import java.util.List; @JsonInclude(JsonInclude.Include.NON_NULL) @@ -16,33 +17,7 @@ public class CreateTaskRequest { private Long assignerId; private Long assigneeId; private String description; - private List actions; - private List resources; private EUrgency urgency; - private EStatus status; - - @Data - public static class Action { - private Long verifierId; - private String description; - private BigDecimal startLatitude; - private BigDecimal startLongitude; - private BigDecimal endLatitude; - private BigDecimal endLongitude; - } - - @Data - public static class Resource { - private Long senderId; - private String categoryTreeId; - private EGender gender; - private Integer quantity; - private BigDecimal latitude; - private BigDecimal longitude; - - - } - } diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/request/UpdateTaskRequest.java b/resq/backend/resq/src/main/java/com/groupa1/resq/request/UpdateTaskRequest.java new file mode 100644 index 00000000..f9f34251 --- /dev/null +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/request/UpdateTaskRequest.java @@ -0,0 +1,12 @@ +package com.groupa1.resq.request; + +import com.groupa1.resq.entity.enums.EStatus; +import com.groupa1.resq.entity.enums.EUrgency; +import lombok.Data; + +@Data +public class UpdateTaskRequest { + private String description; + private EUrgency urgency; + private EStatus status; +} diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/service/TaskService.java b/resq/backend/resq/src/main/java/com/groupa1/resq/service/TaskService.java index 9f9cb71c..d6d72b29 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/service/TaskService.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/service/TaskService.java @@ -1,47 +1,44 @@ package com.groupa1.resq.service; import com.fasterxml.jackson.databind.ObjectMapper; +import com.groupa1.resq.converter.ActionConverter; +import com.groupa1.resq.converter.TaskConverter; import com.groupa1.resq.entity.Action; -import com.groupa1.resq.entity.Feedback; import com.groupa1.resq.entity.Resource; import com.groupa1.resq.entity.Task; import com.groupa1.resq.entity.User; -import com.groupa1.resq.entity.enums.EGender; import com.groupa1.resq.entity.enums.ENotificationEntityType; +import com.groupa1.resq.entity.enums.EResourceStatus; import com.groupa1.resq.entity.enums.EStatus; import com.groupa1.resq.entity.enums.EUrgency; import com.groupa1.resq.exception.EntityNotFoundException; import com.groupa1.resq.repository.ActionRepository; +import com.groupa1.resq.repository.ResourceRepository; import com.groupa1.resq.repository.TaskRepository; import com.groupa1.resq.repository.UserRepository; -import com.groupa1.resq.request.CreateFeedbackRequest; +import com.groupa1.resq.request.AddResourceToTaskRequest; import com.groupa1.resq.request.CreateTaskRequest; -import com.groupa1.resq.response.ActionResponse; -import com.groupa1.resq.response.FeedbackResponse; -import com.groupa1.resq.response.ResourceResponse; -import com.groupa1.resq.response.TaskResponse; +import com.groupa1.resq.dto.TaskDto; +import com.groupa1.resq.request.UpdateTaskRequest; +import com.groupa1.resq.specification.TaskSpecifications; import com.groupa1.resq.util.NullAwareBeanUtilsBean; import com.groupa1.resq.util.NotificationMessages; import jakarta.transaction.Transactional; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.jpa.domain.Specification; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.web.bind.annotation.RequestParam; - -import java.lang.reflect.InvocationTargetException; -import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.Set; @Service @Slf4j - public class TaskService { @Autowired @@ -65,13 +62,26 @@ public class TaskService { @Autowired NotificationService notificationService; + @Autowired + private ActionConverter actionConverter; + + @Autowired + private TaskConverter taskConverter; + + @Autowired + private ResourceRepository resourceRepository; + @Transactional - public ResponseEntity createTask(CreateTaskRequest createTaskRequest) { + public ResponseEntity createTask(CreateTaskRequest createTaskRequest) { if (createTaskRequest.getAssigneeId() == null || createTaskRequest.getAssignerId() == null) { return ResponseEntity.badRequest().body("Assignee and assigner must be specified"); } - User assignee = userService.findById(createTaskRequest.getAssigneeId()); User assigner = userService.findById(createTaskRequest.getAssignerId()); + User assignee = userService.findById(createTaskRequest.getAssigneeId()); + +// if (!assignee.getRoles().contains("RESPONDER")){ +// return ResponseEntity.badRequest().body("Assignee must be a responder"); +// } List actionEntities = new ArrayList<>(); List resourceEntities = new ArrayList<>(); EUrgency urgency = createTaskRequest.getUrgency(); @@ -79,45 +89,6 @@ public ResponseEntity createTask(CreateTaskRequest createTaskRequest) { String description = createTaskRequest.getDescription(); - createTaskRequest.getActions().forEach(action -> { - Action actionEntity = new Action(); - User verifier = userService.findById(action.getVerifierId()); - String actionDescription = action.getDescription(); - BigDecimal startLatitude = action.getStartLatitude(); - BigDecimal startLongitude = action.getStartLongitude(); - BigDecimal endLatitude = action.getEndLatitude(); - BigDecimal endLongitude = action.getEndLongitude(); - actionEntity.setVerifier(verifier); - actionEntity.setDescription(actionDescription); - actionEntity.setCompleted(false); - actionEntity.setStartLatitude(startLatitude); - actionEntity.setStartLongitude(startLongitude); - actionEntity.setEndLatitude(endLatitude); - actionEntity.setEndLongitude(endLongitude); - actionEntity.setCreatedAt(LocalDateTime.now()); - actionEntities.add(actionEntity); - - }); - - createTaskRequest.getResources().forEach( resource -> { - Resource resourceEntity = new Resource(); - User owner = userService.findById(resource.getSenderId()); - String categoryTreeId = resource.getCategoryTreeId();// I think this should a different calculation - EGender gender = resource.getGender(); - Integer quantity = resource.getQuantity(); - BigDecimal latitude = resource.getLatitude(); - BigDecimal longitude = resource.getLongitude(); - resourceEntity.setSender(owner); - resourceEntity.setCategoryTreeId(categoryTreeId); - resourceEntity.setQuantity(quantity); - resourceEntity.setGender(gender); - resourceEntity.setLatitude(latitude); - resourceEntity.setLongitude(longitude); - resourceEntity.setCreatedAt(LocalDateTime.now()); - resourceEntities.add(resourceEntity); - } - ); - Task task = new Task(); task.setAssignee(assignee); task.setAssigner(assigner); @@ -127,23 +98,24 @@ public ResponseEntity createTask(CreateTaskRequest createTaskRequest) { task.setActions(new HashSet<>(actionEntities)); task.setResources(new HashSet<>(resourceEntities)); task.setCreatedAt(LocalDateTime.now()); - - Task savedTask = taskRepository.save(task); - actionEntities.forEach(action -> { - action.setTask(savedTask); - }); - actionRepository.saveAll(actionEntities); + task.setModifiedAt(LocalDateTime.now()); + actionRepository.saveAll(actionEntities); + Task savedTask = taskRepository.save(task); String bodyMessage = String.format(NotificationMessages.TASK_ASSIGNED, assigner.getId(), task.getId()); notificationService.sendNotification("New Task Assigned", bodyMessage, assignee.getId(), task.getId(), ENotificationEntityType.TASK); - return ResponseEntity.ok("Task saved successfully"); + return ResponseEntity.ok(savedTask.getId()); } public ResponseEntity acceptTask(Long taskId, Long userId) { Optional task = taskRepository.findById(taskId); if (task.isPresent()) { + if (task.get().getAssignee().getId() != userId){ + log.error("User is not the assignee of the task"); + return ResponseEntity.badRequest().body("User is not the assignee of the task"); + } Optional user = userRepository.findById(userId); if (user.isPresent()){ task.get().setAssignee(user.get()); @@ -176,63 +148,14 @@ public ResponseEntity declineTask(Long taskId, Long userId){ - public ResponseEntity> viewAllTasks(Long userId) { + public ResponseEntity> viewTasks(Long userId) { Optional> tasks = taskRepository.findByAssignee(userId); - List taskResponses = new ArrayList<>(); + List taskResponses = new ArrayList<>(); if (tasks.isPresent()) { for (Task task : tasks.get()) { - TaskResponse taskResponse = new TaskResponse(); - taskResponse.setId(task.getId()) - .setAssignee(task.getAssignee().getId()) - .setAssigner(task.getAssigner().getId()); - Set actions = task.getActions(); - Set taskActions = new HashSet<>(); - actions.forEach( action -> { - ActionResponse actionResponse = new ActionResponse(); - actionResponse.setId(action.getId()) - .setTaskId(action.getTask().getId()) - .setVerifierId(action.getVerifier().getId()) - .setDescription(action.getDescription()) - .setCompleted(action.isCompleted()) - .setStartLatitude(action.getStartLatitude()) - .setStartLongitude(action.getStartLongitude()) - .setEndLatitude(action.getEndLatitude()) - .setEndLongitude(action.getEndLongitude()) - .setDueDate(action.getDueDate()); - taskActions.add(actionResponse); - }); - taskResponse.setActions(taskActions); - taskResponse.setDescription(task.getDescription()); - taskResponse.setUrgency(task.getUrgency()); - taskResponse.setStatus(task.getStatus()); - - Set taskResources = new HashSet<>(); - ResourceResponse resourceResponse = new ResourceResponse(); - task.getResources().forEach(resource -> { - - resourceResponse.setId(resource.getId()) - .setSenderId(resource.getSender().getId()) - .setQuantity(resource.getQuantity()) - .setGender(resource.getGender()) - .setCategoryId(resource.getCategoryTreeId()) - .setLatitude(resource.getLatitude()) - .setLongitude(resource.getLongitude()); - taskResources.add(resourceResponse); - }); - Set taskFeedbacks = new HashSet<>(); - task.getFeedbacks().forEach(feedback -> { - FeedbackResponse feedbackResponse = new FeedbackResponse(); - feedbackResponse.setId(feedback.getId()) - .setTaskId(feedback.getTask().getId()) - .setUserId(feedback.getCreator().getId()) - .setMessage(feedback.getMessage()); - taskFeedbacks.add(feedbackResponse); - }); - taskResponse.setFeedbacks(taskFeedbacks); - taskResponse.setResources(taskResources); + TaskDto taskResponse = taskConverter.convertToDto(task); taskResponses.add(taskResponse); - } return ResponseEntity.ok(taskResponses); } else { @@ -249,12 +172,13 @@ public ResponseEntity deleteTask(@RequestParam Long taskId){ } @Transactional - public ResponseEntity updateTask(Task newTask, Long taskId) + public ResponseEntity updateTask(UpdateTaskRequest updateTaskRequest, Long taskId) { - throws InvocationTargetException, IllegalAccessException { - //TODO: implement other update methods to update specific fields Task task = taskRepository.findById(taskId).orElseThrow(()-> new EntityNotFoundException("No task found")); - beanUtils.copyProperties(task, newTask); // copy fields of updatedTask to task ignoring null values + task.setDescription(updateTaskRequest.getDescription() != null ? updateTaskRequest.getDescription() : + task.getDescription()); + task.setUrgency(updateTaskRequest.getUrgency() != null ? updateTaskRequest.getUrgency() : task.getUrgency()); + task.setStatus(updateTaskRequest.getStatus() != null ? updateTaskRequest.getStatus() : task.getStatus()); taskRepository.save(task); return ResponseEntity.ok("Task updated successfully"); } @@ -288,6 +212,7 @@ public ResponseEntity unassignTask(Long taskId){ return ResponseEntity.ok("Task unassigned successfully"); } + @Transactional public ResponseEntity completeTask(Long taskId, Long userId){ Task task = taskRepository.findById(taskId).orElseThrow(()-> new EntityNotFoundException("No task found")); User user = userRepository.findById(userId).orElseThrow(()-> new EntityNotFoundException("No user found")); @@ -306,26 +231,79 @@ public ResponseEntity completeTask(Long taskId, Long userId){ return ResponseEntity.badRequest().body("Actions are not done"); } + Set resources = task.getResources(); + resources.forEach( + resource -> { + resource.setStatus(EResourceStatus.DELIVERED); + resourceRepository.save(resource); + } + ); + + task.setStatus(EStatus.DONE); taskRepository.save(task); return ResponseEntity.ok("Task completed"); } - public ResponseEntity giveFeedback(CreateFeedbackRequest feedbackRequest){ - Task task = taskRepository.findById(feedbackRequest.getTaskId()).orElseThrow(()-> new EntityNotFoundException("No task found")); - User user = userRepository.findById(feedbackRequest.getUserId()).orElseThrow(()-> new EntityNotFoundException("No user found")); - Feedback feedback = new Feedback(); - feedback.setCreator(user); - feedback.setMessage(feedbackRequest.getMessage()); - feedback.setTask(task); - task.getFeedbacks().add(feedback); - // TODO: send notification to coordinator + + @Transactional + public ResponseEntity addResources(AddResourceToTaskRequest addResourceToTaskRequest){ + Long taskId = addResourceToTaskRequest.getTaskId(); + List resources = addResourceToTaskRequest.getResourceIds(); + Task task = taskRepository.findById(taskId).orElseThrow(()-> new EntityNotFoundException("No task found")); + for (Long resourceId : resources){ + Resource resource = resourceRepository.findById(resourceId).orElseThrow(()-> new EntityNotFoundException("No resource found")); + resource.setTask(task); + resource.setStatus(EResourceStatus.IN_TASK); + resourceRepository.save(resource); + } + task.getResources().addAll(resourceRepository.findAllById(resources)); taskRepository.save(task); - return ResponseEntity.ok("Feedback saved successfully"); + return ResponseEntity.ok("Resources added successfully to Task"); + } + + @Transactional + public ResponseEntity removeResources(AddResourceToTaskRequest addResourceToTaskRequest){ + Long taskId = addResourceToTaskRequest.getTaskId(); + List resources = addResourceToTaskRequest.getResourceIds(); + Task task = taskRepository.findById(taskId).orElseThrow(()-> new EntityNotFoundException("No task found")); + for (Long resourceId : resources){ + Resource resource = resourceRepository.findById(resourceId).orElseThrow(()-> new EntityNotFoundException("No resource found")); + resource.setTask(null); + resource.setStatus(EResourceStatus.AVAILABLE); + resourceRepository.save(resource); + } + resourceRepository.findAllById(resources) + .forEach(resource -> task.getResources().remove(resource)); + taskRepository.save(task); + return ResponseEntity.ok("Resources removed successfully from Task"); + + + } + + + public ResponseEntity> viewTasksByFilter(Long assignerId, Long assigneeId, EStatus status) { + Specification spec = Specification.where(null); + + if (assignerId != null) { + spec = spec.and(TaskSpecifications.hasAssigner(assignerId)); + } + + if (assigneeId != null) { + spec = spec.and(TaskSpecifications.hasAssignee(assigneeId)); + } + + if(status != null) { + spec = spec.and(TaskSpecifications.hasStatus(status)); + } + + return ResponseEntity.ok(taskRepository.findAll(spec).stream().map(task -> taskConverter.convertToDto(task)).toList()); + } + } diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/specification/TaskSpecifications.java b/resq/backend/resq/src/main/java/com/groupa1/resq/specification/TaskSpecifications.java new file mode 100644 index 00000000..50da2431 --- /dev/null +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/specification/TaskSpecifications.java @@ -0,0 +1,26 @@ +package com.groupa1.resq.specification; + +import com.groupa1.resq.entity.Task; +import com.groupa1.resq.entity.enums.EStatus; +import org.springframework.data.jpa.domain.Specification; + +public class TaskSpecifications { + + public static Specification hasAssignee(Long assigneeId) { + return (root, query, criteriaBuilder) -> + criteriaBuilder.equal(root.get("assignee").get("id"), assigneeId); + } + + public static Specification hasAssigner(Long assignerId) { + return (root, query, criteriaBuilder) -> + criteriaBuilder.equal(root.get("assigner").get("id"), assignerId); + } + + public static Specification hasStatus(EStatus status) { + return (root, query, criteriaBuilder) -> + criteriaBuilder.equal(root.get("status"), status); + } + + + +} diff --git a/resq/backend/resq/src/test/java/com/groupa1/resq/service/ActionServiceTest.java b/resq/backend/resq/src/test/java/com/groupa1/resq/service/ActionServiceTest.java index dce6404c..fd4e55fa 100644 --- a/resq/backend/resq/src/test/java/com/groupa1/resq/service/ActionServiceTest.java +++ b/resq/backend/resq/src/test/java/com/groupa1/resq/service/ActionServiceTest.java @@ -8,7 +8,7 @@ import com.groupa1.resq.repository.TaskRepository; import com.groupa1.resq.repository.UserRepository; import com.groupa1.resq.request.CreateActionRequest; -import com.groupa1.resq.response.ActionResponse; +import com.groupa1.resq.dto.ActionDto; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -46,33 +46,8 @@ public class ActionServiceTest { - @Test - void testCreateAction_withNonExistentTask_shouldReturnBadRequest() { - // Given - CreateActionRequest createActionRequest = new CreateActionRequest(); - createActionRequest.setTaskId(1L); - createActionRequest.setVerifierId(1L); - createActionRequest.setDescription("Test Action"); - createActionRequest.setDueDate(LocalDateTime.now()); - createActionRequest.setStartLatitude(BigDecimal.valueOf(1.0)); - createActionRequest.setStartLongitude(BigDecimal.valueOf(2.0)); - createActionRequest.setEndLatitude(BigDecimal.valueOf(3.0)); - createActionRequest.setEndLongitude(BigDecimal.valueOf(4.0)); - - - - when(userRepository.findById(Mockito.anyLong())).thenReturn( - Optional.of(new User())); - // then - ResponseEntity response = - actionService.createAction(createActionRequest); - assertEquals("No task found", response.getBody()); - - - } - @Test void testViewActions_Success() { // Given @@ -101,7 +76,7 @@ void testViewActions_Success() { when(taskRepository.findById(Mockito.anyLong())).thenReturn(Optional.of(task)); - ResponseEntity> response = actionService.viewActions(taskId); + ResponseEntity> response = actionService.viewActions(taskId); // Then assertEquals(1, response.getBody().size()); diff --git a/resq/backend/resq/src/test/java/com/groupa1/resq/service/TaskServiceTest.java b/resq/backend/resq/src/test/java/com/groupa1/resq/service/TaskServiceTest.java index 64a00e24..02ed2d9d 100644 --- a/resq/backend/resq/src/test/java/com/groupa1/resq/service/TaskServiceTest.java +++ b/resq/backend/resq/src/test/java/com/groupa1/resq/service/TaskServiceTest.java @@ -39,72 +39,8 @@ public class TaskServiceTest { - @Test - void testCreateTask_withEmptyActions_withEmptyResources_shouldReturnSuccess() { - // Given - CreateTaskRequest createTaskRequest = new CreateTaskRequest(); - createTaskRequest.setActions(new ArrayList<>()); - createTaskRequest.setResources(new ArrayList<>()); - createTaskRequest.setAssigneeId(1L); - createTaskRequest.setAssignerId(2L); - createTaskRequest.setDescription("Test description"); - createTaskRequest.setUrgency(EUrgency.HIGH); - - - // when - when(userService.findById(createTaskRequest.getAssigneeId())).thenReturn(new User()); - when(userService.findById(createTaskRequest.getAssignerId())).thenReturn(new User()); - - - // then - ResponseEntity response = taskService.createTask(createTaskRequest); - assertEquals("Task saved successfully", response.getBody()); - } - - @Test - void testCreateTask_withNonSpecifiedAssigneeAssigner_shouldReturnBadRequest() { - // Given - CreateTaskRequest createTaskRequest = new CreateTaskRequest(); - createTaskRequest.setActions(new ArrayList<>()); - createTaskRequest.setResources(new ArrayList<>()); - createTaskRequest.setDescription("Test description"); - createTaskRequest.setUrgency(EUrgency.HIGH); - - // then - ResponseEntity response = taskService.createTask(createTaskRequest); - assertEquals("Assignee and assigner must be specified", - response.getBody()); - } - - @Test - void testCreateTask_withNonEmptyAction_withEmptyResources_shouldReturnSuccess() { - // Given - CreateTaskRequest createTaskRequest = new CreateTaskRequest(); - ArrayList actions = new ArrayList<>(); - actions.add(new CreateTaskRequest.Action()); - createTaskRequest.setActions(actions); - createTaskRequest.setResources(new ArrayList<>()); - createTaskRequest.setAssigneeId(1L); - createTaskRequest.setAssignerId(2L); - createTaskRequest.setDescription("Test description"); - createTaskRequest.setUrgency(EUrgency.HIGH); - - // when - when(userService.findById( - createTaskRequest.getAssigneeId())).thenReturn(new User()); - when(userService.findById( - createTaskRequest.getAssignerId())).thenReturn(new User()); - - // then - ResponseEntity response = - taskService.createTask(createTaskRequest); - assertEquals("Task saved successfully", response.getBody()); - - - } - @Test void testAcceptTask_withExistentTask_shouldReturnSuccess() { From 14f749d60df0d7251b8f2c0711805ca78cab79e4 Mon Sep 17 00:00:00 2001 From: furknbulbul Date: Mon, 18 Dec 2023 16:41:44 +0300 Subject: [PATCH 09/12] implement feedback of a task --- .../resq/controller/FeedbackController.java | 33 +++++++++++ .../resq/converter/FeedbackConverter.java | 19 +++++++ .../FeedbackDto.java} | 7 ++- .../resq/repository/FeedbackRepository.java | 9 +++ .../groupa1/resq/service/FeedbackService.java | 56 +++++++++++++++++++ 5 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 resq/backend/resq/src/main/java/com/groupa1/resq/controller/FeedbackController.java create mode 100644 resq/backend/resq/src/main/java/com/groupa1/resq/converter/FeedbackConverter.java rename resq/backend/resq/src/main/java/com/groupa1/resq/{response/FeedbackResponse.java => dto/FeedbackDto.java} (60%) create mode 100644 resq/backend/resq/src/main/java/com/groupa1/resq/repository/FeedbackRepository.java create mode 100644 resq/backend/resq/src/main/java/com/groupa1/resq/service/FeedbackService.java diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/controller/FeedbackController.java b/resq/backend/resq/src/main/java/com/groupa1/resq/controller/FeedbackController.java new file mode 100644 index 00000000..96c0092f --- /dev/null +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/controller/FeedbackController.java @@ -0,0 +1,33 @@ +package com.groupa1.resq.controller; + +import com.groupa1.resq.request.CreateFeedbackRequest; +import com.groupa1.resq.service.FeedbackService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/feedback") +public class FeedbackController { + + @Autowired + private FeedbackService feedbackService; + + @PreAuthorize("hasRole('RESPONDER')") + @PostMapping("/giveFeedback") + public ResponseEntity giveFeedback(CreateFeedbackRequest feedback) { + return feedbackService.giveFeedback(feedback); + } + + + @PreAuthorize("hasRole('RESPONDER')") + @PostMapping("/deleteFeedback") + public ResponseEntity deleteFeedback(@RequestParam Long feedbackId) { + return feedbackService.deleteFeedback(feedbackId); + } + +} diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/converter/FeedbackConverter.java b/resq/backend/resq/src/main/java/com/groupa1/resq/converter/FeedbackConverter.java new file mode 100644 index 00000000..b3070019 --- /dev/null +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/converter/FeedbackConverter.java @@ -0,0 +1,19 @@ +package com.groupa1.resq.converter; + +import com.groupa1.resq.dto.FeedbackDto; +import com.groupa1.resq.entity.Feedback; +import org.springframework.stereotype.Service; + +@Service +public class FeedbackConverter { + + public FeedbackDto convertToDto(Feedback feedback){ + FeedbackDto feedbackDto = new FeedbackDto(); + feedbackDto.setId(feedback.getId()); + feedbackDto.setTaskId(feedback.getTask().getId()); + feedbackDto.setUserId(feedback.getCreator().getId()); + feedbackDto.setMessage(feedback.getMessage()); + feedbackDto.setCreatedDate(feedback.getCreatedAt()); + return feedbackDto; + } +} diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/response/FeedbackResponse.java b/resq/backend/resq/src/main/java/com/groupa1/resq/dto/FeedbackDto.java similarity index 60% rename from resq/backend/resq/src/main/java/com/groupa1/resq/response/FeedbackResponse.java rename to resq/backend/resq/src/main/java/com/groupa1/resq/dto/FeedbackDto.java index 4b7493c0..73624965 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/response/FeedbackResponse.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/dto/FeedbackDto.java @@ -1,15 +1,18 @@ -package com.groupa1.resq.response; +package com.groupa1.resq.dto; import lombok.Data; import lombok.experimental.Accessors; +import java.time.LocalDateTime; + @Data @Accessors(chain = true) -public class FeedbackResponse { +public class FeedbackDto { private long id; private long taskId; private long userId; private String message; + private LocalDateTime createdDate; diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/repository/FeedbackRepository.java b/resq/backend/resq/src/main/java/com/groupa1/resq/repository/FeedbackRepository.java new file mode 100644 index 00000000..3c29d46a --- /dev/null +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/repository/FeedbackRepository.java @@ -0,0 +1,9 @@ +package com.groupa1.resq.repository; + +import com.groupa1.resq.entity.Feedback; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface FeedbackRepository extends JpaRepository { +} diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/service/FeedbackService.java b/resq/backend/resq/src/main/java/com/groupa1/resq/service/FeedbackService.java new file mode 100644 index 00000000..cf64745c --- /dev/null +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/service/FeedbackService.java @@ -0,0 +1,56 @@ +package com.groupa1.resq.service; + +import com.groupa1.resq.dto.FeedbackDto; +import com.groupa1.resq.entity.Feedback; +import com.groupa1.resq.entity.Task; +import com.groupa1.resq.entity.User; +import com.groupa1.resq.exception.EntityNotFoundException; +import com.groupa1.resq.repository.FeedbackRepository; +import com.groupa1.resq.repository.TaskRepository; +import com.groupa1.resq.repository.UserRepository; +import com.groupa1.resq.request.CreateFeedbackRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +@Service +public class FeedbackService { + + @Autowired + private TaskRepository taskRepository; + + + @Autowired + private UserRepository userRepository; + + @Autowired + private FeedbackRepository feedbackRepository; + + + + public ResponseEntity giveFeedback( + CreateFeedbackRequest feedbackRequest){ + Task task = taskRepository.findById(feedbackRequest.getTaskId()).orElseThrow(()-> new EntityNotFoundException("No task found")); + User user = userRepository.findById(feedbackRequest.getUserId()).orElseThrow(()-> new EntityNotFoundException("No user found")); + Feedback feedback = new Feedback(); + feedback.setCreator(user); + feedback.setMessage(feedbackRequest.getMessage()); + feedback.setTask(task); + task.getFeedbacks().add(feedback); + // TODO: send notification to coordinator + taskRepository.save(task); + return ResponseEntity.ok("Feedback saved successfully"); + } + public ResponseEntity deleteFeedback(Long feedbackId){ + Feedback feedback = feedbackRepository.findById(feedbackId).orElse(null); + if(feedback == null){ + return ResponseEntity.badRequest().body("No feedback found"); + } + feedbackRepository.delete(feedback); + return ResponseEntity.ok("Feedback deleted successfully"); + + } + + + +} From 35005972dd5d0cfb4c145ecdc746d4ce6dd19dd7 Mon Sep 17 00:00:00 2001 From: furknbulbul Date: Mon, 18 Dec 2023 16:44:28 +0300 Subject: [PATCH 10/12] resource in task implemented, in resource task field added --- .../resq/controller/ResourceController.java | 7 +++++-- .../com/groupa1/resq/dto/ResourceDto.java | 3 +++ .../com/groupa1/resq/entity/Resource.java | 7 ++++++- .../resq/entity/enums/EResourceStatus.java | 8 +++++++ .../request/AddResourceToTaskRequest.java | 12 +++++++++++ .../resq/request/CreateResourceRequest.java | 2 ++ .../resq/response/ResourceResponse.java | 21 ------------------- .../groupa1/resq/service/ResourceService.java | 9 +++++++- .../specification/ResourceSpecifications.java | 5 +++++ 9 files changed, 49 insertions(+), 25 deletions(-) create mode 100644 resq/backend/resq/src/main/java/com/groupa1/resq/entity/enums/EResourceStatus.java create mode 100644 resq/backend/resq/src/main/java/com/groupa1/resq/request/AddResourceToTaskRequest.java delete mode 100644 resq/backend/resq/src/main/java/com/groupa1/resq/response/ResourceResponse.java diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/controller/ResourceController.java b/resq/backend/resq/src/main/java/com/groupa1/resq/controller/ResourceController.java index 7e9e26b0..722727fd 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/controller/ResourceController.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/controller/ResourceController.java @@ -1,6 +1,7 @@ package com.groupa1.resq.controller; import com.groupa1.resq.dto.ResourceDto; +import com.groupa1.resq.entity.enums.EResourceStatus; import com.groupa1.resq.request.CreateResourceRequest; import com.groupa1.resq.service.ResourceService; import lombok.extern.slf4j.Slf4j; @@ -50,6 +51,7 @@ public ResponseEntity deleteResource(@RequestParam Long resourceId) { } + @PreAuthorize("hasRole('COORDINATOR') or hasRole('VICTIM') or hasRole('RESPONDER')") @GetMapping("/filterByDistance") public ResponseEntity> filterByDistance(@RequestParam @@ -63,8 +65,9 @@ public ResponseEntity> filterByDistance(@RequestParam public ResponseEntity> filterByCategory(@RequestParam(required = false) String categoryTreeId, @RequestParam(required = false) BigDecimal longitude, @RequestParam(required = false) BigDecimal latitude, - @RequestParam(required = false) Long userId) { + @RequestParam(required = false) Long userId, + @RequestParam(required = false) EResourceStatus status){ log.info("Filtering resources by category"); - return resourceService.filterResource(latitude, longitude, categoryTreeId, userId); + return resourceService.filterResource(latitude, longitude, categoryTreeId, userId, status); } } diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/dto/ResourceDto.java b/resq/backend/resq/src/main/java/com/groupa1/resq/dto/ResourceDto.java index 19da9b50..e2c19cf2 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/dto/ResourceDto.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/dto/ResourceDto.java @@ -1,12 +1,15 @@ package com.groupa1.resq.dto; import com.groupa1.resq.entity.enums.EGender; +import jakarta.persistence.Access; import lombok.Data; +import lombok.experimental.Accessors; import java.math.BigDecimal; import java.time.LocalDateTime; @Data +@Accessors(chain = true) public class ResourceDto { private Long id; private Long senderId; diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/entity/Resource.java b/resq/backend/resq/src/main/java/com/groupa1/resq/entity/Resource.java index d9ef1a32..0e5d09df 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/entity/Resource.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/entity/Resource.java @@ -1,6 +1,7 @@ package com.groupa1.resq.entity; import com.groupa1.resq.entity.enums.EGender; +import com.groupa1.resq.entity.enums.EResourceStatus; import com.groupa1.resq.entity.enums.ESize; import jakarta.persistence.*; import lombok.Data; @@ -26,6 +27,10 @@ public class Resource extends BaseEntity { @JoinColumn(name = "receiver_id") private User receiver; + @ManyToOne + @JoinColumn(name = "task_id") + private Task task; + private String categoryTreeId; private EGender gender; @@ -38,5 +43,5 @@ public class Resource extends BaseEntity { private BigDecimal latitude; private BigDecimal longitude; - + private EResourceStatus status; } diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/entity/enums/EResourceStatus.java b/resq/backend/resq/src/main/java/com/groupa1/resq/entity/enums/EResourceStatus.java new file mode 100644 index 00000000..53b01585 --- /dev/null +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/entity/enums/EResourceStatus.java @@ -0,0 +1,8 @@ +package com.groupa1.resq.entity.enums; + +public enum EResourceStatus { + IN_TASK, + DELIVERED, + CANCELLED, + AVAILABLE +} diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/request/AddResourceToTaskRequest.java b/resq/backend/resq/src/main/java/com/groupa1/resq/request/AddResourceToTaskRequest.java new file mode 100644 index 00000000..83bf0797 --- /dev/null +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/request/AddResourceToTaskRequest.java @@ -0,0 +1,12 @@ +package com.groupa1.resq.request; + +import lombok.Data; + +import java.util.List; + +@Data +public class AddResourceToTaskRequest { + private Long taskId; + private List resourceIds; + +} diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/request/CreateResourceRequest.java b/resq/backend/resq/src/main/java/com/groupa1/resq/request/CreateResourceRequest.java index 87d1c672..43d84a46 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/request/CreateResourceRequest.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/request/CreateResourceRequest.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.groupa1.resq.entity.enums.EGender; +import com.groupa1.resq.entity.enums.EResourceStatus; import lombok.Data; import java.math.BigDecimal; @@ -16,4 +17,5 @@ public class CreateResourceRequest { private BigDecimal longitude; private EGender gender; private String size; + private EResourceStatus status; // This field is only for resource update, default is AVAILABLE } diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/response/ResourceResponse.java b/resq/backend/resq/src/main/java/com/groupa1/resq/response/ResourceResponse.java deleted file mode 100644 index d5089de7..00000000 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/response/ResourceResponse.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.groupa1.resq.response; - -import com.groupa1.resq.entity.User; -import com.groupa1.resq.entity.enums.EGender; -import lombok.Data; -import lombok.experimental.Accessors; - -import java.math.BigDecimal; - -@Data -@Accessors(chain = true) -public class ResourceResponse { - private long id; - private Long senderId; - private int quantity; - private EGender gender; - private String categoryId; - private BigDecimal latitude; - private BigDecimal longitude; - -} diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/service/ResourceService.java b/resq/backend/resq/src/main/java/com/groupa1/resq/service/ResourceService.java index b1dce64d..23a81f21 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/service/ResourceService.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/service/ResourceService.java @@ -4,6 +4,7 @@ import com.groupa1.resq.dto.ResourceDto; import com.groupa1.resq.entity.Resource; import com.groupa1.resq.entity.User; +import com.groupa1.resq.entity.enums.EResourceStatus; import com.groupa1.resq.entity.enums.ESize; import com.groupa1.resq.exception.EntityNotFoundException; import com.groupa1.resq.repository.ResourceRepository; @@ -56,6 +57,8 @@ public ResponseEntity createResource(CreateResourceRequest createResourc resource.setQuantity(createResourceRequest.getQuantity()); resource.setCategoryTreeId(createResourceRequest.getCategoryTreeId()); resource.setSize(ESize.valueOf(createResourceRequest.getSize())); + resource.setStatus(EResourceStatus.AVAILABLE); // default + resource.setGender(createResourceRequest.getGender()); Long resourceId = resourceRepository.save(resource).getId(); return ResponseEntity.ok(resourceId); } @@ -67,6 +70,7 @@ public ResponseEntity updateResource(CreateResourceRequest createResourc resource.setLongitude(createResourceRequest.getLongitude()); resource.setCategoryTreeId(createResourceRequest.getCategoryTreeId()); resource.setSize(ESize.valueOf(createResourceRequest.getSize())); + resource.setStatus(createResourceRequest.getStatus()); resourceRepository.save(resource); return ResponseEntity.ok("Resource updated successfully"); } @@ -80,7 +84,7 @@ public ResponseEntity deleteResource(Long resourceId){ return ResponseEntity.ok("Resource deleted successfully"); } - public ResponseEntity> filterResource(BigDecimal latitude, BigDecimal longitude, String categoryTreeId, Long userId){ + public ResponseEntity> filterResource(BigDecimal latitude, BigDecimal longitude, String categoryTreeId, Long userId, EResourceStatus status){ Specification spec = Specification.where(null); if (longitude != null && latitude != null) { @@ -95,6 +99,9 @@ public ResponseEntity> filterResource(BigDecimal latitude, Big if (userId != null) { spec = spec.and(ResourceSpecifications.hasOwnerId(userId)); } + if (status != null){ + spec = spec.and(ResourceSpecifications.hasStatus(status)); + } return ResponseEntity.ok(resourceRepository.findAll(spec).stream().map(resource -> resourceConverter.convertToDto(resource)).toList()); } diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/specification/ResourceSpecifications.java b/resq/backend/resq/src/main/java/com/groupa1/resq/specification/ResourceSpecifications.java index 3413cbc5..68a08a98 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/specification/ResourceSpecifications.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/specification/ResourceSpecifications.java @@ -1,6 +1,7 @@ package com.groupa1.resq.specification; import com.groupa1.resq.entity.Resource; +import com.groupa1.resq.entity.enums.EResourceStatus; import org.springframework.data.jpa.domain.Specification; import java.math.BigDecimal; @@ -23,4 +24,8 @@ public static Specification hasLongitude(BigDecimal longitude) { return (root, query, builder) -> builder.equal(root.get("longitude"), longitude); } + public static Specification hasStatus(EResourceStatus status){ + return (root, query, builder) -> builder.equal(root.get("status"), status); + } + } From bb70c5299ca5bbebb346f746b0c412718d9d19c5 Mon Sep 17 00:00:00 2001 From: furknbulbul Date: Tue, 19 Dec 2023 10:32:19 +0300 Subject: [PATCH 11/12] auth added to controller --- .../com/groupa1/resq/controller/TaskController.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/controller/TaskController.java b/resq/backend/resq/src/main/java/com/groupa1/resq/controller/TaskController.java index 9a5bd44a..a50c60ec 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/controller/TaskController.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/controller/TaskController.java @@ -38,13 +38,17 @@ public ResponseEntity createTask(@RequestBody CreateTaskRequest createTa @PreAuthorize("hasRole('RESPONDER')") @PostMapping("/acceptTask") - public ResponseEntity acceptTask(@RequestParam Long taskId, @RequestParam Long userId) { + public ResponseEntity acceptTask(@RequestParam Long taskId, Authentication authentication){ + UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal(); + Long userId = userDetails.getId(); return taskService.acceptTask(taskId, userId); } @PreAuthorize("hasRole('RESPONDER')") @PostMapping("/declineTask") - public ResponseEntity declineTask(@RequestParam Long taskId, @RequestParam Long userId) { + public ResponseEntity declineTask(@RequestParam Long taskId, Authentication authentication){ + UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal(); + Long userId = userDetails.getId(); return taskService.declineTask(taskId, userId); } @@ -77,7 +81,7 @@ public ResponseEntity assignTask(@RequestParam Long taskId, @RequestPara @PreAuthorize("hasRole('COORDINATOR')") @PostMapping("/unassignTask") - public ResponseEntity unassignTask(@RequestParam Long taskId, @RequestParam Long userId) { + public ResponseEntity unassignTask(@RequestParam Long taskId) { return taskService.unassignTask(taskId); } From 6d4e315ea950e447fe22c629a38ddb2398d9a01a Mon Sep 17 00:00:00 2001 From: furknbulbul Date: Tue, 19 Dec 2023 10:34:45 +0300 Subject: [PATCH 12/12] auth added to action controller --- .../com/groupa1/resq/controller/ActionController.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/resq/backend/resq/src/main/java/com/groupa1/resq/controller/ActionController.java b/resq/backend/resq/src/main/java/com/groupa1/resq/controller/ActionController.java index ed378562..1ec16d6e 100644 --- a/resq/backend/resq/src/main/java/com/groupa1/resq/controller/ActionController.java +++ b/resq/backend/resq/src/main/java/com/groupa1/resq/controller/ActionController.java @@ -1,5 +1,6 @@ package com.groupa1.resq.controller; +import com.groupa1.resq.auth.UserDetailsImpl; import com.groupa1.resq.request.CreateCommentRequest; import com.groupa1.resq.request.CreateActionRequest; import com.groupa1.resq.dto.ActionDto; @@ -7,6 +8,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.Authentication; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -53,12 +55,16 @@ public ResponseEntity updateAction(@RequestBody CreateActionRequest crea @PreAuthorize("hasRole('RESPONDER')") @PostMapping("/completeAction") - public ResponseEntity completeAction(@RequestParam Long actionId, @RequestParam Long userId) { + public ResponseEntity completeAction(@RequestParam Long actionId, Authentication authentication){ + UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal(); + Long userId = userDetails.getId(); return actionService.completeAction(actionId, userId); } @PreAuthorize("hasRole('FACILITATOR')") @PostMapping("/verifyAction") - public ResponseEntity verifyAction(@RequestParam Long actionId, @RequestParam Long userId){ + public ResponseEntity verifyAction(@RequestParam Long actionId, Authentication authentication){ + UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal(); + Long userId = userDetails.getId(); return actionService.verifyAction(actionId, userId); }