diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/controller/goal/GoalController.java b/src/main/java/no/ntnu/idi/stud/savingsapp/controller/goal/GoalController.java index d523fddfe639fbdd1ad8899a0b89e233a0e518db..5490170fc90b5f61162cadb9da4e2e61713ca0c6 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/controller/goal/GoalController.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/controller/goal/GoalController.java @@ -7,13 +7,11 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; -import no.ntnu.idi.stud.savingsapp.dto.goal.ChallengeDTO; -import no.ntnu.idi.stud.savingsapp.dto.goal.MarkChallengeDTO; -import no.ntnu.idi.stud.savingsapp.dto.goal.CreateGoalDTO; -import no.ntnu.idi.stud.savingsapp.dto.goal.GoalDTO; +import no.ntnu.idi.stud.savingsapp.dto.goal.*; import no.ntnu.idi.stud.savingsapp.exception.ExceptionResponse; import no.ntnu.idi.stud.savingsapp.model.goal.Challenge; import no.ntnu.idi.stud.savingsapp.model.goal.Goal; +import no.ntnu.idi.stud.savingsapp.model.goal.Group; import no.ntnu.idi.stud.savingsapp.security.AuthIdentity; import no.ntnu.idi.stud.savingsapp.service.ChallengeService; import no.ntnu.idi.stud.savingsapp.service.GoalService; @@ -63,7 +61,7 @@ public class GoalController { public ResponseEntity<GoalDTO> createGoal(@AuthenticationPrincipal AuthIdentity identity, @RequestBody CreateGoalDTO request) { Goal createGoal = modelMapper.map(request, Goal.class); - Goal goal = goalService.createGoal(createGoal, identity.getId()); + Goal goal = goalService.createGoal(createGoal, request.getDistribution(), identity.getId()); GoalDTO goalDTO = modelMapper.map(goal, GoalDTO.class); log.info("[GoalController:createGoal] goal: {}", goalDTO.getId()); return ResponseEntity.status(HttpStatus.CREATED).body(goalDTO); @@ -152,4 +150,11 @@ public class GoalController { ChallengeDTO challengeDTO = modelMapper.map(challenge, ChallengeDTO.class); return ResponseEntity.ok(challengeDTO); } + + @GetMapping(value ="/group/{goalId}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<List<GoalDTO>> getGroupInfo(@PathVariable Long goalId) { + Group group = goalService.getGroup(goalId); + List<GoalDTO> goals = group.getGoals().stream().map(g -> modelMapper.map(g, GoalDTO.class)).toList(); + return ResponseEntity.ok(goals); + } } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/CreateGoalDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/CreateGoalDTO.java index 59323f73516b613468164321460cc602370234cc..481a4829629f545adb56b541c67c9df321e5d0d4 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/CreateGoalDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/CreateGoalDTO.java @@ -4,6 +4,7 @@ import lombok.Data; import lombok.NonNull; import java.math.BigDecimal; +import java.util.List; @Data public final class CreateGoalDTO { @@ -19,4 +20,6 @@ public final class CreateGoalDTO { @NonNull private String targetDate; + private List<GroupUserDTO> distribution; + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/GroupUserDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/GroupUserDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..d88a88d88a6b14de472a858050c8d1deb9dd3b69 --- /dev/null +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/GroupUserDTO.java @@ -0,0 +1,13 @@ +package no.ntnu.idi.stud.savingsapp.dto.goal; + +import lombok.Data; +import lombok.NonNull; + +import java.math.BigDecimal; + +@Data +public final class GroupUserDTO { + + private Long userId; + private BigDecimal amount; +} diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/goal/GroupNotFoundException.java b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/goal/GroupNotFoundException.java new file mode 100644 index 0000000000000000000000000000000000000000..efb1667f3e8d119ba7fe50afc04d00a99812b05c --- /dev/null +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/goal/GroupNotFoundException.java @@ -0,0 +1,16 @@ +package no.ntnu.idi.stud.savingsapp.exception.goal; + +public final class GroupNotFoundException extends RuntimeException{ + + /** + * Constructs a GroupNotFoundException with default message. + */ + public GroupNotFoundException() { super("Group not found");} + + /** + * Constructs a GroupNotFoundException with custom message. + * + * @param string the custom exception message + */ + public GroupNotFoundException(String string) {super(string);} +} diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/goal/Group.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/goal/Group.java new file mode 100644 index 0000000000000000000000000000000000000000..46a9403a3d8718e9bccb1f4baea946683e3576c3 --- /dev/null +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/goal/Group.java @@ -0,0 +1,32 @@ +package no.ntnu.idi.stud.savingsapp.model.goal; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import no.ntnu.idi.stud.savingsapp.model.user.User; + +import java.math.BigDecimal; +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Entity +@Table(name = "group") +public class Group { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "group_id") + private Long id; + + @OneToMany + @Column(name = "goals") + private List<Goal> goals; + + @ManyToOne + @JoinColumn(name = "user_id") + private User creator; +} diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/GroupRepository.java b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/GroupRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..e768768a4ce5574e0ef786a0bd4a42ca806d6e41 --- /dev/null +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/GroupRepository.java @@ -0,0 +1,14 @@ +package no.ntnu.idi.stud.savingsapp.repository; + +import no.ntnu.idi.stud.savingsapp.model.goal.Goal; +import no.ntnu.idi.stud.savingsapp.model.goal.Group; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public interface GroupRepository extends JpaRepository<Group, Long> { + + Optional<Group> findByGoals_Id(long id); +} diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/service/GoalService.java b/src/main/java/no/ntnu/idi/stud/savingsapp/service/GoalService.java index 04a8cbba28c539ba2bd93347109928671ad90f6b..d4ca02e5d75f26b04c6f9977046be4591320d3b8 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/service/GoalService.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/service/GoalService.java @@ -1,6 +1,8 @@ package no.ntnu.idi.stud.savingsapp.service; +import no.ntnu.idi.stud.savingsapp.dto.goal.GroupUserDTO; import no.ntnu.idi.stud.savingsapp.model.goal.Goal; +import no.ntnu.idi.stud.savingsapp.model.goal.Group; import org.springframework.stereotype.Service; import java.util.List; @@ -20,7 +22,7 @@ public interface GoalService { * @param userId The ID of the user for whom the goal is being created. * @return The newly created and persisted Goal object. */ - Goal createGoal(Goal goal, long userId); + Goal createGoal(Goal goal, List<GroupUserDTO> GroupUsers, long userId); /** * Retrieves all goals associated with a specific user. @@ -39,4 +41,12 @@ public interface GoalService { * @return A goal object associated with the specified user. */ Goal getGoal(long goalId); + + /** + * Retrieves a group associated with a specific goal + * + * @param goalId the goal that the group contains + * @return A group object associated with the specified goal + */ + Group getGroup(Long goalId); } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/GoalServiceImpl.java b/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/GoalServiceImpl.java index 5ef5a96a498dcbfe8680480bfb2f2997a6590a17..4b8e5077a2658b48b1c41ef8d7b5228396f440d7 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/GoalServiceImpl.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/GoalServiceImpl.java @@ -2,15 +2,20 @@ package no.ntnu.idi.stud.savingsapp.service.impl; import java.sql.Timestamp; import java.time.Instant; +import java.util.ArrayList; import java.util.List; import java.util.Optional; import lombok.extern.slf4j.Slf4j; +import no.ntnu.idi.stud.savingsapp.dto.goal.GroupUserDTO; import no.ntnu.idi.stud.savingsapp.exception.goal.GoalNotFoundException; +import no.ntnu.idi.stud.savingsapp.exception.goal.GroupNotFoundException; import no.ntnu.idi.stud.savingsapp.model.goal.Challenge; import no.ntnu.idi.stud.savingsapp.model.goal.Goal; +import no.ntnu.idi.stud.savingsapp.model.goal.Group; import no.ntnu.idi.stud.savingsapp.model.user.User; import no.ntnu.idi.stud.savingsapp.repository.GoalRepository; +import no.ntnu.idi.stud.savingsapp.repository.GroupRepository; import no.ntnu.idi.stud.savingsapp.service.ChallengeService; import no.ntnu.idi.stud.savingsapp.service.GoalService; import no.ntnu.idi.stud.savingsapp.service.UserService; @@ -33,6 +38,9 @@ public class GoalServiceImpl implements GoalService { @Autowired private ChallengeService challengeService; + @Autowired + private GroupRepository groupRepository; + /** * Creates a new goal for a specific user and generates associated challenges. * @@ -41,12 +49,33 @@ public class GoalServiceImpl implements GoalService { * @return The newly created Goal, now populated with generated challenges and persisted in the database. */ @Override - public Goal createGoal(Goal goal, long userId) { + public Goal createGoal(Goal goal, List<GroupUserDTO> GroupUsers, long userId) { User user = userService.findById(userId); goal.setCreatedAt(Timestamp.from(Instant.now())); goal.setUser(user); List<Challenge> challenges = challengeService.generateChallenges(goal, user); goal.setChallenges(challenges); + + //Create group goal if GroupUsers were added + if(GroupUsers != null && !GroupUsers.isEmpty()) { + List<Goal> groupGoalList = new ArrayList<>(); + for (GroupUserDTO groupUserDTO : GroupUsers) { + Goal groupGoal = new Goal(); + User groupUser = userService.findById(groupUserDTO.getUserId()); + groupGoal.setCreatedAt(Timestamp.from(Instant.now())); + groupGoal.setUser(groupUser); + List<Challenge> challengeList = challengeService.generateChallenges(groupGoal, groupUser); + groupGoal.setChallenges(challengeList); + goalRepository.save(groupGoal); + groupGoalList.add(groupGoal); + } + + Group group = new Group(); + group.setCreator(user); + group.setGoals(groupGoalList); + groupRepository.save(group); + } + return goalRepository.save(goal); } @@ -61,6 +90,12 @@ public class GoalServiceImpl implements GoalService { return goalRepository.findByUser_Id(userId); } + /** + * Retrieves goal associated with a given goal ID. + * + * @param goalId The ID of the user whose goals are to be retrieved. + * @return The goal associated with the given goal ID. + */ @Override public Goal getGoal(long goalId) { Optional<Goal> optionalGoal = goalRepository.findById(goalId); @@ -71,4 +106,21 @@ public class GoalServiceImpl implements GoalService { throw new GoalNotFoundException(); } } + + /** + * + * + * @param goalId the goal that the group contains + * @return The group containing the goal + */ + @Override + public Group getGroup(Long goalId) { + Optional<Group> optionalGroup = groupRepository.findByGoals_Id(goalId); + if (optionalGroup.isPresent()) { + return optionalGroup.get(); + } else { + log.error("[GoalServiceImpl:getGoal] Group is not found from goal, id: {}", goalId); + throw new GroupNotFoundException(); + } + } }