From eeb602e5e79037fcc1868973de68f7d9331ed5a8 Mon Sep 17 00:00:00 2001 From: oguzhekim Date: Sat, 23 Nov 2024 16:25:35 +0300 Subject: [PATCH 1/7] Merge issue#203 branch --- .../com/group7/demo/dtos/PostRequest.java | 1 + .../com/group7/demo/dtos/PostResponse.java | 1 + .../demo/dtos/mapper/CustomerMapper.java | 6 --- .../com/group7/demo/dtos/mapper/Mapper.java | 48 +++++++++++++++++++ .../java/com/group7/demo/models/Post.java | 6 ++- .../demo/repository/UserRepository.java | 2 + .../com/group7/demo/services/PostService.java | 43 +++++++++-------- .../demo/services/TrainingProgramService.java | 41 ++++------------ .../com/group7/demo/services/UserService.java | 3 +- 9 files changed, 89 insertions(+), 62 deletions(-) delete mode 100644 backend/demo-group7/src/main/java/com/group7/demo/dtos/mapper/CustomerMapper.java create mode 100644 backend/demo-group7/src/main/java/com/group7/demo/dtos/mapper/Mapper.java diff --git a/backend/demo-group7/src/main/java/com/group7/demo/dtos/PostRequest.java b/backend/demo-group7/src/main/java/com/group7/demo/dtos/PostRequest.java index acbfd53..9686cc9 100644 --- a/backend/demo-group7/src/main/java/com/group7/demo/dtos/PostRequest.java +++ b/backend/demo-group7/src/main/java/com/group7/demo/dtos/PostRequest.java @@ -13,4 +13,5 @@ public class PostRequest { private String content; private Set tags; + private Long trainingProgramId; } diff --git a/backend/demo-group7/src/main/java/com/group7/demo/dtos/PostResponse.java b/backend/demo-group7/src/main/java/com/group7/demo/dtos/PostResponse.java index 7a98e83..196710c 100644 --- a/backend/demo-group7/src/main/java/com/group7/demo/dtos/PostResponse.java +++ b/backend/demo-group7/src/main/java/com/group7/demo/dtos/PostResponse.java @@ -17,4 +17,5 @@ public class PostResponse { private Set tags; private LocalDateTime createdAt; private String username; + private TrainingProgramResponse trainingProgram; } diff --git a/backend/demo-group7/src/main/java/com/group7/demo/dtos/mapper/CustomerMapper.java b/backend/demo-group7/src/main/java/com/group7/demo/dtos/mapper/CustomerMapper.java deleted file mode 100644 index 87e9882..0000000 --- a/backend/demo-group7/src/main/java/com/group7/demo/dtos/mapper/CustomerMapper.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.group7.demo.dtos.mapper; - - -// TODO: use mapper(mapstruct etc.) or manual -public class CustomerMapper { -} diff --git a/backend/demo-group7/src/main/java/com/group7/demo/dtos/mapper/Mapper.java b/backend/demo-group7/src/main/java/com/group7/demo/dtos/mapper/Mapper.java new file mode 100644 index 0000000..3fc7d9f --- /dev/null +++ b/backend/demo-group7/src/main/java/com/group7/demo/dtos/mapper/Mapper.java @@ -0,0 +1,48 @@ +package com.group7.demo.dtos.mapper; + +import com.group7.demo.dtos.*; +import com.group7.demo.models.*; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.stream.Collectors; + +@Component +public class Mapper { + public PostResponse mapToPostResponse(Post post) { + return new PostResponse( + post.getId(), + post.getContent(), + post.getTags().stream().map(Tag::getName).collect(Collectors.toSet()), // Only tag names + post.getCreatedAt(), + post.getUser().getUsername(), + post.getTrainingProgram() == null ? null : mapToTrainingProgramResponse(post.getTrainingProgram()) + ); + } + + public TrainingProgramResponse mapToTrainingProgramResponse(TrainingProgram program) { + return TrainingProgramResponse.builder() + .id(program.getId()) + .title(program.getTitle()) + .description(program.getDescription()) + .trainerUsername(program.getTrainer().getUsername()) + .createdAt(program.getCreatedAt()) + .exercises(program.getExercises().stream() + .map(this::mapToExerciseDetailResponse) + .collect(Collectors.toList())) + .participants(program.getParticipants() == null ? + List.of() : + program.getParticipants().stream() + .map(userTrainingProgram -> userTrainingProgram.getUser().getUsername()) + .collect(Collectors.toList())) + .build(); + } + + public ExerciseDetail mapToExerciseDetailResponse(TrainingProgramExercise trainingProgramExercise) { + return ExerciseDetail.builder() + .exercise(trainingProgramExercise.getExercise()) + .repetitions(trainingProgramExercise.getRepetitions()) + .sets(trainingProgramExercise.getSets()) + .build(); + } +} diff --git a/backend/demo-group7/src/main/java/com/group7/demo/models/Post.java b/backend/demo-group7/src/main/java/com/group7/demo/models/Post.java index 3573d66..6b162f6 100644 --- a/backend/demo-group7/src/main/java/com/group7/demo/models/Post.java +++ b/backend/demo-group7/src/main/java/com/group7/demo/models/Post.java @@ -1,6 +1,5 @@ package com.group7.demo.models; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import jakarta.persistence.*; import lombok.*; @@ -20,6 +19,8 @@ public class Post { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @Lob + @Column(columnDefinition = "TEXT") private String content; private LocalDateTime createdAt; @@ -36,4 +37,7 @@ public class Post { @JoinColumn(name = "user_id", nullable = false) private User user; + @ManyToOne(fetch = FetchType.LAZY, optional = true) + @JoinColumn(name = "training_program_id") + private TrainingProgram trainingProgram; } diff --git a/backend/demo-group7/src/main/java/com/group7/demo/repository/UserRepository.java b/backend/demo-group7/src/main/java/com/group7/demo/repository/UserRepository.java index 4181df8..d9b4384 100644 --- a/backend/demo-group7/src/main/java/com/group7/demo/repository/UserRepository.java +++ b/backend/demo-group7/src/main/java/com/group7/demo/repository/UserRepository.java @@ -1,12 +1,14 @@ package com.group7.demo.repository; import com.group7.demo.models.User; +import jakarta.transaction.Transactional; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; import java.util.Optional; @Repository +@Transactional public interface UserRepository extends JpaRepository { Optional findByUsername(String username); Optional findByEmail(String email); diff --git a/backend/demo-group7/src/main/java/com/group7/demo/services/PostService.java b/backend/demo-group7/src/main/java/com/group7/demo/services/PostService.java index d56864e..14632af 100644 --- a/backend/demo-group7/src/main/java/com/group7/demo/services/PostService.java +++ b/backend/demo-group7/src/main/java/com/group7/demo/services/PostService.java @@ -2,11 +2,11 @@ import com.group7.demo.dtos.PostRequest; import com.group7.demo.dtos.PostResponse; -import com.group7.demo.models.Post; -import com.group7.demo.models.Tag; -import com.group7.demo.models.User; +import com.group7.demo.dtos.mapper.Mapper; +import com.group7.demo.models.*; import com.group7.demo.repository.PostRepository; import com.group7.demo.repository.TagRepository; +import com.group7.demo.repository.TrainingProgramRepository; import com.group7.demo.repository.UserRepository; import jakarta.persistence.EntityNotFoundException; import jakarta.transaction.Transactional; @@ -28,8 +28,13 @@ public class PostService { private UserRepository userRepository; + private TrainingProgramRepository trainingProgramRepository; + private AuthenticationService authenticationService; + private Mapper mapper; + + @Transactional public PostResponse createPost(PostRequest postRequest, HttpServletRequest request) { Set tags = new HashSet<>(); @@ -43,28 +48,34 @@ public PostResponse createPost(PostRequest postRequest, HttpServletRequest reque tags.add(tag); } User user = authenticationService.getAuthenticatedUserInternal(request); + // Fetch the associated TrainingProgram if provided + TrainingProgram trainingProgram = Optional.ofNullable(postRequest.getTrainingProgramId()) + .flatMap(trainingProgramRepository::findById) + .orElse(null); Post post = Post.builder() .content(postRequest.getContent()) .createdAt(LocalDateTime.now()) .tags(tags) .user(user) // Associate the post with the user + .trainingProgram(trainingProgram) .build(); Post savedPost = postRepository.save(post); - return mapToPostResponse(savedPost); + return mapper.mapToPostResponse(savedPost); } - + @Transactional public List getAllPosts() { List posts = postRepository.findAll(); return posts.stream() - .map(this::mapToPostResponse) + .map(mapper::mapToPostResponse) .collect(Collectors.toList()); } + @Transactional public List getPostsByUser(String username) { User user = userRepository.findByUsername(username) .orElseThrow(() -> new EntityNotFoundException("User not found with username: " + username)); @@ -72,7 +83,7 @@ public List getPostsByUser(String username) { List posts = postRepository.findByUser(user); return posts.stream() - .map(this::mapToPostResponse) + .map(mapper::mapToPostResponse) .collect(Collectors.toList()); } @@ -103,31 +114,21 @@ public void deletePost(Long postId, HttpServletRequest request) throws IllegalAc postRepository.delete(post); } + @Transactional public List getPostsByTags(Set tagNames) { List posts = postRepository.findPostsByTags(tagNames); return posts.stream() - .map(this::mapToPostResponse) + .map(mapper::mapToPostResponse) .collect(Collectors.toList()); } + @Transactional public List getRandomPosts(int count) { List allPosts = postRepository.findAll(); Collections.shuffle(allPosts); return allPosts.stream() .limit(count) - .map(this::mapToPostResponse) + .map(mapper::mapToPostResponse) .collect(Collectors.toList()); } - - private PostResponse mapToPostResponse(Post post) { - return new PostResponse( - post.getId(), - post.getContent(), - post.getTags().stream().map(Tag::getName).collect(Collectors.toSet()), // Only tag names - post.getCreatedAt(), - post.getUser().getUsername() - ); - } - - } diff --git a/backend/demo-group7/src/main/java/com/group7/demo/services/TrainingProgramService.java b/backend/demo-group7/src/main/java/com/group7/demo/services/TrainingProgramService.java index 3e42c0b..2ec93b4 100644 --- a/backend/demo-group7/src/main/java/com/group7/demo/services/TrainingProgramService.java +++ b/backend/demo-group7/src/main/java/com/group7/demo/services/TrainingProgramService.java @@ -3,6 +3,7 @@ import com.group7.demo.dtos.ExerciseDetail; import com.group7.demo.dtos.TrainingProgramRequest; import com.group7.demo.dtos.TrainingProgramResponse; +import com.group7.demo.dtos.mapper.Mapper; import com.group7.demo.models.*; import com.group7.demo.repository.ExerciseRepository; import com.group7.demo.repository.TrainingProgramRepository; @@ -33,6 +34,8 @@ public class TrainingProgramService { private final ExerciseRepository exerciseRepository; + private final Mapper mapper; + @Transactional public TrainingProgramResponse createTrainingProgram(TrainingProgramRequest trainingProgramRequest, HttpServletRequest request) throws IllegalAccessException { User user = authenticationService.getAuthenticatedUserInternal(request); @@ -70,35 +73,7 @@ public TrainingProgramResponse createTrainingProgram(TrainingProgramRequest trai // Save the training program and return a response TrainingProgram savedProgram = trainingProgramRepository.save(trainingProgram); - return mapToTrainingProgramResponse(savedProgram); - } - - // Add a method to map TrainingProgram to TrainingProgramResponse - private TrainingProgramResponse mapToTrainingProgramResponse(TrainingProgram program) { - return TrainingProgramResponse.builder() - .id(program.getId()) - .title(program.getTitle()) - .description(program.getDescription()) - .trainerUsername(program.getTrainer().getUsername()) - .createdAt(program.getCreatedAt()) - .exercises(program.getExercises().stream() - .map(this::mapToExerciseResponse) - .collect(Collectors.toList())) - .participants(program.getParticipants() == null ? - List.of() : - program.getParticipants().stream() - .map(userTrainingProgram -> userTrainingProgram.getUser().getUsername()) - .collect(Collectors.toList())) - .build(); - } - - - private ExerciseDetail mapToExerciseResponse(TrainingProgramExercise trainingProgramExercise) { - return ExerciseDetail.builder() - .exercise(trainingProgramExercise.getExercise()) - .repetitions(trainingProgramExercise.getRepetitions()) - .sets(trainingProgramExercise.getSets()) - .build(); + return mapper.mapToTrainingProgramResponse(savedProgram); } public List getAllTrainingPrograms() { @@ -107,7 +82,7 @@ public List getAllTrainingPrograms() { // Map the list of TrainingProgram entities to TrainingProgramResponse DTOs return trainingPrograms.stream() - .map(this::mapToTrainingProgramResponse) // Use the mapping method to convert to response DTOs + .map(mapper::mapToTrainingProgramResponse) // Use the mapping method to convert to response DTOs .collect(Collectors.toList()); } @@ -117,7 +92,7 @@ public TrainingProgramResponse getTrainingProgramById(Long id) { .orElseThrow(() -> new EntityNotFoundException("Training program not found with id: " + id)); // Map the TrainingProgram entity to TrainingProgramResponse DTO - return mapToTrainingProgramResponse(trainingProgram); + return mapper.mapToTrainingProgramResponse(trainingProgram); } @Transactional @@ -127,7 +102,7 @@ public List getTrainingProgramByTrainer(String username List trainingPrograms = trainingProgramRepository.findByTrainer(user); return trainingPrograms.stream() - .map(this::mapToTrainingProgramResponse) + .map(mapper::mapToTrainingProgramResponse) .collect(Collectors.toList()); } @@ -208,7 +183,7 @@ public List getJoinedTrainingPrograms(String username) // Map the list of UserTrainingProgram entities to TrainingProgramResponse DTOs return userTrainingPrograms.stream() .map(UserTrainingProgram::getTrainingProgram) - .map(this::mapToTrainingProgramResponse) + .map(mapper::mapToTrainingProgramResponse) .collect(Collectors.toList()); } diff --git a/backend/demo-group7/src/main/java/com/group7/demo/services/UserService.java b/backend/demo-group7/src/main/java/com/group7/demo/services/UserService.java index 1141483..db84e79 100644 --- a/backend/demo-group7/src/main/java/com/group7/demo/services/UserService.java +++ b/backend/demo-group7/src/main/java/com/group7/demo/services/UserService.java @@ -6,7 +6,7 @@ import com.group7.demo.models.User; import com.group7.demo.repository.UserRepository; import jakarta.servlet.http.HttpServletRequest; -import lombok.RequiredArgsConstructor; +import jakarta.transaction.Transactional; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; @@ -31,6 +31,7 @@ public UserService(UserRepository userRepository, this.trainingProgramService = trainingProgramService; } + @Transactional public UserProfileResponse getUserProfile(String username) throws Exception { User user = userRepository.findByUsername(username) .orElseThrow(() -> new Exception("User not found")); From 8756cb32a55bbaa3818854742767b49a3b5c9550 Mon Sep 17 00:00:00 2001 From: oguzhekim Date: Sat, 23 Nov 2024 16:51:00 +0300 Subject: [PATCH 2/7] Modify DTOs and Models for tracking --- .../group7/demo/dtos/UserExerciseDetail.java | 16 +++++++++ .../group7/demo/dtos/UserProfileResponse.java | 2 +- .../dtos/UserTrainingProgramResponse.java | 22 ++++++++++++ .../com/group7/demo/dtos/mapper/Mapper.java | 34 +++++++++++++++++++ .../demo/models/UserTrainingProgram.java | 26 ++++++++++++++ 5 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 backend/demo-group7/src/main/java/com/group7/demo/dtos/UserExerciseDetail.java create mode 100644 backend/demo-group7/src/main/java/com/group7/demo/dtos/UserTrainingProgramResponse.java diff --git a/backend/demo-group7/src/main/java/com/group7/demo/dtos/UserExerciseDetail.java b/backend/demo-group7/src/main/java/com/group7/demo/dtos/UserExerciseDetail.java new file mode 100644 index 0000000..2f2ec5f --- /dev/null +++ b/backend/demo-group7/src/main/java/com/group7/demo/dtos/UserExerciseDetail.java @@ -0,0 +1,16 @@ +package com.group7.demo.dtos; + +import com.group7.demo.models.Exercise; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +@AllArgsConstructor +public class UserExerciseDetail { + private Exercise exercise; + private int repetitions; + private int sets; + private boolean completed; +} diff --git a/backend/demo-group7/src/main/java/com/group7/demo/dtos/UserProfileResponse.java b/backend/demo-group7/src/main/java/com/group7/demo/dtos/UserProfileResponse.java index b28d8c1..9476ada 100644 --- a/backend/demo-group7/src/main/java/com/group7/demo/dtos/UserProfileResponse.java +++ b/backend/demo-group7/src/main/java/com/group7/demo/dtos/UserProfileResponse.java @@ -19,5 +19,5 @@ public class UserProfileResponse { private Set following; private List posts; private List trainingPrograms; - private List joinedPrograms; + private List joinedPrograms; } diff --git a/backend/demo-group7/src/main/java/com/group7/demo/dtos/UserTrainingProgramResponse.java b/backend/demo-group7/src/main/java/com/group7/demo/dtos/UserTrainingProgramResponse.java new file mode 100644 index 0000000..014c31f --- /dev/null +++ b/backend/demo-group7/src/main/java/com/group7/demo/dtos/UserTrainingProgramResponse.java @@ -0,0 +1,22 @@ +package com.group7.demo.dtos; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Data +@Builder +@AllArgsConstructor +public class UserTrainingProgramResponse { + private Long id; + private String title; + private List exercises; + private String description; + private String trainerUsername; + private List participants; + private boolean completed; + private LocalDateTime createdAt; +} diff --git a/backend/demo-group7/src/main/java/com/group7/demo/dtos/mapper/Mapper.java b/backend/demo-group7/src/main/java/com/group7/demo/dtos/mapper/Mapper.java index 3fc7d9f..fef59ac 100644 --- a/backend/demo-group7/src/main/java/com/group7/demo/dtos/mapper/Mapper.java +++ b/backend/demo-group7/src/main/java/com/group7/demo/dtos/mapper/Mapper.java @@ -5,6 +5,7 @@ import org.springframework.stereotype.Component; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; @Component @@ -45,4 +46,37 @@ public ExerciseDetail mapToExerciseDetailResponse(TrainingProgramExercise traini .sets(trainingProgramExercise.getSets()) .build(); } + + public UserTrainingProgramResponse mapToUserTrainingProgramResponse(UserTrainingProgram userTrainingProgram) { + TrainingProgram program = userTrainingProgram.getTrainingProgram(); + Map completedExercises = userTrainingProgram.getExerciseProgress(); // Now returns Map + + // Use the new mapper function for exercises + List exerciseDetails = program.getExercises().stream() + .map(exercise -> mapToUserExerciseDetailResponse(exercise, completedExercises)) + .collect(Collectors.toList()); + + return UserTrainingProgramResponse.builder() + .id(program.getId()) + .title(program.getTitle()) + .description(program.getDescription()) + .trainerUsername(program.getTrainer().getUsername()) + .participants(program.getParticipants().stream() + .map(participant -> participant.getUser().getUsername()) + .collect(Collectors.toList())) + .exercises(exerciseDetails) + .completed(userTrainingProgram.isCompleted()) + .createdAt(program.getCreatedAt()) + .build(); + } + + public UserExerciseDetail mapToUserExerciseDetailResponse(TrainingProgramExercise trainingProgramExercise, Map completedExercises) { + Long exerciseId = trainingProgramExercise.getExercise().getId(); + return UserExerciseDetail.builder() + .exercise(trainingProgramExercise.getExercise()) + .repetitions(trainingProgramExercise.getRepetitions()) + .sets(trainingProgramExercise.getSets()) + .completed(completedExercises.getOrDefault(exerciseId, false)) // Use `getOrDefault` to handle missing keys + .build(); + } } diff --git a/backend/demo-group7/src/main/java/com/group7/demo/models/UserTrainingProgram.java b/backend/demo-group7/src/main/java/com/group7/demo/models/UserTrainingProgram.java index 1d02559..249e254 100644 --- a/backend/demo-group7/src/main/java/com/group7/demo/models/UserTrainingProgram.java +++ b/backend/demo-group7/src/main/java/com/group7/demo/models/UserTrainingProgram.java @@ -1,5 +1,7 @@ package com.group7.demo.models; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Builder; @@ -7,6 +9,8 @@ import lombok.NoArgsConstructor; import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; @Entity @Builder @@ -27,5 +31,27 @@ public class UserTrainingProgram { @JoinColumn(name = "training_program_id", nullable = false) private TrainingProgram trainingProgram; + private boolean completed; + + @Lob + @Column(columnDefinition = "TEXT") + private String exerciseProgress; // JSON progress tracking + private LocalDateTime joinedAt; + + // Deserialize the JSON string into a Map + public Map getExerciseProgress() { + if (exerciseProgress == null) { + return new HashMap<>(); // return empty map if no progress is available + } + + try { + ObjectMapper objectMapper = new ObjectMapper(); + return objectMapper.readValue(exerciseProgress, new TypeReference>() {}); + } catch (Exception e) { + e.printStackTrace(); + return new HashMap<>(); // return empty map on error + } + } + } From 2381ec39085d36cb6b6e1a6a5f624a8cbfbfade2 Mon Sep 17 00:00:00 2001 From: oguzhekim Date: Sat, 23 Nov 2024 16:51:45 +0300 Subject: [PATCH 3/7] Use new DTOs and implement new endpoints for tracking --- .../TrainingProgramController.java | 36 ++++++ .../demo/services/TrainingProgramService.java | 122 +++++++++++++++++- .../com/group7/demo/services/UserService.java | 3 +- 3 files changed, 153 insertions(+), 8 deletions(-) diff --git a/backend/demo-group7/src/main/java/com/group7/demo/controllers/TrainingProgramController.java b/backend/demo-group7/src/main/java/com/group7/demo/controllers/TrainingProgramController.java index 9afa94a..263d998 100644 --- a/backend/demo-group7/src/main/java/com/group7/demo/controllers/TrainingProgramController.java +++ b/backend/demo-group7/src/main/java/com/group7/demo/controllers/TrainingProgramController.java @@ -81,4 +81,40 @@ public ResponseEntity> getTrainingProgramsByTraine return ResponseEntity.ok(trainingPrograms); } + @PostMapping("/{trainingProgramId}/exercises/{exerciseId}/complete") + public ResponseEntity markExerciseAsCompleted( + @PathVariable Long trainingProgramId, + @PathVariable Long exerciseId, + HttpServletRequest request + ) { + trainingProgramService.markExerciseAsCompleted(trainingProgramId, exerciseId, request); + return ResponseEntity.ok().build(); + } + + @PostMapping("/{trainingProgramId}/exercises/{exerciseId}/uncomplete") + public ResponseEntity unmarkExerciseAsCompleted( + @PathVariable Long trainingProgramId, + @PathVariable Long exerciseId, + HttpServletRequest request) { + trainingProgramService.unmarkExerciseAsCompleted(trainingProgramId, exerciseId, request); + return ResponseEntity.ok().build(); + } + + @PostMapping("/{trainingProgramId}/complete") + public ResponseEntity markTrainingProgramAsCompleted( + @PathVariable Long trainingProgramId, + HttpServletRequest request + ) { + trainingProgramService.markTrainingProgramAsCompleted(trainingProgramId, request); + return ResponseEntity.ok().build(); + } + + @PostMapping("/{trainingProgramId}/uncomplete") + public ResponseEntity unmarkTrainingProgramAsCompleted( + @PathVariable Long trainingProgramId, + HttpServletRequest request + ) { + trainingProgramService.unmarkTrainingProgramAsCompleted(trainingProgramId, request); + return ResponseEntity.ok().build(); + } } diff --git a/backend/demo-group7/src/main/java/com/group7/demo/services/TrainingProgramService.java b/backend/demo-group7/src/main/java/com/group7/demo/services/TrainingProgramService.java index 2ec93b4..ed65812 100644 --- a/backend/demo-group7/src/main/java/com/group7/demo/services/TrainingProgramService.java +++ b/backend/demo-group7/src/main/java/com/group7/demo/services/TrainingProgramService.java @@ -1,8 +1,8 @@ package com.group7.demo.services; -import com.group7.demo.dtos.ExerciseDetail; -import com.group7.demo.dtos.TrainingProgramRequest; -import com.group7.demo.dtos.TrainingProgramResponse; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.group7.demo.dtos.*; import com.group7.demo.dtos.mapper.Mapper; import com.group7.demo.models.*; import com.group7.demo.repository.ExerciseRepository; @@ -17,6 +17,7 @@ import java.time.LocalDateTime; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; @Service @@ -76,6 +77,7 @@ public TrainingProgramResponse createTrainingProgram(TrainingProgramRequest trai return mapper.mapToTrainingProgramResponse(savedProgram); } + @Transactional public List getAllTrainingPrograms() { // Fetch all training programs from the repository List trainingPrograms = trainingProgramRepository.findAll(); @@ -86,6 +88,7 @@ public List getAllTrainingPrograms() { .collect(Collectors.toList()); } + @Transactional public TrainingProgramResponse getTrainingProgramById(Long id) { // Find the training program by ID, or throw an exception if not found TrainingProgram trainingProgram = trainingProgramRepository.findById(id) @@ -133,11 +136,28 @@ public void joinTrainingProgram(Long trainingProgramId , HttpServletRequest requ throw new IllegalStateException("User has already joined the training program."); } + // Initialize the progress JSON object + ObjectMapper mapper = new ObjectMapper(); + Map exerciseProgress = trainingProgram.getExercises().stream() + .collect(Collectors.toMap( + exercise -> exercise.getExercise().getId(), // Exercise ID + exercise -> false // Not completed yet + )); + + String progressJson; + try { + progressJson = mapper.writeValueAsString(exerciseProgress); + } catch (JsonProcessingException e) { + throw new IllegalStateException("Failed to initialize exercise progress JSON", e); + } + // Create a new UserTrainingProgram entity UserTrainingProgram userTrainingProgram = UserTrainingProgram.builder() .user(user) .trainingProgram(trainingProgram) .joinedAt(LocalDateTime.now()) + .completed(false) + .exerciseProgress(progressJson) .build(); // Save the UserTrainingProgram entity @@ -161,6 +181,7 @@ public void leaveTrainingProgram(Long trainingProgramId, HttpServletRequest requ userTrainingProgramRepository.delete(userTrainingProgram); } + @Transactional public List getRegisteredUsernames(Long trainingProgramId) { // Fetch the training program by its ID TrainingProgram trainingProgram = trainingProgramRepository.findById(trainingProgramId) @@ -173,19 +194,106 @@ public List getRegisteredUsernames(Long trainingProgramId) { } // Return the list of joined training programs for the authenticated user - public List getJoinedTrainingPrograms(String username) throws Exception { + @Transactional + public List getJoinedTrainingPrograms(String username) throws Exception { // Fetch the authenticated user User user = userService.getUserByUsername(username); // Fetch the list of training programs the user has joined List userTrainingPrograms = userTrainingProgramRepository.findByUser(user); - // Map the list of UserTrainingProgram entities to TrainingProgramResponse DTOs + // Map the list of UserTrainingProgram entities to UserTrainingProgramResponse DTOs return userTrainingPrograms.stream() - .map(UserTrainingProgram::getTrainingProgram) - .map(mapper::mapToTrainingProgramResponse) + .map(mapper::mapToUserTrainingProgramResponse) // Map to UserTrainingProgramResponse instead of TrainingProgramResponse .collect(Collectors.toList()); } + @Transactional + public void markExerciseAsCompleted(Long trainingProgramId, Long exerciseId, HttpServletRequest request) { + User user = authenticationService.getAuthenticatedUserInternal(request); + + UserTrainingProgram userTrainingProgram = userTrainingProgramRepository.findByUserIdAndTrainingProgramId(user.getId(), trainingProgramId) + .orElseThrow(() -> new EntityNotFoundException("User Training Program not found")); + + // Get the current progress map + Map exerciseProgress = userTrainingProgram.getExerciseProgress(); + + // Mark the exercise as completed + exerciseProgress.put(exerciseId, true); + + // Serialize the updated exercise progress map back to JSON + ObjectMapper objectMapper = new ObjectMapper(); + try { + String updatedProgressJson = objectMapper.writeValueAsString(exerciseProgress); + userTrainingProgram.setExerciseProgress(updatedProgressJson); // Save the updated JSON string + } catch (Exception e) { + e.printStackTrace(); + // Handle exception, possibly throw a runtime exception or return an error response + } + + // Check if the whole program is completed + boolean allCompleted = exerciseProgress.values().stream().allMatch(Boolean::booleanValue); + if (allCompleted) { + userTrainingProgram.setCompleted(true); + } + + userTrainingProgramRepository.save(userTrainingProgram); + } + + @Transactional + public void unmarkExerciseAsCompleted(Long trainingProgramId, Long exerciseId, HttpServletRequest request) { + User user = authenticationService.getAuthenticatedUserInternal(request); + + UserTrainingProgram userTrainingProgram = userTrainingProgramRepository.findByUserIdAndTrainingProgramId(user.getId(), trainingProgramId) + .orElseThrow(() -> new EntityNotFoundException("User Training Program not found")); + + // Get the current progress map from the serialized exerciseProgress + Map exerciseProgress = userTrainingProgram.getExerciseProgress(); + + // Mark the exercise as incomplete (unmark) + exerciseProgress.put(exerciseId, false); + + // Serialize the updated progress map back to JSON + ObjectMapper objectMapper = new ObjectMapper(); + try { + String updatedProgressJson = objectMapper.writeValueAsString(exerciseProgress); + userTrainingProgram.setExerciseProgress(updatedProgressJson); // Save the updated JSON string + } catch (Exception e) { + e.printStackTrace(); + // Handle exception, possibly throw a runtime exception or return an error response + } + + // Check if the whole program is completed + boolean allCompleted = exerciseProgress.values().stream().allMatch(Boolean::booleanValue); + userTrainingProgram.setCompleted(allCompleted); + + userTrainingProgramRepository.save(userTrainingProgram); + } + + @Transactional + public void markTrainingProgramAsCompleted(Long trainingProgramId, HttpServletRequest request) { + User user = authenticationService.getAuthenticatedUserInternal(request); + + UserTrainingProgram userTrainingProgram = userTrainingProgramRepository.findByUserIdAndTrainingProgramId(user.getId(), trainingProgramId) + .orElseThrow(() -> new EntityNotFoundException("User Training Program not found")); + + // Mark the entire training program as completed + userTrainingProgram.setCompleted(true); + + userTrainingProgramRepository.save(userTrainingProgram); + } + + @Transactional + public void unmarkTrainingProgramAsCompleted(Long trainingProgramId, HttpServletRequest request) { + User user = authenticationService.getAuthenticatedUserInternal(request); + + UserTrainingProgram userTrainingProgram = userTrainingProgramRepository.findByUserIdAndTrainingProgramId(user.getId(), trainingProgramId) + .orElseThrow(() -> new EntityNotFoundException("User Training Program not found")); + + // Unmark the entire training program as completed + userTrainingProgram.setCompleted(false); + + userTrainingProgramRepository.save(userTrainingProgram); + } } diff --git a/backend/demo-group7/src/main/java/com/group7/demo/services/UserService.java b/backend/demo-group7/src/main/java/com/group7/demo/services/UserService.java index db84e79..0e5e4c4 100644 --- a/backend/demo-group7/src/main/java/com/group7/demo/services/UserService.java +++ b/backend/demo-group7/src/main/java/com/group7/demo/services/UserService.java @@ -3,6 +3,7 @@ import com.group7.demo.dtos.PostResponse; import com.group7.demo.dtos.TrainingProgramResponse; import com.group7.demo.dtos.UserProfileResponse; +import com.group7.demo.dtos.UserTrainingProgramResponse; import com.group7.demo.models.User; import com.group7.demo.repository.UserRepository; import jakarta.servlet.http.HttpServletRequest; @@ -48,7 +49,7 @@ public UserProfileResponse getUserProfile(String username) throws Exception { List posts = postService.getPostsByUser(user.getUsername()); List trainingPrograms = trainingProgramService.getTrainingProgramByTrainer(user.getUsername()); - List joinedPrograms = trainingProgramService.getJoinedTrainingPrograms(user.getUsername()); + List joinedPrograms = trainingProgramService.getJoinedTrainingPrograms(user.getUsername()); return UserProfileResponse.builder() .username(user.getUsername()) From 4826a21db8e7bee51a7627d45f64473b8bb1323b Mon Sep 17 00:00:00 2001 From: oguzhekim Date: Sun, 24 Nov 2024 14:07:39 +0300 Subject: [PATCH 4/7] Add enum logic for status of the user training program --- .../TrainingProgramController.java | 18 +++-- .../dtos/UserTrainingProgramResponse.java | 3 +- .../com/group7/demo/dtos/mapper/Mapper.java | 2 +- .../demo/models/UserTrainingProgram.java | 5 +- .../enums/UserTrainingProgramStatus.java | 7 ++ .../UserTrainingProgramRepository.java | 3 +- .../demo/services/TrainingProgramService.java | 76 ++++++++++--------- 7 files changed, 65 insertions(+), 49 deletions(-) create mode 100644 backend/demo-group7/src/main/java/com/group7/demo/models/enums/UserTrainingProgramStatus.java diff --git a/backend/demo-group7/src/main/java/com/group7/demo/controllers/TrainingProgramController.java b/backend/demo-group7/src/main/java/com/group7/demo/controllers/TrainingProgramController.java index 263d998..8a64a5e 100644 --- a/backend/demo-group7/src/main/java/com/group7/demo/controllers/TrainingProgramController.java +++ b/backend/demo-group7/src/main/java/com/group7/demo/controllers/TrainingProgramController.java @@ -2,6 +2,7 @@ import com.group7.demo.dtos.TrainingProgramRequest; import com.group7.demo.dtos.TrainingProgramResponse; +import com.group7.demo.dtos.UserTrainingProgramResponse; import com.group7.demo.services.TrainingProgramService; import jakarta.servlet.http.HttpServletRequest; import lombok.AllArgsConstructor; @@ -9,6 +10,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import java.util.Collections; import java.util.List; @RestController @@ -109,12 +111,14 @@ public ResponseEntity markTrainingProgramAsCompleted( return ResponseEntity.ok().build(); } - @PostMapping("/{trainingProgramId}/uncomplete") - public ResponseEntity unmarkTrainingProgramAsCompleted( - @PathVariable Long trainingProgramId, - HttpServletRequest request - ) { - trainingProgramService.unmarkTrainingProgramAsCompleted(trainingProgramId, request); - return ResponseEntity.ok().build(); + @GetMapping("/joined/{username}") + public ResponseEntity> getJoinedTrainingPrograms(@PathVariable String username) { + try { + List responses = trainingProgramService.getJoinedTrainingPrograms(username); + return ResponseEntity.ok(responses); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(Collections.emptyList()); + } } } diff --git a/backend/demo-group7/src/main/java/com/group7/demo/dtos/UserTrainingProgramResponse.java b/backend/demo-group7/src/main/java/com/group7/demo/dtos/UserTrainingProgramResponse.java index 014c31f..2933a02 100644 --- a/backend/demo-group7/src/main/java/com/group7/demo/dtos/UserTrainingProgramResponse.java +++ b/backend/demo-group7/src/main/java/com/group7/demo/dtos/UserTrainingProgramResponse.java @@ -1,5 +1,6 @@ package com.group7.demo.dtos; +import com.group7.demo.models.enums.UserTrainingProgramStatus; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -17,6 +18,6 @@ public class UserTrainingProgramResponse { private String description; private String trainerUsername; private List participants; - private boolean completed; + private UserTrainingProgramStatus status; private LocalDateTime createdAt; } diff --git a/backend/demo-group7/src/main/java/com/group7/demo/dtos/mapper/Mapper.java b/backend/demo-group7/src/main/java/com/group7/demo/dtos/mapper/Mapper.java index fef59ac..77d9bb0 100644 --- a/backend/demo-group7/src/main/java/com/group7/demo/dtos/mapper/Mapper.java +++ b/backend/demo-group7/src/main/java/com/group7/demo/dtos/mapper/Mapper.java @@ -65,7 +65,7 @@ public UserTrainingProgramResponse mapToUserTrainingProgramResponse(UserTraining .map(participant -> participant.getUser().getUsername()) .collect(Collectors.toList())) .exercises(exerciseDetails) - .completed(userTrainingProgram.isCompleted()) + .status(userTrainingProgram.getStatus()) .createdAt(program.getCreatedAt()) .build(); } diff --git a/backend/demo-group7/src/main/java/com/group7/demo/models/UserTrainingProgram.java b/backend/demo-group7/src/main/java/com/group7/demo/models/UserTrainingProgram.java index 249e254..db5e3c8 100644 --- a/backend/demo-group7/src/main/java/com/group7/demo/models/UserTrainingProgram.java +++ b/backend/demo-group7/src/main/java/com/group7/demo/models/UserTrainingProgram.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import com.group7.demo.models.enums.UserTrainingProgramStatus; import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Builder; @@ -31,7 +32,9 @@ public class UserTrainingProgram { @JoinColumn(name = "training_program_id", nullable = false) private TrainingProgram trainingProgram; - private boolean completed; + @Enumerated(EnumType.STRING) + @Column(nullable = false) + private UserTrainingProgramStatus status; @Lob @Column(columnDefinition = "TEXT") diff --git a/backend/demo-group7/src/main/java/com/group7/demo/models/enums/UserTrainingProgramStatus.java b/backend/demo-group7/src/main/java/com/group7/demo/models/enums/UserTrainingProgramStatus.java new file mode 100644 index 0000000..ae137c4 --- /dev/null +++ b/backend/demo-group7/src/main/java/com/group7/demo/models/enums/UserTrainingProgramStatus.java @@ -0,0 +1,7 @@ +package com.group7.demo.models.enums; + +public enum UserTrainingProgramStatus { + ONGOING, + LEFT, + COMPLETED +} diff --git a/backend/demo-group7/src/main/java/com/group7/demo/repository/UserTrainingProgramRepository.java b/backend/demo-group7/src/main/java/com/group7/demo/repository/UserTrainingProgramRepository.java index 2bb87f6..94e9538 100644 --- a/backend/demo-group7/src/main/java/com/group7/demo/repository/UserTrainingProgramRepository.java +++ b/backend/demo-group7/src/main/java/com/group7/demo/repository/UserTrainingProgramRepository.java @@ -1,6 +1,5 @@ package com.group7.demo.repository; -import com.group7.demo.models.TrainingProgram; import com.group7.demo.models.User; import com.group7.demo.models.UserTrainingProgram; import org.springframework.data.jpa.repository.JpaRepository; @@ -9,7 +8,7 @@ import java.util.Optional; public interface UserTrainingProgramRepository extends JpaRepository { - boolean existsByUserAndTrainingProgram(User user, TrainingProgram trainingProgram); + List findAllByUserAndTrainingProgramId(User user, Long trainingProgramId); Optional findByUserIdAndTrainingProgramId(Long userId, Long programId); List findByUser(User user); diff --git a/backend/demo-group7/src/main/java/com/group7/demo/services/TrainingProgramService.java b/backend/demo-group7/src/main/java/com/group7/demo/services/TrainingProgramService.java index ed65812..f20a4ea 100644 --- a/backend/demo-group7/src/main/java/com/group7/demo/services/TrainingProgramService.java +++ b/backend/demo-group7/src/main/java/com/group7/demo/services/TrainingProgramService.java @@ -5,6 +5,7 @@ import com.group7.demo.dtos.*; import com.group7.demo.dtos.mapper.Mapper; import com.group7.demo.models.*; +import com.group7.demo.models.enums.UserTrainingProgramStatus; import com.group7.demo.repository.ExerciseRepository; import com.group7.demo.repository.TrainingProgramRepository; import com.group7.demo.repository.UserTrainingProgramRepository; @@ -131,9 +132,14 @@ public void joinTrainingProgram(Long trainingProgramId , HttpServletRequest requ TrainingProgram trainingProgram = trainingProgramRepository.findById(trainingProgramId) .orElseThrow(() -> new EntityNotFoundException("Training Program not found with id: " + trainingProgramId)); - boolean alreadyJoined = userTrainingProgramRepository.existsByUserAndTrainingProgram(user, trainingProgram); - if (alreadyJoined) { - throw new IllegalStateException("User has already joined the training program."); + // Check for all past participations + List pastEntries = userTrainingProgramRepository.findAllByUserAndTrainingProgramId(user, trainingProgramId); + + boolean hasOngoingEntry = pastEntries.stream() + .anyMatch(entry -> entry.getStatus() == UserTrainingProgramStatus.ONGOING); + + if (hasOngoingEntry) { + throw new IllegalStateException("User is already actively participating in this training program."); } // Initialize the progress JSON object @@ -156,7 +162,7 @@ public void joinTrainingProgram(Long trainingProgramId , HttpServletRequest requ .user(user) .trainingProgram(trainingProgram) .joinedAt(LocalDateTime.now()) - .completed(false) + .status(UserTrainingProgramStatus.ONGOING) .exerciseProgress(progressJson) .build(); @@ -164,23 +170,6 @@ public void joinTrainingProgram(Long trainingProgramId , HttpServletRequest requ userTrainingProgramRepository.save(userTrainingProgram); } - @Transactional - public void leaveTrainingProgram(Long trainingProgramId, HttpServletRequest request) { - // Fetch the authenticated user from the request - User user = authenticationService.getAuthenticatedUserInternal(request); - - // Fetch the training program by its ID - TrainingProgram trainingProgram = trainingProgramRepository.findById(trainingProgramId) - .orElseThrow(() -> new EntityNotFoundException("Training program not found with id: " + trainingProgramId)); - - // Check if the user is participating in the program - UserTrainingProgram userTrainingProgram = userTrainingProgramRepository.findByUserIdAndTrainingProgramId(user.getId(), trainingProgram.getId()) - .orElseThrow(() -> new IllegalStateException("User is not participating in this program.")); - - // Remove the user from the program - userTrainingProgramRepository.delete(userTrainingProgram); - } - @Transactional public List getRegisteredUsernames(Long trainingProgramId) { // Fetch the training program by its ID @@ -208,12 +197,20 @@ public List getJoinedTrainingPrograms(String userna .collect(Collectors.toList()); } + private UserTrainingProgram getOngoingUserTrainingProgram(User user, Long trainingProgramId) { + // Fetch all entries and filter the ongoing one + return userTrainingProgramRepository.findAllByUserAndTrainingProgramId(user, trainingProgramId) + .stream() + .filter(entry -> entry.getStatus() == UserTrainingProgramStatus.ONGOING) + .findFirst() + .orElseThrow(() -> new IllegalStateException("No ongoing training program found.")); + } + @Transactional public void markExerciseAsCompleted(Long trainingProgramId, Long exerciseId, HttpServletRequest request) { User user = authenticationService.getAuthenticatedUserInternal(request); - UserTrainingProgram userTrainingProgram = userTrainingProgramRepository.findByUserIdAndTrainingProgramId(user.getId(), trainingProgramId) - .orElseThrow(() -> new EntityNotFoundException("User Training Program not found")); + UserTrainingProgram userTrainingProgram = getOngoingUserTrainingProgram(user, trainingProgramId); // Get the current progress map Map exerciseProgress = userTrainingProgram.getExerciseProgress(); @@ -227,25 +224,26 @@ public void markExerciseAsCompleted(Long trainingProgramId, Long exerciseId, Htt String updatedProgressJson = objectMapper.writeValueAsString(exerciseProgress); userTrainingProgram.setExerciseProgress(updatedProgressJson); // Save the updated JSON string } catch (Exception e) { - e.printStackTrace(); - // Handle exception, possibly throw a runtime exception or return an error response + throw new IllegalStateException("Failed to update exercise progress JSON", e); } + //TODO: Is it needed? // Check if the whole program is completed boolean allCompleted = exerciseProgress.values().stream().allMatch(Boolean::booleanValue); if (allCompleted) { - userTrainingProgram.setCompleted(true); + userTrainingProgram.setStatus(UserTrainingProgramStatus.COMPLETED); } userTrainingProgramRepository.save(userTrainingProgram); } + + @Transactional public void unmarkExerciseAsCompleted(Long trainingProgramId, Long exerciseId, HttpServletRequest request) { User user = authenticationService.getAuthenticatedUserInternal(request); - UserTrainingProgram userTrainingProgram = userTrainingProgramRepository.findByUserIdAndTrainingProgramId(user.getId(), trainingProgramId) - .orElseThrow(() -> new EntityNotFoundException("User Training Program not found")); + UserTrainingProgram userTrainingProgram = getOngoingUserTrainingProgram(user, trainingProgramId); // Get the current progress map from the serialized exerciseProgress Map exerciseProgress = userTrainingProgram.getExerciseProgress(); @@ -263,9 +261,14 @@ public void unmarkExerciseAsCompleted(Long trainingProgramId, Long exerciseId, H // Handle exception, possibly throw a runtime exception or return an error response } + //TODO: ask if it is needed // Check if the whole program is completed boolean allCompleted = exerciseProgress.values().stream().allMatch(Boolean::booleanValue); - userTrainingProgram.setCompleted(allCompleted); + if (allCompleted){ + userTrainingProgram.setStatus(UserTrainingProgramStatus.COMPLETED); + } else { + userTrainingProgram.setStatus(UserTrainingProgramStatus.ONGOING); + } userTrainingProgramRepository.save(userTrainingProgram); } @@ -274,24 +277,23 @@ public void unmarkExerciseAsCompleted(Long trainingProgramId, Long exerciseId, H public void markTrainingProgramAsCompleted(Long trainingProgramId, HttpServletRequest request) { User user = authenticationService.getAuthenticatedUserInternal(request); - UserTrainingProgram userTrainingProgram = userTrainingProgramRepository.findByUserIdAndTrainingProgramId(user.getId(), trainingProgramId) - .orElseThrow(() -> new EntityNotFoundException("User Training Program not found")); + UserTrainingProgram userTrainingProgram = getOngoingUserTrainingProgram(user, trainingProgramId); // Mark the entire training program as completed - userTrainingProgram.setCompleted(true); + userTrainingProgram.setStatus(UserTrainingProgramStatus.COMPLETED); userTrainingProgramRepository.save(userTrainingProgram); } @Transactional - public void unmarkTrainingProgramAsCompleted(Long trainingProgramId, HttpServletRequest request) { + public void leaveTrainingProgram(Long trainingProgramId, HttpServletRequest request) { User user = authenticationService.getAuthenticatedUserInternal(request); - UserTrainingProgram userTrainingProgram = userTrainingProgramRepository.findByUserIdAndTrainingProgramId(user.getId(), trainingProgramId) - .orElseThrow(() -> new EntityNotFoundException("User Training Program not found")); + UserTrainingProgram userTrainingProgram = getOngoingUserTrainingProgram(user, trainingProgramId); + - // Unmark the entire training program as completed - userTrainingProgram.setCompleted(false); + // Mark the training program as left + userTrainingProgram.setStatus(UserTrainingProgramStatus.LEFT); userTrainingProgramRepository.save(userTrainingProgram); } From 83951de66f90634dcf1562a4bd5ce4d62d162f2a Mon Sep 17 00:00:00 2001 From: oguzhekim Date: Sun, 24 Nov 2024 14:12:33 +0300 Subject: [PATCH 5/7] Removed auto completing program on exercises completion --- .../demo/services/TrainingProgramService.java | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/backend/demo-group7/src/main/java/com/group7/demo/services/TrainingProgramService.java b/backend/demo-group7/src/main/java/com/group7/demo/services/TrainingProgramService.java index f20a4ea..03551ba 100644 --- a/backend/demo-group7/src/main/java/com/group7/demo/services/TrainingProgramService.java +++ b/backend/demo-group7/src/main/java/com/group7/demo/services/TrainingProgramService.java @@ -227,13 +227,6 @@ public void markExerciseAsCompleted(Long trainingProgramId, Long exerciseId, Htt throw new IllegalStateException("Failed to update exercise progress JSON", e); } - //TODO: Is it needed? - // Check if the whole program is completed - boolean allCompleted = exerciseProgress.values().stream().allMatch(Boolean::booleanValue); - if (allCompleted) { - userTrainingProgram.setStatus(UserTrainingProgramStatus.COMPLETED); - } - userTrainingProgramRepository.save(userTrainingProgram); } @@ -261,15 +254,6 @@ public void unmarkExerciseAsCompleted(Long trainingProgramId, Long exerciseId, H // Handle exception, possibly throw a runtime exception or return an error response } - //TODO: ask if it is needed - // Check if the whole program is completed - boolean allCompleted = exerciseProgress.values().stream().allMatch(Boolean::booleanValue); - if (allCompleted){ - userTrainingProgram.setStatus(UserTrainingProgramStatus.COMPLETED); - } else { - userTrainingProgram.setStatus(UserTrainingProgramStatus.ONGOING); - } - userTrainingProgramRepository.save(userTrainingProgram); } From 5dd8347354aa7850fe1c2f4b675f648d84c8ef62 Mon Sep 17 00:00:00 2001 From: oguzhekim Date: Sun, 24 Nov 2024 15:28:23 +0300 Subject: [PATCH 6/7] Ensured order of exercises in training program --- .../main/java/com/group7/demo/dtos/ExerciseDetail.java | 1 + .../java/com/group7/demo/dtos/UserExerciseDetail.java | 1 + .../src/main/java/com/group7/demo/dtos/mapper/Mapper.java | 8 ++++++-- .../com/group7/demo/services/TrainingProgramService.java | 4 ++-- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/backend/demo-group7/src/main/java/com/group7/demo/dtos/ExerciseDetail.java b/backend/demo-group7/src/main/java/com/group7/demo/dtos/ExerciseDetail.java index 2aee738..5593e60 100644 --- a/backend/demo-group7/src/main/java/com/group7/demo/dtos/ExerciseDetail.java +++ b/backend/demo-group7/src/main/java/com/group7/demo/dtos/ExerciseDetail.java @@ -9,6 +9,7 @@ @Builder @AllArgsConstructor public class ExerciseDetail { + private Long id; private Exercise exercise; private int repetitions; private int sets; diff --git a/backend/demo-group7/src/main/java/com/group7/demo/dtos/UserExerciseDetail.java b/backend/demo-group7/src/main/java/com/group7/demo/dtos/UserExerciseDetail.java index 2f2ec5f..3110975 100644 --- a/backend/demo-group7/src/main/java/com/group7/demo/dtos/UserExerciseDetail.java +++ b/backend/demo-group7/src/main/java/com/group7/demo/dtos/UserExerciseDetail.java @@ -9,6 +9,7 @@ @Builder @AllArgsConstructor public class UserExerciseDetail { + private Long id; private Exercise exercise; private int repetitions; private int sets; diff --git a/backend/demo-group7/src/main/java/com/group7/demo/dtos/mapper/Mapper.java b/backend/demo-group7/src/main/java/com/group7/demo/dtos/mapper/Mapper.java index 77d9bb0..ee527f9 100644 --- a/backend/demo-group7/src/main/java/com/group7/demo/dtos/mapper/Mapper.java +++ b/backend/demo-group7/src/main/java/com/group7/demo/dtos/mapper/Mapper.java @@ -4,6 +4,7 @@ import com.group7.demo.models.*; import org.springframework.stereotype.Component; +import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -30,6 +31,7 @@ public TrainingProgramResponse mapToTrainingProgramResponse(TrainingProgram prog .createdAt(program.getCreatedAt()) .exercises(program.getExercises().stream() .map(this::mapToExerciseDetailResponse) + .sorted(Comparator.comparing(ExerciseDetail::getId)) .collect(Collectors.toList())) .participants(program.getParticipants() == null ? List.of() : @@ -41,6 +43,7 @@ public TrainingProgramResponse mapToTrainingProgramResponse(TrainingProgram prog public ExerciseDetail mapToExerciseDetailResponse(TrainingProgramExercise trainingProgramExercise) { return ExerciseDetail.builder() + .id(trainingProgramExercise.getId()) .exercise(trainingProgramExercise.getExercise()) .repetitions(trainingProgramExercise.getRepetitions()) .sets(trainingProgramExercise.getSets()) @@ -54,6 +57,7 @@ public UserTrainingProgramResponse mapToUserTrainingProgramResponse(UserTraining // Use the new mapper function for exercises List exerciseDetails = program.getExercises().stream() .map(exercise -> mapToUserExerciseDetailResponse(exercise, completedExercises)) + .sorted(Comparator.comparing(UserExerciseDetail::getId)) .collect(Collectors.toList()); return UserTrainingProgramResponse.builder() @@ -71,12 +75,12 @@ public UserTrainingProgramResponse mapToUserTrainingProgramResponse(UserTraining } public UserExerciseDetail mapToUserExerciseDetailResponse(TrainingProgramExercise trainingProgramExercise, Map completedExercises) { - Long exerciseId = trainingProgramExercise.getExercise().getId(); return UserExerciseDetail.builder() + .id(trainingProgramExercise.getId()) .exercise(trainingProgramExercise.getExercise()) .repetitions(trainingProgramExercise.getRepetitions()) .sets(trainingProgramExercise.getSets()) - .completed(completedExercises.getOrDefault(exerciseId, false)) // Use `getOrDefault` to handle missing keys + .completed(completedExercises.getOrDefault(trainingProgramExercise.getId(), false)) // Use `getOrDefault` to handle missing keys .build(); } } diff --git a/backend/demo-group7/src/main/java/com/group7/demo/services/TrainingProgramService.java b/backend/demo-group7/src/main/java/com/group7/demo/services/TrainingProgramService.java index 03551ba..39fa1e3 100644 --- a/backend/demo-group7/src/main/java/com/group7/demo/services/TrainingProgramService.java +++ b/backend/demo-group7/src/main/java/com/group7/demo/services/TrainingProgramService.java @@ -146,8 +146,8 @@ public void joinTrainingProgram(Long trainingProgramId , HttpServletRequest requ ObjectMapper mapper = new ObjectMapper(); Map exerciseProgress = trainingProgram.getExercises().stream() .collect(Collectors.toMap( - exercise -> exercise.getExercise().getId(), // Exercise ID - exercise -> false // Not completed yet + TrainingProgramExercise::getId, // Exercise ID + TrainingProgramExercise -> false // Not completed yet )); String progressJson; From 99877ee5b2a1d64f1348acf515fc5f3023be073d Mon Sep 17 00:00:00 2001 From: oguzhekim Date: Sun, 24 Nov 2024 15:53:47 +0300 Subject: [PATCH 7/7] Removed duplicates in participants field --- .../group7/demo/controllers/TrainingProgramController.java | 5 +++-- .../java/com/group7/demo/dtos/TrainingProgramResponse.java | 3 ++- .../com/group7/demo/dtos/UserTrainingProgramResponse.java | 3 ++- .../src/main/java/com/group7/demo/dtos/mapper/Mapper.java | 7 ++++--- .../com/group7/demo/services/TrainingProgramService.java | 5 +++-- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/backend/demo-group7/src/main/java/com/group7/demo/controllers/TrainingProgramController.java b/backend/demo-group7/src/main/java/com/group7/demo/controllers/TrainingProgramController.java index 8a64a5e..94e5320 100644 --- a/backend/demo-group7/src/main/java/com/group7/demo/controllers/TrainingProgramController.java +++ b/backend/demo-group7/src/main/java/com/group7/demo/controllers/TrainingProgramController.java @@ -12,6 +12,7 @@ import java.util.Collections; import java.util.List; +import java.util.Set; @RestController @RequestMapping("/api/training-programs") @@ -71,8 +72,8 @@ public ResponseEntity leaveProgram(@PathVariable Long programId, HttpSer } @GetMapping("/{programId}/participants") - public ResponseEntity> getRegisteredUsernames(@PathVariable Long programId) { - List usernames = trainingProgramService.getRegisteredUsernames(programId); + public ResponseEntity> getRegisteredUsernames(@PathVariable Long programId) { + Set usernames = trainingProgramService.getRegisteredUsernames(programId); return ResponseEntity.ok(usernames); } diff --git a/backend/demo-group7/src/main/java/com/group7/demo/dtos/TrainingProgramResponse.java b/backend/demo-group7/src/main/java/com/group7/demo/dtos/TrainingProgramResponse.java index 84faf29..efb4586 100644 --- a/backend/demo-group7/src/main/java/com/group7/demo/dtos/TrainingProgramResponse.java +++ b/backend/demo-group7/src/main/java/com/group7/demo/dtos/TrainingProgramResponse.java @@ -6,6 +6,7 @@ import java.time.LocalDateTime; import java.util.List; +import java.util.Set; @Data @Builder @@ -16,6 +17,6 @@ public class TrainingProgramResponse { private List exercises; private String description; private String trainerUsername; - private List participants; + private Set participants; private LocalDateTime createdAt; } \ No newline at end of file diff --git a/backend/demo-group7/src/main/java/com/group7/demo/dtos/UserTrainingProgramResponse.java b/backend/demo-group7/src/main/java/com/group7/demo/dtos/UserTrainingProgramResponse.java index 2933a02..02bb190 100644 --- a/backend/demo-group7/src/main/java/com/group7/demo/dtos/UserTrainingProgramResponse.java +++ b/backend/demo-group7/src/main/java/com/group7/demo/dtos/UserTrainingProgramResponse.java @@ -7,6 +7,7 @@ import java.time.LocalDateTime; import java.util.List; +import java.util.Set; @Data @Builder @@ -17,7 +18,7 @@ public class UserTrainingProgramResponse { private List exercises; private String description; private String trainerUsername; - private List participants; + private Set participants; private UserTrainingProgramStatus status; private LocalDateTime createdAt; } diff --git a/backend/demo-group7/src/main/java/com/group7/demo/dtos/mapper/Mapper.java b/backend/demo-group7/src/main/java/com/group7/demo/dtos/mapper/Mapper.java index ee527f9..e6ee821 100644 --- a/backend/demo-group7/src/main/java/com/group7/demo/dtos/mapper/Mapper.java +++ b/backend/demo-group7/src/main/java/com/group7/demo/dtos/mapper/Mapper.java @@ -7,6 +7,7 @@ import java.util.Comparator; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; @Component @@ -34,10 +35,10 @@ public TrainingProgramResponse mapToTrainingProgramResponse(TrainingProgram prog .sorted(Comparator.comparing(ExerciseDetail::getId)) .collect(Collectors.toList())) .participants(program.getParticipants() == null ? - List.of() : + Set.of() : program.getParticipants().stream() .map(userTrainingProgram -> userTrainingProgram.getUser().getUsername()) - .collect(Collectors.toList())) + .collect(Collectors.toSet())) .build(); } @@ -67,7 +68,7 @@ public UserTrainingProgramResponse mapToUserTrainingProgramResponse(UserTraining .trainerUsername(program.getTrainer().getUsername()) .participants(program.getParticipants().stream() .map(participant -> participant.getUser().getUsername()) - .collect(Collectors.toList())) + .collect(Collectors.toSet())) .exercises(exerciseDetails) .status(userTrainingProgram.getStatus()) .createdAt(program.getCreatedAt()) diff --git a/backend/demo-group7/src/main/java/com/group7/demo/services/TrainingProgramService.java b/backend/demo-group7/src/main/java/com/group7/demo/services/TrainingProgramService.java index 39fa1e3..8091645 100644 --- a/backend/demo-group7/src/main/java/com/group7/demo/services/TrainingProgramService.java +++ b/backend/demo-group7/src/main/java/com/group7/demo/services/TrainingProgramService.java @@ -19,6 +19,7 @@ import java.time.LocalDateTime; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; @Service @@ -171,7 +172,7 @@ public void joinTrainingProgram(Long trainingProgramId , HttpServletRequest requ } @Transactional - public List getRegisteredUsernames(Long trainingProgramId) { + public Set getRegisteredUsernames(Long trainingProgramId) { // Fetch the training program by its ID TrainingProgram trainingProgram = trainingProgramRepository.findById(trainingProgramId) .orElseThrow(() -> new EntityNotFoundException("Training program not found with id: " + trainingProgramId)); @@ -179,7 +180,7 @@ public List getRegisteredUsernames(Long trainingProgramId) { // Fetch the list of participants' usernames return trainingProgram.getParticipants().stream() .map(userTrainingProgram -> userTrainingProgram.getUser().getUsername()) - .collect(Collectors.toList()); + .collect(Collectors.toSet()); } // Return the list of joined training programs for the authenticated user